Skip to content

Commit ea8a502

Browse files
committed
Remove array indexer, make object indexer key lookup
1 parent 622d9c9 commit ea8a502

File tree

5 files changed

+80
-121
lines changed

5 files changed

+80
-121
lines changed

doc/basics.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
6363
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. If you
6464
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
6565
* **Object Iteration:** You can iterate through an object's fields, too: `for (auto [key, value] : object)`
66+
* **Array Index:** To get at an array value by index, use the at() method: `array.at(0)` gets the
67+
first element.
68+
> Note that array[0] does not compile, because implementing [] gives the impression indexing is a
69+
> O(1) operation, which it is not presently in simdjson.
6670
6771
Here are some examples of all of the above:
6872

@@ -98,10 +102,13 @@ for (dom::object car : cars) {
98102
}
99103
```
100104

105+
106+
101107
JSON Pointer
102108
------------
103109

104-
The simdjson library also supports JSON pointer, letting you reach further down into the document:
110+
The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rfc6901) through the
111+
at() method, letting you reach further down into the document in a single call:
105112

106113
```c++
107114
auto cars_json = R"( [
@@ -111,7 +118,7 @@ auto cars_json = R"( [
111118
] )"_padded;
112119
dom::parser parser;
113120
dom::element cars = parser.parse(cars_json);
114-
cout << cars["/0/tire_pressure/1"] << endl; // Prints 39.9
121+
cout << cars.at("0/tire_pressure/1") << endl; // Prints 39.9
115122
```
116123

117124
Error Handling

include/simdjson/document.h

Lines changed: 40 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -251,38 +251,34 @@ class element : protected internal::tape_ref {
251251
#endif // SIMDJSON_EXCEPTIONS
252252

253253
/**
254-
* Get the value associated with the given JSON pointer.
254+
* Get the value associated with the given key.
255+
*
256+
* The key will be matched against **unescaped** JSON:
255257
*
256258
* dom::parser parser;
257-
* element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
258-
* doc["/foo/a/1"] == 20
259-
* doc["/"]["foo"]["a"].at(1) == 20
260-
* doc[""]["foo"]["a"].at(1) == 20
259+
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
260+
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
261261
*
262-
* @return The value associated with the given JSON pointer, or:
263-
* - NO_SUCH_FIELD if a field does not exist in an object
264-
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
265-
* - INCORRECT_TYPE if a non-integer is used to access an array
266-
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
262+
* @return The value associated with this field, or:
263+
* - NO_SUCH_FIELD if the field does not exist in the object
264+
* - INCORRECT_TYPE if this is not an object
267265
*/
268-
inline simdjson_result<element> operator[](const std::string_view &json_pointer) const noexcept;
266+
inline simdjson_result<element> operator[](const std::string_view &key) const noexcept;
269267

270268
/**
271-
* Get the value associated with the given JSON pointer.
269+
* Get the value associated with the given key.
270+
*
271+
* The key will be matched against **unescaped** JSON:
272272
*
273273
* dom::parser parser;
274-
* element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
275-
* doc["/foo/a/1"] == 20
276-
* doc["/"]["foo"]["a"].at(1) == 20
277-
* doc[""]["foo"]["a"].at(1) == 20
274+
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
275+
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
278276
*
279-
* @return The value associated with the given JSON pointer, or:
280-
* - NO_SUCH_FIELD if a field does not exist in an object
281-
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
282-
* - INCORRECT_TYPE if a non-integer is used to access an array
283-
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
277+
* @return The value associated with this field, or:
278+
* - NO_SUCH_FIELD if the field does not exist in the object
279+
* - INCORRECT_TYPE if this is not an object
284280
*/
285-
inline simdjson_result<element> operator[](const char *json_pointer) const noexcept;
281+
inline simdjson_result<element> operator[](const char *key) const noexcept;
286282

287283
/**
288284
* Get the value associated with the given JSON pointer.
@@ -390,38 +386,6 @@ class array : protected internal::tape_ref {
390386
*/
391387
inline iterator end() const noexcept;
392388

393-
/**
394-
* Get the value associated with the given JSON pointer.
395-
*
396-
* dom::parser parser;
397-
* array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
398-
* a["0/foo/a/1"] == 20
399-
* a["0"]["foo"]["a"].at(1) == 20
400-
*
401-
* @return The value associated with the given JSON pointer, or:
402-
* - NO_SUCH_FIELD if a field does not exist in an object
403-
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
404-
* - INCORRECT_TYPE if a non-integer is used to access an array
405-
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
406-
*/
407-
inline simdjson_result<element> operator[](const std::string_view &json_pointer) const noexcept;
408-
409-
/**
410-
* Get the value associated with the given JSON pointer.
411-
*
412-
* dom::parser parser;
413-
* array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
414-
* a["0/foo/a/1"] == 20
415-
* a["0"]["foo"]["a"].at(1) == 20
416-
*
417-
* @return The value associated with the given JSON pointer, or:
418-
* - NO_SUCH_FIELD if a field does not exist in an object
419-
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
420-
* - INCORRECT_TYPE if a non-integer is used to access an array
421-
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
422-
*/
423-
inline simdjson_result<element> operator[](const char *json_pointer) const noexcept;
424-
425389
/**
426390
* Get the value associated with the given JSON pointer.
427391
*
@@ -511,36 +475,34 @@ class object : protected internal::tape_ref {
511475
inline iterator end() const noexcept;
512476

513477
/**
514-
* Get the value associated with the given JSON pointer.
478+
* Get the value associated with the given key.
479+
*
480+
* The key will be matched against **unescaped** JSON:
515481
*
516482
* dom::parser parser;
517-
* object obj = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
518-
* obj["foo/a/1"] == 20
519-
* obj["foo"]["a"].at(1) == 20
483+
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
484+
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
520485
*
521-
* @return The value associated with the given JSON pointer, or:
522-
* - NO_SUCH_FIELD if a field does not exist in an object
523-
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
524-
* - INCORRECT_TYPE if a non-integer is used to access an array
525-
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
486+
* @return The value associated with this field, or:
487+
* - NO_SUCH_FIELD if the field does not exist in the object
488+
* - INCORRECT_TYPE if this is not an object
526489
*/
527-
inline simdjson_result<element> operator[](const std::string_view &json_pointer) const noexcept;
490+
inline simdjson_result<element> operator[](const std::string_view &key) const noexcept;
528491

529492
/**
530-
* Get the value associated with the given JSON pointer.
493+
* Get the value associated with the given key.
494+
*
495+
* The key will be matched against **unescaped** JSON:
531496
*
532497
* dom::parser parser;
533-
* object obj = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
534-
* obj["foo/a/1"] == 20
535-
* obj["foo"]["a"].at(1) == 20
498+
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
499+
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
536500
*
537-
* @return The value associated with the given JSON pointer, or:
538-
* - NO_SUCH_FIELD if a field does not exist in an object
539-
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
540-
* - INCORRECT_TYPE if a non-integer is used to access an array
541-
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
501+
* @return The value associated with this field, or:
502+
* - NO_SUCH_FIELD if the field does not exist in the object
503+
* - INCORRECT_TYPE if this is not an object
542504
*/
543-
inline simdjson_result<element> operator[](const char *json_pointer) const noexcept;
505+
inline simdjson_result<element> operator[](const char *key) const noexcept;
544506

545507
/**
546508
* Get the value associated with the given JSON pointer.
@@ -1467,8 +1429,8 @@ struct simdjson_result<dom::element> : public internal::simdjson_result_base<dom
14671429
template<typename T>
14681430
inline simdjson_result<T> get() const noexcept;
14691431

1470-
inline simdjson_result<dom::element> operator[](const std::string_view &json_pointer) const noexcept;
1471-
inline simdjson_result<dom::element> operator[](const char *json_pointer) const noexcept;
1432+
inline simdjson_result<dom::element> operator[](const std::string_view &key) const noexcept;
1433+
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
14721434
inline simdjson_result<dom::element> at(const std::string_view &json_pointer) const noexcept;
14731435
inline simdjson_result<dom::element> at(size_t index) const noexcept;
14741436
inline simdjson_result<dom::element> at_key(const std::string_view &key) const noexcept;
@@ -1494,8 +1456,6 @@ struct simdjson_result<dom::array> : public internal::simdjson_result_base<dom::
14941456
really_inline simdjson_result(dom::array value) noexcept;
14951457
really_inline simdjson_result(error_code error) noexcept;
14961458

1497-
inline simdjson_result<dom::element> operator[](const std::string_view &json_pointer) const noexcept;
1498-
inline simdjson_result<dom::element> operator[](const char *json_pointer) const noexcept;
14991459
inline simdjson_result<dom::element> at(const std::string_view &json_pointer) const noexcept;
15001460
inline simdjson_result<dom::element> at(size_t index) const noexcept;
15011461

@@ -1513,8 +1473,8 @@ struct simdjson_result<dom::object> : public internal::simdjson_result_base<dom:
15131473
really_inline simdjson_result(dom::object value) noexcept;
15141474
really_inline simdjson_result(error_code error) noexcept;
15151475

1516-
inline simdjson_result<dom::element> operator[](const std::string_view &json_pointer) const noexcept;
1517-
inline simdjson_result<dom::element> operator[](const char *json_pointer) const noexcept;
1476+
inline simdjson_result<dom::element> operator[](const std::string_view &key) const noexcept;
1477+
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
15181478
inline simdjson_result<dom::element> at(const std::string_view &json_pointer) const noexcept;
15191479
inline simdjson_result<dom::element> at_key(const std::string_view &key) const noexcept;
15201480
inline simdjson_result<dom::element> at_key_case_insensitive(const std::string_view &key) const noexcept;

include/simdjson/inline/document.h

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,28 +38,28 @@ inline simdjson_result<T> simdjson_result<dom::element>::get() const noexcept {
3838
return first.get<T>();
3939
}
4040

41-
inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](const std::string_view &json_pointer) const noexcept {
42-
if (error()) { return *this; }
43-
return first[json_pointer];
41+
inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](const std::string_view &key) const noexcept {
42+
if (error()) { return error(); }
43+
return first[key];
4444
}
45-
inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](const char *json_pointer) const noexcept {
46-
if (error()) { return *this; }
47-
return first[json_pointer];
45+
inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](const char *key) const noexcept {
46+
if (error()) { return error(); }
47+
return first[key];
4848
}
4949
inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view &json_pointer) const noexcept {
50-
if (error()) { return *this; }
50+
if (error()) { return error(); }
5151
return first.at(json_pointer);
5252
}
5353
inline simdjson_result<dom::element> simdjson_result<dom::element>::at(size_t index) const noexcept {
54-
if (error()) { return *this; }
54+
if (error()) { return error(); }
5555
return first.at(index);
5656
}
5757
inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key(const std::string_view &key) const noexcept {
58-
if (error()) { return *this; }
58+
if (error()) { return error(); }
5959
return first.at_key(key);
6060
}
6161
inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key_case_insensitive(const std::string_view &key) const noexcept {
62-
if (error()) { return *this; }
62+
if (error()) { return error(); }
6363
return first.at_key_case_insensitive(key);
6464
}
6565

@@ -115,14 +115,6 @@ inline dom::array::iterator simdjson_result<dom::array>::end() const noexcept(fa
115115

116116
#endif // SIMDJSON_EXCEPTIONS
117117

118-
inline simdjson_result<dom::element> simdjson_result<dom::array>::operator[](const std::string_view &json_pointer) const noexcept {
119-
if (error()) { return error(); }
120-
return first.at(json_pointer);
121-
}
122-
inline simdjson_result<dom::element> simdjson_result<dom::array>::operator[](const char *json_pointer) const noexcept {
123-
if (error()) { return error(); }
124-
return first.at(json_pointer);
125-
}
126118
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(const std::string_view &json_pointer) const noexcept {
127119
if (error()) { return error(); }
128120
return first.at(json_pointer);
@@ -142,13 +134,13 @@ really_inline simdjson_result<dom::object>::simdjson_result(dom::object value) n
142134
really_inline simdjson_result<dom::object>::simdjson_result(error_code error) noexcept
143135
: internal::simdjson_result_base<dom::object>(error) {}
144136

145-
inline simdjson_result<dom::element> simdjson_result<dom::object>::operator[](const std::string_view &json_pointer) const noexcept {
137+
inline simdjson_result<dom::element> simdjson_result<dom::object>::operator[](const std::string_view &key) const noexcept {
146138
if (error()) { return error(); }
147-
return first[json_pointer];
139+
return first[key];
148140
}
149-
inline simdjson_result<dom::element> simdjson_result<dom::object>::operator[](const char *json_pointer) const noexcept {
141+
inline simdjson_result<dom::element> simdjson_result<dom::object>::operator[](const char *key) const noexcept {
150142
if (error()) { return error(); }
151-
return first[json_pointer];
143+
return first[key];
152144
}
153145
inline simdjson_result<dom::element> simdjson_result<dom::object>::at(const std::string_view &json_pointer) const noexcept {
154146
if (error()) { return error(); }
@@ -603,11 +595,11 @@ inline object::iterator object::end() const noexcept {
603595
return iterator(doc, after_element() - 1);
604596
}
605597

606-
inline simdjson_result<element> object::operator[](const std::string_view &json_pointer) const noexcept {
607-
return at(json_pointer);
598+
inline simdjson_result<element> object::operator[](const std::string_view &key) const noexcept {
599+
return at_key(key);
608600
}
609-
inline simdjson_result<element> object::operator[](const char *json_pointer) const noexcept {
610-
return at(json_pointer);
601+
inline simdjson_result<element> object::operator[](const char *key) const noexcept {
602+
return at_key(key);
611603
}
612604
inline simdjson_result<element> object::at(const std::string_view &json_pointer) const noexcept {
613605
size_t slash = json_pointer.find('/');
@@ -840,11 +832,11 @@ inline element::operator object() const noexcept(false) { return get<object>();
840832

841833
#endif
842834

843-
inline simdjson_result<element> element::operator[](const std::string_view &json_pointer) const noexcept {
844-
return at(json_pointer);
835+
inline simdjson_result<element> element::operator[](const std::string_view &key) const noexcept {
836+
return at_key(key);
845837
}
846-
inline simdjson_result<element> element::operator[](const char *json_pointer) const noexcept {
847-
return at(json_pointer);
838+
inline simdjson_result<element> element::operator[](const char *key) const noexcept {
839+
return at_key(key);
848840
}
849841
inline simdjson_result<element> element::at(const std::string_view &json_pointer) const noexcept {
850842
switch (type()) {

tests/basictests.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -805,14 +805,14 @@ namespace dom_api_tests {
805805

806806
bool document_object_index() {
807807
std::cout << "Running " << __func__ << std::endl;
808-
string json(R"({ "a": 1, "b": 2, "c": 3})");
808+
string json(R"({ "a": 1, "b": 2, "c/d": 3})");
809809
dom::parser parser;
810810
auto [doc, error] = parser.parse(json);
811811
if (doc["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; }
812812
if (doc["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; }
813-
if (doc["c"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(doc[\"c\"]) to be 3, was " << doc["c"].first << endl; return false; }
813+
if (doc["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; }
814814
// Check all three again in backwards order, to ensure we can go backwards
815-
if (doc["c"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(doc[\"c\"]) to be 3, was " << doc["c"].first << endl; return false; }
815+
if (doc["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; }
816816
if (doc["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; }
817817
if (doc["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; }
818818

@@ -825,7 +825,7 @@ namespace dom_api_tests {
825825

826826
bool object_index() {
827827
std::cout << "Running " << __func__ << std::endl;
828-
string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })");
828+
string json(R"({ "obj": { "a": 1, "b": 2, "c/d": 3 } })");
829829
dom::parser parser;
830830
auto [doc, error] = parser.parse(json);
831831
if (error) { cerr << "Error: " << error << endl; return false; }
@@ -839,9 +839,9 @@ namespace dom_api_tests {
839839
obj["obj"].get<dom::object>().tie(obj, error); // tie(...) = fails with "no viable overloaded '='" on Apple clang version 11.0.0
840840
if (obj["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; }
841841
if (obj["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; }
842-
if (obj["c"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; }
842+
if (obj["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; }
843843
// Check all three again in backwards order, to ensure we can go backwards
844-
if (obj["c"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; }
844+
if (obj["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; }
845845
if (obj["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; }
846846
if (obj["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; }
847847

0 commit comments

Comments
 (0)