2 #ifndef SIMDJSON_SERIALIZATION_INL_H
3 #define SIMDJSON_SERIALIZATION_INL_H
5 #include "simdjson/dom/base.h"
6 #include "simdjson/dom/serialization.h"
7 #include "simdjson/dom/parser.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"
18 inline bool parser::print_json(std::ostream &os)
const noexcept {
19 if (!valid) {
return false; }
20 simdjson::internal::string_builder<> sb;
21 sb.append(doc.root());
22 std::string_view answer = sb.str();
28 simdjson::internal::string_builder<> sb;
30 return (out << sb.str());
32 #if SIMDJSON_EXCEPTIONS
35 return (out << x.
value());
39 simdjson::internal::string_builder<> sb;
41 return (out << sb.str());
43 #if SIMDJSON_EXCEPTIONS
46 return (out << x.
value());
50 simdjson::internal::string_builder<> sb;
52 return (out << sb.str());
54 #if SIMDJSON_EXCEPTIONS
57 return (out << x.
value());
71 struct escape_sequence {
84 static char *fast_itoa(
char *output, int64_t value) noexcept {
87 uint64_t value_positive;
95 std::memcpy(&value_positive, &value,
sizeof(value));
96 value_positive = (~value_positive) + 1;
98 value_positive = value;
103 const char *
const end_buffer = buffer + 20;
104 char *write_pointer = buffer + 19;
108 while(value_positive >= 10) {
109 *write_pointer-- = char(
'0' + (value_positive % 10));
110 value_positive /= 10;
112 *write_pointer = char(
'0' + value_positive);
113 size_t len = end_buffer - write_pointer;
114 std::memcpy(output, write_pointer, len);
126 static char *fast_itoa(
char *output, uint64_t value) noexcept {
129 const char *
const end_buffer = buffer + 20;
130 char *write_pointer = buffer + 19;
135 *write_pointer-- = char(
'0' + (value % 10));
138 *write_pointer = char(
'0' + value);
139 size_t len = end_buffer - write_pointer;
140 std::memcpy(output, write_pointer, len);
152 template<
class formatter>
153 simdjson_inline
void base_formatter<formatter>::number(uint64_t x) {
154 char number_buffer[24];
155 char *newp = fast_itoa(number_buffer, x);
156 buffer.insert(buffer.end(), number_buffer, newp);
159 template<
class formatter>
160 simdjson_inline
void base_formatter<formatter>::number(int64_t x) {
161 char number_buffer[24];
162 char *newp = fast_itoa(number_buffer, x);
163 buffer.insert(buffer.end(), number_buffer, newp);
166 template<
class formatter>
167 simdjson_inline
void base_formatter<formatter>::number(
double x) {
168 char number_buffer[24];
172 char *newp = internal::to_chars(number_buffer,
nullptr, x);
173 buffer.insert(buffer.end(), number_buffer, newp);
176 template<
class formatter>
177 simdjson_inline
void base_formatter<formatter>::start_array() { one_char(
'['); }
180 template<
class formatter>
181 simdjson_inline
void base_formatter<formatter>::end_array() { one_char(
']'); }
183 template<
class formatter>
184 simdjson_inline
void base_formatter<formatter>::start_object() { one_char(
'{'); }
186 template<
class formatter>
187 simdjson_inline
void base_formatter<formatter>::end_object() { one_char(
'}'); }
189 template<
class formatter>
190 simdjson_inline
void base_formatter<formatter>::comma() { one_char(
','); }
192 template<
class formatter>
193 simdjson_inline
void base_formatter<formatter>::true_atom() {
194 const char * s =
"true";
195 buffer.insert(buffer.end(), s, s + 4);
198 template<
class formatter>
199 simdjson_inline
void base_formatter<formatter>::false_atom() {
200 const char * s =
"false";
201 buffer.insert(buffer.end(), s, s + 5);
204 template<
class formatter>
205 simdjson_inline
void base_formatter<formatter>::null_atom() {
206 const char * s =
"null";
207 buffer.insert(buffer.end(), s, s + 4);
210 template<
class formatter>
211 simdjson_inline
void base_formatter<formatter>::one_char(
char c) { buffer.push_back(c); }
213 template<
class formatter>
214 simdjson_inline
void base_formatter<formatter>::key(std::string_view unescaped) {
219 template<
class formatter>
220 simdjson_inline
void base_formatter<formatter>::string(std::string_view unescaped) {
228 constexpr
static char needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
229 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
231 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
237 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
238 for(;i + 8 <= unescaped.length(); i += 8) {
242 if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
243 | needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
244 | needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
245 | needs_escaping[uint8_t(unescaped[i+6])] | needs_escaping[uint8_t(unescaped[i+7])]
248 for(;i < unescaped.length(); i++) {
249 if(needs_escaping[uint8_t(unescaped[i])]) {
break; }
257 buffer.insert(buffer.end(), unescaped.data(), unescaped.data() + i);
261 for (; i < unescaped.length(); i++) {
262 switch (unescaped[i]) {
265 const char * s =
"\\\"";
266 buffer.insert(buffer.end(), s, s + 2);
271 const char * s =
"\\\\";
272 buffer.insert(buffer.end(), s, s + 2);
276 if (uint8_t(unescaped[i]) <= 0x1F) {
280 constexpr
static escape_sequence escaped[32] = {
281 {6,
"\\u0000"}, {6,
"\\u0001"}, {6,
"\\u0002"}, {6,
"\\u0003"},
282 {6,
"\\u0004"}, {6,
"\\u0005"}, {6,
"\\u0006"}, {6,
"\\u0007"},
283 {2,
"\\b"}, {2,
"\\t"}, {2,
"\\n"}, {6,
"\\u000b"},
284 {2,
"\\f"}, {2,
"\\r"}, {6,
"\\u000e"}, {6,
"\\u000f"},
285 {6,
"\\u0010"}, {6,
"\\u0011"}, {6,
"\\u0012"}, {6,
"\\u0013"},
286 {6,
"\\u0014"}, {6,
"\\u0015"}, {6,
"\\u0016"}, {6,
"\\u0017"},
287 {6,
"\\u0018"}, {6,
"\\u0019"}, {6,
"\\u001a"}, {6,
"\\u001b"},
288 {6,
"\\u001c"}, {6,
"\\u001d"}, {6,
"\\u001e"}, {6,
"\\u001f"}};
289 auto u = escaped[uint8_t(unescaped[i])];
290 buffer.insert(buffer.end(), u.string, u.string + u.length);
292 one_char(unescaped[i]);
300 template<
class formatter>
301 inline void base_formatter<formatter>::clear() {
305 template<
class formatter>
306 simdjson_inline std::string_view base_formatter<formatter>::str()
const {
307 return std::string_view(buffer.data(), buffer.size());
310 simdjson_inline
void mini_formatter::print_newline() {
314 simdjson_inline
void mini_formatter::print_indents(
size_t depth) {
319 simdjson_inline
void mini_formatter::print_space() {
323 simdjson_inline
void pretty_formatter::print_newline() {
327 simdjson_inline
void pretty_formatter::print_indents(
size_t depth) {
328 if(this->indent_step <= 0) {
331 for(
size_t i = 0; i < this->indent_step * depth; i++) {
336 simdjson_inline
void pretty_formatter::print_space() {
344 template <
class serializer>
348 constexpr
size_t MAX_DEPTH = 16;
349 bool is_object[MAX_DEPTH];
350 is_object[0] =
false;
351 bool after_value =
false;
353 internal::tape_ref iter(value.tape);
358 format.print_newline();
361 format.print_indents(depth);
365 if (is_object[depth]) {
366 format.key(iter.get_string_view());
367 format.print_space();
370 switch (iter.tape_ref_type()) {
373 case tape_type::START_ARRAY: {
376 if (simdjson_unlikely(depth >= MAX_DEPTH)) {
378 iter.json_index = iter.matching_brace_index() - 1;
384 format.start_array();
388 if (iter.tape_ref_type() == tape_type::END_ARRAY) {
394 is_object[depth] =
false;
396 format.print_newline();
401 case tape_type::START_OBJECT: {
404 if (simdjson_unlikely(depth >= MAX_DEPTH)) {
406 iter.json_index = iter.matching_brace_index() - 1;
412 format.start_object();
416 if (iter.tape_ref_type() == tape_type::END_OBJECT) {
422 is_object[depth] =
true;
424 format.print_newline();
429 case tape_type::STRING:
430 format.string(iter.get_string_view());
432 case tape_type::INT64:
433 format.number(iter.next_tape_value<int64_t>());
437 case tape_type::UINT64:
438 format.number(iter.next_tape_value<uint64_t>());
442 case tape_type::DOUBLE:
443 format.number(iter.next_tape_value<
double>());
447 case tape_type::TRUE_VALUE:
450 case tape_type::FALSE_VALUE:
453 case tape_type::NULL_VALUE:
458 case tape_type::END_ARRAY:
459 case tape_type::END_OBJECT:
460 case tape_type::ROOT:
461 SIMDJSON_UNREACHABLE();
467 while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY ||
468 iter.tape_ref_type() == tape_type::END_OBJECT)) {
469 format.print_newline();
471 format.print_indents(depth);
472 if (iter.tape_ref_type() == tape_type::END_ARRAY) {
481 }
while (depth != 0);
483 format.print_newline();
486 template <
class serializer>
488 format.start_object();
489 auto pair = value.begin();
490 auto end = value.end();
493 for (++pair; pair != end; ++pair) {
501 template <
class serializer>
503 format.start_array();
504 auto iter = value.begin();
505 auto end = value.end();
508 for (++iter; iter != end; ++iter) {
516 template <
class serializer>
522 template <
class serializer>
523 simdjson_inline
void string_builder<serializer>::clear() {
527 template <
class serializer>
528 simdjson_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.