11# Csv::Parser (csv-parser)
2- *** Compile-time and runtime CSV parser written in C++17 ***
2+ *** Compile-time and runtime CSV parser written in Modern C++***
33
44[ ![ GitHub release (latest SemVer)] ( https://img.shields.io/github/v/release/ashaduri/csv-parser?label=Version )] ( https://github.com/ashaduri/csv-parser )
55![ GitHub] ( https://img.shields.io/github/license/ashaduri/csv-parser )
6- ![ Language] ( https://img.shields.io/badge/language-ISO %20C++17 -blue )
6+ ![ Language] ( https://img.shields.io/badge/language-Modern %20C++-blue )
77
88
99## Features
1010- Header-only.
11- - Requires only standard C++ (C++17).
12- - Supports reading CSV data from ` std::string_view ` during compilation (using ` constexpr ` ) .
11+ - Requires only standard C++ (minimum C++17, with C++23 support providing additional functionality ).
12+ - Supports reading CSV data from ` std::string_view ` at compile-time .
1313- Fully supports [ RFC 4180] ( https://www.ietf.org/rfc/rfc4180.txt ) , including quoted values, escaped quotes, and newlines in field values.
1414- Liberal in terms of accepting not-quite-standard CSV files, but detects errors when needed.
1515- Supports Excel CSV variations.
16- - Supports reading data as different types (string, double, empty field) (runtime only).
16+ - Supports reading data as different types (string, double, empty field), with some restrictions when parsing at
17+ compile-time.
18+ - Modular design allows for easy extension of the library.
1719- Extensively tested using [ Catch2] ( https://github.com/catchorg/Catch2 ) .
1820
1921## API Reference
@@ -114,11 +116,14 @@ std::cout << "Row 1, column 2: " << matrix_data[info.matrixIndex(1, 2)] << std::
114116return EXIT_SUCCESS;
115117```
116118
117- ### Compile-Time Parsing
119+ ### Compile-Time Parsing Into 2D ` std::array `
118120
119121Currently, parsing at compile-time has some restrictions:
120- - Only string_views are supported for output (no doubles).
121122- To collapse consecutive double-quotes in strings, a compile-time-allocated buffer has to be used.
123+ - By default, only string_views are supported for output (no numeric types).
124+ - If using C++23 or later, integral types are supported as well.
125+ - If compile-time parsing of floating point numbers is needed,
126+ [ fast_float] ( https://github.com/fastfloat/fast_float ) can be plugged in.
122127
123128One (possibly useful) consequence of compile-time parsing is that a parse error also causes a compilation error.
124129
@@ -130,12 +135,11 @@ One (possibly useful) consequence of compile-time parsing is that a parse error
130135
131136using namespace std ::string_view_literals;
132137
138+ constexpr std::size_t columns = 2, rows = 2;
133139constexpr std::string_view data =
134140R"(abc, "def"
135141"with ""quote inside",6)";
136142
137- constexpr std::size_t columns = 2, rows = 2;
138-
139143constexpr Csv::Parser parser;
140144
141145// parse into std::array<std::array<CellStringReference, rows>, columns>
@@ -158,6 +162,103 @@ constexpr auto buffer = matrix[0][1].getCleanStringBuffer<buffer_size>();
158162static_assert(buffer.getStringView() == R"(with "quote inside)"sv);
159163```
160164
165+ ### Compile-Time Parsing of Integral Matrix Into 1D Vector
166+
167+ The library can be used to parse CSV data at compile-time into a 1D vector, in row-major
168+ or column-major order.
169+ Additionally, compile-time parsing of integral types is supported since C++23.
170+
171+ #### Example:
172+ ```cpp
173+ #include "csv_parser.h"
174+
175+ // ...
176+
177+ using namespace std::string_view_literals;
178+
179+ constexpr std::size_t columns = 2, rows = 3;
180+ constexpr std::string_view data =
181+ R"(11, -12
182+ 21, 4
183+ 60, -10)";
184+
185+ // Use Csv::LocaleUnawareBehaviorPolicy to avoid locale issues and allow compile-time integer parsing.
186+ constexpr Csv::Parser<Csv::LocaleUnawareBehaviorPolicy> parser;
187+
188+ // Parse into std::array<CellStringReference, rows * columns> in row-major order
189+ {
190+ constexpr auto matrix = parser.parseToArray<rows, columns>(data, Csv::MatrixOrder::RowMajor);
191+
192+ static_assert(matrix[0].getOriginalStringView() == "11"sv);
193+ static_assert(matrix[2].getOriginalStringView() == "21"sv);
194+ }
195+
196+ // Parse into std::array<std::int64_t, rows * columns> in column-major order.
197+ // Compile-time parsing to integers is supported since C++23.
198+ #if __cplusplus >= 202300L
199+ {
200+ constexpr auto matrix = parser.parseToArray<rows, columns, std::int64_t>(data, Csv::MatrixOrder::ColumnMajor);
201+
202+ static_assert(matrix[0] == 11);
203+ static_assert(matrix[2] == 60);
204+ }
205+ #endif
206+ ```
207+
208+
209+ ### Compile-Time Parsing of Numeric Matrix Using External Library for Floating Point Numbers
210+
211+ A library like [ fast_float] ( https://github.com/fastfloat/fast_float ) can be used to parse floating point
212+ numbers at compile-time. This is done by creating a custom policy that implements the ` readNumber ` and
213+ ` create ` methods.
214+ This approach also allows for improving the performance of parsing floating point numbers compared
215+ to the standard library.
216+
217+ #### Example:
218+ ``` cpp
219+ #include " csv_parser.h"
220+ #include " fast_float/fast_float.h"
221+
222+ // Custom policy which uses fast_float library for parsing to floating point.
223+ struct CustomPolicy : Csv::LocaleUnawareBehaviorPolicy {
224+ template<typename Number >
225+ static constexpr std::optional<Number > readNumber(std::string_view cell)
226+ {
227+ Number parsed_value = 0;
228+ auto [ ptr, ec] = fast_float::from_chars(cell.begin(), cell.end(), parsed_value);
229+ if (ec == std::errc() && ptr == (cell.end())) {
230+ return parsed_value;
231+ }
232+ return std::nullopt;
233+ }
234+
235+ template<typename CellT>
236+ static constexpr CellT create(std::string_view cell, Csv::CellTypeHint hint)
237+ {
238+ return readNumber<CellT>(cell).value_or(std::numeric_limits<CellT>::quiet_NaN());
239+ }
240+ };
241+
242+
243+ void parse ()
244+ {
245+ constexpr std::string_view data =
246+ R"(11.6, -12.3
247+ 2e5, -inf
248+ nan, inf)";
249+
250+ // Use custom policy which uses fast_float library for parsing to floating point.
251+ constexpr Csv::Parser<CustomPolicy> parser;
252+ constexpr std::size_t columns = 2, rows = 3;
253+
254+ // Parse into std::array<double, rows * columns> in row-major order
255+ constexpr auto matrix = parser.parseToArray<rows, columns, double>(data, Csv::MatrixOrder::RowMajor);
256+
257+ static_assert (matrix[ 0] == 11.6);
258+ static_assert(matrix[ 3] == -std::numeric_limits<double >::infinity());
259+ }
260+ ```
261+
161262
162263## Copyright
163264
0 commit comments