10#if !defined(CSV_ENABLE_THREADS) || CSV_ENABLE_THREADS
13#include <unordered_set>
27#define CSV_INIT_WITH_OPTIONAL_DCL(data_ref, value_ref, ...) \
29 if ((value_ref).empty()) { \
30 std::lock_guard<std::mutex> lock((data_ref).double_quote_init_lock); \
31 if ((value_ref).empty()) { \
37#define CSV_INIT_WITH_OPTIONAL_DCL(data_ref, value_ref, ...) \
40 if ((value_ref).empty()) { \
48 class IBasicCSVParser;
50 static const std::string ERROR_NAN =
"Not a number.";
51 static const std::string ERROR_OVERFLOW =
"Overflow error.";
52 static const std::string ERROR_FLOAT_TO_INT =
53 "Attempted to convert a floating point value to an integral type.";
54 static const std::string ERROR_NEG_TO_UNSIGNED =
"Negative numbers cannot be converted to unsigned types.";
76 operator std::string()
const {
77 return std::string(this->sv);
108 template<
typename T = std::
string> T
get() {
110 if (
const auto* err = check_convert(out))
throw std::runtime_error(err);
129 template<
typename T = std::
string>
131 return check_convert(out) ==
nullptr;
137 template<
typename T =
long long>
139 static_assert(std::is_integral<T>::value,
140 "try_parse_hex only works with integral types (int, long, long long, etc.)");
141 return internals::try_parse_hex(this->sv, parsedValue);
168 static_assert(std::is_arithmetic<T>::value,
169 "T should be a numeric value.");
171 if (this->_type != DataType::UNKNOWN) {
176 return internals::is_equal(value,
static_cast<long double>(other), 0.000001L);
184 return internals::is_equal(out,
static_cast<long double>(other), 0.000001L);
214 long double value = 0;
223 const char* check_convert(T& out)
noexcept {
226 return internals::ERROR_NAN.c_str();
231 return internals::ERROR_FLOAT_TO_INT.c_str();
235 return internals::ERROR_NEG_TO_UNSIGNED.c_str();
241 if (this->value > internals::get_uint_max<
sizeof(T)>())
242 return internals::ERROR_OVERFLOW.c_str();
244 else if (internals::type_num<T>() < this->_type) {
245 return internals::ERROR_OVERFLOW.c_str();
249 out =
static_cast<T
>(this->value);
253 CONSTEXPR_14
void get_value() noexcept {
257 if ((
int)_type < 0) {
258 this->_type = internals::data_type(this->sv, &this->value);
271 CSVRow(internals::RawCSVDataPtr _data) : data(_data) {}
272 CSVRow(internals::RawCSVDataPtr _data,
size_t _data_start,
size_t _field_bounds)
273 : data(_data), data_start(_data_start), fields_start(_field_bounds) {}
274 CSVRow(internals::RawCSVDataPtr _data,
size_t _data_start,
size_t _field_bounds,
size_t _row_length)
275 : data(_data), data_start(_data_start), fields_start(_field_bounds), row_length(_row_length) {}
287 std::string
to_json(
const std::vector<std::string>& subset = {})
const;
288 std::string
to_json_array(
const std::vector<std::string>& subset = {})
const;
292 return this->data->col_names->get_col_names();
302 const std::vector<std::string>& subset
308 return std::views::iota(
size_t{0}, this->
size())
309 | std::views::transform([
this](
size_t i) {
return this->get_field(i); });
321 operator std::vector<std::string>()
const;
338#ifndef DOXYGEN_SHOULD_SKIP_THIS
340 using difference_type = int;
341 using pointer = std::shared_ptr<CSVField>;
343 using iterator_category = std::random_access_iterator_tag;
347 reference operator*()
const;
348 pointer operator->()
const;
354 iterator operator+(difference_type n)
const;
355 iterator operator-(difference_type n)
const;
359 return this->i == other.i;
362 CONSTEXPR bool operator!=(
const iterator& other)
const noexcept {
return !operator==(other); }
369 const CSVRow * daddy =
nullptr;
370 internals::RawCSVDataPtr data =
nullptr;
371 std::shared_ptr<CSVField> field =
nullptr;
390 inline
csv::
string_view get_field_impl(
size_t index, const internals::RawCSVDataPtr& _data)
const {
393 if (index >= this->
size())
394 throw std::runtime_error(
"Index out of bounds.");
396 const size_t field_index = this->fields_start + index;
397 auto field = _data->fields[field_index];
398 auto field_str =
csv::string_view(_data->data).substr(this->data_start + field.start, field.length);
400 if (field.has_double_quote) {
401 auto& value = _data->double_quote_fields[field_index];
402 CSV_INIT_WITH_OPTIONAL_DCL((*_data), value,
403 bool prev_ch_quote =
false;
404 for (
size_t i = 0; i < field.length; i++) {
405 if (_data->parse_flags[field_str[i] +
CHAR_OFFSET] == ParseFlags::QUOTE) {
407 prev_ch_quote = false;
411 prev_ch_quote = true;
415 value += field_str[i];
419 if (_data->has_ws_trimming)
423 else if (_data->has_ws_trimming) {
424 field_str = internals::get_trimmed(field_str, _data->ws_flags);
436 csv::string_view get_field_safe(
size_t index, internals::RawCSVDataPtr _data)
const;
438 internals::RawCSVDataPtr data;
441 size_t data_start = 0;
444 size_t fields_start = 0;
447 size_t row_length = 0;
451#pragma region CSVField::get Specializations
455 inline std::string CSVField::get<std::string>() {
456 return std::string(this->sv);
471 CONSTEXPR_14
long double CSVField::get<long double>() {
473 throw std::runtime_error(internals::ERROR_NAN);
480 inline bool CSVField::try_get<std::string>(std::string& out)
noexcept {
481 out = std::string(this->sv);
494 CONSTEXPR_14
bool CSVField::try_get<long double>(
long double& out)
noexcept {
502#pragma endregion CSVField::get Specializations
507 CONSTEXPR bool CSVField::operator==(
const char * other)
const noexcept
509 return this->sv == other;
516 return this->sv == other;
520#undef CSV_INIT_WITH_OPTIONAL_DCL
Data type representing individual CSV values.
CONSTEXPR_14 bool is_num() noexcept
Returns true if field is an integer or float.
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...
CONSTEXPR_14 bool is_str() noexcept
Returns true if field is a non-numeric, non-empty string.
CONSTEXPR_14 bool is_int() noexcept
Returns true if field is an integer.
CONSTEXPR_14 bool is_null() noexcept
Returns true if field is an empty string or string of whitespace characters.
constexpr CSVField(csv::string_view _sv) noexcept
Constructs a CSVField from a string_view.
CONSTEXPR_14 DataType type() noexcept
Return the type of the underlying CSV data.
T get()
Returns the value casted to the requested type, performing type checking before.
CONSTEXPR_14 bool operator==(T other) const noexcept
Compares the contents of this field to a numeric value.
bool try_get(T &out) noexcept
Non-throwing equivalent of get().
CONSTEXPR_14 bool is_float() noexcept
Returns true if field is a floating point value.
CONSTEXPR csv::string_view get_sv() const noexcept
Return a string view over the field's contents.
bool try_parse_hex(T &parsedValue)
Parse a hexadecimal value, returning false if the value is not hex.
A random access iterator over the contents of a CSV row.
CONSTEXPR bool operator==(const iterator &other) const noexcept
Two iterators are equal if they point to the same field.
Data structure for representing CSV rows.
iterator end() const noexcept
Return an iterator pointing to just after the end of the CSVRow.
std::reverse_iterator< iterator > reverse_iterator
A reverse iterator over the contents of a CSVRow.
std::string to_json(const std::vector< std::string > &subset={}) const
Convert a CSV row to a JSON object, i.e.
CONSTEXPR bool empty() const noexcept
Indicates whether row is empty or not.
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,...
std::string to_json_array(const std::vector< std::string > &subset={}) const
Convert a CSV row to a JSON array, i.e.
auto to_sv_range() const
Convert this CSVRow into a std::ranges::input_range of string_views.
std::unordered_map< std::string, std::string > to_unordered_map() const
Convert this CSVRow into an unordered map.
CONSTEXPR size_t size() const noexcept
Return the number of fields in this row.
std::vector< std::string > get_col_names() const
Retrieve this row's associated column names.
CSVField operator[](size_t n) const
Return a CSVField object corrsponding to the nth value in the row.
iterator begin() const
Return an iterator pointing to the first field.
CSVRow(internals::RawCSVDataPtr _data)
Construct a CSVRow view over parsed row storage.
Abstract base class which provides CSV parsing logic.
A standalone header file containing shared code.
#define IF_CONSTEXPR
Expands to if constexpr in C++17 and if otherwise.
ParseFlags
An enum used for describing the significance of each character with respect to CSV parsing.
#define CONSTEXPR
Expands to constexpr in decent compilers and inline otherwise.
Implements data type parsing functionality.
The all encompassing namespace.
DataType
Enumerates the different CSV field types that are recognized by this library.
@ CSV_INT64
64-bit integer (long long on MSVC/GCC)
@ CSV_DOUBLE
Floating point value.
@ CSV_STRING
Non-numeric string.
constexpr unsigned CHAR_OFFSET
Offset to convert char into array index.
nonstd::string_view string_view
The string_view class used by this library.
Implements Functions related to hexadecimal parsing.
Internal data structures for CSV parsing.