Skip to content

Commit b84a3a0

Browse files
authored
Merge branch 'master' into issue961
2 parents 696b0e2 + 49d7023 commit b84a3a0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1889
-1165
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/parse_stream.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,15 @@ int main(int argc, char *argv[]) {
8787

8888
auto start = std::chrono::steady_clock::now();
8989
count = 0;
90-
for (auto result : parser.parse_many(p, i)) {
90+
simdjson::dom::document_stream docs;
91+
if ((error = parser.parse_many(p, i).get(docs))) {
92+
std::wcerr << "Parsing failed with: " << error << std::endl;
93+
exit(1);
94+
}
95+
for (auto result : docs) {
9196
error = result.error();
92-
if (error != simdjson::SUCCESS) {
93-
std::wcerr << "Parsing failed with: " << error_message(error) << std::endl;
97+
if (error) {
98+
std::wcerr << "Parsing failed with: " << error << std::endl;
9499
exit(1);
95100
}
96101
count++;
@@ -134,10 +139,15 @@ int main(int argc, char *argv[]) {
134139

135140
auto start = std::chrono::steady_clock::now();
136141
// This includes allocation of the parser
137-
for (auto result : parser.parse_many(p, optimal_batch_size)) {
142+
simdjson::dom::document_stream docs;
143+
if ((error = parser.parse_many(p, optimal_batch_size).get(docs))) {
144+
std::wcerr << "Parsing failed with: " << error << std::endl;
145+
exit(1);
146+
}
147+
for (auto result : docs) {
138148
error = result.error();
139-
if (error != simdjson::SUCCESS) {
140-
std::wcerr << "Parsing failed with: " << error_message(error) << std::endl;
149+
if (error) {
150+
std::wcerr << "Parsing failed with: " << error << std::endl;
141151
exit(1);
142152
}
143153
}

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: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ And another one:
163163
auto abstract_json = R"(
164164
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
165165
dom::parser parser;
166-
double v = parser.parse(abstract_json)["str"]["123"]["abc"].get<double>();
166+
double v = parser.parse(abstract_json)["str"]["123"]["abc"];
167167
cout << "number: " << v << endl;
168168
```
169169

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

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

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

226225
```c++
227226
// C++ 11 version for comparison
228-
dom::parser parser;
229227
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
230-
simdjson::error_code error;
228+
dom::parser parser;
231229
dom::object object;
232-
error = parser.parse(json).get(object);
230+
auto error = parser.parse(json).get(object);
233231
if (!error) { cerr << error << endl; return; }
234232
for (dom::key_value_pair field : object) {
235233
cout << field.key << " = " << field.value << endl;
@@ -257,41 +255,31 @@ Error Handling
257255
--------------
258256

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

262260
```c++
263-
auto [doc, error] = parser.parse(json); // doc is a dom::element
261+
dom::element doc;
262+
auto error = parser.parse(json).get(doc);
264263
if (error) { cerr << error << endl; exit(1); }
265-
// Use document here now that we've checked for the error
266264
```
267265
268266
When you use the code this way, it is your responsibility to check for error before using the
269267
result: if there is an error, the result value will not be valid and using it will caused undefined
270268
behavior.
271269
272-
> Note: because of the way `auto [x, y]` works in C++, you have to define new variables each time you
273-
> use it. If your project treats aliased, this means you can't use the same names in `auto [x, error]`
274-
> without triggering warnings or error (and particularly can't use the word "error" every time). To
275-
> circumvent this, you can use this instead:
276-
>
277-
> ```c++
278-
> dom::element doc;
279-
> auto error = parser.parse(json).get(doc); // <-- Assigns to doc and error just like "auto [doc, error]"
280-
> ```
281-
282-
283270
We can write a "quick start" example where we attempt to parse a file and access some data, without triggering exceptions:
284271
285272
```C++
286273
#include "simdjson.h"
287274
288275
int main(void) {
289276
simdjson::dom::parser parser;
277+
290278
simdjson::dom::element tweets;
291279
auto error = parser.load("twitter.json").get(tweets);
292280
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
293-
simdjson::dom::element res;
294281
282+
simdjson::dom::element res;
295283
if ((error = tweets["search_metadata"]["count"].get(res))) {
296284
std::cerr << "could not access keys" << std::endl;
297285
return EXIT_FAILURE;
@@ -394,8 +382,7 @@ And another one:
394382
cout << "number: " << v << endl;
395383
```
396384
397-
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*.
398-
385+
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*.
399386
400387
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.
401388
@@ -505,7 +492,8 @@ Here is a simple example, given "x.json" with this content:
505492

506493
```c++
507494
dom::parser parser;
508-
for (dom::element doc : parser.load_many(filename)) {
495+
dom::document_stream docs = parser.load_many(filename);
496+
for (dom::element doc : docs) {
509497
cout << doc["foo"] << endl;
510498
}
511499
// Prints 1 2 3

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
*

0 commit comments

Comments
 (0)