simdjson  3.1.5
Ridiculously Fast JSON
array-inl.h
1 namespace simdjson {
2 namespace SIMDJSON_IMPLEMENTATION {
3 namespace ondemand {
4 
5 //
6 // ### Live States
7 //
8 // While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
9 // always SUCCESS:
10 //
11 // - Start: This is the state when the array is first found and the iterator is just past the `{`.
12 // In this state, at_start == true.
13 // - Next: After we hand a scalar value to the user, or an array/object which they then fully
14 // iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
15 // depth == iter->depth, at_start == false, and error == SUCCESS.
16 // - Unfinished Business: When we hand an array/object to the user which they do not fully
17 // iterate over, we need to finish that iteration by skipping child values until we reach the
18 // Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
19 //
20 // ## Error States
21 //
22 // In error states, we will yield exactly one more value before stopping. iter->depth == depth
23 // and at_start is always false. We decrement after yielding the error, moving to the Finished
24 // state.
25 //
26 // - Chained Error: When the array iterator is part of an error chain--for example, in
27 // `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
28 // array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
29 // iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
30 // - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
31 // we flag that as an error and treat it exactly the same as a Chained Error. In this state,
32 // error == TAPE_ERROR, iter->depth == depth, and at_start == false.
33 //
34 // ## Terminal State
35 //
36 // The terminal state has iter->depth < depth. at_start is always false.
37 //
38 // - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
39 // by decrementing depth. In this state, iter->depth < depth, at_start == false, and
40 // error == SUCCESS.
41 //
42 
43 simdjson_inline array::array(const value_iterator &_iter) noexcept
44  : iter{_iter}
45 {
46 }
47 
48 simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
49  // We don't need to know if the array is empty to start iteration, but we do want to know if there
50  // is an error--thus `simdjson_unused`.
51  simdjson_unused bool has_value;
52  SIMDJSON_TRY( iter.start_array().get(has_value) );
53  return array(iter);
54 }
55 simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
56  simdjson_unused bool has_value;
57  SIMDJSON_TRY( iter.start_root_array().get(has_value) );
58  return array(iter);
59 }
60 simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
61  bool has_value;
62  SIMDJSON_TRY(iter.started_array().get(has_value));
63  return array(iter);
64 }
65 
66 simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
67 #if SIMDJSON_DEVELOPMENT_CHECKS
68  if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
69 #endif
70  return array_iterator(iter);
71 }
72 simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
73  return array_iterator(iter);
74 }
75 simdjson_inline error_code array::consume() noexcept {
76  auto error = iter.json_iter().skip_child(iter.depth()-1);
77  if(error) { iter.abandon(); }
78  return error;
79 }
80 
82  const uint8_t * starting_point{iter.peek_start()};
83  auto error = consume();
84  if(error) { return error; }
85  // After 'consume()', we could be left pointing just beyond the document, but that
86  // is ok because we are not going to dereference the final pointer position, we just
87  // use it to compute the length in bytes.
88  const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
89  return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
90 }
91 
92 SIMDJSON_PUSH_DISABLE_WARNINGS
93 SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
94 simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
95  size_t count{0};
96  // Important: we do not consume any of the values.
97  for(simdjson_unused auto v : *this) { count++; }
98  // The above loop will always succeed, but we want to report errors.
99  if(iter.error()) { return iter.error(); }
100  // We need to move back at the start because we expect users to iterate through
101  // the array after counting the number of elements.
102  iter.reset_array();
103  return count;
104 }
105 SIMDJSON_POP_DISABLE_WARNINGS
106 
107 simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
108  bool is_not_empty;
109  auto error = iter.reset_array().get(is_not_empty);
110  if(error) { return error; }
111  return !is_not_empty;
112 }
113 
114 inline simdjson_result<bool> array::reset() & noexcept {
115  return iter.reset_array();
116 }
117 
118 inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
119  if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
120  json_pointer = json_pointer.substr(1);
121  // - means "the append position" or "the element after the end of the array"
122  // We don't support this, because we're returning a real element, not a position.
123  if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
124 
125  // Read the array index
126  size_t array_index = 0;
127  size_t i;
128  for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
129  uint8_t digit = uint8_t(json_pointer[i] - '0');
130  // Check for non-digit in array index. If it's there, we're trying to get a field in an object
131  if (digit > 9) { return INCORRECT_TYPE; }
132  array_index = array_index*10 + digit;
133  }
134 
135  // 0 followed by other digits is invalid
136  if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
137 
138  // Empty string is invalid; so is a "/" with no digits before it
139  if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
140  // Get the child
141  auto child = at(array_index);
142  // If there is an error, it ends here
143  if(child.error()) {
144  return child;
145  }
146 
147  // If there is a /, we're not done yet, call recursively.
148  if (i < json_pointer.length()) {
149  child = child.at_pointer(json_pointer.substr(i));
150  }
151  return child;
152 }
153 
154 simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
155  size_t i = 0;
156  for (auto value : *this) {
157  if (i == index) { return value; }
158  i++;
159  }
160  return INDEX_OUT_OF_BOUNDS;
161 }
162 
163 } // namespace ondemand
164 } // namespace SIMDJSON_IMPLEMENTATION
165 } // namespace simdjson
166 
167 namespace simdjson {
168 
169 simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::simdjson_result(
170  SIMDJSON_IMPLEMENTATION::ondemand::array &&value
171 ) noexcept
172  : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array>(
173  std::forward<SIMDJSON_IMPLEMENTATION::ondemand::array>(value)
174  )
175 {
176 }
177 simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::simdjson_result(
178  error_code error
179 ) noexcept
180  : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array>(error)
181 {
182 }
183 
184 simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::begin() noexcept {
185  if (error()) { return error(); }
186  return first.begin();
187 }
188 simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::end() noexcept {
189  if (error()) { return error(); }
190  return first.end();
191 }
192 simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::count_elements() & noexcept {
193  if (error()) { return error(); }
194  return first.count_elements();
195 }
196 simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::is_empty() & noexcept {
197  if (error()) { return error(); }
198  return first.is_empty();
199 }
200 simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::at(size_t index) noexcept {
201  if (error()) { return error(); }
202  return first.at(index);
203 }
204 simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::at_pointer(std::string_view json_pointer) noexcept {
205  if (error()) { return error(); }
206  return first.at_pointer(json_pointer);
207 }
208 } // namespace simdjson
simdjson_inline simdjson_result< value > at(size_t index) noexcept
Get the value at the given index.
Definition: array-inl.h:154
value_iterator iter
Iterator marking current position.
Definition: array.h:160
simdjson_inline simdjson_result< bool > is_empty() &noexcept
This method scans the beginning of the array and checks whether the array is empty.
Definition: array-inl.h:107
simdjson_result< value > at_pointer(std::string_view json_pointer) noexcept
Get the value associated with the given JSON pointer.
Definition: array-inl.h:118
static simdjson_inline simdjson_result< array > start(value_iterator &iter) noexcept
Begin array iteration.
Definition: array-inl.h:48
simdjson_inline simdjson_result< array_iterator > begin() noexcept
Begin array iteration.
Definition: array-inl.h:66
simdjson_inline array() noexcept=default
Create a new invalid array.
simdjson_inline error_code consume() noexcept
Go to the end of the array, no matter where you are right now.
Definition: array-inl.h:75
simdjson_inline simdjson_result< size_t > count_elements() &noexcept
This method scans the array and counts the number of elements.
Definition: array-inl.h:94
static simdjson_inline simdjson_result< array > start_root(value_iterator &iter) noexcept
Begin array iteration from the root.
Definition: array-inl.h:55
static simdjson_inline simdjson_result< array > started(value_iterator &iter) noexcept
Begin array iteration.
Definition: array-inl.h:60
simdjson_inline simdjson_result< std::string_view > raw_json() noexcept
Consumes the array and returns a string_view instance corresponding to the array as represented in JS...
Definition: array-inl.h:81
simdjson_inline simdjson_result< array_iterator > end() noexcept
Sentinel representing the end of the array.
Definition: array-inl.h:72
simdjson_result< bool > reset() &noexcept
Reset the iterator so that we are pointing back at the beginning of the array.
Definition: array-inl.h:114
An ephemeral JSON value returned during iteration.
Definition: value.h:17
We want to support argument-dependent lookup (ADL).
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
@ OUT_OF_ORDER_ITERATION
tried to iterate an array or object out of order
Definition: error.h:43
@ INDEX_OUT_OF_BOUNDS
JSON array index too large.
Definition: error.h:36
@ 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