simdjson 4.0.7
Ridiculously Fast JSON
Loading...
Searching...
No Matches
object-inl.h
1#ifndef SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
2
3#ifndef SIMDJSON_CONDITIONAL_INCLUDE
4#define SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
5#include "simdjson/generic/ondemand/base.h"
6#include "simdjson/generic/ondemand/field.h"
7#include "simdjson/generic/ondemand/object.h"
8#include "simdjson/generic/ondemand/object_iterator.h"
9#include "simdjson/generic/ondemand/raw_json_string.h"
10#include "simdjson/generic/ondemand/json_iterator.h"
11#include "simdjson/generic/ondemand/value-inl.h"
12#if SIMDJSON_STATIC_REFLECTION
13#include "simdjson/generic/ondemand/json_string_builder.h" // for constevalutil::fixed_string
14#include <meta>
15#endif
16#endif // SIMDJSON_CONDITIONAL_INCLUDE
17
18namespace simdjson {
19namespace SIMDJSON_IMPLEMENTATION {
20namespace ondemand {
21
22simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
23 bool has_value;
24 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
25 if (!has_value) {
26 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
27 return NO_SUCH_FIELD;
28 }
29 return value(iter.child());
30}
31simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
32 bool has_value;
33 SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
34 if (!has_value) {
35 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
36 return NO_SUCH_FIELD;
37 }
38 return value(iter.child());
39}
40simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
41 return find_field_unordered(key);
42}
43simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
44 return std::forward<object>(*this).find_field_unordered(key);
45}
46simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
47 bool has_value;
48 SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
49 if (!has_value) {
50 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
51 return NO_SUCH_FIELD;
52 }
53 return value(iter.child());
54}
55simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
56 bool has_value;
57 SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
58 if (!has_value) {
59 logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
60 return NO_SUCH_FIELD;
61 }
62 return value(iter.child());
63}
64
65simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
66 SIMDJSON_TRY( iter.start_object().error() );
67 return object(iter);
68}
69simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
70 SIMDJSON_TRY( iter.start_root_object().error() );
71 return object(iter);
72}
73simdjson_warn_unused simdjson_inline error_code object::consume() noexcept {
74 if(iter.is_at_key()) {
88 simdjson_unused raw_json_string actual_key;
89 auto error = iter.field_key().get(actual_key);
90 if (error) { iter.abandon(); return error; };
91 // Let us move to the value while we are at it.
92 if ((error = iter.field_value())) { iter.abandon(); return error; }
93 }
94 auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
95 if(error_skip) { iter.abandon(); }
96 return error_skip;
97}
98
100 const uint8_t * starting_point{iter.peek_start()};
101 auto error = consume();
102 if(error) { return error; }
103 const uint8_t * final_point{iter._json_iter->peek()};
104 return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
105}
106
107simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
108 SIMDJSON_TRY( iter.started_object().error() );
109 return object(iter);
110}
111
112simdjson_inline object object::resume(const value_iterator &iter) noexcept {
113 return iter;
114}
115
116simdjson_inline object::object(const value_iterator &_iter) noexcept
117 : iter{_iter}
118{
119}
120
121simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
122#if SIMDJSON_DEVELOPMENT_CHECKS
123 if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
124#endif
125 return object_iterator(iter);
126}
127simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
128 return object_iterator(iter);
129}
130
131inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
132 if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
133 json_pointer = json_pointer.substr(1);
134 size_t slash = json_pointer.find('/');
135 std::string_view key = json_pointer.substr(0, slash);
136 // Grab the child with the given key
138
139 // If there is an escape character in the key, unescape it and then get the child.
140 size_t escape = key.find('~');
141 if (escape != std::string_view::npos) {
142 // Unescape the key
143 std::string unescaped(key);
144 do {
145 switch (unescaped[escape+1]) {
146 case '0':
147 unescaped.replace(escape, 2, "~");
148 break;
149 case '1':
150 unescaped.replace(escape, 2, "/");
151 break;
152 default:
153 return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
154 }
155 escape = unescaped.find('~', escape+1);
156 } while (escape != std::string::npos);
157 child = find_field(unescaped); // Take note find_field does not unescape keys when matching
158 } else {
159 child = find_field(key);
160 }
161 if(child.error()) {
162 return child; // we do not continue if there was an error
163 }
164 // If there is a /, we have to recurse and look up more of the path
165 if (slash != std::string_view::npos) {
166 child = child.at_pointer(json_pointer.substr(slash));
167 }
168 return child;
169}
170
171inline simdjson_result<value> object::at_path(std::string_view json_path) noexcept {
173 if (json_pointer == "-1") {
175 }
176 return at_pointer(json_pointer);
177}
178
179simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
180 size_t count{0};
181 // Important: we do not consume any of the values.
182 for(simdjson_unused auto v : *this) { count++; }
183 // The above loop will always succeed, but we want to report errors.
184 if(iter.error()) { return iter.error(); }
185 // We need to move back at the start because we expect users to iterate through
186 // the object after counting the number of elements.
187 iter.reset_object();
188 return count;
189}
190
191simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
192 bool is_not_empty;
193 auto error = iter.reset_object().get(is_not_empty);
194 if(error) { return error; }
195 return !is_not_empty;
196}
197
198simdjson_inline simdjson_result<bool> object::reset() & noexcept {
199 return iter.reset_object();
200}
201
202#if SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
203
204template<constevalutil::fixed_string... FieldNames, typename T>
205 requires(std::is_class_v<T> && (sizeof...(FieldNames) > 0))
206simdjson_warn_unused simdjson_inline error_code object::extract_into(T& out) & noexcept {
207 // Helper to check if a field name matches any of the requested fields
208 auto should_extract = [](std::string_view field_name) constexpr -> bool {
209 return ((FieldNames.view() == field_name) || ...);
210 };
211
212 // Iterate through all members of T using reflection
213 template for (constexpr auto mem : std::define_static_array(
214 std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
215
216 if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
217 constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
218
219 // Only extract this field if it's in our list of requested fields
220 if constexpr (should_extract(key)) {
221 // Try to find and extract the field
222 if constexpr (concepts::optional_type<decltype(out.[:mem:])>) {
223 // For optional fields, it's ok if they're missing
224 auto field_result = find_field_unordered(key);
225 if (!field_result.error()) {
226 auto error = field_result.get(out.[:mem:]);
227 if (error && error != NO_SUCH_FIELD) {
228 return error;
229 }
230 } else if (field_result.error() != NO_SUCH_FIELD) {
231 return field_result.error();
232 } else {
233 out.[:mem:].reset();
234 }
235 } else {
236 // For required fields (in the requested list), fail if missing
237 SIMDJSON_TRY((*this)[key].get(out.[:mem:]));
238 }
239 }
240 }
241 };
242
243 return SUCCESS;
244}
245
246#endif // SIMDJSON_SUPPORTS_CONCEPTS && SIMDJSON_STATIC_REFLECTION
247
248} // namespace ondemand
249} // namespace SIMDJSON_IMPLEMENTATION
250} // namespace simdjson
251
252namespace simdjson {
253
254simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object &&value) noexcept
255 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(value)) {}
256simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(error_code error) noexcept
257 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(error) {}
258
259simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() noexcept {
260 if (error()) { return error(); }
261 return first.begin();
262}
263simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept {
264 if (error()) { return error(); }
265 return first.end();
266}
267simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) & noexcept {
268 if (error()) { return error(); }
269 return first.find_field_unordered(key);
270}
271simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field_unordered(std::string_view key) && noexcept {
272 if (error()) { return error(); }
273 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field_unordered(key);
274}
275simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) & noexcept {
276 if (error()) { return error(); }
277 return first[key];
278}
279simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) && noexcept {
280 if (error()) { return error(); }
281 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first)[key];
282}
283simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) & noexcept {
284 if (error()) { return error(); }
285 return first.find_field(key);
286}
287simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_field(std::string_view key) && noexcept {
288 if (error()) { return error(); }
289 return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field(key);
290}
291
292simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_pointer(std::string_view json_pointer) noexcept {
293 if (error()) { return error(); }
294 return first.at_pointer(json_pointer);
295}
296
297simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::at_path(
298 std::string_view json_path) noexcept {
299 if (error()) {
300 return error();
301 }
302 return first.at_path(json_path);
303}
304
305inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::reset() noexcept {
306 if (error()) { return error(); }
307 return first.reset();
308}
309
310inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::is_empty() noexcept {
311 if (error()) { return error(); }
312 return first.is_empty();
313}
314
315simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::count_fields() & noexcept {
316 if (error()) { return error(); }
317 return first.count_fields();
318}
319
320simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::raw_json() noexcept {
321 if (error()) { return error(); }
322 return first.raw_json();
323}
324
325} // namespace simdjson
326
327#endif // SIMDJSON_GENERIC_ONDEMAND_OBJECT_INL_H
simdjson_result< value > at_pointer(std::string_view json_pointer) noexcept
Get the value associated with the given JSON pointer.
Definition array-inl.h:131
A forward-only JSON object field iterator.
Definition object.h:20
simdjson_inline object() noexcept=default
Create a new invalid object.
simdjson_inline simdjson_result< value > find_field_unordered(std::string_view key) &noexcept
Look up a field by name on an object, without regard to key order.
Definition object-inl.h:22
simdjson_inline simdjson_result< std::string_view > raw_json() noexcept
Consumes the object and returns a string_view instance corresponding to the object as represented in ...
Definition object-inl.h:99
simdjson_warn_unused simdjson_inline error_code consume() noexcept
Go to the end of the object, no matter where you are right now.
Definition object-inl.h:73
simdjson_inline simdjson_result< value > find_field(std::string_view key) &noexcept
Look up a field by name on an object (order-sensitive).
Definition object-inl.h:46
simdjson_result< bool > is_empty() &noexcept
This method scans the beginning of the object and checks whether the object is empty.
Definition object-inl.h:191
simdjson_result< bool > reset() &noexcept
Reset the iterator so that we are pointing back at the beginning of the object.
Definition object-inl.h:198
simdjson_result< value > at_path(std::string_view json_path) noexcept
Get the value associated with the given JSONPath expression.
Definition object-inl.h:171
simdjson_result< value > at_pointer(std::string_view json_pointer) noexcept
Get the value associated with the given JSON pointer.
Definition object-inl.h:131
simdjson_inline simdjson_result< size_t > count_fields() &noexcept
This method scans the object and counts the number of key-value pairs.
Definition object-inl.h:179
A string escaped per JSON rules, terminated with quote (").
An ephemeral JSON value returned during iteration.
Definition value.h:21
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
@ OUT_OF_ORDER_ITERATION
tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
Definition error.h:46
@ NO_SUCH_FIELD
JSON field not found in object.
Definition error.h:40
@ SUCCESS
No error.
Definition error.h:20
@ 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.
The result of a simdjson operation that could fail.
Definition error.h:278