Vince's CSV Parser
Loading...
Searching...
No Matches
csv_row.hpp
Go to the documentation of this file.
1
5#pragma once
6#include <chrono>
7#include <cstddef>
8#include <cstdint>
9#include <cmath>
10#include <iterator>
11#include <memory> // For CSVField
12#include <limits> // For CSVField
13#include <unordered_set>
14#include <string>
15#include <sstream>
16#include <vector>
17
18#include "common.hpp"
19#ifdef CSV_HAS_CXX17
20#include <optional>
21#endif
22#ifdef CSV_HAS_CXX23
23#if defined(__has_include)
24#if __has_include(<expected>)
25#include <expected>
26#ifdef __cpp_lib_expected
27#define CSV_HAS_STD_EXPECTED
28#endif
29#endif
30#endif
31#endif
32#include "csv_exceptions.hpp"
33#ifdef CSV_HAS_CXX20
34#include <ranges>
35#endif
36#include "data_type.hpp"
37#include "../external/classify_scalar.hpp"
38#include "json_converter.hpp"
39#include "raw_csv_data.hpp"
40
41namespace csv {
42 namespace internals {
43 template<typename RowSink, typename ParsePolicy, typename FieldPolicy, typename RowPolicy>
44 class CSVParserCore;
45 struct CSVRowRowPolicy;
46 namespace parser {
47 class CSVParserDriverBase;
48 }
49 namespace speculative {
50 struct CSVRowFragment;
51 }
52
53 namespace data_frame { struct RowViewAccessor; }
54
55 static const std::string ERROR_NAN = "Not a number.";
56 static const std::string ERROR_OVERFLOW = "Overflow error.";
57 static const std::string ERROR_FLOAT_TO_INT =
58 "Attempted to convert a floating point value to an integral type.";
59 static const std::string ERROR_NEG_TO_UNSIGNED = "Negative numbers cannot be converted to unsigned types.";
60
61 // Applied when CSVRow exposes a field view with configured whitespace trimming.
62 csv::string_view get_trimmed(csv::string_view sv, const WhitespaceMap& ws_flags) noexcept;
63 }
64
74 class CSVField {
75 public:
77 constexpr explicit CSVField(csv::string_view _sv) noexcept
78 : sv(_sv.data() ? _sv : csv::string_view("")) {}
79
80 CSVField(csv::string_view _sv, const internals::CSVFieldScalar& scalar) noexcept
81 : sv(_sv.data() ? _sv : csv::string_view("")),
82 type_(scalar.type) {
83 switch (scalar.type) {
88 this->value_.integer = scalar.integer;
89 break;
92 this->value_.floating = scalar.floating;
93 break;
95 this->value_.timestamp = scalar.timestamp;
96 break;
98 this->value_.boolean = scalar.boolean;
99 break;
100 default:
101 break;
102 }
103 }
104
105 operator csv::string_view() const noexcept {
106 return this->sv;
107 }
108
109 operator std::string() const {
110 return std::string(this->sv);
111 }
112
139#if CSV_EXCEPTIONS_ENABLED
140 template<typename T = std::string> T get() const {
141 T out{};
143 try_get(out, err);
144 if (err != CSVConversionError::None) throw std::runtime_error(csv_conversion_error_message(err));
145 return out;
146 }
147#endif
148
149#ifdef CSV_HAS_STD_EXPECTED
161 template<typename T = std::string>
162 std::expected<T, CSVConversionError> as() const {
163 T out{};
165 try_get(out, err);
166 return (err != CSVConversionError::None)
167 ? std::expected<T, CSVConversionError>(std::unexpected(err))
168 : std::expected<T, CSVConversionError>(out);
169 }
170#endif
171
187 template<typename T = std::string>
188 bool try_get(T& out) const noexcept {
189 CSVConversionError error;
190 return try_get(out, error);
191 }
192
196 template<typename T>
197 bool try_get(T& out, CSVConversionError& error) const noexcept {
198 error = check_convert(out);
199 return error == CSVConversionError::None;
200 }
201
202#ifdef CSV_HAS_CXX17
211 template<typename T>
212 operator std::optional<T>() const {
213 T out{};
214 return try_get(out) ? std::optional<T>(out) : std::nullopt;
215 }
216#endif
217
221 template<typename T = long long>
222 bool try_parse_hex(T& parsedValue) const {
223 static_assert(std::is_integral<T>::value,
224 "try_parse_hex only works with integral types (int, long, long long, etc.)");
225
226 return classify_scalar::parse_hex(this->sv.data(), this->sv.data() + this->sv.size(), parsedValue);
227 }
228
235 bool try_parse_decimal(long double& dVal, const char decimalSymbol = '.');
236
242 bool try_parse_timestamp(std::uint64_t& out) const noexcept;
243
245#ifdef DOXYGEN_SHOULD_SKIP_THIS
246 template<typename T>
247 bool try_parse_timestamp(T& out) const noexcept;
248#else
249 template<typename T>
250 internals::enable_if_t<
251 std::is_integral<T>::value && std::is_unsigned<T>::value && !std::is_same<T, bool>::value
252 && (sizeof(T) >= sizeof(std::uint64_t)),
253 bool
254 >
255 try_parse_timestamp(T& out) const noexcept {
256 std::uint64_t milliseconds = 0;
257 if (!this->try_parse_timestamp(milliseconds))
258 return false;
259
260 out = static_cast<T>(milliseconds);
261 return true;
262 }
263#endif
264
266 template<typename Rep, typename Period>
267 bool try_parse_timestamp(std::chrono::duration<Rep, Period>& out) const noexcept {
268 std::uint64_t milliseconds = 0;
269 if (!this->try_parse_timestamp(milliseconds))
270 return false;
271
272 out = std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(
273 std::chrono::milliseconds(milliseconds));
274 return true;
275 }
276
278 template<typename Duration>
279 bool try_parse_timestamp(std::chrono::time_point<std::chrono::system_clock, Duration>& out) const noexcept {
280 std::uint64_t milliseconds = 0;
281 if (!this->try_parse_timestamp(milliseconds))
282 return false;
283
284 out = std::chrono::time_point<std::chrono::system_clock, Duration>(
285 std::chrono::duration_cast<Duration>(std::chrono::milliseconds(milliseconds)));
286 return true;
287 }
288
302 template<typename T>
303 inline bool operator==(T other) const noexcept
304 {
305 static_assert(std::is_arithmetic<T>::value,
306 "T should be a numeric value.");
307
308 this->get_value();
309 if (this->type_ < DataType::CSV_INT8 || this->type_ > DataType::CSV_DOUBLE || this->type_ == DataType::CSV_BIGINT) {
310 return false;
311 }
312
313 return internals::is_equal(this->numeric_value_as_long_double(), static_cast<long double>(other), 0.000001L);
314 }
315
317 CONSTEXPR csv::string_view get_sv() const noexcept { return this->sv; }
318
320 inline bool is_null() const noexcept { return type() == DataType::CSV_NULL; }
321
323 inline bool is_str() const noexcept { return type() == DataType::CSV_STRING; }
324
326 inline bool is_num() const noexcept {
328 }
329
331 inline bool is_int() const noexcept {
332 return (type() >= DataType::CSV_INT8) && (type() <= DataType::CSV_INT64);
333 }
334
336 inline bool is_float() const noexcept { return type() == DataType::CSV_DOUBLE; }
337
339 inline bool is_bool() const noexcept { return type() == DataType::CSV_BOOL; }
340
342 inline bool is_timestamp() const noexcept { return type() == DataType::CSV_TIMESTAMP; }
343
345 inline DataType type() const noexcept {
346 this->get_value();
347 return type_;
348 }
349
350 private:
351 // GCC emits a psABI note for by-value APIs involving unions with long double.
352 // This is a workaround to keep the logs clean without sacrificing the benefits of a union on other compilers.
353 // Give only GCC users the struct tax so normal builds and strict CI logs stay quiet.
354#if defined(__GNUC__) && !defined(__clang__)
355 struct FieldValue {
356 constexpr FieldValue() noexcept
357 : integer(0), floating(0), timestamp(0), boolean(false) {}
358
359 std::int64_t integer;
360 long double floating;
361 std::uint64_t timestamp;
362 bool boolean;
363 };
364#else
365 union FieldValue {
366 constexpr FieldValue() noexcept : floating(0) {}
367
368 std::int64_t integer;
369 long double floating;
370 std::uint64_t timestamp;
371 bool boolean;
372 };
373#endif
374
375 struct FieldValueOutput {
376 FieldValue& value;
377
378 template<classify_scalar::ScalarKind Kind>
379 typename std::enable_if<
380 Kind == classify_scalar::scalar_int8
381 || Kind == classify_scalar::scalar_int16
382 || Kind == classify_scalar::scalar_int32
383 || Kind == classify_scalar::scalar_int64,
384 void>::type set(std::int64_t parsed) const noexcept {
385 value.integer = parsed;
386 }
387
388 template<classify_scalar::ScalarKind Kind>
389 typename std::enable_if<Kind == classify_scalar::scalar_float, void>::type set(long double parsed) const noexcept {
390 value.floating = parsed;
391 }
392
393 template<classify_scalar::ScalarKind Kind>
394 typename std::enable_if<Kind == classify_scalar::scalar_bool, void>::type set(bool parsed) const noexcept {
395 value.boolean = parsed;
396 }
397
398 template<classify_scalar::ScalarKind Kind>
399 typename std::enable_if<Kind == classify_scalar::scalar_timestamp, void>::type set(std::uint64_t parsed) const noexcept {
400 value.timestamp = parsed;
401 }
402 };
403
404 mutable FieldValue value_;
405 csv::string_view sv = "";
406 mutable DataType type_ = DataType::UNKNOWN;
408 bool stores_integral() const noexcept {
409 return type_ >= DataType::CSV_INT8 && type_ <= DataType::CSV_INT64;
410 }
411
412 long double numeric_value_as_long_double() const noexcept {
413 return stores_integral()
414 ? static_cast<long double>(value_.integer)
415 : value_.floating;
416 }
417
418 void cache_parsed_value(DataType parsed_type, long double parsed_value) noexcept {
419 type_ = parsed_type;
420
421 if (parsed_type >= DataType::CSV_INT8 && parsed_type <= DataType::CSV_INT64) {
422 value_.integer = static_cast<std::int64_t>(parsed_value);
423 }
424 else if (parsed_type == DataType::CSV_DOUBLE || parsed_type == DataType::CSV_BIGINT) {
425 value_.floating = parsed_value;
426 }
427 }
428
432 CSVConversionError check_convert(std::string& out) const noexcept {
433 out.assign(this->sv.data(), this->sv.size());
435 }
436
437 CSVConversionError check_convert(csv::string_view& out) const noexcept {
438 out = this->sv;
440 }
441
442 CSVConversionError check_convert(long double& out) const noexcept {
444 out = this->numeric_value_as_long_double();
446 }
447
448 CSVConversionError check_convert(bool& out) const noexcept {
449 if (this->type() != DataType::CSV_BOOL)
451
452 out = this->value_.boolean;
454 }
455
456 template<typename Rep, typename Period>
457 CSVConversionError check_convert(std::chrono::duration<Rep, Period>& out) const noexcept {
458 if (this->type() != DataType::CSV_TIMESTAMP)
460
461 out = std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(
462 std::chrono::milliseconds(this->value_.timestamp));
464 }
465
466 template<typename Duration>
467 CSVConversionError check_convert(std::chrono::time_point<std::chrono::system_clock, Duration>& out) const noexcept {
468 if (this->type() != DataType::CSV_TIMESTAMP)
470
471 out = std::chrono::time_point<std::chrono::system_clock, Duration>(
472 std::chrono::duration_cast<Duration>(std::chrono::milliseconds(this->value_.timestamp)));
474 }
475
476 template<typename T>
477 CSVConversionError check_convert(T& out) const noexcept {
478 IF_CONSTEXPR(std::is_arithmetic<T>::value) {
479 if (!this->is_num())
481 if (this->type_ == DataType::CSV_BIGINT)
483 }
484
485 IF_CONSTEXPR(std::is_integral<T>::value) {
486 if (this->is_float())
488
489 IF_CONSTEXPR(std::is_unsigned<T>::value) {
490 if (this->numeric_value_as_long_double() < 0)
492 }
493 }
494
495 IF_CONSTEXPR(!std::is_floating_point<T>::value) {
496 const long double value = this->numeric_value_as_long_double();
497 if (value < static_cast<long double>(std::numeric_limits<T>::min())
498 || value > static_cast<long double>(std::numeric_limits<T>::max())) {
500 }
501 }
502
503 out = this->stores_integral()
504 ? static_cast<T>(this->value_.integer)
505 : static_cast<T>(this->value_.floating);
507 }
508
510 inline void get_value() const noexcept {
511 if ((int)type_ < 0) {
512 if (this->sv.empty()) {
513 type_ = DataType::CSV_NULL;
514 return;
515 }
516
517 const char* first = this->sv.data();
518 const char* last = first + this->sv.size();
519 typedef classify_scalar::policy_pack<
520 classify_scalar::builtin_numeric_policy<'.', false>,
521 classify_scalar::builtin_timestamp_policy,
522 classify_scalar::builtin_bool_policy
523 > csv_field_policy_pack;
524
525 type_ = classify_scalar::classify_scalar<
526 DataType,
527 true>(first, last, FieldValueOutput{ this->value_ }, csv_field_policy_pack());
528 }
529 }
530 };
531
533 class CSVRow {
534 public:
535 template<typename RowSink, typename ParsePolicy, typename FieldPolicy, typename RowPolicy>
536 friend class internals::CSVParserCore;
537 friend struct internals::CSVRowRowPolicy;
538 friend struct internals::data_frame::RowViewAccessor;
539 friend internals::parser::CSVParserDriverBase;
540 friend struct internals::speculative::CSVRowFragment;
541
542 CSVRow() = default;
543
545 CSVRow(internals::RawCSVDataPtr _data) : data(_data) {}
546 CSVRow(internals::RawCSVDataPtr _data, size_t _data_start, size_t _field_bounds)
547 : data(_data), data_start(_data_start), fields_start(_field_bounds) {}
548 CSVRow(internals::RawCSVDataPtr _data, size_t _data_start, size_t _field_bounds, size_t _row_length)
549 : data(_data), data_start(_data_start), fields_start(_field_bounds), row_length(_row_length) {}
550
552 CONSTEXPR bool empty() const noexcept { return this->size() == 0; }
553
555 CONSTEXPR size_t size() const noexcept { return row_length; }
556
558 size_t byte_offset() const noexcept {
559 return this->data ? this->data->source_start + this->data_start : 0;
560 }
561
564
567 CSVField try_field(size_t index, CSVError& error) const;
568 CSVField try_field(csv::string_view name, CSVError& error) const;
569
570#if CSV_EXCEPTIONS_ENABLED
572 CSVField operator[](size_t n) const;
574 CSVField operator[](csv::string_view col_name) const;
575#endif
576#if !CSV_EXCEPTIONS_ENABLED
578 inline std::string to_json() const {
579 const auto* converter = this->get_json_converter();
580 return converter ? converter->row_to_json(this->size(),
581 [this](size_t i) { return this->get_field(i); }) : "{}";
582 }
584 inline std::string to_json_array() const {
585 const auto* converter = this->get_json_converter();
586 return converter ? converter->row_to_json_array(this->size(),
587 [this](size_t i) { return this->get_field(i); }) : "[]";
588 }
589#endif
591 inline std::string try_to_json(const std::vector<std::string>& subset, CSVError& error) const {
592 error.clear();
593 const auto* converter = this->get_json_converter();
594 return converter ? converter->try_row_to_json(this->size(),
595 [this](size_t i) { return this->get_field(i); }, subset, error) : "{}";
596 }
597 inline std::string try_to_json_array(const std::vector<std::string>& subset, CSVError& error) const {
598 error.clear();
599 const auto* converter = this->get_json_converter();
600 return converter ? converter->try_row_to_json_array(this->size(),
601 [this](size_t i) { return this->get_field(i); }, subset, error) : "[]";
602 }
603#if CSV_EXCEPTIONS_ENABLED
604 inline std::string to_json(const std::vector<std::string>& subset = {}) const {
605 CSVError error;
606 auto out = try_to_json(subset, error);
607 internals::throw_error(error);
608 return out;
609 }
610 inline std::string to_json_array(const std::vector<std::string>& subset = {}) const {
611 CSVError error;
612 auto out = try_to_json_array(subset, error);
613 internals::throw_error(error);
614 return out;
615 }
616#endif
617
619 const std::vector<std::string>& get_col_names() const {
620 return this->data->col_names->get_col_names();
621 }
622
624 internals::ConstColNamesPtr col_names_ptr() const noexcept {
625 return this->data->col_names;
626 }
627
631#if CSV_EXCEPTIONS_ENABLED
632 std::unordered_map<std::string, std::string> to_unordered_map() const;
633#endif
634
636#if CSV_EXCEPTIONS_ENABLED
637 std::unordered_map<std::string, std::string> to_unordered_map(
638 const std::vector<std::string>& subset
639 ) const;
640#endif
641
642 #ifdef CSV_HAS_CXX20
647 auto to_sv_range() const {
648 return std::views::iota(size_t{0}, this->size())
649 | std::views::transform([this](size_t i) { return this->get_field(i); });
650 }
651 #endif
652
661 operator std::vector<std::string>() const;
662
670 csv::string_view raw_str() const noexcept;
672
682 class iterator {
683 public:
687 class pointer {
688 public:
689 explicit pointer(const CSVField& field) noexcept;
690 CSVField* operator->() noexcept;
691 const CSVField* operator->() const noexcept;
692
693 private:
694 CSVField field_;
695 };
696
697#ifndef DOXYGEN_SHOULD_SKIP_THIS
698 using value_type = CSVField;
699 using difference_type = std::ptrdiff_t;
700 using reference = CSVField;
701 using iterator_category = std::input_iterator_tag;
702#ifdef CSV_HAS_CXX20
703 using iterator_concept = std::random_access_iterator_tag;
704#endif
705#endif
706 iterator() = default;
707 iterator(const CSVRow* row, difference_type index) noexcept;
708
709 reference operator*() const;
710 pointer operator->() const;
711 reference operator[](difference_type n) const;
712
713 iterator operator++(int) noexcept;
714 iterator& operator++() noexcept;
715 iterator operator--(int) noexcept;
716 iterator& operator--() noexcept;
717 iterator operator+(difference_type n) const noexcept;
718 iterator operator-(difference_type n) const noexcept;
719 iterator& operator+=(difference_type n) noexcept;
720 iterator& operator-=(difference_type n) noexcept;
721 difference_type operator-(const iterator& other) const noexcept;
722 friend iterator operator+(difference_type n, const iterator& it) noexcept;
723
724 bool operator==(const iterator& other) const noexcept;
725 bool operator!=(const iterator& other) const noexcept;
726 bool operator<(const iterator& other) const noexcept;
727 bool operator>(const iterator& other) const noexcept;
728 bool operator<=(const iterator& other) const noexcept;
729 bool operator>=(const iterator& other) const noexcept;
730
731 private:
732 internals::RawCSVDataPtr data_;
733 size_t data_start_ = 0;
734 size_t fields_start_ = 0;
735 size_t row_length_ = 0;
736 difference_type index_ = 0;
737 };
738
744 public:
745#ifndef DOXYGEN_SHOULD_SKIP_THIS
746 using value_type = iterator::value_type;
747 using difference_type = iterator::difference_type;
748 using pointer = iterator::pointer;
749 using reference = iterator::reference;
750 using iterator_category = std::input_iterator_tag;
751#ifdef CSV_HAS_CXX20
752 using iterator_concept = std::random_access_iterator_tag;
753#endif
754#endif
755 reverse_iterator() = default;
756 explicit reverse_iterator(iterator base) noexcept;
757
758 reference operator*() const;
759 pointer operator->() const;
760 reference operator[](difference_type n) const;
761
762 reverse_iterator operator++(int) noexcept;
763 reverse_iterator& operator++() noexcept;
764 reverse_iterator operator--(int) noexcept;
765 reverse_iterator& operator--() noexcept;
766 reverse_iterator operator+(difference_type n) const noexcept;
767 reverse_iterator operator-(difference_type n) const noexcept;
768 reverse_iterator& operator+=(difference_type n) noexcept;
769 reverse_iterator& operator-=(difference_type n) noexcept;
770 difference_type operator-(const reverse_iterator& other) const noexcept;
771 friend reverse_iterator operator+(difference_type n, const reverse_iterator& it) noexcept;
772
773 bool operator==(const reverse_iterator& other) const noexcept;
774 bool operator!=(const reverse_iterator& other) const noexcept;
775 bool operator<(const reverse_iterator& other) const noexcept;
776 bool operator>(const reverse_iterator& other) const noexcept;
777 bool operator<=(const reverse_iterator& other) const noexcept;
778 bool operator>=(const reverse_iterator& other) const noexcept;
779
781 iterator base() const noexcept;
782
783 private:
784 iterator base_;
785 };
786
788 std::unordered_map<std::string, std::string> try_to_unordered_map(CSVError& error) const;
789 std::unordered_map<std::string, std::string> try_to_unordered_map(
790 CSVError& error, const std::vector<std::string>& subset) const;
791
796 iterator begin() const noexcept;
797 iterator end() const noexcept;
798 reverse_iterator rbegin() const noexcept;
799 reverse_iterator rend() const noexcept;
801
802 private:
803 std::unordered_map<std::string, std::string> to_unordered_map_impl(
804 const std::vector<std::string>* subset, CSVError& error) const;
805
807 inline csv::string_view get_field_impl(size_t index, const internals::RawCSVDataPtr& _data) const {
808#if CSV_EXCEPTIONS_ENABLED
809 if (index >= this->size())
810 throw std::runtime_error(internals::CSV_ERROR_INDEX_OUT_OF_BOUNDS);
811#else
812 CSV_DEBUG_ASSERT(index < this->size());
813#endif
814
815 const size_t field_index = this->fields_start + index;
816 const auto field = _data->fields[field_index];
817 csv::string_view field_str;
818 if (field.has_realized_storage()) {
819 field_str = _data->quote_arena.view(field.start, field.length);
820 }
821 else {
822 field_str = csv::string_view(_data->data).substr(this->data_start + field.start, field.length);
823 }
824
825 if (_data->has_ws_trimming) {
826 field_str = internals::get_trimmed(field_str, _data->ws_flags);
827 }
828
829 return field_str;
830 }
831
832 CSVField make_field(size_t index, const internals::RawCSVDataPtr& _data) const;
833
835 csv::string_view get_field(size_t index) const;
836
840 csv::string_view get_field_safe(size_t index, internals::RawCSVDataPtr _data) const;
841
842 const internals::JsonConverter* get_json_converter() const {
843 if (this->data.get() == nullptr) {
844 return nullptr;
845 }
846
847 return &this->data->json_converter.get_or_create([this]() {
848 const std::vector<std::string> columns = this->data->col_names
849 ? this->data->col_names->get_col_names()
850 : std::vector<std::string>();
851 return std::make_shared<internals::JsonConverter>(columns);
852 });
853 }
854
855 internals::RawCSVDataPtr data;
856
858 size_t data_start = 0;
859
861 size_t fields_start = 0;
862
864 size_t row_length = 0;
865
867 size_t data_end = (std::numeric_limits<size_t>::max)();
868 };
869
870#ifdef _MSC_VER
871#pragma region CSVField::get Specializations
872#endif
873#if CSV_EXCEPTIONS_ENABLED
875 template<>
876 inline std::string CSVField::get<std::string>() const {
877 return std::string(this->sv);
878 }
879
885 template<>
886 CONSTEXPR_14 csv::string_view CSVField::get<csv::string_view>() const {
887 return this->sv;
888 }
889
891 template<>
892 inline long double CSVField::get<long double>() const {
893 if (!is_num())
894 throw std::runtime_error(internals::ERROR_NAN);
895
896 return this->numeric_value_as_long_double();
897 }
898
899#endif
900
901 // Preserve the existing constexpr view-retrieval API.
902 template<>
903 CONSTEXPR_14 bool CSVField::try_get<csv::string_view>(csv::string_view& out) const noexcept {
904 out = this->sv;
905 return true;
906 }
907#ifdef _MSC_VER
908#pragma endregion CSVField::get Specializations
909#endif
910
912 template<>
913 CONSTEXPR bool CSVField::operator==(const char * other) const noexcept
914 {
915 return this->sv == other;
916 }
917
919 template<>
921 {
922 return this->sv == other;
923 }
924}
Data type representing individual CSV values.
Definition csv_row.hpp:74
bool try_parse_decimal(long double &dVal, const char decimalSymbol='.')
Attempts to parse a decimal (or integer) value using the given symbol, returning true if the value is...
Definition csv_row.cpp:164
bool try_get(T &out, CSVConversionError &error) const noexcept
Convert with the same rules as try_get(), retaining the failure reason.
Definition csv_row.hpp:197
bool try_parse_timestamp(T &out) const noexcept
Parse this field as Unix milliseconds in a 64-bit unsigned integer.
bool is_timestamp() const noexcept
Returns true if field is a timestamp value.
Definition csv_row.hpp:342
bool try_parse_timestamp(std::uint64_t &out) const noexcept
Parse this field as Unix milliseconds.
Definition csv_row.cpp:198
DataType type() const noexcept
Return the type of the underlying CSV data.
Definition csv_row.hpp:345
bool is_num() const noexcept
Returns true if field is an integer or float.
Definition csv_row.hpp:326
bool is_bool() const noexcept
Returns true if field is a boolean value.
Definition csv_row.hpp:339
bool operator==(T other) const noexcept
Compares the contents of this field to a numeric value.
Definition csv_row.hpp:303
bool is_str() const noexcept
Returns true if field is a non-numeric, non-empty string.
Definition csv_row.hpp:323
bool try_parse_timestamp(std::chrono::duration< Rep, Period > &out) const noexcept
Parse this field as a timestamp duration since the Unix epoch.
Definition csv_row.hpp:267
bool try_parse_hex(T &parsedValue) const
Parse a hexadecimal value, returning false if the value is not hex.
Definition csv_row.hpp:222
bool try_get(T &out) const noexcept
Non-throwing equivalent of get().
Definition csv_row.hpp:188
bool is_null() const noexcept
Returns true if field is an empty string or string of whitespace characters.
Definition csv_row.hpp:320
constexpr CSVField(csv::string_view _sv) noexcept
Constructs a CSVField from a string_view.
Definition csv_row.hpp:77
T get() const
Returns the value casted to the requested type, performing type checking before.
Definition csv_row.hpp:140
bool is_float() const noexcept
Returns true if field is a floating point value.
Definition csv_row.hpp:336
bool is_int() const noexcept
Returns true if field is an integer.
Definition csv_row.hpp:331
CONSTEXPR csv::string_view get_sv() const noexcept
Return a string view over the field's contents.
Definition csv_row.hpp:317
bool try_parse_timestamp(std::chrono::time_point< std::chrono::system_clock, Duration > &out) const noexcept
Parse this field as a std::chrono::system_clock time point.
Definition csv_row.hpp:279
std::expected< T, CSVConversionError > as() const
Return this field as T, preserving conversion failure as CSVConversionError.
Definition csv_row.hpp:162
Temporary arrow proxy owning a field value, without a heap allocation.
Definition csv_row.hpp:687
Iterator producing short-lived CSVField values with independent lazy conversion caches.
Definition csv_row.hpp:682
Reverse field-value iterator available since C++11.
Definition csv_row.hpp:743
Data structure for representing CSV rows.
Definition csv_row.hpp:533
CSVField try_field(size_t index, CSVError &error) const
Checked field retrieval.
Definition csv_row.cpp:47
CONSTEXPR bool empty() const noexcept
Indicates whether row is empty or not.
Definition csv_row.hpp:552
csv::string_view raw_str() const noexcept
Return a string_view of the raw bytes of this row as they appear in the underlying parse buffer,...
Definition csv_row.cpp:75
const std::vector< std::string > & get_col_names() const
Retrieve this row's associated column names.
Definition csv_row.hpp:619
std::unordered_map< std::string, std::string > try_to_unordered_map(CSVError &error) const
Materialize named values; unknown names or absent header positions report an error.
Definition csv_row.cpp:93
auto to_sv_range() const
Convert this CSVRow into a std::ranges::input_range of string_views.
Definition csv_row.hpp:647
std::unordered_map< std::string, std::string > to_unordered_map() const
Convert this CSVRow into an unordered map.
Definition csv_row.cpp:127
CONSTEXPR size_t size() const noexcept
Return the number of fields in this row.
Definition csv_row.hpp:555
std::string try_to_json(const std::vector< std::string > &subset, CSVError &error) const
Serialize a subset, reporting unknown column names.
Definition csv_row.hpp:591
CSVField operator[](size_t n) const
Return the field at n.
Definition csv_row.cpp:30
internals::ConstColNamesPtr col_names_ptr() const noexcept
Internal accessor for preserving resolved column-name lookup policy across helper types.
Definition csv_row.hpp:624
size_t byte_offset() const noexcept
Return the absolute byte offset where this row starts in the source.
Definition csv_row.hpp:558
CSVRow(internals::RawCSVDataPtr _data)
Construct a CSVRow view over parsed row storage.
Definition csv_row.hpp:545
A standalone header file containing shared code.
#define IF_CONSTEXPR
Expands to if constexpr in C++17 and if otherwise.
Definition common.hpp:191
#define CONSTEXPR
Expands to constexpr in decent compilers and inline otherwise.
Definition common.hpp:259
Shared exception message templates and throw helpers.
CSV scalar type classification adapter.
Internal JSON serialization helpers for row-like CSV data.
The all encompassing namespace.
DataType
Enumerates the different CSV field types recognized by this library.
Definition data_type.hpp:14
@ CSV_TIMESTAMP
Timestamp value.
@ CSV_INT64
64-bit integer
@ CSV_DOUBLE
Floating point value.
@ CSV_BOOL
Boolean value.
@ CSV_NULL
Empty string.
@ CSV_BIGINT
Integer too large to fit in 64 bits.
@ CSV_INT16
16-bit integer
@ CSV_INT32
32-bit integer
@ CSV_INT8
8-bit integer
@ CSV_STRING
Non-scalar string.
CSVConversionError
Non-throwing CSVField conversion result.
Definition csv_error.hpp:23
@ FloatToInt
A floating point field was requested as an integral type.
@ Overflow
The parsed value does not fit in the requested target type.
@ NegativeToUnsigned
A negative value was requested as an unsigned type.
@ None
Conversion succeeded.
@ NotANumber
The field is not compatible with the requested target type.
const char * csv_conversion_error_message(CSVConversionError error) noexcept
Return a stable human-readable description for a CSVConversionError.
Definition csv_error.hpp:53
std::string_view string_view
The string_view class used by this library.
Definition common.hpp:182
Internal data structures for CSV parsing.
A diagnostic whose text remains valid for the lifetime of the error.
Definition csv_error.hpp:94
Cached scalar classification and parsed value for one CSV field.
Definition data_type.hpp:35