simdjson  3.1.8
Ridiculously Fast JSON
document-inl.h
1 #ifndef SIMDJSON_INLINE_DOCUMENT_H
2 #define SIMDJSON_INLINE_DOCUMENT_H
3 
4 // Inline implementations go in here.
5 
6 #include "simdjson/dom/document.h"
7 #include "simdjson/dom/element.h"
8 #include "simdjson/internal/tape_ref.h"
9 #include "simdjson/internal/jsonformatutils.h"
10 #include <ostream>
11 #include <cstring>
12 
13 namespace simdjson {
14 namespace dom {
15 
16 //
17 // document inline implementation
18 //
19 inline element document::root() const noexcept {
20  return element(internal::tape_ref(this, 1));
21 }
22 simdjson_warn_unused
23 inline size_t document::capacity() const noexcept {
24  return allocated_capacity;
25 }
26 
27 simdjson_warn_unused
28 inline error_code document::allocate(size_t capacity) noexcept {
29  if (capacity == 0) {
30  string_buf.reset();
31  tape.reset();
32  allocated_capacity = 0;
33  return SUCCESS;
34  }
35 
36  // a pathological input like "[[[[..." would generate capacity tape elements, so
37  // need a capacity of at least capacity + 1, but it is also possible to do
38  // worse with "[7,7,7,7,6,7,7,7,6,7,7,6,[7,7,7,7,6,7,7,7,6,7,7,6,7,7,7,7,7,7,6"
39  //where capacity + 1 tape elements are
40  // generated, see issue https://github.com/simdjson/simdjson/issues/345
41  size_t tape_capacity = SIMDJSON_ROUNDUP_N(capacity + 3, 64);
42  // a document with only zero-length strings... could have capacity/3 string
43  // and we would need capacity/3 * 5 bytes on the string buffer
44  size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * capacity / 3 + SIMDJSON_PADDING, 64);
45  string_buf.reset( new (std::nothrow) uint8_t[string_capacity]);
46  tape.reset(new (std::nothrow) uint64_t[tape_capacity]);
47  if(!(string_buf && tape)) {
48  allocated_capacity = 0;
49  string_buf.reset();
50  tape.reset();
51  return MEMALLOC;
52  }
53  // Technically the allocated_capacity might be larger than capacity
54  // so the next line is pessimistic.
55  allocated_capacity = capacity;
56  return SUCCESS;
57 }
58 
59 inline bool document::dump_raw_tape(std::ostream &os) const noexcept {
60  uint32_t string_length;
61  size_t tape_idx = 0;
62  uint64_t tape_val = tape[tape_idx];
63  uint8_t type = uint8_t(tape_val >> 56);
64  os << tape_idx << " : " << type;
65  tape_idx++;
66  size_t how_many = 0;
67  if (type == 'r') {
68  how_many = size_t(tape_val & internal::JSON_VALUE_MASK);
69  } else {
70  // Error: no starting root node?
71  return false;
72  }
73  os << "\t// pointing to " << how_many << " (right after last node)\n";
74  uint64_t payload;
75  for (; tape_idx < how_many; tape_idx++) {
76  os << tape_idx << " : ";
77  tape_val = tape[tape_idx];
78  payload = tape_val & internal::JSON_VALUE_MASK;
79  type = uint8_t(tape_val >> 56);
80  switch (type) {
81  case '"': // we have a string
82  os << "string \"";
83  std::memcpy(&string_length, string_buf.get() + payload, sizeof(uint32_t));
84  os << internal::escape_json_string(std::string_view(
85  reinterpret_cast<const char *>(string_buf.get() + payload + sizeof(uint32_t)),
86  string_length
87  ));
88  os << '"';
89  os << '\n';
90  break;
91  case 'l': // we have a long int
92  if (tape_idx + 1 >= how_many) {
93  return false;
94  }
95  os << "integer " << static_cast<int64_t>(tape[++tape_idx]) << "\n";
96  break;
97  case 'u': // we have a long uint
98  if (tape_idx + 1 >= how_many) {
99  return false;
100  }
101  os << "unsigned integer " << tape[++tape_idx] << "\n";
102  break;
103  case 'd': // we have a double
104  os << "float ";
105  if (tape_idx + 1 >= how_many) {
106  return false;
107  }
108  double answer;
109  std::memcpy(&answer, &tape[++tape_idx], sizeof(answer));
110  os << answer << '\n';
111  break;
112  case 'n': // we have a null
113  os << "null\n";
114  break;
115  case 't': // we have a true
116  os << "true\n";
117  break;
118  case 'f': // we have a false
119  os << "false\n";
120  break;
121  case '{': // we have an object
122  os << "{\t// pointing to next tape location " << uint32_t(payload)
123  << " (first node after the scope), "
124  << " saturated count "
125  << ((payload >> 32) & internal::JSON_COUNT_MASK)<< "\n";
126  break; case '}': // we end an object
127  os << "}\t// pointing to previous tape location " << uint32_t(payload)
128  << " (start of the scope)\n";
129  break;
130  case '[': // we start an array
131  os << "[\t// pointing to next tape location " << uint32_t(payload)
132  << " (first node after the scope), "
133  << " saturated count "
134  << ((payload >> 32) & internal::JSON_COUNT_MASK)<< "\n";
135  break;
136  case ']': // we end an array
137  os << "]\t// pointing to previous tape location " << uint32_t(payload)
138  << " (start of the scope)\n";
139  break;
140  case 'r': // we start and end with the root node
141  // should we be hitting the root node?
142  return false;
143  default:
144  return false;
145  }
146  }
147  tape_val = tape[tape_idx];
148  payload = tape_val & internal::JSON_VALUE_MASK;
149  type = uint8_t(tape_val >> 56);
150  os << tape_idx << " : " << type << "\t// pointing to " << payload
151  << " (start root)\n";
152  return true;
153 }
154 
155 } // namespace dom
156 } // namespace simdjson
157 
158 #endif // SIMDJSON_INLINE_DOCUMENT_H
element root() const noexcept
Get the root element of this document as a JSON array.
Definition: document-inl.h:19
A JSON element.
Definition: element.h:40
We want to support argument-dependent lookup (ADL).
error_code
All possible errors returned by simdjson.
Definition: error.h:17
@ MEMALLOC
Error allocating memory, most likely out of memory.
Definition: error.h:20
@ SUCCESS
No error.
Definition: error.h:18
constexpr size_t SIMDJSON_PADDING
The amount of padding needed in a buffer to parse JSON.
Definition: common_defs.h:45