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