1 #include "simdjson.h"
2 #include "test_ondemand.h"
3
4 using namespace std;
5 using namespace simdjson;
6 using error_code=simdjson::error_code;
7
8
9
10 #if SIMDJSON_EXCEPTIONS
11
number_tests()12 bool number_tests() {
13 ondemand::parser parser;
14 padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999])"_padded;
15 ondemand::document doc = parser.iterate(docdata);
16 ondemand::array arr = doc.get_array();
17 for(ondemand::value val : arr) {
18 std::cout << val << " ";
19 std::cout << "negative: " << val.is_negative() << " ";
20 std::cout << "is_integer: " << val.is_integer() << " ";
21 ondemand::number num = val.get_number();
22 ondemand::number_type t = num.get_number_type();
23 // direct computation without materializing the number:
24 ondemand::number_type dt = val.get_number_type();
25 if(t != dt) { throw std::runtime_error("bug"); }
26 switch(t) {
27 case ondemand::number_type::signed_integer:
28 std::cout << "integer: " << int64_t(num) << " ";
29 std::cout << "integer: " << num.get_int64() << std::endl;
30 break;
31 case ondemand::number_type::unsigned_integer:
32 std::cout << "large 64-bit integer: " << uint64_t(num) << " ";
33 std::cout << "large 64-bit integer: " << num.get_uint64() << std::endl;
34 break;
35 case ondemand::number_type::floating_point_number:
36 std::cout << "float: " << double(num) << " ";
37 std::cout << "float: " << num.get_double() << std::endl;
38 break;
39 }
40 }
41 return true;
42
43 }
44
recursive_print_json(ondemand::value element)45 void recursive_print_json(ondemand::value element) {
46 bool add_comma;
47 switch (element.type()) {
48 case ondemand::json_type::array:
49 cout << "[";
50 add_comma = false;
51 for (auto child : element.get_array()) {
52 if (add_comma) {
53 cout << ",";
54 }
55 // We need the call to value() to get
56 // an ondemand::value type.
57 recursive_print_json(child.value());
58 add_comma = true;
59 }
60 cout << "]";
61 break;
62 case ondemand::json_type::object:
63 cout << "{";
64 add_comma = false;
65 for (auto field : element.get_object()) {
66 if (add_comma) {
67 cout << ",";
68 }
69 // key() returns the key as it appears in the raw
70 // JSON document, if we want the unescaped key,
71 // we should do field.unescaped_key().
72 cout << "\"" << field.key() << "\": ";
73 recursive_print_json(field.value());
74 add_comma = true;
75 }
76 cout << "}\n";
77 break;
78 case ondemand::json_type::number:
79 // assume it fits in a double
80 cout << element.get_double();
81 break;
82 case ondemand::json_type::string:
83 // get_string() would return escaped string, but
84 // we are happy with unescaped string.
85 cout << "\"" << element.get_raw_json_string() << "\"";
86 break;
87 case ondemand::json_type::boolean:
88 cout << element.get_bool();
89 break;
90 case ondemand::json_type::null:
91 cout << "null";
92 break;
93 }
94 }
95
basics_treewalk()96 bool basics_treewalk() {
97 padded_string json[3] = {R"( [
98 { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
99 { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
100 { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
101 ] )"_padded, R"( {"key":"value"} )"_padded, "[12,3]"_padded};
102 ondemand::parser parser;
103 for(size_t i = 0 ; i < 3; i++) {
104 ondemand::document doc = parser.iterate(json[i]);
105 ondemand::value val = doc;
106 recursive_print_json(val);
107 std::cout << std::endl;
108 }
109 return true;
110 }
111
basics_1()112 bool basics_1() {
113 TEST_START();
114
115 ondemand::parser parser;
116 auto json = padded_string::load("twitter.json");
117 ondemand::document doc = parser.iterate(json); // load and parse a file
118
119 simdjson_unused auto unused_doc = doc.get_object();
120
121 TEST_SUCCEED();
122 }
123
basics_2()124 bool basics_2() {
125 TEST_START();
126
127 ondemand::parser parser;
128 auto json = "[1,2,3]"_padded; // The _padded suffix creates a simdjson::padded_string instance
129 ondemand::document doc = parser.iterate(json); // parse a string
130
131 simdjson_unused auto unused_doc = doc.get_array();
132
133 TEST_SUCCEED();
134 }
135
basics_3()136 bool basics_3() {
137 TEST_START();
138
139 ondemand::parser parser;
140 char json[3+SIMDJSON_PADDING];
141 strcpy(json, "[1]");
142 ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
143
144 simdjson_unused auto unused_doc = doc.get_array();
145
146 TEST_SUCCEED();
147 }
148
149
json_array_with_array_count()150 bool json_array_with_array_count() {
151 TEST_START();
152 ondemand::parser parser;
153 auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
154 auto doc = parser.iterate(cars_json);
155 auto arr = doc.get_array();
156 size_t count = arr.count_elements();
157 ASSERT_EQUAL(4, count);
158 std::cout << count << std::endl;
159 // We deliberately do it twice:
160 count = arr.count_elements();
161 ASSERT_EQUAL(4, count);
162 std::cout << count << std::endl;
163 // Next, we check whether we can iterate normally:
164 std::vector<double> values(count);
165 size_t index = 0;
166 for(double x : arr) { values[index++] = x; }
167 ASSERT_EQUAL(index, count);
168 TEST_SUCCEED();
169 }
170
json_value_with_array_count()171 bool json_value_with_array_count() {
172 TEST_START();
173 ondemand::parser parser;
174 auto cars_json = R"( {"array":[ 40.1, 39.9, 37.7, 40.4 ]} )"_padded;
175 auto doc = parser.iterate(cars_json);
176 auto val = doc["array"];
177 size_t count = val.count_elements();
178 ASSERT_EQUAL(4, count);
179 std::cout << count << std::endl;
180 // We deliberately do it twice:
181 count = val.count_elements();
182 ASSERT_EQUAL(4, count);
183 std::cout << count << std::endl;
184 std::vector<double> values(count);
185 // Next, we check whether we can iterate normally:
186 size_t index = 0;
187 for(double x : val) { values[index++] = x; }
188 ASSERT_EQUAL(index, count);
189 TEST_SUCCEED();
190 }
191
192
json_array_count()193 bool json_array_count() {
194 TEST_START();
195 ondemand::parser parser;
196 auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
197 auto doc = parser.iterate(cars_json);
198 size_t count = doc.count_elements();
199 ASSERT_EQUAL(4, count);
200 std::cout << count << std::endl;
201 // We deliberately do it twice:
202 count = doc.count_elements();
203 ASSERT_EQUAL(4, count);
204 std::cout << count << std::endl;
205 std::vector<double> values(count);
206 size_t index = 0;
207 for(double x : doc) { values[index++] = x; }
208 ASSERT_EQUAL(index, count);
209 TEST_SUCCEED();
210 }
211
json_array_count_complex()212 bool json_array_count_complex() {
213 TEST_START();
214 ondemand::parser parser;
215 auto cars_json = R"( { "test":[ { "val1":1, "val2":2 }, { "val1":1, "val2":2 }, { "val1":1, "val2":2 } ] } )"_padded;
216 auto doc = parser.iterate(cars_json);
217 auto test_array = doc.find_field("test").get_array();
218 size_t count = test_array.count_elements();
219 std::cout << "Number of elements: " << count << std::endl;
220 size_t c = 0;
221 for(ondemand::object elem : test_array) {
222 std::cout << simdjson::to_json_string(elem);
223 c++;
224 }
225 std::cout << std::endl;
226 ASSERT_EQUAL(c, count);
227 TEST_SUCCEED();
228
229 }
230
json_object_count()231 bool json_object_count() {
232 TEST_START();
233 auto json = R"( { "test":{ "val1":1, "val2":2 } } )"_padded;
234 ondemand::parser parser;
235 ondemand::document doc;
236 ASSERT_SUCCESS(parser.iterate(json).get(doc));
237 size_t count;
238 ASSERT_SUCCESS(doc.count_fields().get(count));
239 ASSERT_EQUAL(count,1);
240 ondemand::object object;
241 size_t new_count;
242 ASSERT_SUCCESS(doc.find_field("test").get_object().get(object));
243 ASSERT_SUCCESS(object.count_fields().get(new_count));
244 ASSERT_EQUAL(new_count, 2);
245 TEST_SUCCEED();
246 }
247
using_the_parsed_json_1()248 bool using_the_parsed_json_1() {
249 TEST_START();
250
251 try {
252
253 ondemand::parser parser;
254 auto json = R"( { "x": 1, "y": 2 } )"_padded;
255 auto doc = parser.iterate(json);
256 double y = doc.find_field("y"); // The cursor is now after the 2 (at })
257 double x = doc.find_field("x"); // This fails, because there are no more fields after "y"
258
259 cout << x << ", " << y << endl;
260 } catch (...) {
261 TEST_SUCCEED();
262 }
263 TEST_FAIL("expected an exception");
264 }
265
using_the_parsed_json_2()266 bool using_the_parsed_json_2() {
267 TEST_START();
268
269 ondemand::parser parser;
270 auto json = R"( { "x": 1, "y": 2 } )"_padded;
271 auto doc = parser.iterate(json);
272 double y = doc["y"]; // The cursor is now after the 2 (at })
273 double x = doc["x"]; // Success: [] loops back around to find "x"
274
275 cout << x << ", " << y << endl;
276
277 TEST_SUCCEED();
278 }
279
big_integer()280 bool big_integer() {
281 TEST_START();
282 simdjson::ondemand::parser parser;
283 simdjson::padded_string docdata = R"({"value":12321323213213213213213213213211223})"_padded;
284 simdjson::ondemand::document doc = parser.iterate(docdata);
285 simdjson::ondemand::object obj = doc.get_object();
286 string_view token = obj["value"].raw_json_token();
287 std::cout << token << std::endl;
288 // token == "12321323213213213213213213213211223"
289 TEST_SUCCEED();
290 }
291
big_integer_in_string()292 bool big_integer_in_string() {
293 TEST_START();
294 simdjson::ondemand::parser parser;
295 simdjson::padded_string docdata = R"({"value":"12321323213213213213213213213211223"})"_padded;
296 simdjson::ondemand::document doc = parser.iterate(docdata);
297 simdjson::ondemand::object obj = doc.get_object();
298 string_view token = obj["value"].raw_json_token();
299 std::cout << token << std::endl;
300 // token == "\"12321323213213213213213213213211223\""
301 TEST_SUCCEED();
302 }
using_the_parsed_json_3()303 bool using_the_parsed_json_3() {
304 TEST_START();
305
306 ondemand::parser parser;
307 auto cars_json = R"( [
308 { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
309 { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
310 { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
311 ] )"_padded;
312
313 // Iterating through an array of objects
314 for (ondemand::object car : parser.iterate(cars_json)) {
315 // Accessing a field by name
316 cout << "Make/Model: " << std::string_view(car["make"]) << "/" << std::string_view(car["model"]) << endl;
317
318 // Casting a JSON element to an integer
319 uint64_t year = car["year"];
320 cout << "- This car is " << 2020 - year << " years old." << endl;
321
322 // Iterating through an array of floats
323 double total_tire_pressure = 0;
324 for (double tire_pressure : car["tire_pressure"]) {
325 total_tire_pressure += tire_pressure;
326 }
327 cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
328 }
329
330 TEST_SUCCEED();
331 }
332
333
using_the_parsed_json_rewind()334 bool using_the_parsed_json_rewind() {
335 TEST_START();
336
337 ondemand::parser parser;
338 auto cars_json = R"( [
339 { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
340 { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
341 { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
342 ] )"_padded;
343
344 auto doc = parser.iterate(cars_json);
345 size_t count = 0;
346 for (simdjson_unused ondemand::object car : doc) {
347 if(car["make"] == "Toyota") { count++; }
348 }
349 std::cout << "We have " << count << " Toyota cars.\n";
350 doc.rewind();
351 for (ondemand::object car : doc) {
352 cout << "Make/Model: " << std::string_view(car["make"]) << "/" << std::string_view(car["model"]) << endl;
353 }
354 TEST_SUCCEED();
355 }
356
357
using_the_parsed_json_rewind_array()358 bool using_the_parsed_json_rewind_array() {
359 TEST_START();
360
361 ondemand::parser parser;
362 auto cars_json = R"( [
363 { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
364 { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
365 { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
366 ] )"_padded;
367
368 auto doc = parser.iterate(cars_json);
369 ondemand::array arr = doc.get_array();
370 size_t count = 0;
371 for (simdjson_unused ondemand::object car : arr) {
372 if(car["make"] == "Toyota") { count++; }
373 }
374 std::cout << "We have " << count << " Toyota cars.\n";
375 arr.reset();
376 for (ondemand::object car : arr) {
377 cout << "Make/Model: " << std::string_view(car["make"]) << "/" << std::string_view(car["model"]) << endl;
378 }
379 TEST_SUCCEED();
380 }
381
382
using_the_parsed_json_4()383 bool using_the_parsed_json_4() {
384 TEST_START();
385
386 ondemand::parser parser;
387 auto points_json = R"( [
388 { "12345" : {"x":12.34, "y":56.78, "z": 9998877} },
389 { "12545" : {"x":11.44, "y":12.78, "z": 11111111} }
390 ] )"_padded;
391
392 // Parse and iterate through an array of objects
393 for (ondemand::object points : parser.iterate(points_json)) {
394 // Iterating through an object, you iterate through key-value pairs (a 'field').
395 for (auto point : points) {
396 // Get the key corresponding the the field 'point'.
397 cout << "id: " << std::string_view(point.unescaped_key()) << ": (";
398 // Get the value corresponding the the field 'point'.
399 ondemand::object xyz = point.value();
400 cout << xyz["x"].get_double() << ", ";
401 cout << xyz["y"].get_double() << ", ";
402 cout << xyz["z"].get_int64() << endl;
403 }
404 }
405
406 TEST_SUCCEED();
407 }
408
using_the_parsed_json_5()409 bool using_the_parsed_json_5() {
410 TEST_START();
411
412 auto abstract_json = R"(
413 { "str" : { "123" : {"abc" : 3.14 } } }
414 )"_padded;
415 ondemand::parser parser;
416 auto doc = parser.iterate(abstract_json);
417 cout << doc["str"]["123"]["abc"].get_double() << endl; // Prints 3.14
418
419 TEST_SUCCEED();
420 }
421
422 #endif // SIMDJSON_EXCEPTIONS
423
424
425
using_the_parsed_json_no_exceptions()426 bool using_the_parsed_json_no_exceptions() {
427 TEST_START();
428
429 ondemand::parser parser;
430 auto cars_json = R"( [
431 { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
432 { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
433 { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
434 ] )"_padded;
435 ondemand::document doc;
436
437 // Iterating through an array of objects
438 auto error = parser.iterate(cars_json).get(doc);
439 if(error) { std::cerr << error << std::endl; return false; }
440 ondemand::array cars;
441 error = doc.get_array().get(cars);
442
443 for (auto car_value : cars) {
444 ondemand::object car;
445 error = car_value.get_object().get(car);
446 if(error) { std::cerr << error << std::endl; return false; }
447
448 // Accessing a field by name
449 std::string_view make;
450 std::string_view model;
451 error = car["make"].get(make);
452 if(error) { std::cerr << error << std::endl; return false; }
453 error = car["model"].get(model);
454 if(error) { std::cerr << error << std::endl; return false; }
455
456 cout << "Make/Model: " << make << "/" << model << endl;
457
458 // Casting a JSON element to an integer
459 uint64_t year;
460 error = car["year"].get(year);
461 if(error) { std::cerr << error << std::endl; return false; }
462 cout << "- This car is " << 2020 - year << " years old." << endl;
463
464 // Iterating through an array of floats
465 double total_tire_pressure = 0;
466 ondemand::array pressures;
467 error = car["tire_pressure"].get_array().get(pressures);
468 if(error) { std::cerr << error << std::endl; return false; }
469 for (auto tire_pressure_value : pressures) {
470 double tire_pressure;
471 error = tire_pressure_value.get_double().get(tire_pressure);
472 if(error) { std::cerr << error << std::endl; return false; }
473 total_tire_pressure += tire_pressure;
474 }
475 cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
476 }
477 TEST_SUCCEED();
478 }
using_the_parsed_json_6_process()479 int using_the_parsed_json_6_process() {
480 auto abstract_json = R"(
481 { "str" : { "123" : {"abc" : 3.14 } } }
482 )"_padded;
483 ondemand::parser parser;
484
485 double value;
486 auto doc = parser.iterate(abstract_json);
487 auto error = doc["str"]["123"]["abc"].get(value);
488 if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
489 cout << value << endl; // Prints 3.14
490
491 return EXIT_SUCCESS;
492 }
493
exception_free_object_loop()494 bool exception_free_object_loop() {
495 auto json = R"({"k\u0065y": 1})"_padded;
496 ondemand::parser parser;
497 ondemand::document doc;
498 auto error = parser.iterate(json).get(doc);
499 if(error) { return false; }
500 ondemand::object object;
501 error = doc.get_object().get(object);
502 if(error) { return false; }
503 for(auto field : object) {
504 std::string_view keyv;
505 error = field.unescaped_key().get(keyv);
506 if(error) { return false; }
507 if(keyv == "key") {
508 uint64_t intvalue;
509 error = field.value().get(intvalue);
510 if(error) { return false; }
511 std::cout << intvalue;
512 }
513 }
514 return true;
515 }
516
517
exception_free_object_loop_no_escape()518 bool exception_free_object_loop_no_escape() {
519 auto json = R"({"k\u0065y": 1})"_padded;
520 ondemand::parser parser;
521 ondemand::document doc;
522 auto error = parser.iterate(json).get(doc);
523 if(error) { return false; }
524 ondemand::object object;
525 error = doc.get_object().get(object);
526 if(error) { return false; }
527 for(auto field : object) {
528 ondemand::raw_json_string keyv;
529 error = field.key().get(keyv);
530 /**
531 * If you need to escape the keys, you can do
532 * std::string_view keyv;
533 * error = field.unescaped_key().get(keyv);
534 */
535 if(error) { return false; }
536 if(keyv == "key") {
537 uint64_t intvalue;
538 error = field.value().get(intvalue);
539 if(error) { return false; }
540 std::cout << intvalue;
541 }
542 }
543 return true;
544 }
545
using_the_parsed_json_6()546 bool using_the_parsed_json_6() {
547 TEST_START();
548 ASSERT_EQUAL(using_the_parsed_json_6_process(), EXIT_SUCCESS);
549 TEST_SUCCEED();
550 }
551
552 const padded_string cars_json = R"( [
553 { "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
554 { "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
555 { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
556 ] )"_padded;
557
json_pointer_simple()558 bool json_pointer_simple() {
559 TEST_START();
560 ondemand::parser parser;
561 ondemand::document cars;
562 double x;
563 ASSERT_SUCCESS(parser.iterate(cars_json).get(cars));
564 ASSERT_SUCCESS(cars.at_pointer("/0/tire_pressure/1").get(x));
565 ASSERT_EQUAL(x,39.9);
566 TEST_SUCCEED();
567 }
568
json_pointer_multiple()569 bool json_pointer_multiple() {
570 TEST_START();
571 ondemand::parser parser;
572 ondemand::document cars;
573 size_t size;
574 ASSERT_SUCCESS(parser.iterate(cars_json).get(cars));
575 ASSERT_SUCCESS(cars.count_elements().get(size));
576 double expected[] = {39.9, 31, 30};
577 for (size_t i = 0; i < size; i++) {
578 std::string json_pointer = "/" + std::to_string(i) + "/tire_pressure/1";
579 double x;
580 ASSERT_SUCCESS(cars.at_pointer(json_pointer).get(x));
581 ASSERT_EQUAL(x,expected[i]);
582 }
583 TEST_SUCCEED();
584 }
585
json_pointer_rewind()586 bool json_pointer_rewind() {
587 TEST_START();
588 auto json = R"( {
589 "k0": 27,
590 "k1": [13,26],
591 "k2": true
592 } )"_padded;
593
594 ondemand::parser parser;
595 ondemand::document doc;
596 uint64_t i;
597 bool b;
598 ASSERT_SUCCESS(parser.iterate(json).get(doc));
599 ASSERT_SUCCESS(doc.at_pointer("/k1/1").get(i));
600 ASSERT_EQUAL(i,26);
601 ASSERT_SUCCESS(doc.at_pointer("/k2").get(b));
602 ASSERT_EQUAL(b,true);
603 doc.rewind(); // Need to manually rewind to be able to use find_field properly from start of document
604 ASSERT_SUCCESS(doc.find_field("k0").get(i));
605 ASSERT_EQUAL(i,27);
606 TEST_SUCCEED();
607 }
608
iterate_many_example()609 bool iterate_many_example() {
610 TEST_START();
611 auto json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )"_padded;
612 simdjson::ondemand::parser parser;
613 simdjson::ondemand::document_stream stream;
614 ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
615 auto i = stream.begin();
616 size_t count{0};
617 size_t expected_indexes[3] = {0,9,29};
618 std::string_view expected_doc[3] = {"[1,2,3]", R"({"1":1,"2":3,"4":4})", "[1,2,3]"};
619 for(; i != stream.end(); ++i) {
620 auto doc = *i;
621 ASSERT_SUCCESS(doc.type());
622 ASSERT_SUCCESS(i.error());
623 ASSERT_EQUAL(i.current_index(),expected_indexes[count]);
624 ASSERT_EQUAL(i.source(),expected_doc[count]);
625 count++;
626 }
627 TEST_SUCCEED();
628 }
629
my_string(ondemand::document & doc)630 std::string my_string(ondemand::document& doc) {
631 std::stringstream ss;
632 ss << doc;
633 return ss.str();
634 }
635
iterate_many_truncated_example()636 bool iterate_many_truncated_example() {
637 TEST_START();
638 auto json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )"_padded;
639 simdjson::ondemand::parser parser;
640 simdjson::ondemand::document_stream stream;
641 ASSERT_SUCCESS( parser.iterate_many(json,json.size()).get(stream) );
642 std::string_view expected[2] = {"[1,2,3]", R"({"1":1,"2":3,"4":4})"};
643 size_t count{0};
644 for(auto i = stream.begin(); i != stream.end(); ++i) {
645 ASSERT_EQUAL(i.source(),expected[count++]);
646 }
647 size_t truncated = stream.truncated_bytes();
648 ASSERT_EQUAL(truncated,39);
649 TEST_SUCCEED();
650 }
651
652 bool ndjson_basics_example() {
653 TEST_START();
654 auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
655 ondemand::parser parser;
656 ondemand::document_stream docs;
657 ASSERT_SUCCESS( parser.iterate_many(json).get(docs) );
658 size_t count{0};
659 int64_t expected[3] = {1,2,3};
660 for (auto doc : docs) {
661 int64_t actual;
662 ASSERT_SUCCESS( doc["foo"].get(actual) );
663 ASSERT_EQUAL( actual,expected[count++] );
664 }
665 TEST_SUCCEED();
666 }
667 bool stream_capacity_example() {
668 auto json = R"([1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100])"_padded;
669 ondemand::parser parser;
670 ondemand::document_stream stream;
671 size_t counter{0};
672 auto error = parser.iterate_many(json, 50).get(stream);
673 if( error ) { /* handle the error */ }
674 for (auto doc: stream) {
675 if(counter < 6) {
676 int64_t val;
677 error = doc.at_pointer("/4").get(val);
678 if( error ) { /* handle the error */ }
679 std::cout << "5 = " << val << std::endl;
680 } else {
681 ondemand::value val;
682 error = doc.at_pointer("/4").get(val);
683 // error == simdjson::CAPACITY
684 if(error) {
685 std::cerr << error << std::endl;
686 // We left 293 bytes unprocessed at the tail end of the input.
687 std::cout << " unprocessed bytes at the end: " << stream.truncated_bytes() << std::endl;
688 break;
689 }
690 }
691 counter++;
692 }
693 return true;
694 }
695
696
697
698 bool simple_error_example() {
699 ondemand::parser parser;
700 auto json = R"({"bad number":3.14.1 })"_padded;
701 ondemand::document doc;
702 if( parser.iterate(json).get(doc) != SUCCESS ) { return false; }
703 double x;
704 auto error = doc["bad number"].get_double().get(x);
705 // returns "simdjson::NUMBER_ERROR"
706 if(error != SUCCESS) {
707 std::cout << error << std::endl;
708 return false;
709 }
710 std::cout << "Got " << x << std::endl;
711 return true;
712 }
713
714
715 #if SIMDJSON_EXCEPTIONS
716 bool simple_error_example_except() {
717 TEST_START();
718 ondemand::parser parser;
719 auto json = R"({"bad number":3.14.1 })"_padded;
720 try {
721 ondemand::document doc = parser.iterate(json);
722 double x = doc["bad number"].get_double();
723 std::cout << "Got " << x << std::endl;
724 return true;
725 } catch(simdjson_error& e) {
726 // e.error() == NUMBER_ERROR
727 std::cout << e.error() << std::endl;
728 return false;
729 }
730 }
731
732 int64_t current_location_tape_error_with_except() {
733 auto broken_json = R"( {"double": 13.06, false, "integer": -343} )"_padded;
734 ondemand::parser parser;
735 ondemand::document doc = parser.iterate(broken_json);
736 try {
737 return int64_t(doc["integer"]);
738 } catch(simdjson_error& err) {
739 std::cerr << err.error() << std::endl;
740 std::cerr << doc.current_location() << std::endl;
741 return -1;
742 }
743 }
744
745 #endif
746
747 int load_example() {
748 simdjson::ondemand::parser parser;
749 simdjson::ondemand::document tweets;
750 padded_string json;
751 auto error = padded_string::load("twitter.json").get(json);
752 if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
753 error = parser.iterate(json).get(tweets);
754 if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
755 uint64_t identifier;
756 error = tweets["statuses"].at(0)["id"].get(identifier);
757 if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
758 std::cout << identifier << std::endl;
759 return EXIT_SUCCESS;
760 }
761
762
763 int example_1() {
764 TEST_START();
765 simdjson::ondemand::parser parser;
766 //auto error = padded_string::load("twitter.json").get(json);
767 // if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
768 padded_string json = R"( {
769 "statuses": [
770 {
771 "id": 505874924095815700
772 },
773 {
774 "id": 505874922023837700
775 }
776 ],
777 "search_metadata": {
778 "count": 100
779 }
780 } )"_padded;
781
782 simdjson::ondemand::document tweets;
783 auto error = parser.iterate(json).get(tweets);
784 if( error ) { return EXIT_FAILURE; }
785 simdjson::ondemand::value res;
786 error = tweets["search_metadata"]["count"].get(res);
787 if (error != SUCCESS) {
788 std::cerr << "could not access keys" << std::endl;
789 return EXIT_FAILURE;
790 }
791 std::cout << res << " results." << std::endl;
792 return true;
793 }
794 #if SIMDJSON_EXCEPTIONS
795 int load_example_except() {
796 simdjson::ondemand::parser parser;
797 padded_string json = padded_string::load("twitter.json");
798 simdjson::ondemand::document tweets = parser.iterate(json);
799 uint64_t identifier = tweets["statuses"].at(0)["id"];
800 std::cout << identifier << std::endl;
801 return EXIT_SUCCESS;
802 }
803 #endif
804 bool test_load_example() {
805 TEST_START();
806 simdjson::ondemand::parser parser;
807 simdjson::ondemand::document tweets;
808 padded_string json = R"( {"statuses":[{"id":1234}]} )"_padded;
809 auto error = parser.iterate(json).get(tweets);
810 if(error) { std::cerr << error << std::endl; return false; }
811 uint64_t identifier;
812 error = tweets["statuses"].at(0)["id"].get(identifier);
813 if(error) { std::cerr << error << std::endl; return false; }
814 std::cout << identifier << std::endl;
815 return identifier == 1234;
816 }
817
818 bool current_location_tape_error() {
819 TEST_START();
820 auto broken_json = R"( {"double": 13.06, false, "integer": -343} )"_padded;
821 ondemand::parser parser;
822 ondemand::document doc;
823 ASSERT_SUCCESS(parser.iterate(broken_json).get(doc));
824 const char * ptr;
825 int64_t i;
826 ASSERT_ERROR(doc["integer"].get_int64().get(i), TAPE_ERROR);
827 ASSERT_SUCCESS(doc.current_location().get(ptr));
828 ASSERT_EQUAL(ptr, "false, \"integer\": -343} ");
829 TEST_SUCCEED();
830 }
831
current_location_user_error()832 bool current_location_user_error() {
833 TEST_START();
834 auto json = R"( [1,2,3] )"_padded;
835 ondemand::parser parser;
836 ondemand::document doc;
837 ASSERT_SUCCESS(parser.iterate(json).get(doc));
838 const char * ptr;
839 int64_t i;
840 ASSERT_ERROR(doc["integer"].get_int64().get(i), INCORRECT_TYPE);
841 ASSERT_SUCCESS(doc.current_location().get(ptr));
842 ASSERT_EQUAL(ptr, "[1,2,3] ");
843 TEST_SUCCEED();
844 }
845
current_location_out_of_bounds()846 bool current_location_out_of_bounds() {
847 TEST_START();
848 auto json = R"( [1,2,3] )"_padded;
849 ondemand::parser parser;
850 ondemand::document doc;
851 ASSERT_SUCCESS(parser.iterate(json).get(doc));
852 uint64_t expected[3] = {1, 2, 3};
853 size_t count{0};
854 for (auto val : doc) {
855 uint64_t i;
856 ASSERT_SUCCESS(val.get_uint64().get(i));
857 ASSERT_EQUAL(i, expected[count++]);
858 }
859 ASSERT_EQUAL(count, 3);
860 ASSERT_ERROR(doc.current_location(), OUT_OF_BOUNDS);
861 TEST_SUCCEED();
862 }
863
current_location_no_error()864 bool current_location_no_error() {
865 TEST_START();
866 auto json = R"( [[1,2,3], -23.4, {"key": "value"}, true] )"_padded;
867 ondemand::parser parser;
868 ondemand::document doc;
869 ASSERT_SUCCESS(parser.iterate(json).get(doc));
870 const char * ptr;
871 for (auto val : doc) {
872 ondemand::object obj;
873 auto error = val.get_object().get(obj);
874 if (!error) {
875 ASSERT_SUCCESS(doc.current_location().get(ptr));
876 ASSERT_EQUAL(ptr, "\"key\": \"value\"}, true] ");
877 }
878 }
879 TEST_SUCCEED();
880 }
881
main()882 int main() {
883 #if SIMDJSON_EXCEPTIONS
884 basics_treewalk();
885 #endif
886 if (
887 true
888 #if SIMDJSON_EXCEPTIONS
889 // && basics_1() // Fails because twitter.json isn't in current directory. Compile test only.
890 && json_value_with_array_count()
891 && json_array_with_array_count()
892 && json_array_count_complex()
893 && json_array_count()
894 && json_object_count()
895 && using_the_parsed_json_rewind()
896 && using_the_parsed_json_rewind_array()
897 && basics_2()
898 && using_the_parsed_json_1()
899 && using_the_parsed_json_2()
900 && big_integer()
901 && big_integer_in_string()
902 && using_the_parsed_json_3()
903 && using_the_parsed_json_4()
904 && using_the_parsed_json_5()
905 #endif
906 && using_the_parsed_json_6()
907 && json_pointer_simple()
908 && json_pointer_multiple()
909 && json_pointer_rewind()
910 && iterate_many_example()
911 && iterate_many_truncated_example()
912 && ndjson_basics_example()
913 && stream_capacity_example()
914 && test_load_example()
915 && example_1()
916 && using_the_parsed_json_no_exceptions()
917 && current_location_tape_error()
918 && current_location_user_error()
919 && current_location_out_of_bounds()
920 && current_location_no_error()
921 #if SIMDJSON_EXCEPTIONS
922 && number_tests()
923 && current_location_tape_error_with_except()
924 #endif
925 ) {
926 return 0;
927 } else {
928 return 1;
929 }
930 }
931