header_utils
Loading...
Searching...
No Matches
formats.h
1
4
5#pragma once
6
7#include "string_ops.h"
8
10{
13
14 namespace detail
15 {
16 constexpr int get_char(std::string_view& str) { if (str.empty()) { return -1; } const auto result = static_cast<unsigned char>(str[0]); str.remove_prefix(1); return result; }
17 constexpr int get_invalid_char(std::type_identity<std::string_view>) { return -1; }
18
19 inline int get_char(std::istream& strm) { return strm.get(); }
20 template <typename T>
21 requires std::derived_from<T, std::istream>
22 constexpr int get_invalid_char(std::type_identity<T>) { return -1; }
23 }
24
27
28 namespace csv
29 {
38 // TODO: Extend this to accept any char type
39 // TODO: Perhaps it would be best if we didn't allocate the row vector each time (we're moving it away currently)
40 // but reuse its storage (and the storage of its members)
41 // TODO: Extend this to use our own buffers API
42 template <typename BUFFER, typename ROW_CALLBACK>
44 {
45 using ghassanpl::formats::detail::get_char;
46 using ghassanpl::formats::detail::get_invalid_char;
47
48 static constexpr auto invalid_value = get_invalid_char(std::type_identity<std::remove_cvref_t<decltype(buffer)>>{});
49 bool in_quote = false;
50 intptr_t line = 0;
51
52 std::vector<std::string> row;
53 std::string current_cell;
54 int cp = 0;
55 while ((cp = get_char(buffer)) != invalid_value)
56 {
57 if (in_quote)
58 {
59 if (cp == '"')
60 {
61 if ((cp = get_char(buffer)) == invalid_value)
62 break;
63 if (cp != '"')
64 {
65 in_quote = false;
66 goto no_quote;
67 }
68 }
69 current_cell += (char)cp;
70 }
71 else
72 {
74
75 if (cp == '\r')
76 {
77 if ((cp = get_char(buffer)) == invalid_value)
78 break;
79 if (cp != '\n')
80 {
81 current_cell += '\r';
82 current_cell += (char)cp;
83 continue;
84 }
85 }
86
87 if (cp == '\n')
88 {
89 row.push_back(std::exchange(current_cell, {}));
90 if (!row_callback(line++, std::exchange(row, {})))
91 return line;
92 }
93 else if (cp == '"')
94 in_quote = true;
95 else if (cp == ',')
96 row.push_back(std::exchange(current_cell, {}));
97 else
98 current_cell += (char)cp;
99 }
100 }
101
102 if (!current_cell.empty())
103 row.push_back(std::move(current_cell));
104 if (!row.empty())
105 row_callback(line++, std::move(row));
106
107 return line;
108 }
109 }
110
111}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
intptr_t load(BUFFER &&buffer, ROW_CALLBACK &&row_callback)
Loads a CSV text file from buffer, calling row_callback for each row.
Definition formats.h:43
The below code is based on Sun's libm library code, which is licensed under the following license: