simdjson  3.11.0
Ridiculously Fast JSON
array-inl.h
1 #ifndef SIMDJSON_ARRAY_INL_H
2 #define SIMDJSON_ARRAY_INL_H
3 
4 #include <utility>
5 
6 #include "simdjson/dom/base.h"
7 #include "simdjson/dom/array.h"
8 #include "simdjson/dom/element.h"
9 #include "simdjson/error-inl.h"
10 #include "simdjson/jsonpathutil.h"
11 #include "simdjson/internal/tape_ref-inl.h"
12 
13 #include <limits>
14 
15 namespace simdjson {
16 
17 //
18 // simdjson_result<dom::array> inline implementation
19 //
20 simdjson_inline simdjson_result<dom::array>::simdjson_result() noexcept
21  : internal::simdjson_result_base<dom::array>() {}
22 simdjson_inline simdjson_result<dom::array>::simdjson_result(dom::array value) noexcept
23  : internal::simdjson_result_base<dom::array>(std::forward<dom::array>(value)) {}
24 simdjson_inline simdjson_result<dom::array>::simdjson_result(error_code error) noexcept
25  : internal::simdjson_result_base<dom::array>(error) {}
26 
27 #if SIMDJSON_EXCEPTIONS
28 
29 inline dom::array::iterator simdjson_result<dom::array>::begin() const noexcept(false) {
30  if (error()) { throw simdjson_error(error()); }
31  return first.begin();
32 }
33 inline dom::array::iterator simdjson_result<dom::array>::end() const noexcept(false) {
34  if (error()) { throw simdjson_error(error()); }
35  return first.end();
36 }
37 inline size_t simdjson_result<dom::array>::size() const noexcept(false) {
38  if (error()) { throw simdjson_error(error()); }
39  return first.size();
40 }
41 
42 #endif // SIMDJSON_EXCEPTIONS
43 
44 inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std::string_view json_pointer) const noexcept {
45  if (error()) { return error(); }
46  return first.at_pointer(json_pointer);
47 }
48 
49  inline simdjson_result<dom::element> simdjson_result<dom::array>::at_path(std::string_view json_path) const noexcept {
50  auto json_pointer = json_path_to_pointer_conversion(json_path);
51  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
52  return at_pointer(json_pointer);
53  }
54 
55 inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
56  if (error()) { return error(); }
57  return first.at(index);
58 }
59 
60 namespace dom {
61 
62 //
63 // array inline implementation
64 //
65 simdjson_inline array::array() noexcept : tape{} {}
66 simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
67 inline array::iterator array::begin() const noexcept {
68  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
69  return internal::tape_ref(tape.doc, tape.json_index + 1);
70 }
71 inline array::iterator array::end() const noexcept {
72  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
73  return internal::tape_ref(tape.doc, tape.after_element() - 1);
74 }
75 inline size_t array::size() const noexcept {
76  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
77  return tape.scope_count();
78 }
79 inline size_t array::number_of_slots() const noexcept {
80  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
81  return tape.matching_brace_index() - tape.json_index;
82 }
83 inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
84  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
85  if(json_pointer.empty()) { // an empty string means that we return the current node
86  return element(this->tape); // copy the current node
87  } else if(json_pointer[0] != '/') { // otherwise there is an error
88  return INVALID_JSON_POINTER;
89  }
90  json_pointer = json_pointer.substr(1);
91  // - means "the append position" or "the element after the end of the array"
92  // We don't support this, because we're returning a real element, not a position.
93  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
94 
95  // Read the array index
96  size_t array_index = 0;
97  size_t i;
98  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
99  uint8_t digit = uint8_t(json_pointer[i] - '0');
100  // Check for non-digit in array index. If it's there, we're trying to get a field in an object
101  if (digit > 9) { return INCORRECT_TYPE; }
102  array_index = array_index*10 + digit;
103  }
104 
105  // 0 followed by other digits is invalid
106  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
107 
108  // Empty string is invalid; so is a "/" with no digits before it
109  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
110 
111  // Get the child
112  auto child = array(tape).at(array_index);
113  // If there is an error, it ends here
114  if(child.error()) {
115  return child;
116  }
117  // If there is a /, we're not done yet, call recursively.
118  if (i < json_pointer.length()) {
119  child = child.at_pointer(json_pointer.substr(i));
120  }
121  return child;
122 }
123 
124 inline simdjson_result<element> array::at_path(std::string_view json_path) const noexcept {
125  auto json_pointer = json_path_to_pointer_conversion(json_path);
126  if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
127  return at_pointer(json_pointer);
128 }
129 
130 inline simdjson_result<element> array::at(size_t index) const noexcept {
131  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
132  size_t i=0;
133  for (auto element : *this) {
134  if (i == index) { return element; }
135  i++;
136  }
137  return INDEX_OUT_OF_BOUNDS;
138 }
139 
140 inline array::operator element() const noexcept {
141  return element(tape);
142 }
143 
144 //
145 // array::iterator inline implementation
146 //
147 simdjson_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
148 inline element array::iterator::operator*() const noexcept {
149  return element(tape);
150 }
152  tape.json_index = tape.after_element();
153  return *this;
154 }
156  array::iterator out = *this;
157  ++*this;
158  return out;
159 }
160 inline bool array::iterator::operator!=(const array::iterator& other) const noexcept {
161  return tape.json_index != other.tape.json_index;
162 }
163 inline bool array::iterator::operator==(const array::iterator& other) const noexcept {
164  return tape.json_index == other.tape.json_index;
165 }
166 inline bool array::iterator::operator<(const array::iterator& other) const noexcept {
167  return tape.json_index < other.tape.json_index;
168 }
169 inline bool array::iterator::operator<=(const array::iterator& other) const noexcept {
170  return tape.json_index <= other.tape.json_index;
171 }
172 inline bool array::iterator::operator>=(const array::iterator& other) const noexcept {
173  return tape.json_index >= other.tape.json_index;
174 }
175 inline bool array::iterator::operator>(const array::iterator& other) const noexcept {
176  return tape.json_index > other.tape.json_index;
177 }
178 
179 } // namespace dom
180 
181 
182 } // namespace simdjson
183 
184 #include "simdjson/dom/element-inl.h"
185 
186 #if defined(__cpp_lib_ranges)
187 static_assert(std::ranges::view<simdjson::dom::array>);
188 static_assert(std::ranges::sized_range<simdjson::dom::array>);
189 #if SIMDJSON_EXCEPTIONS
190 static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::array>>);
191 static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::array>>);
192 #endif // SIMDJSON_EXCEPTIONS
193 #endif // defined(__cpp_lib_ranges)
194 
195 #endif // SIMDJSON_ARRAY_INL_H
bool operator!=(const iterator &other) const noexcept
Check if these values come from the same place in the JSON.
Definition: array-inl.h:160
iterator & operator++() noexcept
Get the next value.
Definition: array-inl.h:151
reference operator*() const noexcept
Get the actual value.
Definition: array-inl.h:148
JSON array.
Definition: array.h:13
size_t number_of_slots() const noexcept
Get the total number of slots used by this array on the tape.
Definition: array-inl.h:79
iterator end() const noexcept
One past the last array element.
Definition: array-inl.h:71
size_t size() const noexcept
Get the size of the array (number of immediate children).
Definition: array-inl.h:75
simdjson_result< element > at(size_t index) const noexcept
Get the value at the given index.
Definition: array-inl.h:130
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:83
simdjson_inline array() noexcept
Create a new, invalid array.
Definition: array-inl.h:65
simdjson_result< element > at_path(std::string_view json_path) const noexcept
Get the value associated with the given JSONPath expression.
Definition: array-inl.h:124
iterator begin() const noexcept
Return the first array element.
Definition: array-inl.h:67
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
@ INCORRECT_TYPE
JSON element has a different type than user expected.
Definition: error.h:37
@ INDEX_OUT_OF_BOUNDS
JSON array index too large.
Definition: error.h:39
@ INVALID_JSON_POINTER
Invalid JSON pointer syntax.
Definition: error.h:42
std::string json_path_to_pointer_conversion(std::string_view json_path)
Converts JSONPath to JSON Pointer.
Definition: jsonpathutil.h:13
The result of a simdjson operation that could fail.
Definition: error.h:215
simdjson_inline error_code error() const noexcept
The error.
Definition: error-inl.h:131