85 template<
typename StoreCellFunction>
86 constexpr void parse(std::string_view data, StoreCellFunction storeCellFunc)
const;
98 template<
typename Vector2D>
99 constexpr void parseTo2DVector(std::string_view data, Vector2D& values)
const;
113 template<std::
size_t rows, std::
size_t columns,
typename Cell = CellStringReference>
127 template<
typename Vector>
139 template<
typename Vector>
141 std::optional<std::size_t> rows_hint, std::optional<std::size_t> columns)
const;
152 template<
typename Vector>
154 std::size_t rows, std::optional<std::size_t> columns_hint)
const;
166 template<std::
size_t rows, std::
size_t columns,
typename Cell = CellStringReference>
174 enum class MachineState {
185 MachineState machine_state = MachineState::AtCellStart;
186 std::size_t current_row = 0, current_column = 0;
187 std::string_view current_value;
188 bool escaped_quotes_encountered =
false;
192 constexpr void switchToNextColumn()
194 current_value = std::string_view();
195 escaped_quotes_encountered =
false;
202 [[nodiscard]]
constexpr std::size_t switchToNextLine(
const std::string_view& data, std::size_t current_pos)
204 current_value = std::string_view();
205 escaped_quotes_encountered =
false;
209 if (
auto next_char = peek(data, current_pos); data[current_pos] ==
'\r' && next_char ==
'\n') {
217 constexpr void increaseCurrentValueSize(std::size_t by_chars)
219 current_value = std::string_view(current_value.data(), current_value.size() + by_chars);
224 constexpr void restartCurrentValue(
const std::string_view& data, std::size_t current_pos, std::size_t size)
226 current_value = data.substr(current_pos, size);
227 escaped_quotes_encountered =
false;
235 [[nodiscard]]
static constexpr std::char_traits<char>::int_type peek(
const std::string_view& data,
236 std::size_t current_pos, std::size_t advance_chars = 1)
238 if ((current_pos + advance_chars) < data.size()) {
239 return std::char_traits<char>::to_int_type(data[current_pos + advance_chars]);
241 return std::char_traits<char>::eof();
247 [[nodiscard]]
static constexpr std::char_traits<char>::int_type readChar(
248 const std::string_view& data, std::size_t pos)
250 return peek(data, pos, 0);
256 template <
typename StoreCellFunction>
257 constexpr void store(StoreCellFunction storeCellFunc,
258 const ParserState& state, CellTypeHint type_hint)
const
260 if (type_hint == CellTypeHint::Empty && !BehaviorPolicy::useEmptyCellType()) {
261 type_hint = CellTypeHint::StringWithoutEscapedQuotes;
263 storeCellFunc(state.current_row, state.current_column, state.current_value, type_hint);
281 for (std::size_t pos = 0; pos <= data.size(); ++pos) {
282 auto current_char = readChar(data, pos);
284 switch (state.machine_state) {
286 case MachineState::AtCellStart:
288 switch(current_char) {
292 state.machine_state = MachineState::InLeadingWhiteSpace;
293 state.restartCurrentValue(data, pos, 1);
299 state.machine_state = MachineState::InsideQuotedValue;
300 state.restartCurrentValue(data, pos + 1, 0);
304 store(storeCellFunc, state, CellTypeHint::Empty);
305 state.switchToNextColumn();
310 store(storeCellFunc, state, CellTypeHint::Empty);
311 state.machine_state = MachineState::AtCellStart;
313 pos = state.switchToNextLine(data, pos);
315 case std::char_traits<char>::eof():
318 if (state.current_column != 0) {
319 store(storeCellFunc, state, CellTypeHint::Empty);
324 state.machine_state = MachineState::InsideUnquotedValue;
325 state.restartCurrentValue(data, pos, 1);
332 case MachineState::InLeadingWhiteSpace:
334 switch(current_char) {
338 state.increaseCurrentValueSize(1);
344 state.machine_state = MachineState::InsideQuotedValue;
345 state.restartCurrentValue(data, pos + 1, 0);
349 store(storeCellFunc, state, CellTypeHint::StringWithoutEscapedQuotes);
350 state.machine_state = MachineState::AtCellStart;
351 state.switchToNextColumn();
356 store(storeCellFunc, state, CellTypeHint::StringWithoutEscapedQuotes);
357 state.machine_state = MachineState::AtCellStart;
359 pos = state.switchToNextLine(data, pos);
361 case std::char_traits<char>::eof():
363 store(storeCellFunc, state, CellTypeHint::StringWithoutEscapedQuotes);
367 state.machine_state = MachineState::InsideUnquotedValue;
368 state.increaseCurrentValueSize(1);
375 case MachineState::InsideUnquotedValue:
377 switch(current_char) {
382 if (peek(data, pos) !=
'\"') {
383 throw ParseError(state.current_row, state.current_column);
387 state.increaseCurrentValueSize(2);
388 state.escaped_quotes_encountered =
true;
392 store(storeCellFunc, state, state.escaped_quotes_encountered ?
393 CellTypeHint::StringWithEscapedQuotes : CellTypeHint::UnquotedData);
394 state.machine_state = MachineState::AtCellStart;
395 state.switchToNextColumn();
400 store(storeCellFunc, state, state.escaped_quotes_encountered ?
401 CellTypeHint::StringWithEscapedQuotes : CellTypeHint::UnquotedData);
402 state.machine_state = MachineState::AtCellStart;
404 pos = state.switchToNextLine(data, pos);
406 case std::char_traits<char>::eof():
408 store(storeCellFunc, state, state.escaped_quotes_encountered ?
409 CellTypeHint::StringWithEscapedQuotes : CellTypeHint::UnquotedData);
413 state.increaseCurrentValueSize(1);
420 case MachineState::InsideQuotedValue:
422 switch(current_char) {
425 if (peek(data, pos) ==
'\"') {
428 state.increaseCurrentValueSize(2);
429 state.escaped_quotes_encountered =
true;
432 store(storeCellFunc, state, state.escaped_quotes_encountered ?
433 CellTypeHint::StringWithEscapedQuotes : CellTypeHint::StringWithoutEscapedQuotes);
434 state.machine_state = MachineState::AfterQuotedValue;
437 case std::char_traits<char>::eof():
439 throw ParseError(state.current_row, state.current_column);
442 state.increaseCurrentValueSize(1);
449 case MachineState::AfterQuotedValue:
451 switch(current_char) {
458 state.machine_state = MachineState::AtCellStart;
459 state.switchToNextColumn();
464 state.machine_state = MachineState::AtCellStart;
465 pos = state.switchToNextLine(data, pos);
467 case std::char_traits<char>::eof():
472 throw ParseError(state.current_row, state.current_column);
537 std::optional<std::size_t> rows_hint, std::optional<std::size_t> columns)
const
539 Vector parsed_values;
540 if (rows_hint.has_value() && columns.has_value()) {
541 parsed_values.reserve(rows_hint.value() * columns.value());
545 info.
setOrder(MatrixOrder::RowMajor);
547 bool unknown_columns = !columns.has_value();
548 if (!unknown_columns) {
551 std::size_t read_columns = 0;
555 [&](std::size_t row, std::size_t column, std::string_view cell_data, [[maybe_unused]]
CellTypeHint hint)
557 if (unknown_columns) {
559 read_columns = column + 1;
560 parsed_values.resize(read_columns);
561 }
else if (row == 1) {
562 unknown_columns =
false;
564 if (rows_hint.has_value()) {
565 parsed_values.reserve(rows_hint.value() * info.getColumns());
570 if (!unknown_columns) {
571 if (parsed_values.size() < ((row + 1) * info.
getColumns())) {
572 parsed_values.resize((row + 1) * info.getColumns());
576 BehaviorPolicy::template create<typename Vector::value_type>(cell_data, hint);
579 std::swap(values, parsed_values);
581 if (values.empty()) {
583 empty_info.
setOrder(MatrixOrder::RowMajor);