34 std::vector<std::pair<std::string, std::string>> run()
36 std::vector<std::pair<std::string, std::string>> cells;
40 if (_pos != _text.size()) fail(
"unexpected text after the value");
46 static std::string child_path(
const std::string& path,
const std::string& key)
48 if (path.empty())
return key;
49 std::string out = path;
55 [[noreturn]]
void fail(
const char* what)
const
57 throw std::invalid_argument(
"flatten_json: " + std::string{what} +
" at offset " +
58 std::to_string(_pos));
63 while (_pos < _text.size() &&
64 (_text[_pos] ==
' ' || _text[_pos] ==
'\t' || _text[_pos] ==
'\n' || _text[_pos] ==
'\r'))
70 [[nodiscard]]
char peek()
const
72 if (_pos >= _text.size()) fail(
"unexpected end");
76 static void append_utf8(std::string& out, std::uint32_t cp)
80 out +=
static_cast<char>(cp);
84 out +=
static_cast<char>(0xC0U | (cp >> 6U));
85 out +=
static_cast<char>(0x80U | (cp & 0x3FU));
87 else if (cp < 0x10000U)
89 out +=
static_cast<char>(0xE0U | (cp >> 12U));
90 out +=
static_cast<char>(0x80U | ((cp >> 6U) & 0x3FU));
91 out +=
static_cast<char>(0x80U | (cp & 0x3FU));
95 out +=
static_cast<char>(0xF0U | (cp >> 18U));
96 out +=
static_cast<char>(0x80U | ((cp >> 12U) & 0x3FU));
97 out +=
static_cast<char>(0x80U | ((cp >> 6U) & 0x3FU));
98 out +=
static_cast<char>(0x80U | (cp & 0x3FU));
104 if (_pos + 4 > _text.size()) fail(
"short \\u escape");
106 for (
int i = 0; i < 4; ++i)
108 const char c = _text[_pos++];
110 if (c >=
'0' && c <=
'9') v |=
static_cast<std::uint32_t
>(c -
'0');
111 else if (c >=
'a' && c <=
'f') v |=
static_cast<std::uint32_t
>(c -
'a' + 10);
112 else if (c >=
'A' && c <=
'F') v |=
static_cast<std::uint32_t
>(c -
'A' + 10);
113 else fail(
"bad \\u escape");
118 std::string string_value()
120 if (peek() !=
'"') fail(
"expected a string");
125 const char c = peek();
127 if (c ==
'"')
return out;
133 const char e = peek();
137 case '"': out +=
'"';
break;
138 case '\\': out +=
'\\';
break;
139 case '/': out +=
'/';
break;
140 case 'b': out +=
'\b';
break;
141 case 'f': out +=
'\f';
break;
142 case 'n': out +=
'\n';
break;
143 case 'r': out +=
'\r';
break;
144 case 't': out +=
'\t';
break;
147 std::uint32_t cp = hex4();
148 if (cp >= 0xD800U && cp <= 0xDBFFU && _pos + 1 < _text.size() &&
149 _text[_pos] ==
'\\' && _text[_pos + 1] ==
'u')
152 const std::uint32_t lo = hex4();
153 if (lo < 0xDC00U || lo > 0xDFFFU) fail(
"bad surrogate pair");
154 cp = 0x10000U + ((cp - 0xD800U) << 10U) + (lo - 0xDC00U);
156 append_utf8(out, cp);
159 default: fail(
"bad escape");
169 const char c = peek();
172 (void)string_value();
174 else if (c ==
'{' || c ==
'[')
176 const char close = c ==
'{' ?
'}' :
']';
189 (void)string_value();
191 if (peek() !=
':') fail(
"expected ':'");
196 const char sep = peek();
198 if (sep == close)
return;
199 if (sep !=
',') fail(
"expected ',' or the end of the container");
204 const std::size_t start = _pos;
205 while (_pos < _text.size() && _text[_pos] !=
',' && _text[_pos] !=
'}' &&
206 _text[_pos] !=
']' && _text[_pos] !=
' ' && _text[_pos] !=
'\n' &&
207 _text[_pos] !=
'\r' && _text[_pos] !=
'\t')
211 if (_pos == start) fail(
"expected a value");
216 void value(
const std::string& path, std::vector<std::pair<std::string, std::string>>& cells)
218 const char c = peek();
221 const std::size_t start = _pos;
227 if (!path.empty()) cells.emplace_back(path, std::string{_text.substr(start, 2)});
233 const std::string key = string_value();
235 if (peek() !=
':') fail(
"expected ':'");
238 value(child_path(path, key), cells);
240 const char sep = peek();
242 if (sep ==
'}')
return;
243 if (sep !=
',') fail(
"expected ',' or '}'");
248 const std::size_t start = _pos;
250 cells.emplace_back(path, std::string{_text.substr(start, _pos - start)});
255 cells.emplace_back(path, string_value());
258 const std::size_t start = _pos;
260 const std::string_view token = _text.substr(start, _pos - start);
261 cells.emplace_back(path, token ==
"null" ? std::string{} : std::string{token});
264 std::string_view _text;
358 if (!_header_written)
360 _columns.reserve(cells.size());
361 for (
const auto& cell : cells) _columns.push_back(cell.first);
363 _header_written =
true;
365 std::vector<std::string> row(_columns.size());
366 bool in_order = cells.size() == _columns.size();
367 for (std::size_t i = 0; in_order && i < cells.size(); ++i)
369 in_order = cells[i].first == _columns[i];
373 for (std::size_t i = 0; i < cells.size(); ++i) row[i] = cells[i].second;
377 std::unordered_map<std::string_view, std::size_t> position;
378 position.reserve(_columns.size());
379 for (std::size_t i = 0; i < _columns.size(); ++i) position.emplace(_columns[i], i);
380 for (
const auto& cell : cells)
382 if (
const auto it = position.find(cell.first); it != position.end())
384 row[it->second] = cell.second;
394 template <json_result T>
402 [[nodiscard]]
const std::vector<std::string>&
columns() const noexcept {
return _columns; }
406 [[nodiscard]] std::size_t
records() const noexcept {
return _records; }
409 void write_row(
const std::vector<std::string>& fields)
411 for (std::size_t i = 0; i < fields.size(); ++i)
413 if (i > 0) _out->put(
',');
414 write_field(fields[i]);
419 void write_field(
const std::string& field)
421 if (field.find_first_of(
",\"\r\n") == std::string::npos)
423 _out->write(field.data(),
static_cast<std::streamsize
>(field.size()));
427 for (
const char c : field)
429 if (c ==
'"') _out->put(
'"');
436 std::vector<std::string> _columns;
437 bool _header_written{
false};
438 std::size_t _records{0};