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
10namespace simdjson {
11
12//
13// simdjson_result<dom::element> inline implementation
14//
15simdjson_inline simdjson_result<dom::element>::simdjson_result() noexcept
16 : internal::simdjson_result_base<dom::element>() {}
17simdjson_inline simdjson_result<dom::element>::simdjson_result(dom::element &&value) noexcept
18 : internal::simdjson_result_base<dom::element>(std::forward<dom::element>(t&: value)) {}
19simdjson_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
20 : internal::simdjson_result_base<dom::element>(error) {}
21inline simdjson_result<dom::element_type> simdjson_result<dom::element>::type() const noexcept {
22 if (error()) { return error(); }
23 return first.type();
24}
25
26template<typename T>
27simdjson_inline bool simdjson_result<dom::element>::is() const noexcept {
28 return !error() && first.is<T>();
29}
30template<typename T>
31simdjson_inline simdjson_result<T> simdjson_result<dom::element>::get() const noexcept {
32 if (error()) { return error(); }
33 return first.get<T>();
34}
35template<typename T>
36simdjson_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
41simdjson_inline simdjson_result<dom::array> simdjson_result<dom::element>::get_array() const noexcept {
42 if (error()) { return error(); }
43 return first.get_array();
44}
45simdjson_inline simdjson_result<dom::object> simdjson_result<dom::element>::get_object() const noexcept {
46 if (error()) { return error(); }
47 return first.get_object();
48}
49simdjson_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}
53simdjson_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}
57simdjson_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}
61simdjson_inline simdjson_result<int64_t> simdjson_result<dom::element>::get_int64() const noexcept {
62 if (error()) { return error(); }
63 return first.get_int64();
64}
65simdjson_inline simdjson_result<uint64_t> simdjson_result<dom::element>::get_uint64() const noexcept {
66 if (error()) { return error(); }
67 return first.get_uint64();
68}
69simdjson_inline simdjson_result<double> simdjson_result<dom::element>::get_double() const noexcept {
70 if (error()) { return error(); }
71 return first.get_double();
72}
73simdjson_inline simdjson_result<bool> simdjson_result<dom::element>::get_bool() const noexcept {
74 if (error()) { return error(); }
75 return first.get_bool();
76}
77
78simdjson_inline bool simdjson_result<dom::element>::is_array() const noexcept {
79 return !error() && first.is_array();
80}
81simdjson_inline bool simdjson_result<dom::element>::is_object() const noexcept {
82 return !error() && first.is_object();
83}
84simdjson_inline bool simdjson_result<dom::element>::is_string() const noexcept {
85 return !error() && first.is_string();
86}
87simdjson_inline bool simdjson_result<dom::element>::is_int64() const noexcept {
88 return !error() && first.is_int64();
89}
90simdjson_inline bool simdjson_result<dom::element>::is_uint64() const noexcept {
91 return !error() && first.is_uint64();
92}
93simdjson_inline bool simdjson_result<dom::element>::is_double() const noexcept {
94 return !error() && first.is_double();
95}
96simdjson_inline bool simdjson_result<dom::element>::is_number() const noexcept {
97 return !error() && first.is_number();
98}
99simdjson_inline bool simdjson_result<dom::element>::is_bool() const noexcept {
100 return !error() && first.is_bool();
101}
102
103simdjson_inline bool simdjson_result<dom::element>::is_null() const noexcept {
104 return !error() && first.is_null();
105}
106
107simdjson_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}
111simdjson_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}
115simdjson_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 ")]]
121simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
122SIMDJSON_PUSH_DISABLE_WARNINGS
123SIMDJSON_DISABLE_DEPRECATED_WARNING
124 if (error()) { return error(); }
125 return first.at(json_pointer);
126SIMDJSON_POP_DISABLE_WARNINGS
127}
128#endif // SIMDJSON_DISABLE_DEPRECATED_API
129simdjson_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}
133simdjson_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}
137simdjson_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
144simdjson_inline simdjson_result<dom::element>::operator bool() const noexcept(false) {
145 return get<bool>();
146}
147simdjson_inline simdjson_result<dom::element>::operator const char *() const noexcept(false) {
148 return get<const char *>();
149}
150simdjson_inline simdjson_result<dom::element>::operator std::string_view() const noexcept(false) {
151 return get<std::string_view>();
152}
153simdjson_inline simdjson_result<dom::element>::operator uint64_t() const noexcept(false) {
154 return get<uint64_t>();
155}
156simdjson_inline simdjson_result<dom::element>::operator int64_t() const noexcept(false) {
157 return get<int64_t>();
158}
159simdjson_inline simdjson_result<dom::element>::operator double() const noexcept(false) {
160 return get<double>();
161}
162simdjson_inline simdjson_result<dom::element>::operator dom::array() const noexcept(false) {
163 return get<dom::array>();
164}
165simdjson_inline simdjson_result<dom::element>::operator dom::object() const noexcept(false) {
166 return get<dom::object>();
167}
168
169simdjson_inline dom::array::iterator simdjson_result<dom::element>::begin() const noexcept(false) {
170 if (error()) { throw simdjson_error(error()); }
171 return first.begin();
172}
173simdjson_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
180namespace dom {
181
182//
183// element inline implementation
184//
185simdjson_inline element::element() noexcept : tape{} {}
186simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
187
188inline 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
194inline 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}
203inline simdjson_result<const char *> element::get_c_str() const noexcept {
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}
213inline simdjson_result<size_t> element::get_string_length() const noexcept {
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}
223inline simdjson_result<std::string_view> element::get_string() const noexcept {
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}
232inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
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}
246inline simdjson_result<int64_t> element::get_int64() const noexcept {
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}
261inline simdjson_result<double> element::get_double() const noexcept {
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}
283inline simdjson_result<array> element::get_array() const noexcept {
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}
292inline simdjson_result<object> element::get_object() const noexcept {
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
302template<typename T>
303simdjson_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)
307template<>
308simdjson_warn_unused simdjson_inline error_code element::get<element>(element &value) const noexcept {
309 value = element(tape);
310 return SUCCESS;
311}
312template<typename T>
313inline void element::tie(T &value, error_code &error) && noexcept {
314 error = get<T>(value);
315}
316
317template<typename T>
318simdjson_inline bool element::is() const noexcept {
319 auto result = get<T>();
320 return !result.error();
321}
322
323template<> inline simdjson_result<array> element::get<array>() const noexcept { return get_array(); }
324template<> inline simdjson_result<object> element::get<object>() const noexcept { return get_object(); }
325template<> inline simdjson_result<const char *> element::get<const char *>() const noexcept { return get_c_str(); }
326template<> inline simdjson_result<std::string_view> element::get<std::string_view>() const noexcept { return get_string(); }
327template<> inline simdjson_result<int64_t> element::get<int64_t>() const noexcept { return get_int64(); }
328template<> inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept { return get_uint64(); }
329template<> inline simdjson_result<double> element::get<double>() const noexcept { return get_double(); }
330template<> inline simdjson_result<bool> element::get<bool>() const noexcept { return get_bool(); }
331
332inline bool element::is_array() const noexcept { return is<array>(); }
333inline bool element::is_object() const noexcept { return is<object>(); }
334inline bool element::is_string() const noexcept { return is<std::string_view>(); }
335inline bool element::is_int64() const noexcept { return is<int64_t>(); }
336inline bool element::is_uint64() const noexcept { return is<uint64_t>(); }
337inline bool element::is_double() const noexcept { return is<double>(); }
338inline bool element::is_bool() const noexcept { return is<bool>(); }
339inline bool element::is_number() const noexcept { return is_int64() || is_uint64() || is_double(); }
340
341inline bool element::is_null() const noexcept {
342 return tape.is_null_on_tape();
343}
344
345#if SIMDJSON_EXCEPTIONS
346
347inline element::operator bool() const noexcept(false) { return get<bool>(); }
348inline element::operator const char*() const noexcept(false) { return get<const char *>(); }
349inline element::operator std::string_view() const noexcept(false) { return get<std::string_view>(); }
350inline element::operator uint64_t() const noexcept(false) { return get<uint64_t>(); }
351inline element::operator int64_t() const noexcept(false) { return get<int64_t>(); }
352inline element::operator double() const noexcept(false) { return get<double>(); }
353inline element::operator array() const noexcept(false) { return get<array>(); }
354inline element::operator object() const noexcept(false) { return get<object>(); }
355
356inline array::iterator element::begin() const noexcept(false) {
357 return get<array>().begin();
358}
359inline array::iterator element::end() const noexcept(false) {
360 return get<array>().end();
361}
362
363#endif // SIMDJSON_EXCEPTIONS
364
365inline simdjson_result<element> element::operator[](std::string_view key) const noexcept {
366 return at_key(key);
367}
368inline simdjson_result<element> element::operator[](const char *key) const noexcept {
369 return at_key(key);
370}
371
372inline 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 ")]]
391inline 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(json_pointer: std_pointer);
395}
396#endif // SIMDJSON_DISABLE_DEPRECATED_API
397
398inline simdjson_result<element> element::at(size_t index) const noexcept {
399 return get<array>().at(index);
400}
401inline simdjson_result<element> element::at_key(std::string_view key) const noexcept {
402 return get<object>().at_key(key);
403}
404inline 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
408inline 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(os&: out);
411}
412
413
414inline 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
442