2#ifndef SIMDJSON_SERIALIZATION_INL_H
3#define SIMDJSON_SERIALIZATION_INL_H
5#include "simdjson/dom/base.h"
6#include "simdjson/dom/parser.h"
7#include "simdjson/dom/serialization.h"
8#include "simdjson/internal/tape_type.h"
10#include "simdjson/dom/array-inl.h"
11#include "simdjson/dom/object-inl.h"
12#include "simdjson/internal/tape_ref-inl.h"
18inline bool parser::print_json(std::ostream &os)
const noexcept {
22 simdjson::internal::string_builder<> sb;
23 sb.append(doc.root());
24 std::string_view answer = sb.str();
29inline std::ostream &operator<<(std::ostream &out,
31 simdjson::internal::string_builder<> sb;
33 return (out << sb.str());
35#if SIMDJSON_EXCEPTIONS
37operator<<(std::ostream &out,
42 return (out << x.
value());
46 simdjson::internal::string_builder<> sb;
48 return (out << sb.str());
50#if SIMDJSON_EXCEPTIONS
52operator<<(std::ostream &out,
57 return (out << x.
value());
60inline std::ostream &operator<<(std::ostream &out,
62 simdjson::internal::string_builder<> sb;
64 return (out << sb.str());
66#if SIMDJSON_EXCEPTIONS
68operator<<(std::ostream &out,
73 return (out << x.
value());
87struct escape_sequence {
101static char *fast_itoa(
char *output, int64_t value)
noexcept {
104 uint64_t value_positive;
112 std::memcpy(&value_positive, &value,
sizeof(value));
113 value_positive = (~value_positive) + 1;
115 value_positive = value;
120 const char *
const end_buffer = buffer + 20;
121 char *write_pointer = buffer + 19;
125 while (value_positive >= 10) {
126 *write_pointer-- = char(
'0' + (value_positive % 10));
127 value_positive /= 10;
129 *write_pointer = char(
'0' + value_positive);
130 size_t len = end_buffer - write_pointer;
131 std::memcpy(output, write_pointer, len);
143static char *fast_itoa(
char *output, uint64_t value)
noexcept {
146 const char *
const end_buffer = buffer + 20;
147 char *write_pointer = buffer + 19;
151 while (value >= 10) {
152 *write_pointer-- = char(
'0' + (value % 10));
155 *write_pointer = char(
'0' + value);
156 size_t len = end_buffer - write_pointer;
157 std::memcpy(output, write_pointer, len);
168template <
class formatter>
169simdjson_inline
void base_formatter<formatter>::number(uint64_t x) {
170 char number_buffer[24];
171 char *newp = fast_itoa(number_buffer, x);
172 chars(number_buffer, newp);
175template <
class formatter>
176simdjson_inline
void base_formatter<formatter>::number(int64_t x) {
177 char number_buffer[24];
178 char *newp = fast_itoa(number_buffer, x);
179 chars(number_buffer, newp);
182template <
class formatter>
183simdjson_inline
void base_formatter<formatter>::number(
double x) {
184 char number_buffer[24];
188 char *newp = internal::to_chars(number_buffer,
nullptr, x);
189 chars(number_buffer, newp);
192template <
class formatter>
193simdjson_inline
void base_formatter<formatter>::start_array() {
197template <
class formatter>
198simdjson_inline
void base_formatter<formatter>::end_array() {
202template <
class formatter>
203simdjson_inline
void base_formatter<formatter>::start_object() {
207template <
class formatter>
208simdjson_inline
void base_formatter<formatter>::end_object() {
212template <
class formatter>
213simdjson_inline
void base_formatter<formatter>::comma() {
217template <
class formatter>
218simdjson_inline
void base_formatter<formatter>::true_atom() {
219 const char *s =
"true";
223template <
class formatter>
224simdjson_inline
void base_formatter<formatter>::false_atom() {
225 const char *s =
"false";
229template <
class formatter>
230simdjson_inline
void base_formatter<formatter>::null_atom() {
231 const char *s =
"null";
235template <
class formatter>
236simdjson_inline
void base_formatter<formatter>::one_char(
char c) {
240template <
class formatter>
241simdjson_inline
void base_formatter<formatter>::chars(
const char *begin,
243 buffer.append(begin, end);
246template <
class formatter>
248base_formatter<formatter>::key(std::string_view unescaped) {
253template <
class formatter>
255base_formatter<formatter>::string(std::string_view unescaped) {
263 constexpr static char needs_escaping[] = {
264 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
265 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
275 for (; i + 8 <= unescaped.length(); i += 8) {
280 if (needs_escaping[uint8_t(unescaped[i])] |
281 needs_escaping[uint8_t(unescaped[i + 1])] |
282 needs_escaping[uint8_t(unescaped[i + 2])] |
283 needs_escaping[uint8_t(unescaped[i + 3])] |
284 needs_escaping[uint8_t(unescaped[i + 4])] |
285 needs_escaping[uint8_t(unescaped[i + 5])] |
286 needs_escaping[uint8_t(unescaped[i + 6])] |
287 needs_escaping[uint8_t(unescaped[i + 7])]) {
291 for (; i < unescaped.length(); i++) {
292 if (needs_escaping[uint8_t(unescaped[i])]) {
302 chars(unescaped.data(), unescaped.data() + i);
306 for (; i < unescaped.length(); i++) {
307 switch (unescaped[i]) {
309 const char *s =
"\\\"";
313 const char *s =
"\\\\";
317 if (uint8_t(unescaped[i]) <= 0x1F) {
321 constexpr static escape_sequence escaped[32] = {
322 {6,
"\\u0000"}, {6,
"\\u0001"}, {6,
"\\u0002"}, {6,
"\\u0003"},
323 {6,
"\\u0004"}, {6,
"\\u0005"}, {6,
"\\u0006"}, {6,
"\\u0007"},
324 {2,
"\\b"}, {2,
"\\t"}, {2,
"\\n"}, {6,
"\\u000b"},
325 {2,
"\\f"}, {2,
"\\r"}, {6,
"\\u000e"}, {6,
"\\u000f"},
326 {6,
"\\u0010"}, {6,
"\\u0011"}, {6,
"\\u0012"}, {6,
"\\u0013"},
327 {6,
"\\u0014"}, {6,
"\\u0015"}, {6,
"\\u0016"}, {6,
"\\u0017"},
328 {6,
"\\u0018"}, {6,
"\\u0019"}, {6,
"\\u001a"}, {6,
"\\u001b"},
329 {6,
"\\u001c"}, {6,
"\\u001d"}, {6,
"\\u001e"}, {6,
"\\u001f"}};
330 auto u = escaped[uint8_t(unescaped[i])];
331 chars(u.string, u.string + u.length);
333 one_char(unescaped[i]);
340template <
class formatter>
inline void base_formatter<formatter>::clear() {
344template <
class formatter>
345simdjson_inline std::string_view base_formatter<formatter>::str()
const {
349simdjson_inline
void mini_formatter::print_newline() {
return; }
351simdjson_inline
void mini_formatter::print_indents(
size_t depth) {
356simdjson_inline
void mini_formatter::print_space() {
return; }
358simdjson_inline
void pretty_formatter::print_newline() { one_char(
'\n'); }
360simdjson_inline
void pretty_formatter::print_indents(
size_t depth) {
361 if (this->indent_step <= 0) {
364 for (
size_t i = 0; i < this->indent_step * depth; i++) {
369simdjson_inline
void pretty_formatter::print_space() { one_char(
' '); }
375template <
class serializer>
379 constexpr size_t MAX_DEPTH = 16;
380 bool is_object[MAX_DEPTH];
381 is_object[0] =
false;
382 bool after_value =
false;
384 internal::tape_ref iter(value.tape);
389 format.print_newline();
392 format.print_indents(depth);
396 if (is_object[depth]) {
397 format.key(iter.get_string_view());
398 format.print_space();
401 switch (iter.tape_ref_type()) {
404 case tape_type::START_ARRAY: {
407 if (simdjson_unlikely(depth >= MAX_DEPTH)) {
409 iter.json_index = iter.matching_brace_index() - 1;
415 format.start_array();
419 if (iter.tape_ref_type() == tape_type::END_ARRAY) {
425 is_object[depth] =
false;
427 format.print_newline();
432 case tape_type::START_OBJECT: {
435 if (simdjson_unlikely(depth >= MAX_DEPTH)) {
437 iter.json_index = iter.matching_brace_index() - 1;
443 format.start_object();
447 if (iter.tape_ref_type() == tape_type::END_OBJECT) {
453 is_object[depth] =
true;
455 format.print_newline();
460 case tape_type::STRING:
461 format.string(iter.get_string_view());
463 case tape_type::BIGINT: {
465 auto sv = iter.get_string_view();
466 format.chars(sv.data(), sv.data() + sv.size());
469 case tape_type::INT64:
470 format.number(iter.next_tape_value<int64_t>());
474 case tape_type::UINT64:
475 format.number(iter.next_tape_value<uint64_t>());
479 case tape_type::DOUBLE:
480 format.number(iter.next_tape_value<
double>());
484 case tape_type::TRUE_VALUE:
487 case tape_type::FALSE_VALUE:
490 case tape_type::NULL_VALUE:
495 case tape_type::END_ARRAY:
496 case tape_type::END_OBJECT:
497 case tape_type::ROOT:
498 SIMDJSON_UNREACHABLE();
504 while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY ||
505 iter.tape_ref_type() == tape_type::END_OBJECT)) {
506 format.print_newline();
508 format.print_indents(depth);
509 if (iter.tape_ref_type() == tape_type::END_ARRAY) {
518 }
while (depth != 0);
520 format.print_newline();
523template <
class serializer>
525 format.start_object();
526 auto pair = value.begin();
527 auto end = value.end();
530 for (++pair; pair != end; ++pair) {
538template <
class serializer>
540 format.start_array();
541 auto iter = value.begin();
542 auto end = value.end();
545 for (++iter; iter != end; ++iter) {
553template <
class serializer>
560template <
class serializer>
561simdjson_inline
void string_builder<serializer>::clear() {
565template <
class serializer>
566simdjson_inline std::string_view string_builder<serializer>::str()
const {
Key/value pair in an object.
std::string_view key
key in the key-value pair
element value
value in the key-value pair
The top level simdjson namespace, containing everything the library provides.
Exception thrown when an exception-supporting simdjson method is called.
The result of a simdjson operation that could fail.
simdjson_inline error_code error() const noexcept
The error.
simdjson_inline T & value() &noexcept(false)
Get the result value.