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