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();
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());
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::INT64:
464 format.number(iter.next_tape_value<int64_t>());
468 case tape_type::UINT64:
469 format.number(iter.next_tape_value<uint64_t>());
473 case tape_type::DOUBLE:
474 format.number(iter.next_tape_value<
double>());
478 case tape_type::TRUE_VALUE:
481 case tape_type::FALSE_VALUE:
484 case tape_type::NULL_VALUE:
489 case tape_type::END_ARRAY:
490 case tape_type::END_OBJECT:
491 case tape_type::ROOT:
492 SIMDJSON_UNREACHABLE();
498 while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY ||
499 iter.tape_ref_type() == tape_type::END_OBJECT)) {
500 format.print_newline();
502 format.print_indents(depth);
503 if (iter.tape_ref_type() == tape_type::END_ARRAY) {
512 }
while (depth != 0);
514 format.print_newline();
517template <
class serializer>
519 format.start_object();
520 auto pair = value.begin();
521 auto end = value.end();
524 for (++pair; pair != end; ++pair) {
532template <
class serializer>
534 format.start_array();
535 auto iter = value.begin();
536 auto end = value.end();
539 for (++iter; iter != end; ++iter) {
547template <
class serializer>
554template <
class serializer>
555simdjson_inline
void string_builder<serializer>::clear() {
559template <
class serializer>
560simdjson_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.