csv-parser 1.1.0
Csv::Parser (csv-parser)
Loading...
Searching...
No Matches
csv_cell.h
Go to the documentation of this file.
1/**************************************************************************
2Copyright: (C) 2021 - 2025 Alexander Shaduri
3License: Zlib
4***************************************************************************/
5
6#ifndef CSV_CELL_H
7#define CSV_CELL_H
8
9#include "csv_util.h"
11
12#include <string_view>
13#include <string>
14#include <optional>
15#include <algorithm>
16#include <variant>
17#include <limits>
18#include <stdexcept>
19#include <array>
20
28namespace Csv {
29
30
38
39
41enum class CellType {
42 Empty,
43 Double,
44 String,
45};
46
47
48
52 public:
53
55 constexpr CellReference() = default;
56
62 template<typename BehaviorPolicy>
63 constexpr CellReference(std::string_view cell, CellTypeHint hint, BehaviorPolicy policy) noexcept;
64
66 [[nodiscard]] inline constexpr CellType getType() const;
67
69 [[nodiscard]] inline constexpr bool isEmpty() const;
70
74 [[nodiscard]] inline constexpr std::optional<double> getDouble() const;
75
81 [[nodiscard]] inline constexpr std::optional<std::string_view> getOriginalStringView(
82 bool* has_escaped_quotes = nullptr) const;
83
88 [[nodiscard]] inline std::optional<std::string> getCleanString() const;
89
96 template<std::size_t BufferSize>
97 [[nodiscard]] constexpr CellStringBuffer<BufferSize> getCleanStringBuffer() const;
98
101 [[nodiscard]] constexpr std::size_t getRequiredBufferSize() const;
102
103
104 private:
105
107 struct Empty { };
108
110 struct String {
111 std::string_view view;
112 bool has_escaped_quotes = false;
113 };
114
116 std::variant<
117 Empty,
118 double,
119 String
120 > value_ = Empty();
121};
122
123
124
128 public:
129
131 CellValue() = default;
132
138 template<typename BehaviorPolicy>
139 CellValue(std::string_view cell, CellTypeHint hint, BehaviorPolicy policy);
140
142 [[nodiscard]] inline CellType getType() const;
143
145 [[nodiscard]] inline bool isEmpty() const;
146
150 [[nodiscard]] inline std::optional<double> getDouble() const;
151
156 [[nodiscard]] inline std::optional<std::string> getString() const;
157
158 private:
159
161 struct Empty { };
162
164 std::variant<
165 Empty,
166 double,
167 std::string
168 > value_ = Empty();
169};
170
171
172
178 public:
179
181 constexpr CellDoubleValue() = default;
182
189 template<typename BehaviorPolicy>
190 constexpr explicit CellDoubleValue(std::string_view cell,
191 CellTypeHint hint_ignored, BehaviorPolicy policy) noexcept;
192
195 [[nodiscard]] inline constexpr double getValue() const;
196
197 private:
199 double value_ = std::numeric_limits<double>::quiet_NaN();
200};
201
202
203
204
210 public:
211
213 constexpr CellStringReference() = default;
214
220 template<typename BehaviorPolicy>
221 constexpr CellStringReference(std::string_view cell, CellTypeHint hint, BehaviorPolicy policy) noexcept;
222
227 [[nodiscard]] inline constexpr std::string_view getOriginalStringView(
228 bool* has_escaped_quotes = nullptr) const noexcept;
229
234 [[nodiscard]] inline std::string getCleanString();
235
242 template<std::size_t BufferSize>
243 [[nodiscard]] constexpr CellStringBuffer<BufferSize> getCleanStringBuffer() const;
244
247 [[nodiscard]] constexpr std::size_t getRequiredBufferSize() const;
248
249
250 private:
251
253 std::string_view value_;
254
256 bool has_escaped_quotes_ = false;
257
258};
259
260
261
266 public:
267
269 CellStringValue() = default;
270
276 template<typename BehaviorPolicy>
277 CellStringValue(std::string_view cell, CellTypeHint hint, BehaviorPolicy policy);
278
282 [[nodiscard]] inline const std::string& getString() const;
283
284 private:
286 std::string value_;
287};
288
289
290
291
292// ----- Implementation
293
294
295
296template<typename BehaviorPolicy>
297constexpr CellReference::CellReference(std::string_view cell, CellTypeHint hint,
298 [[maybe_unused]] BehaviorPolicy policy) noexcept
299{
300 switch (hint) {
301 case CellTypeHint::Empty:
302 // Nothing, value is empty
303 break;
304
305 case CellTypeHint::StringWithEscapedQuotes:
306 value_ = String{cell, true};
307 break;
308
309 case CellTypeHint::StringWithoutEscapedQuotes:
310 value_ = String{cell, false};
311 break;
312
313 case CellTypeHint::UnquotedData:
314 if (auto double_value = BehaviorPolicy::template readNumber<double>(cell); double_value.has_value()) {
315 value_ = double_value.value();
316 } else {
317 value_ = String{cell, false};
318 }
319 break;
320 }
321}
322
323
324
326{
327 if (std::holds_alternative<Empty>(value_)) {
328 return CellType::Empty;
329 }
330 if (std::holds_alternative<double>(value_)) {
331 return CellType::Double;
332 }
333 if (std::holds_alternative<String>(value_)) {
334 return CellType::String;
335 }
336 throw std::bad_variant_access();
337}
338
339
340
341constexpr bool CellReference::isEmpty() const
342{
343 return std::holds_alternative<Empty>(value_);
344}
345
346
347
348constexpr std::optional<double> CellReference::getDouble() const
349{
350 if (std::holds_alternative<double>(value_)) {
351 return std::get<double>(value_);
352 }
353 return {};
354}
355
356
357
358constexpr std::optional<std::string_view> CellReference::getOriginalStringView(bool* has_escaped_quotes) const
359{
360 if (std::holds_alternative<String>(value_)) {
361 const auto& s = std::get<String>(value_);
362 if (has_escaped_quotes) {
363 *has_escaped_quotes = s.has_escaped_quotes;
364 }
365 return s.view;
366 }
367 return {};
368}
369
370
371
372std::optional<std::string> CellReference::getCleanString() const
373{
374 if (std::holds_alternative<String>(value_)) {
375 const auto& s = std::get<String>(value_);
376 return s.has_escaped_quotes ? cleanString(s.view) : std::string(s.view);
377 }
378 return {};
379}
380
381
382
383template<std::size_t BufferSize>
385{
386 // This throws bad variant access
387 const auto& s = std::get<String>(value_);
388 return CellStringBuffer<BufferSize>(s.view, s.has_escaped_quotes);
389}
390
391
392
393constexpr std::size_t CellReference::getRequiredBufferSize() const
394{
395 // This throws bad variant access
396 const auto& s = std::get<String>(value_);
397 return s.has_escaped_quotes ? getCleanStringSize(s.view) : s.view.size();
398}
399
400
401
402
403
404template<typename BehaviorPolicy>
405CellValue::CellValue(std::string_view cell, CellTypeHint hint, [[maybe_unused]] BehaviorPolicy policy)
406{
407 switch (hint) {
408 case CellTypeHint::Empty:
409 // Nothing, value is empty
410 break;
411
412 case CellTypeHint::StringWithEscapedQuotes:
413 value_ = cleanString(cell);
414 break;
415
416 case CellTypeHint::StringWithoutEscapedQuotes:
417 value_ = std::string(cell);
418 break;
419
420 case CellTypeHint::UnquotedData:
421 if (auto double_value = BehaviorPolicy::template readNumber<double>(cell); double_value.has_value()) {
422 value_ = double_value.value();
423 } else {
424 value_ = std::string(cell);
425 }
426 break;
427 }
428}
429
430
431
433{
434 if (std::holds_alternative<Empty>(value_)) {
435 return CellType::Empty;
436 }
437 if (std::holds_alternative<double>(value_)) {
438 return CellType::Double;
439 }
440 if (std::holds_alternative<std::string>(value_)) {
441 return CellType::String;
442 }
443 throw std::bad_variant_access();
444}
445
446
447
449{
450 return std::holds_alternative<Empty>(value_);
451}
452
453
454
455std::optional<double> CellValue::getDouble() const
456{
457 if (std::holds_alternative<double>(value_)) {
458 return std::get<double>(value_);
459 }
460 return {};
461}
462
463
464
465std::optional<std::string> CellValue::getString() const
466{
467 if (std::holds_alternative<std::string>(value_)) {
468 return std::get<std::string>(value_);
469 }
470 return {};
471}
472
473
474
475
476
477template<typename BehaviorPolicy>
478constexpr CellDoubleValue::CellDoubleValue(std::string_view cell,
479 [[maybe_unused]] CellTypeHint hint_ignored, [[maybe_unused]] BehaviorPolicy policy) noexcept
480{
481 if (auto double_value = BehaviorPolicy::template readNumber<double>(cell); double_value.has_value()) {
482 value_ = double_value.value();
483 }
484}
485
486
487
488constexpr double CellDoubleValue::getValue() const
489{
490 return value_;
491}
492
493
494
495
496
497template<typename BehaviorPolicy>
498constexpr CellStringReference::CellStringReference(std::string_view cell, CellTypeHint hint,
499 [[maybe_unused]] BehaviorPolicy policy) noexcept
500 : value_(cell),
501 has_escaped_quotes_(hint == CellTypeHint::StringWithEscapedQuotes)
502{ }
503
504
505
506constexpr std::string_view CellStringReference::getOriginalStringView(bool* has_escaped_quotes) const noexcept
507{
508 if (has_escaped_quotes) {
509 *has_escaped_quotes = has_escaped_quotes_;
510 }
511 return value_;
512}
513
514
515
517{
518 return has_escaped_quotes_ ? cleanString(value_) : std::string(value_);
519}
520
521
522
523template<std::size_t BufferSize>
525{
526 return CellStringBuffer<BufferSize>(value_, has_escaped_quotes_);
527}
528
529
530
532{
533 return getCleanStringSize(value_);
534}
535
536
537
538
539
540template<typename BehaviorPolicy>
542 [[maybe_unused]] BehaviorPolicy policy)
543 : value_(hint == CellTypeHint::StringWithEscapedQuotes ? cleanString(cell) : std::string(cell))
544{ }
545
546
547
548const std::string& CellStringValue::getString() const
549{
550 return value_;
551}
552
553
554
555
556} // end ns
557
558
559
560#endif
Data inside a single cell, stored as a value of double type.
Definition csv_cell.h:177
constexpr double getValue() const
Get the cell value if cell type is Double.
Definition csv_cell.h:488
constexpr CellDoubleValue()=default
Constructor, setting the value to std::numeric_limits<double>::quiet_NaN().
Data inside a single cell, potentially stored as a reference to the original data.
Definition csv_cell.h:51
constexpr CellStringBuffer< BufferSize > getCleanStringBuffer() const
Get a string buffer with collapsed consecutive double-quotes.
Definition csv_cell.h:384
constexpr std::optional< double > getDouble() const
Get the cell value as a double.
Definition csv_cell.h:348
constexpr CellReference()=default
Constructor, creates an Empty value.
constexpr CellType getType() const
Get data type.
Definition csv_cell.h:325
constexpr std::optional< std::string_view > getOriginalStringView(bool *has_escaped_quotes=nullptr) const
Get stored data reference as string_view to the original CSV data.
Definition csv_cell.h:358
constexpr std::size_t getRequiredBufferSize() const
Get required buffer size to use as getCleanStringBuffer()'s template argument.
Definition csv_cell.h:393
std::optional< std::string > getCleanString() const
Get stored cell data as std::string.
Definition csv_cell.h:372
constexpr bool isEmpty() const
Check whether the data is of CellType::Empty type.
Definition csv_cell.h:341
A helper class for compile-time buffer construction and string unescaping.
Definition csv_cell_string_buffer.h:29
String data inside a single cell, stored as a reference to the original data.
Definition csv_cell.h:209
std::string getCleanString()
Get stored cell reference a std::string.
Definition csv_cell.h:516
constexpr std::size_t getRequiredBufferSize() const
Get required buffer size to use as getCleanStringBuffer()'s template argument.
Definition csv_cell.h:531
constexpr CellStringReference()=default
Constructor, creates an empty string reference.
constexpr std::string_view getOriginalStringView(bool *has_escaped_quotes=nullptr) const noexcept
Get stored cell reference as string_view.
Definition csv_cell.h:506
constexpr CellStringBuffer< BufferSize > getCleanStringBuffer() const
Get a string buffer with collapsed consecutive double-quotes.
Definition csv_cell.h:524
A value of a cell.
Definition csv_cell.h:265
const std::string & getString() const
Get stored cell reference as string.
Definition csv_cell.h:548
CellStringValue()=default
Constructor.
Data inside a single cell, stored as a copy.
Definition csv_cell.h:127
std::optional< std::string > getString() const
Get stored cell value as std::string.
Definition csv_cell.h:465
CellType getType() const
Get cell type.
Definition csv_cell.h:432
bool isEmpty() const
Check whether the cell is of CellType::Empty type.
Definition csv_cell.h:448
std::optional< double > getDouble() const
Get the cell value if cell type is Double.
Definition csv_cell.h:455
CellValue()=default
Constructor, creates an Empty value.
CellTypeHint
Type hint associated with the cell to determine the type of the cell value.
Definition csv_cell.h:32
@ StringWithEscapedQuotes
Quoted or unquoted string with escaped quotes inside.
@ Empty
Empty data (no quotes, no whitespace).
@ StringWithoutEscapedQuotes
Quoted or unquoted string without any escaped quotes inside.
@ UnquotedData
Unquoted data, no escaped quotes inside.
CellType
Type of the cell value.
Definition csv_cell.h:41
@ String
String data.
@ Double
double value
Helper for compile-time buffer construction and string unescaping.
Utility functions used by the library.
constexpr std::size_t getCleanStringSize(std::string_view uncollapsed_view)
Get size of a cleaned-up string given the uncollapsed string.
Definition csv_util.h:104
std::string cleanString(std::string_view view)
Unescape a string - collapse every occurrence of 2 consecutive double-quotes to one.
Definition csv_util.h:88