simdjson  3.1.7
Ridiculously Fast JSON
element-inl.h
1 #ifndef SIMDJSON_INLINE_ELEMENT_H
2 #define SIMDJSON_INLINE_ELEMENT_H
3 
4 #include "simdjson/dom/array.h"
5 #include "simdjson/dom/element.h"
6 #include "simdjson/dom/object.h"
7 #include <cstring>
8 #include <utility>
9 
10 namespace simdjson {
11 
12 //
13 // simdjson_result<dom::element> inline implementation
14 //
15 simdjson_inline simdjson_result<dom::element>::simdjson_result() noexcept
16  : internal::simdjson_result_base<dom::element>() {}
17 simdjson_inline simdjson_result<dom::element>::simdjson_result(dom::element &&value) noexcept
18  : internal::simdjson_result_base<dom::element>(std::forward<dom::element>(value)) {}
19 simdjson_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
20  : internal::simdjson_result_base<dom::element>(error) {}
21 inline simdjson_result<dom::element_type> simdjson_result<dom::element>::type() const noexcept {
22  if (error()) { return error(); }
23  return first.type();
24 }
25 
26 template<typename T>
27 simdjson_inline bool simdjson_result<dom::element>::is() const noexcept {
28  return !error() && first.is<T>();
29 }
30 template<typename T>
31 simdjson_inline simdjson_result<T> simdjson_result<dom::element>::get() const noexcept {
32  if (error()) { return error(); }
33  return first.get<T>();
34 }
35 template<typename T>
36 simdjson_warn_unused simdjson_inline error_code simdjson_result<dom::element>::get(T &value) const noexcept {
37  if (error()) { return error(); }
38  return first.get<T>(value);
39 }
40 
41 simdjson_inline simdjson_result<dom::array> simdjson_result<dom::element>::get_array() const noexcept {
42  if (error()) { return error(); }
43  return first.get_array();
44 }
45 simdjson_inline simdjson_result<dom::object> simdjson_result<dom::element>::get_object() const noexcept {
46  if (error()) { return error(); }
47  return first.get_object();
48 }
49 simdjson_inline simdjson_result<const char *> simdjson_result<dom::element>::get_c_str() const noexcept {
50  if (error()) { return error(); }
51  return first.get_c_str();
52 }
53 simdjson_inline simdjson_result<size_t> simdjson_result<dom::element>::get_string_length() const noexcept {
54  if (error()) { return error(); }
55  return first.get_string_length();
56 }
57 simdjson_inline simdjson_result<std::string_view> simdjson_result<dom::element>::get_string() const noexcept {
58  if (error()) { return error(); }
59  return first.get_string();
60 }
61 simdjson_inline simdjson_result<int64_t> simdjson_result<dom::element>::get_int64() const noexcept {
62  if (error()) { return error(); }
63  return first.get_int64();
64 }
65 simdjson_inline simdjson_result<uint64_t> simdjson_result<dom::element>::get_uint64() const noexcept {
66  if (error()) { return error(); }
67  return first.get_uint64();
68 }
69 simdjson_inline simdjson_result<double> simdjson_result<dom::element>::get_double() const noexcept {
70  if (error()) { return error(); }
71  return first.get_double();
72 }
73 simdjson_inline simdjson_result<bool> simdjson_result<dom::element>::get_bool() const noexcept {
74  if (error()) { return error(); }
75  return first.get_bool();
76 }
77 
78 simdjson_inline bool simdjson_result<dom::element>::is_array() const noexcept {
79  return !error() && first.is_array();
80 }
81 simdjson_inline bool simdjson_result<dom::element>::is_object() const noexcept {
82  return !error() && first.is_object();
83 }
84 simdjson_inline bool simdjson_result<dom::element>::is_string() const noexcept {
85  return !error() && first.is_string();
86 }
87 simdjson_inline bool simdjson_result<dom::element>::is_int64() const noexcept {
88  return !error() && first.is_int64();
89 }
90 simdjson_inline bool simdjson_result<dom::element>::is_uint64() const noexcept {
91  return !error() && first.is_uint64();
92 }
93 simdjson_inline bool simdjson_result<dom::element>::is_double() const noexcept {
94  return !error() && first.is_double();
95 }
96 simdjson_inline bool simdjson_result<dom::element>::is_number() const noexcept {
97  return !error() && first.is_number();
98 }
99 simdjson_inline bool simdjson_result<dom::element>::is_bool() const noexcept {
100  return !error() && first.is_bool();
101 }
102 
103 simdjson_inline bool simdjson_result<dom::element>::is_null() const noexcept {
104  return !error() && first.is_null();
105 }
106 
107 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](std::string_view key) const noexcept {
108  if (error()) { return error(); }
109  return first[key];
110 }
111 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](const char *key) const noexcept {
112  if (error()) { return error(); }
113  return first[key];
114 }
115 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_pointer(const std::string_view json_pointer) const noexcept {
116  if (error()) { return error(); }
117  return first.at_pointer(json_pointer);
118 }
119 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
120 [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
121 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
122 SIMDJSON_PUSH_DISABLE_WARNINGS
123 SIMDJSON_DISABLE_DEPRECATED_WARNING
124  if (error()) { return error(); }
125  return first.at(json_pointer);
126 SIMDJSON_POP_DISABLE_WARNINGS
127 }
128 #endif // SIMDJSON_DISABLE_DEPRECATED_API
129 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(size_t index) const noexcept {
130  if (error()) { return error(); }
131  return first.at(index);
132 }
133 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key(std::string_view key) const noexcept {
134  if (error()) { return error(); }
135  return first.at_key(key);
136 }
137 simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key_case_insensitive(std::string_view key) const noexcept {
138  if (error()) { return error(); }
139  return first.at_key_case_insensitive(key);
140 }
141 
142 #if SIMDJSON_EXCEPTIONS
143 
144 simdjson_inline simdjson_result<dom::element>::operator bool() const noexcept(false) {
145  return get<bool>();
146 }
147 simdjson_inline simdjson_result<dom::element>::operator const char *() const noexcept(false) {
148  return get<const char *>();
149 }
150 simdjson_inline simdjson_result<dom::element>::operator std::string_view() const noexcept(false) {
151  return get<std::string_view>();
152 }
153 simdjson_inline simdjson_result<dom::element>::operator uint64_t() const noexcept(false) {
154  return get<uint64_t>();
155 }
156 simdjson_inline simdjson_result<dom::element>::operator int64_t() const noexcept(false) {
157  return get<int64_t>();
158 }
159 simdjson_inline simdjson_result<dom::element>::operator double() const noexcept(false) {
160  return get<double>();
161 }
162 simdjson_inline simdjson_result<dom::element>::operator dom::array() const noexcept(false) {
163  return get<dom::array>();
164 }
165 simdjson_inline simdjson_result<dom::element>::operator dom::object() const noexcept(false) {
166  return get<dom::object>();
167 }
168 
169 simdjson_inline dom::array::iterator simdjson_result<dom::element>::begin() const noexcept(false) {
170  if (error()) { throw simdjson_error(error()); }
171  return first.begin();
172 }
173 simdjson_inline dom::array::iterator simdjson_result<dom::element>::end() const noexcept(false) {
174  if (error()) { throw simdjson_error(error()); }
175  return first.end();
176 }
177 
178 #endif // SIMDJSON_EXCEPTIONS
179 
180 namespace dom {
181 
182 //
183 // element inline implementation
184 //
185 simdjson_inline element::element() noexcept : tape{} {}
186 simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
187 
188 inline element_type element::type() const noexcept {
189  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
190  auto tape_type = tape.tape_ref_type();
191  return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type);
192 }
193 
194 inline simdjson_result<bool> element::get_bool() const noexcept {
195  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
196  if(tape.is_true()) {
197  return true;
198  } else if(tape.is_false()) {
199  return false;
200  }
201  return INCORRECT_TYPE;
202 }
204  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
205  switch (tape.tape_ref_type()) {
206  case internal::tape_type::STRING: {
207  return tape.get_c_str();
208  }
209  default:
210  return INCORRECT_TYPE;
211  }
212 }
214  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
215  switch (tape.tape_ref_type()) {
216  case internal::tape_type::STRING: {
217  return tape.get_string_length();
218  }
219  default:
220  return INCORRECT_TYPE;
221  }
222 }
224  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
225  switch (tape.tape_ref_type()) {
226  case internal::tape_type::STRING:
227  return tape.get_string_view();
228  default:
229  return INCORRECT_TYPE;
230  }
231 }
233  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
234  if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken
235  if(tape.is_int64()) {
236  int64_t result = tape.next_tape_value<int64_t>();
237  if (result < 0) {
238  return NUMBER_OUT_OF_RANGE;
239  }
240  return uint64_t(result);
241  }
242  return INCORRECT_TYPE;
243  }
244  return tape.next_tape_value<int64_t>();
245 }
247  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
248  if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken
249  if(tape.is_uint64()) {
250  uint64_t result = tape.next_tape_value<uint64_t>();
251  // Wrapping max in parens to handle Windows issue: https://stackoverflow.com/questions/11544073/how-do-i-deal-with-the-max-macro-in-windows-h-colliding-with-max-in-std
252  if (result > uint64_t((std::numeric_limits<int64_t>::max)())) {
253  return NUMBER_OUT_OF_RANGE;
254  }
255  return static_cast<int64_t>(result);
256  }
257  return INCORRECT_TYPE;
258  }
259  return tape.next_tape_value<int64_t>();
260 }
262  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
263  // Performance considerations:
264  // 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight
265  // comparison.
266  // 2. Using a switch-case relies on the compiler guessing what kind of code generation
267  // we want... But the compiler cannot know that we expect the type to be "double"
268  // most of the time.
269  // We can expect get<double> to refer to a double type almost all the time.
270  // It is important to craft the code accordingly so that the compiler can use this
271  // information. (This could also be solved with profile-guided optimization.)
272  if(simdjson_unlikely(!tape.is_double())) { // branch rarely taken
273  if(tape.is_uint64()) {
274  return double(tape.next_tape_value<uint64_t>());
275  } else if(tape.is_int64()) {
276  return double(tape.next_tape_value<int64_t>());
277  }
278  return INCORRECT_TYPE;
279  }
280  // this is common:
281  return tape.next_tape_value<double>();
282 }
284  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
285  switch (tape.tape_ref_type()) {
286  case internal::tape_type::START_ARRAY:
287  return array(tape);
288  default:
289  return INCORRECT_TYPE;
290  }
291 }
293  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
294  switch (tape.tape_ref_type()) {
295  case internal::tape_type::START_OBJECT:
296  return object(tape);
297  default:
298  return INCORRECT_TYPE;
299  }
300 }
301 
302 template<typename T>
303 simdjson_warn_unused simdjson_inline error_code element::get(T &value) const noexcept {
304  return get<T>().get(value);
305 }
306 // An element-specific version prevents recursion with simdjson_result::get<element>(value)
307 template<>
308 simdjson_warn_unused simdjson_inline error_code element::get<element>(element &value) const noexcept {
309  value = element(tape);
310  return SUCCESS;
311 }
312 template<typename T>
313 inline void element::tie(T &value, error_code &error) && noexcept {
314  error = get<T>(value);
315 }
316 
317 template<typename T>
318 simdjson_inline bool element::is() const noexcept {
319  auto result = get<T>();
320  return !result.error();
321 }
322 
323 template<> inline simdjson_result<array> element::get<array>() const noexcept { return get_array(); }
324 template<> inline simdjson_result<object> element::get<object>() const noexcept { return get_object(); }
325 template<> inline simdjson_result<const char *> element::get<const char *>() const noexcept { return get_c_str(); }
326 template<> inline simdjson_result<std::string_view> element::get<std::string_view>() const noexcept { return get_string(); }
327 template<> inline simdjson_result<int64_t> element::get<int64_t>() const noexcept { return get_int64(); }
328 template<> inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept { return get_uint64(); }
329 template<> inline simdjson_result<double> element::get<double>() const noexcept { return get_double(); }
330 template<> inline simdjson_result<bool> element::get<bool>() const noexcept { return get_bool(); }
331 
332 inline bool element::is_array() const noexcept { return is<array>(); }
333 inline bool element::is_object() const noexcept { return is<object>(); }
334 inline bool element::is_string() const noexcept { return is<std::string_view>(); }
335 inline bool element::is_int64() const noexcept { return is<int64_t>(); }
336 inline bool element::is_uint64() const noexcept { return is<uint64_t>(); }
337 inline bool element::is_double() const noexcept { return is<double>(); }
338 inline bool element::is_bool() const noexcept { return is<bool>(); }
339 inline bool element::is_number() const noexcept { return is_int64() || is_uint64() || is_double(); }
340 
341 inline bool element::is_null() const noexcept {
342  return tape.is_null_on_tape();
343 }
344 
345 #if SIMDJSON_EXCEPTIONS
346 
347 inline element::operator bool() const noexcept(false) { return get<bool>(); }
348 inline element::operator const char*() const noexcept(false) { return get<const char *>(); }
349 inline element::operator std::string_view() const noexcept(false) { return get<std::string_view>(); }
350 inline element::operator uint64_t() const noexcept(false) { return get<uint64_t>(); }
351 inline element::operator int64_t() const noexcept(false) { return get<int64_t>(); }
352 inline element::operator double() const noexcept(false) { return get<double>(); }
353 inline element::operator array() const noexcept(false) { return get<array>(); }
354 inline element::operator object() const noexcept(false) { return get<object>(); }
355 
356 inline array::iterator element::begin() const noexcept(false) {
357  return get<array>().begin();
358 }
359 inline array::iterator element::end() const noexcept(false) {
360  return get<array>().end();
361 }
362 
363 #endif // SIMDJSON_EXCEPTIONS
364 
365 inline simdjson_result<element> element::operator[](std::string_view key) const noexcept {
366  return at_key(key);
367 }
368 inline simdjson_result<element> element::operator[](const char *key) const noexcept {
369  return at_key(key);
370 }
371 
372 inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
373  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
374  switch (tape.tape_ref_type()) {
375  case internal::tape_type::START_OBJECT:
376  return object(tape).at_pointer(json_pointer);
377  case internal::tape_type::START_ARRAY:
378  return array(tape).at_pointer(json_pointer);
379  default: {
380  if(!json_pointer.empty()) { // a non-empty string is invalid on an atom
381  return INVALID_JSON_POINTER;
382  }
383  // an empty string means that we return the current node
384  dom::element copy(*this);
385  return simdjson_result<element>(std::move(copy));
386  }
387  }
388 }
389 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
390 [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
391 inline simdjson_result<element> element::at(std::string_view json_pointer) const noexcept {
392  // version 0.4 of simdjson allowed non-compliant pointers
393  auto std_pointer = (json_pointer.empty() ? "" : "/") + std::string(json_pointer.begin(), json_pointer.end());
394  return at_pointer(std_pointer);
395 }
396 #endif // SIMDJSON_DISABLE_DEPRECATED_API
397 
398 inline simdjson_result<element> element::at(size_t index) const noexcept {
399  return get<array>().at(index);
400 }
401 inline simdjson_result<element> element::at_key(std::string_view key) const noexcept {
402  return get<object>().at_key(key);
403 }
404 inline simdjson_result<element> element::at_key_case_insensitive(std::string_view key) const noexcept {
405  return get<object>().at_key_case_insensitive(key);
406 }
407 
408 inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
409  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
410  return tape.doc->dump_raw_tape(out);
411 }
412 
413 
414 inline std::ostream& operator<<(std::ostream& out, element_type type) {
415  switch (type) {
416  case element_type::ARRAY:
417  return out << "array";
418  case element_type::OBJECT:
419  return out << "object";
420  case element_type::INT64:
421  return out << "int64_t";
422  case element_type::UINT64:
423  return out << "uint64_t";
424  case element_type::DOUBLE:
425  return out << "double";
426  case element_type::STRING:
427  return out << "string";
428  case element_type::BOOL:
429  return out << "bool";
430  case element_type::NULL_VALUE:
431  return out << "null";
432  default:
433  return out << "unexpected content!!!"; // abort() usage is forbidden in the library
434  }
435 }
436 
437 } // namespace dom
438 
439 } // namespace simdjson
440 
441 #endif // SIMDJSON_INLINE_ELEMENT_H
JSON array.
Definition: array.h:22
simdjson_result< element > at_pointer(std::string_view json_pointer) const noexcept
Get the value associated with the given JSON pointer.
Definition: array-inl.h:71
A JSON element.
Definition: element.h:40
bool is_object() const noexcept
Whether this element is a json object.
Definition: element-inl.h:333
bool is_double() const noexcept
Whether this element is a json number that fits in a double.
Definition: element-inl.h:337
simdjson_inline element_type type() const noexcept
The type of this element.
Definition: element-inl.h:188
bool is_number() const noexcept
Whether this element is a json number.
Definition: element-inl.h:339
simdjson_result< const char * > get_c_str() const noexcept
Cast this element to a null-terminated C string.
Definition: element-inl.h:203
simdjson_result< element > at_pointer(const std::string_view json_pointer) const noexcept
Get the value associated with the given JSON pointer.
Definition: element-inl.h:372
simdjson_result< double > get_double() const noexcept
Cast this element to a double floating-point.
Definition: element-inl.h:261
simdjson_result< T > get() const noexcept
Get the value as the provided type (T).
Definition: element.h:220
simdjson_inline bool is() const noexcept
Tell whether the value can be cast to provided type (T).
Definition: element-inl.h:318
simdjson_result< element > at_key_case_insensitive(std::string_view key) const noexcept
Get the value associated with the given key in a case-insensitive manner.
Definition: element-inl.h:404
void tie(T &value, error_code &error) &&noexcept
Get the value as the provided type (T), setting error if it's not the given type.
simdjson_result< bool > get_bool() const noexcept
Cast this element to a bool.
Definition: element-inl.h:194
bool is_string() const noexcept
Whether this element is a json string.
Definition: element-inl.h:334
simdjson_result< element > at_key(std::string_view key) const noexcept
Get the value associated with the given key.
Definition: element-inl.h:401
dom::array::iterator end() const noexcept(false)
Iterate over each element in this array.
Definition: element-inl.h:359
simdjson_result< array > get_array() const noexcept
Cast this element to an array.
Definition: element-inl.h:283
simdjson_result< size_t > get_string_length() const noexcept
Gives the length in bytes of the string.
Definition: element-inl.h:213
simdjson_inline element() noexcept
Create a new, invalid element.
Definition: element-inl.h:185
simdjson_result< uint64_t > get_uint64() const noexcept
Cast this element to an unsigned integer.
Definition: element-inl.h:232
dom::array::iterator begin() const noexcept(false)
Iterate over each element in this array.
Definition: element-inl.h:356
simdjson_result< element > at(const std::string_view json_pointer) const noexcept
Version 0.4 of simdjson used an incorrect interpretation of the JSON Pointer standard and allowed the...
Definition: element-inl.h:391
simdjson_result< int64_t > get_int64() const noexcept
Cast this element to a signed integer.
Definition: element-inl.h:246
simdjson_result< object > get_object() const noexcept
Cast this element to an object.
Definition: element-inl.h:292
bool is_uint64() const noexcept
Whether this element is a json number that fits in an unsigned 64-bit integer.
Definition: element-inl.h:336
simdjson_result< element > operator[](std::string_view key) const noexcept
Get the value associated with the given key.
Definition: element-inl.h:365
bool is_int64() const noexcept
Whether this element is a json number that fits in a signed 64-bit integer.
Definition: element-inl.h:335
bool is_null() const noexcept
Whether this element is a json null.
Definition: element-inl.h:341
simdjson_result< std::string_view > get_string() const noexcept
Cast this element to a string.
Definition: element-inl.h:223
bool is_array() const noexcept
Whether this element is a json array.
Definition: element-inl.h:332
bool is_bool() const noexcept
Whether this element is a json true or false.
Definition: element-inl.h:338
JSON object.
Definition: object.h:22
simdjson_result< element > at_pointer(std::string_view json_pointer) const noexcept
Get the value associated with the given JSON pointer.
Definition: object-inl.h:86
We want to support argument-dependent lookup (ADL).
std::ostream & operator<<(std::ostream &out, error_code error) noexcept
Write the error message to the output stream.
Definition: error-inl.h:36
error_code
All possible errors returned by simdjson.
Definition: error.h:17
@ INCORRECT_TYPE
JSON element has a different type than user expected.
Definition: error.h:34
@ NUMBER_OUT_OF_RANGE
JSON number does not fit in 64 bits.
Definition: error.h:35
@ SUCCESS
No error.
Definition: error.h:18
@ INVALID_JSON_POINTER
Invalid JSON pointer reference.
Definition: error.h:39
The result of a simdjson operation that could fail.
Definition: error.h:205
simdjson_inline error_code error() const noexcept
The error.
Definition: error-inl.h:132
simdjson_warn_unused simdjson_inline error_code get(T &value) &&noexcept
Move the value to the provided variable.
Definition: error-inl.h:127