Skip to content

Commit c650ea9

Browse files
authored
Merge pull request simdjson#960 from simdjson/jkeiser/idiomatic-get
Convert simdjson to use .get()
2 parents eef1171 + e369d45 commit c650ea9

29 files changed

+508
-563
lines changed

benchmark/bench_dom_api.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ static void iterator_twitter_default_profile(State& state) {
407407
set<string_view> default_users;
408408
ParsedJson::Iterator iter(pj);
409409

410-
// for (dom::object tweet : doc["statuses"].get<dom::array>()) {
410+
// for (dom::object tweet : doc["statuses"]) {
411411
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
412412
if (iter.down()) { // first status
413413
do {
@@ -480,23 +480,24 @@ static void iterator_twitter_image_sizes(State& state) {
480480
set<tuple<uint64_t, uint64_t>> image_sizes;
481481
ParsedJson::Iterator iter(pj);
482482

483-
// for (dom::object tweet : doc["statuses"].get<dom::array>()) {
483+
// for (dom::object tweet : doc["statuses"]) {
484484
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
485485
if (iter.down()) { // first status
486486
do {
487487

488-
// auto [media, not_found] = tweet["entities"]["media"];
488+
// dom::object media;
489+
// not_found = tweet["entities"]["media"].get(media);
489490
// if (!not_found) {
490491
if (iter.move_to_key("entities")) {
491492
if (!iter.is_object()) { return; }
492493
if (iter.move_to_key("media")) {
493494
if (!iter.is_array()) { return; }
494495

495-
// for (dom::object image : media.get<dom::array>()) {
496+
// for (dom::object image : media) {
496497
if (iter.down()) { // first media
497498
do {
498499

499-
// for (auto [key, size] : image["sizes"].get<dom::object>()) {
500+
// for (auto [key, size] : dom::object(image["sizes"])) {
500501
if (!(iter.move_to_key("sizes") && iter.is_object())) { return; }
501502
if (iter.down()) { // first size
502503
do {

benchmark/distinctuseridcompetition.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,18 @@ void print_vec(const std::vector<int64_t> &v) {
4040

4141
// simdjson_recurse below come be implemented like so but it is slow:
4242
/*void simdjson_recurse(std::vector<int64_t> & v, simdjson::dom::element element) {
43-
if (element.is<simdjson::dom::array>()) {
44-
auto [array, array_error] = element.get<simdjson::dom::array>();
43+
error_code error;
44+
if (element.is_array()) {
45+
dom::array array;
46+
error = element.get(array);
4547
for (auto child : array) {
4648
if (child.is<simdjson::dom::array>() || child.is<simdjson::dom::object>()) {
4749
simdjson_recurse(v, child);
4850
}
4951
}
50-
} else if (element.is<simdjson::dom::object>()) {
51-
auto [object, error] = element.get<simdjson::dom::object>();
52+
} else if (element.is_object()) {
5253
int64_t id;
53-
error = object["user"]["id"].get(id);
54+
error = element["user"]["id"].get(id);
5455
if(!error) {
5556
v.push_back(id);
5657
}
@@ -330,7 +331,8 @@ int main(int argc, char *argv[]) {
330331
std::cerr << "warning: ignoring everything after " << argv[optind + 1]
331332
<< std::endl;
332333
}
333-
auto [p, error] = simdjson::padded_string::load(filename);
334+
simdjson::padded_string p;
335+
auto error = simdjson::padded_string::load(filename).get(p);
334336
if (error) {
335337
std::cerr << "Could not load the file " << filename << std::endl;
336338
return EXIT_FAILURE;

benchmark/minifiercompetition.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ int main(int argc, char *argv[]) {
7575
exit(1);
7676
}
7777
const char *filename = argv[optind];
78-
auto [p, error] = simdjson::padded_string::load(filename);
78+
simdjson::padded_string p;
79+
auto error = simdjson::padded_string::load(filename).get(p);
7980
if (error) {
8081
std::cerr << "Could not load the file " << filename << std::endl;
8182
return EXIT_FAILURE;

benchmark/parseandstatcompetition.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ void simdjson_recurse(stat_t &s, simdjson::dom::element element) {
105105
never_inline stat_t simdjson_compute_stats(const simdjson::padded_string &p) {
106106
stat_t s{};
107107
simdjson::dom::parser parser;
108-
auto [doc, error] = parser.parse(p);
108+
simdjson::dom::element doc;
109+
auto error = parser.parse(p).get(doc);
109110
if (error) {
110111
s.valid = false;
111112
return s;
@@ -154,11 +155,11 @@ static void GenStatPlus(Stat &stat, const dom::element &v) {
154155
break;
155156
case dom::element_type::STRING: {
156157
stat.stringCount++;
157-
std::string_view sv = v.get<std::string_view>();
158+
auto sv = std::string_view(v);
158159
stat.stringLength += sv.size();
159160
} break;
160161
case dom::element_type::BOOL:
161-
if (v.get<bool>()) {
162+
if (bool(v)) {
162163
stat.trueCount++;
163164
} else {
164165
stat.falseCount++;
@@ -409,7 +410,8 @@ int main(int argc, char *argv[]) {
409410
std::cerr << "warning: ignoring everything after " << argv[optind + 1]
410411
<< std::endl;
411412
}
412-
auto [p, error] = simdjson::padded_string::load(filename);
413+
simdjson::padded_string p;
414+
auto error = simdjson::padded_string::load(filename).get(p);
413415
if (error) {
414416
std::cerr << "Could not load the file " << filename << std::endl;
415417
return EXIT_FAILURE;
@@ -464,9 +466,10 @@ int main(int argc, char *argv[]) {
464466
printf("API traversal tests\n");
465467
printf("Based on https://github.com/miloyip/nativejson-benchmark\n");
466468
simdjson::dom::parser parser;
467-
auto [doc, err] = parser.parse(p);
468-
if (err) {
469-
std::cerr << err << std::endl;
469+
simdjson::dom::element doc;
470+
auto error = parser.parse(p).get(doc);
471+
if (error) {
472+
std::cerr << error << std::endl;
470473
}
471474
size_t refval = simdjson_compute_stats_refplus(doc).objectCount;
472475

benchmark/parsingcompetition.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ inline void reset_stream(std::stringstream & is) {
8282

8383

8484
bool bench(const char *filename, bool verbose, bool just_data, double repeat_multiplier) {
85-
auto [p, err] = simdjson::padded_string::load(filename);
86-
if (err) {
87-
std::cerr << "Could not load the file " << filename << std::endl;
85+
simdjson::padded_string p;
86+
auto error = simdjson::padded_string::load(filename).get(p);
87+
if (error) {
88+
std::cerr << "Could not load the file " << filename << ": " << error << std::endl;
8889
return false;
8990
}
9091

benchmark/statisticalmodel.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ void simdjson_recurse(stat_t &s, simdjson::dom::element element) {
9696
stat_t simdjson_compute_stats(const simdjson::padded_string &p) {
9797
stat_t answer{};
9898
simdjson::dom::parser parser;
99-
auto [doc, error] = parser.parse(p);
99+
simdjson::dom::element doc;
100+
auto error = parser.parse(p).get(doc);
100101
if (error) {
101102
answer.valid = false;
102103
return answer;
@@ -136,7 +137,8 @@ int main(int argc, char *argv[]) {
136137
std::cerr << "warning: ignoring everything after " << argv[optind + 1]
137138
<< std::endl;
138139
}
139-
auto [p, error] = simdjson::padded_string::load(filename);
140+
simdjson::padded_string p;
141+
auto error = simdjson::padded_string::load(filename).get(p);
140142
if (error) {
141143
std::cerr << "Could not load the file " << filename << std::endl;
142144
return EXIT_FAILURE;

doc/basics.md

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ And another one:
164164
auto abstract_json = R"(
165165
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
166166
dom::parser parser;
167-
double v = parser.parse(abstract_json)["str"]["123"]["abc"].get<double>();
167+
double v = parser.parse(abstract_json)["str"]["123"]["abc"];
168168
cout << "number: " << v << endl;
169169
```
170170

@@ -208,14 +208,13 @@ Your input string does not need any padding. Any string will do. The `validate_u
208208
C++17 Support
209209
-------------
210210

211-
While the simdjson library can be used in any project using C++ 11 and above, it has special support
212-
for C++ 17. The APIs for field iteration and error handling in particular are designed to work
213-
nicely with C++17's destructuring syntax. For example:
211+
While the simdjson library can be used in any project using C++ 11 and above, field iteration has special support C++ 17's destructuring syntax. For example:
214212

215213
```c++
216-
dom::parser parser;
217214
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
218-
auto [object, error] = parser.parse(json).get<dom::object>();
215+
dom::parser parser;
216+
dom::object object;
217+
auto error = parser.parse(json).get(object);
219218
if (error) { cerr << error << endl; return; }
220219
for (auto [key, value] : object) {
221220
cout << key << " = " << value << endl;
@@ -226,11 +225,10 @@ For comparison, here is the C++ 11 version of the same code:
226225

227226
```c++
228227
// C++ 11 version for comparison
229-
dom::parser parser;
230228
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
231-
simdjson::error_code error;
229+
dom::parser parser;
232230
dom::object object;
233-
error = parser.parse(json).get(object);
231+
auto error = parser.parse(json).get(object);
234232
if (!error) { cerr << error << endl; return; }
235233
for (dom::key_value_pair field : object) {
236234
cout << field.key << " = " << field.value << endl;
@@ -258,41 +256,31 @@ Error Handling
258256
--------------
259257

260258
All simdjson APIs that can fail return `simdjson_result<T>`, which is a &lt;value, error_code&gt;
261-
pair. The error codes and values can be accessed directly, reading the error like so:
259+
pair. You can retrieve the value with .get(), like so:
262260

263261
```c++
264-
auto [doc, error] = parser.parse(json); // doc is a dom::element
262+
dom::element doc;
263+
auto error = parser.parse(json).get(doc);
265264
if (error) { cerr << error << endl; exit(1); }
266-
// Use document here now that we've checked for the error
267265
```
268266
269267
When you use the code this way, it is your responsibility to check for error before using the
270268
result: if there is an error, the result value will not be valid and using it will caused undefined
271269
behavior.
272270
273-
> Note: because of the way `auto [x, y]` works in C++, you have to define new variables each time you
274-
> use it. If your project treats aliased, this means you can't use the same names in `auto [x, error]`
275-
> without triggering warnings or error (and particularly can't use the word "error" every time). To
276-
> circumvent this, you can use this instead:
277-
>
278-
> ```c++
279-
> dom::element doc;
280-
> auto error = parser.parse(json).get(doc); // <-- Assigns to doc and error just like "auto [doc, error]"
281-
> ```
282-
283-
284271
We can write a "quick start" example where we attempt to parse a file and access some data, without triggering exceptions:
285272
286273
```C++
287274
#include "simdjson.h"
288275
289276
int main(void) {
290277
simdjson::dom::parser parser;
278+
291279
simdjson::dom::element tweets;
292280
auto error = parser.load("twitter.json").get(tweets);
293281
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
294-
simdjson::dom::element res;
295282
283+
simdjson::dom::element res;
296284
if ((error = tweets["search_metadata"]["count"].get(res))) {
297285
std::cerr << "could not access keys" << std::endl;
298286
return EXIT_FAILURE;
@@ -395,8 +383,7 @@ And another one:
395383
cout << "number: " << v << endl;
396384
```
397385
398-
Notice how we can string several operation (`parser.parse(abstract_json)["str"]["123"]["abc"].get<double>()`) and only check for the error once, a strategy we call *error chaining*.
399-
386+
Notice how we can string several operations (`parser.parse(abstract_json)["str"]["123"]["abc"].get(v)`) and only check for the error once, a strategy we call *error chaining*.
400387
401388
The next two functions will take as input a JSON document containing an array with a single element, either a string or a number. They return true upon success.
402389

doc/performance.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ without bound:
6868
```c++
6969
dom::parser parser(1000*1000); // Never grow past documents > 1MB
7070
for (web_request request : listen()) {
71-
auto [doc, error] = parser.parse(request.body);
71+
dom::element doc;
72+
auto error = parser.parse(request.body).get(doc);
7273
// If the document was above our limit, emit 413 = payload too large
7374
if (error == CAPACITY) { request.respond(413); continue; }
7475
// ...
@@ -82,11 +83,12 @@ without bound:
8283
8384
```c++
8485
dom::parser parser(0); // This parser will refuse to automatically grow capacity
85-
simdjson::error_code allocate_error = parser.allocate(1000*1000); // This allocates enough capacity to handle documents <= 1MB
86-
if (allocate_error) { cerr << allocate_error << endl; exit(1); }
86+
auto error = parser.allocate(1000*1000); // This allocates enough capacity to handle documents <= 1MB
87+
if (error) { cerr << error << endl; exit(1); }
8788
8889
for (web_request request : listen()) {
89-
auto [doc, error] = parser.parse(request.body);
90+
dom::element doc;
91+
error = parser.parse(request.body).get(doc);
9092
// If the document was above our limit, emit 413 = payload too large
9193
if (error == CAPACITY) { request.respond(413); continue; }
9294
// ...

include/simdjson/dom/array.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class array {
6868
* Get the value associated with the given JSON pointer.
6969
*
7070
* dom::parser parser;
71-
* array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])");
71+
* array a = parser.parse(R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded);
7272
* a.at("0/foo/a/1") == 20
7373
* a.at("0")["foo"]["a"].at(1) == 20
7474
*

include/simdjson/dom/element.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,8 @@ class element {
336336
* The key will be matched against **unescaped** JSON:
337337
*
338338
* dom::parser parser;
339-
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
340-
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
339+
* parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get<uint64_t>().first == 1
340+
* parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
341341
*
342342
* @return The value associated with this field, or:
343343
* - NO_SUCH_FIELD if the field does not exist in the object
@@ -351,8 +351,8 @@ class element {
351351
* The key will be matched against **unescaped** JSON:
352352
*
353353
* dom::parser parser;
354-
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
355-
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
354+
* parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get<uint64_t>().first == 1
355+
* parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
356356
*
357357
* @return The value associated with this field, or:
358358
* - NO_SUCH_FIELD if the field does not exist in the object
@@ -364,7 +364,7 @@ class element {
364364
* Get the value associated with the given JSON pointer.
365365
*
366366
* dom::parser parser;
367-
* element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})");
367+
* element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded);
368368
* doc.at("/foo/a/1") == 20
369369
* doc.at("/")["foo"]["a"].at(1) == 20
370370
* doc.at("")["foo"]["a"].at(1) == 20
@@ -391,8 +391,8 @@ class element {
391391
* The key will be matched against **unescaped** JSON:
392392
*
393393
* dom::parser parser;
394-
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
395-
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
394+
* parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get<uint64_t>().first == 1
395+
* parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
396396
*
397397
* @return The value associated with this field, or:
398398
* - NO_SUCH_FIELD if the field does not exist in the object

0 commit comments

Comments
 (0)