simdjson  3.3.0
Ridiculously Fast JSON
object-inl.h
1 #ifndef SIMDJSON_OBJECT_INL_H
2 #define SIMDJSON_OBJECT_INL_H
3 
4 #include "simdjson/dom/base.h"
5 #include "simdjson/dom/object.h"
6 #include "simdjson/dom/document.h"
7 
8 #include "simdjson/dom/element-inl.h"
9 #include "simdjson/error-inl.h"
10 
11 #include <cstring>
12 
13 namespace simdjson {
14 
15 //
16 // simdjson_result<dom::object> inline implementation
17 //
18 simdjson_inline simdjson_result<dom::object>::simdjson_result() noexcept
19  : internal::simdjson_result_base<dom::object>() {}
20 simdjson_inline simdjson_result<dom::object>::simdjson_result(dom::object value) noexcept
21  : internal::simdjson_result_base<dom::object>(std::forward<dom::object>(value)) {}
22 simdjson_inline simdjson_result<dom::object>::simdjson_result(error_code error) noexcept
23  : internal::simdjson_result_base<dom::object>(error) {}
24 
25 inline simdjson_result<dom::element> simdjson_result<dom::object>::operator[](std::string_view key) const noexcept {
26  if (error()) { return error(); }
27  return first[key];
28 }
29 inline simdjson_result<dom::element> simdjson_result<dom::object>::operator[](const char *key) const noexcept {
30  if (error()) { return error(); }
31  return first[key];
32 }
33 inline simdjson_result<dom::element> simdjson_result<dom::object>::at_pointer(std::string_view json_pointer) const noexcept {
34  if (error()) { return error(); }
35  return first.at_pointer(json_pointer);
36 }
37 inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
38  if (error()) { return error(); }
39  return first.at_key(key);
40 }
41 inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key_case_insensitive(std::string_view key) const noexcept {
42  if (error()) { return error(); }
43  return first.at_key_case_insensitive(key);
44 }
45 
46 #if SIMDJSON_EXCEPTIONS
47 
48 inline dom::object::iterator simdjson_result<dom::object>::begin() const noexcept(false) {
49  if (error()) { throw simdjson_error(error()); }
50  return first.begin();
51 }
52 inline dom::object::iterator simdjson_result<dom::object>::end() const noexcept(false) {
53  if (error()) { throw simdjson_error(error()); }
54  return first.end();
55 }
56 inline size_t simdjson_result<dom::object>::size() const noexcept(false) {
57  if (error()) { throw simdjson_error(error()); }
58  return first.size();
59 }
60 
61 #endif // SIMDJSON_EXCEPTIONS
62 
63 namespace dom {
64 
65 //
66 // object inline implementation
67 //
68 simdjson_inline object::object() noexcept : tape{} {}
69 simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
70 inline object::iterator object::begin() const noexcept {
71  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
72  return internal::tape_ref(tape.doc, tape.json_index + 1);
73 }
74 inline object::iterator object::end() const noexcept {
75  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
76  return internal::tape_ref(tape.doc, tape.after_element() - 1);
77 }
78 inline size_t object::size() const noexcept {
79  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
80  return tape.scope_count();
81 }
82 
83 inline simdjson_result<element> object::operator[](std::string_view key) const noexcept {
84  return at_key(key);
85 }
86 inline simdjson_result<element> object::operator[](const char *key) const noexcept {
87  return at_key(key);
88 }
89 inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept {
90  SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
91  if(json_pointer.empty()) { // an empty string means that we return the current node
92  return element(this->tape); // copy the current node
93  } else if(json_pointer[0] != '/') { // otherwise there is an error
94  return INVALID_JSON_POINTER;
95  }
96  json_pointer = json_pointer.substr(1);
97  size_t slash = json_pointer.find('/');
98  std::string_view key = json_pointer.substr(0, slash);
99  // Grab the child with the given key
101 
102  // If there is an escape character in the key, unescape it and then get the child.
103  size_t escape = key.find('~');
104  if (escape != std::string_view::npos) {
105  // Unescape the key
106  std::string unescaped(key);
107  do {
108  switch (unescaped[escape+1]) {
109  case '0':
110  unescaped.replace(escape, 2, "~");
111  break;
112  case '1':
113  unescaped.replace(escape, 2, "/");
114  break;
115  default:
116  return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
117  }
118  escape = unescaped.find('~', escape+1);
119  } while (escape != std::string::npos);
120  child = at_key(unescaped);
121  } else {
122  child = at_key(key);
123  }
124  if(child.error()) {
125  return child; // we do not continue if there was an error
126  }
127  // If there is a /, we have to recurse and look up more of the path
128  if (slash != std::string_view::npos) {
129  child = child.at_pointer(json_pointer.substr(slash));
130  }
131  return child;
132 }
133 
134 inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
135  iterator end_field = end();
136  for (iterator field = begin(); field != end_field; ++field) {
137  if (field.key_equals(key)) {
138  return field.value();
139  }
140  }
141  return NO_SUCH_FIELD;
142 }
143 // In case you wonder why we need this, please see
144 // https://github.com/simdjson/simdjson/issues/323
145 // People do seek keys in a case-insensitive manner.
146 inline simdjson_result<element> object::at_key_case_insensitive(std::string_view key) const noexcept {
147  iterator end_field = end();
148  for (iterator field = begin(); field != end_field; ++field) {
149  if (field.key_equals_case_insensitive(key)) {
150  return field.value();
151  }
152  }
153  return NO_SUCH_FIELD;
154 }
155 
156 //
157 // object::iterator inline implementation
158 //
159 simdjson_inline object::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
160 inline const key_value_pair object::iterator::operator*() const noexcept {
161  return key_value_pair(key(), value());
162 }
163 inline bool object::iterator::operator!=(const object::iterator& other) const noexcept {
164  return tape.json_index != other.tape.json_index;
165 }
166 inline bool object::iterator::operator==(const object::iterator& other) const noexcept {
167  return tape.json_index == other.tape.json_index;
168 }
169 inline bool object::iterator::operator<(const object::iterator& other) const noexcept {
170  return tape.json_index < other.tape.json_index;
171 }
172 inline bool object::iterator::operator<=(const object::iterator& other) const noexcept {
173  return tape.json_index <= other.tape.json_index;
174 }
175 inline bool object::iterator::operator>=(const object::iterator& other) const noexcept {
176  return tape.json_index >= other.tape.json_index;
177 }
178 inline bool object::iterator::operator>(const object::iterator& other) const noexcept {
179  return tape.json_index > other.tape.json_index;
180 }
182  tape.json_index++;
183  tape.json_index = tape.after_element();
184  return *this;
185 }
187  object::iterator out = *this;
188  ++*this;
189  return out;
190 }
191 inline std::string_view object::iterator::key() const noexcept {
192  return tape.get_string_view();
193 }
194 inline uint32_t object::iterator::key_length() const noexcept {
195  return tape.get_string_length();
196 }
197 inline const char* object::iterator::key_c_str() const noexcept {
198  return reinterpret_cast<const char *>(&tape.doc->string_buf[size_t(tape.tape_value()) + sizeof(uint32_t)]);
199 }
200 inline element object::iterator::value() const noexcept {
201  return element(internal::tape_ref(tape.doc, tape.json_index + 1));
202 }
203 
217 inline bool object::iterator::key_equals(std::string_view o) const noexcept {
218  // We use the fact that the key length can be computed quickly
219  // without access to the string buffer.
220  const uint32_t len = key_length();
221  if(o.size() == len) {
222  // We avoid construction of a temporary string_view instance.
223  return (memcmp(o.data(), key_c_str(), len) == 0);
224  }
225  return false;
226 }
227 
228 inline bool object::iterator::key_equals_case_insensitive(std::string_view o) const noexcept {
229  // We use the fact that the key length can be computed quickly
230  // without access to the string buffer.
231  const uint32_t len = key_length();
232  if(o.size() == len) {
233  // See For case-insensitive string comparisons, avoid char-by-char functions
234  // https://lemire.me/blog/2020/04/30/for-case-insensitive-string-comparisons-avoid-char-by-char-functions/
235  // Note that it might be worth rolling our own strncasecmp function, with vectorization.
236  return (simdjson_strncasecmp(o.data(), key_c_str(), len) == 0);
237  }
238  return false;
239 }
240 //
241 // key_value_pair inline implementation
242 //
243 inline key_value_pair::key_value_pair(std::string_view _key, element _value) noexcept :
244  key(_key), value(_value) {}
245 
246 } // namespace dom
247 
248 } // namespace simdjson
249 
250 #if defined(__cpp_lib_ranges)
251 static_assert(std::ranges::view<simdjson::dom::object>);
252 static_assert(std::ranges::sized_range<simdjson::dom::object>);
253 #if SIMDJSON_EXCEPTIONS
254 static_assert(std::ranges::view<simdjson::simdjson_result<simdjson::dom::object>>);
255 static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::object>>);
256 #endif // SIMDJSON_EXCEPTIONS
257 #endif // defined(__cpp_lib_ranges)
258 
259 #endif // SIMDJSON_OBJECT_INL_H
A JSON element.
Definition: element.h:31
Key/value pair in an object.
Definition: object.h:214
bool operator!=(const iterator &other) const noexcept
Check if these values come from the same place in the JSON.
Definition: object-inl.h:163
element value() const noexcept
Get the value of this key/value pair.
Definition: object-inl.h:200
bool key_equals(std::string_view o) const noexcept
Returns true if the key in this key/value pair is equal to the provided string_view.
Definition: object-inl.h:217
const char * key_c_str() const noexcept
Get the key of this key/value pair.
Definition: object-inl.h:197
uint32_t key_length() const noexcept
Get the length (in bytes) of the key in this key/value pair.
Definition: object-inl.h:194
const value_type operator*() const noexcept
Get the actual key/value pair.
Definition: object-inl.h:160
bool key_equals_case_insensitive(std::string_view o) const noexcept
Returns true if the key in this key/value pair is equal to the provided string_view in a case-insensi...
Definition: object-inl.h:228
std::string_view key() const noexcept
Get the key of this key/value pair.
Definition: object-inl.h:191
iterator & operator++() noexcept
Get the next key/value pair.
Definition: object-inl.h:181
simdjson_result< element > at_key(std::string_view key) const noexcept
Get the value associated with the given key.
Definition: object-inl.h:134
iterator end() const noexcept
One past the last key/value pair.
Definition: object-inl.h:74
size_t size() const noexcept
Get the size of the object (number of keys).
Definition: object-inl.h:78
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: object-inl.h:146
simdjson_result< element > operator[](std::string_view key) const noexcept
Get the value associated with the given key.
Definition: object-inl.h:83
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:89
simdjson_inline object() noexcept
Create a new, invalid object.
Definition: object-inl.h:68
iterator begin() const noexcept
Return the first key/value pair.
Definition: object-inl.h:70
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
@ NO_SUCH_FIELD
JSON field not found in object.
Definition: error.h:39
@ INVALID_JSON_POINTER
Invalid JSON pointer reference.
Definition: error.h:41
The result of a simdjson operation that could fail.
Definition: error.h:207
simdjson_inline error_code error() const noexcept
The error.
Definition: error-inl.h:131