1 #include <iostream>
2 #include "simdjson.h"
3 
4 using namespace std;
5 using namespace simdjson;
6 using error_code=simdjson::error_code;
7 
basics_1()8 void basics_1() {
9   const char *filename = "x.txt";
10 
11   dom::parser parser;
12   dom::element doc = parser.load(filename); // load and parse a file
13 
14   cout << doc;
15 }
16 
basics_2()17 void basics_2() {
18   dom::parser parser;
19   dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string
20 
21   cout << doc;
22 }
23 
basics_dom_1()24 void basics_dom_1() {
25   auto cars_json = R"( [
26     { "make": "Toyota", "model": "Camry",  "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
27     { "make": "Kia",    "model": "Soul",   "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
28     { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
29   ] )"_padded;
30   dom::parser parser;
31 
32   // Parse and iterate through each car
33   for (dom::object car : parser.parse(cars_json)) {
34     // Accessing a field by name
35     cout << "Make/Model: " << car["make"] << "/" << car["model"] << endl;
36 
37     // Casting a JSON element to an integer
38     uint64_t year = car["year"];
39     cout << "- This car is " << 2020 - year << "years old." << endl;
40 
41     // Iterating through an array of floats
42     double total_tire_pressure = 0;
43     for (double tire_pressure : car["tire_pressure"]) {
44       total_tire_pressure += tire_pressure;
45     }
46     cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
47 
48     // Writing out all the information about the car
49     for (auto field : car) {
50       cout << "- " << field.key << ": " << field.value << endl;
51     }
52   }
53 }
54 
parse_many_truncated()55 void parse_many_truncated() {
56     auto json = R"([1,2,3]  {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string  )"_padded;
57     simdjson::dom::parser parser;
58     simdjson::dom::document_stream stream;
59     auto error = parser.parse_many(json,json.size()).get(stream);
60     if(error) { std::cerr << error << std::endl; return; }
61     for(auto doc : stream) {
62        std::cout << doc << std::endl;
63     }
64     std::cout << stream.truncated_bytes() << " bytes "<< std::endl; // returns 39 bytes
65 }
66 
67 void basics_dom_2() {
68   auto cars_json = R"( [
69     { "make": "Toyota", "model": "Camry",  "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
70     { "make": "Kia",    "model": "Soul",   "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
71     { "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
72   ] )"_padded;
73   dom::parser parser;
74   dom::element cars = parser.parse(cars_json);
75   cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
76   for (dom::element car_element : cars) {
77     dom::object car;
78     simdjson::error_code error;
79     if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; }
80     double x = car.at_pointer("/tire_pressure/1");
81     cout << x << endl; // Prints 39.9, 31 and 30
82   }
83 }
84 
85 void basics_dom_3() {
86   auto abstract_json = R"( [
87     {  "12345" : {"a":12.34, "b":56.78, "c": 9998877}   },
88     {  "12545" : {"a":11.44, "b":12.78, "c": 11111111}  }
89   ] )"_padded;
90   dom::parser parser;
91 
92   // Parse and iterate through an array of objects
93   for (dom::object obj : parser.parse(abstract_json)) {
94     for(const auto key_value : obj) {
95       cout << "key: " << key_value.key << " : ";
96       dom::object innerobj = key_value.value;
97       cout << "a: " << double(innerobj["a"]) << ", ";
98       cout << "b: " << double(innerobj["b"]) << ", ";
99       cout << "c: " << int64_t(innerobj["c"]) << endl;
100     }
101   }
102 }
103 
104 void basics_dom_4() {
105   auto abstract_json = R"(
106     {  "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
107   dom::parser parser;
108   double v = parser.parse(abstract_json)["str"]["123"]["abc"];
109   cout << "number: " << v << endl;
110 }
111 
112 namespace ondemand_treewalk {
113   // We use a template function because we need to
114   // support both ondemand::value and ondemand::document
115   // as a parameter type. Note that we move the values.
116   template <class T>
117   void recursive_print_json(T&& element) {
118     bool add_comma;
119     switch (element.type()) {
120     case ondemand::json_type::array:
121       cout << "[";
122       add_comma = false;
123       for (auto child : element.get_array()) {
124         if (add_comma) {
125           cout << ",";
126         }
127         // We need the call to value() to get
128         // an ondemand::value type.
129         recursive_print_json(child.value());
130         add_comma = true;
131       }
132       cout << "]";
133       break;
134     case ondemand::json_type::object:
135       cout << "{";
136       add_comma = false;
137       for (auto field : element.get_object()) {
138         if (add_comma) {
139           cout << ",";
140         }
141         // key() returns the unescaped key, if we
142         // want the escaped key, we should do
143         // field.unescaped_key().
144         cout << "\"" << field.key() << "\": ";
145         recursive_print_json(field.value());
146         add_comma = true;
147       }
148       cout << "}";
149       break;
150     case ondemand::json_type::number:
151       // assume it fits in a double
152       cout << element.get_double();
153       break;
154     case ondemand::json_type::string:
155       // get_string() would return escaped string, but
156       // we are happy with unescaped string.
157       cout << "\"" << element.get_raw_json_string() << "\"";
158       break;
159     case ondemand::json_type::boolean:
160       cout << element.get_bool();
161       break;
162     case ondemand::json_type::null:
163       cout << "null";
164       break;
165     }
166   }
167 
basics_treewalk()168   void basics_treewalk() {
169     ondemand::parser parser;
170     auto json = padded_string::load("twitter.json");
171     recursive_print_json(parser.iterate(json));
172   }
173 
174 }
175 
176 namespace treewalk_1 {
print_json(dom::element element)177   void print_json(dom::element element) {
178     switch (element.type()) {
179       case dom::element_type::ARRAY:
180         cout << "[";
181         for (dom::element child : dom::array(element)) {
182           print_json(child);
183           cout << ",";
184         }
185         cout << "]";
186         break;
187       case dom::element_type::OBJECT:
188         cout << "{";
189         for (dom::key_value_pair field : dom::object(element)) {
190           cout << "\"" << field.key << "\": ";
191           print_json(field.value);
192         }
193         cout << "}";
194         break;
195       case dom::element_type::INT64:
196         cout << int64_t(element) << endl;
197         break;
198       case dom::element_type::UINT64:
199         cout << uint64_t(element) << endl;
200         break;
201       case dom::element_type::DOUBLE:
202         cout << double(element) << endl;
203         break;
204       case dom::element_type::STRING:
205         cout << std::string_view(element) << endl;
206         break;
207       case dom::element_type::BOOL:
208         cout << bool(element) << endl;
209         break;
210       case dom::element_type::NULL_VALUE:
211         cout << "null" << endl;
212         break;
213     }
214   }
215 
basics_treewalk_1()216   void basics_treewalk_1() {
217     dom::parser parser;
218     print_json(parser.load("twitter.json"));
219   }
220 }
221 
222 #ifdef SIMDJSON_CPLUSPLUS17
basics_cpp17_1()223 void basics_cpp17_1() {
224   padded_string json = R"(  { "foo": 1, "bar": 2 }  )"_padded;
225   dom::parser parser;
226   dom::object object;
227   auto error = parser.parse(json).get(object);
228   if (error) { cerr << error << endl; return; }
229   for (auto [key, value] : object) {
230     cout << key << " = " << value << endl;
231   }
232 }
233 #endif
234 
basics_cpp17_2()235 void basics_cpp17_2() {
236   // C++ 11 version for comparison
237   padded_string json = R"(  { "foo": 1, "bar": 2 }  )"_padded;
238   dom::parser parser;
239   dom::object object;
240   auto error = parser.parse(json).get(object);
241   if (error) { cerr << error << endl; return; }
242   for (dom::key_value_pair field : object) {
243     cout << field.key << " = " << field.value << endl;
244   }
245 }
246 
basics_ndjson()247 void basics_ndjson() {
248   dom::parser parser;
249   for (dom::element doc : parser.load_many("x.txt")) {
250     cout << doc["foo"] << endl;
251   }
252   // Prints 1 2 3
253 }
254 
basics_ndjson_parse_many()255 void basics_ndjson_parse_many() {
256   dom::parser parser;
257   auto json = R"({ "foo": 1 }
258 { "foo": 2 }
259 { "foo": 3 })"_padded;
260   dom::document_stream docs = parser.parse_many(json);
261   for (dom::element doc : docs) {
262     cout << doc["foo"] << endl;
263   }
264 }
implementation_selection_1()265 void implementation_selection_1() {
266   cout << "simdjson v" << STRINGIFY(SIMDJSON_VERSION) << endl;
267   cout << "Detected the best implementation for your machine: " << simdjson::active_implementation->name();
268   cout << "(" << simdjson::active_implementation->description() << ")" << endl;
269 }
270 
unescaped_key()271 void unescaped_key() {
272     auto json = R"({"k\u0065y": 1})"_padded;
273     ondemand::parser parser;
274     auto doc = parser.iterate(json);
275     ondemand::object object = doc.get_object();
276     for(auto field : object) {
277       // parses and writes out the key, after unescaping it,
278       // to a string buffer. This should be expected to be much
279       // more costly than accessing the raw string ("key()").
280       std::string_view keyv = field.unescaped_key();
281       if(keyv == "key") {
282          std::cout << uint64_t(field.value());
283       }
284       // You can access the raw value like so:
285       // ondemand::raw_json_string keyv = field.key();
286       // if(keyv == R"(k\u0065y)") {
287     }
288 }
289 
implementation_selection_2()290 void implementation_selection_2() {
291   for (auto implementation : simdjson::available_implementations) {
292     cout << implementation->name() << ": " << implementation->description() << endl;
293   }
294 }
295 
implementation_selection_2_safe()296 void implementation_selection_2_safe() {
297   for (auto implementation : simdjson::available_implementations) {
298     if(implementation->supported_by_runtime_system()) {
299       cout << implementation->name() << ": " << implementation->description() << endl;
300     }
301   }
302 }
implementation_selection_3()303 void implementation_selection_3() {
304   cout << simdjson::available_implementations["fallback"]->description() << endl;
305 }
306 
implementation_selection_safe()307 void implementation_selection_safe() {
308   auto my_implementation = simdjson::available_implementations["haswell"];
309   if(! my_implementation) { exit(1); }
310   if(! my_implementation->supported_by_runtime_system()) { exit(1); }
311   simdjson::active_implementation = my_implementation;
312 }
313 
implementation_selection_4()314 void implementation_selection_4() {
315   // Use the fallback implementation, even though my machine is fast enough for anything
316   simdjson::active_implementation = simdjson::available_implementations["fallback"];
317 }
318 
ondemand_performance_1()319 void ondemand_performance_1() {
320   ondemand::parser parser;
321 
322   // This initializes buffers  big enough to handle this JSON.
323   auto json = "[ true, false ]"_padded;
324   auto doc = parser.iterate(json);
325   for(bool i : doc.get_array()) {
326     cout << i << endl;
327   }
328 
329 
330   // This reuses the existing buffers
331   auto number_json = "[1, 2, 3]"_padded;
332   doc = parser.iterate(number_json);
333   for(int64_t i : doc.get_array()) {
334     cout << i << endl;
335   }
336 }
337 
performance_1()338 void performance_1() {
339   dom::parser parser;
340 
341   // This initializes buffers and a document big enough to handle this JSON.
342   dom::element doc = parser.parse("[ true, false ]"_padded);
343   cout << doc << endl;
344 
345   // This reuses the existing buffers, and reuses and *overwrites* the old document
346   doc = parser.parse("[1, 2, 3]"_padded);
347   cout << doc << endl;
348 
349   // This also reuses the existing buffers, and reuses and *overwrites* the old document
350   dom::element doc2 = parser.parse("true"_padded);
351   // Even if you keep the old reference around, doc and doc2 refer to the same document.
352   cout << doc << endl;
353   cout << doc2 << endl;
354 }
355 
356 #ifdef SIMDJSON_CPLUSPLUS17
357 SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
358 // The web_request part of this is aspirational, so we compile as much as we can here
performance_2()359 void performance_2() {
360   dom::parser parser(1000*1000); // Never grow past documents > 1MB
361   /* for (web_request request : listen()) */ {
362     dom::element doc;
363     auto body = "1"_padded; /*request.body*/
364     auto error = parser.parse(body/*request.body*/).get(doc);
365     // If the document was above our limit, emit 413 = payload too large
366     if (error == CAPACITY) { /* request.respond(413); continue; */ }
367     // ...
368   }
369 }
370 
371 // The web_request part of this is aspirational, so we compile as much as we can here
performance_3()372 void performance_3() {
373   dom::parser parser(0); // This parser will refuse to automatically grow capacity
374   auto error = parser.allocate(1000*1000); // This allocates enough capacity to handle documents <= 1MB
375   if (error) { cerr << error << endl; exit(1); }
376 
377   /* for (web_request request : listen()) */ {
378     dom::element doc;
379     auto body = "1"_padded;/*request.body*/
380     auto error = parser.parse(body).get(doc);
381     // If the document was above our limit, emit 413 = payload too large
382     if (error == CAPACITY) { /* request.respond(413); continue; */ }
383     // ...
384   }
385 }
386 SIMDJSON_POP_DISABLE_WARNINGS
387 #endif
388 
minify()389 void minify() {
390   const char * some_string = "[ 1, 2, 3, 4] ";
391   size_t length = std::strlen(some_string);
392   std::unique_ptr<char[]> buffer{new char[length]};
393   size_t new_length{};
394   auto error = simdjson::minify(some_string, length, buffer.get(), new_length);
395   if(error != simdjson::SUCCESS) {
396     std::cerr << "error " << error << std::endl;
397     abort();
398   } else {
399     const char * expected_string = "[1,2,3,4]";
400     size_t expected_length = std::strlen(expected_string);
401     if(expected_length != new_length) {
402       std::cerr << "mismatched length (error) " << std::endl;
403       abort();
404     }
405     for(size_t i = 0; i < new_length; i++) {
406       if(expected_string[i] != buffer.get()[i]) {
407         std::cerr << "mismatched content (error) " << std::endl;
408         abort();
409       }
410     }
411   }
412 }
413 
is_correct()414 bool is_correct() {
415   const char * some_string = "[ 1, 2, 3, 4] ";
416   size_t length = std::strlen(some_string);
417   bool is_ok = simdjson::validate_utf8(some_string, length);
418   return is_ok;
419 }
420 
is_correct_string_view()421 bool is_correct_string_view() {
422   const char * some_string = "[ 1, 2, 3, 4] ";
423   size_t length = std::strlen(some_string);
424   std::string_view v(some_string, length);
425   bool is_ok = simdjson::validate_utf8(v);
426   return is_ok;
427 }
428 
is_correct_string()429 bool is_correct_string() {
430   const std::string some_string = "[ 1, 2, 3, 4] ";
431   bool is_ok = simdjson::validate_utf8(some_string);
432   return is_ok;
433 }
434 
parse_documentation()435 void parse_documentation() {
436   const char *json      = R"({"key":"value"})";
437   const size_t json_len = std::strlen(json);
438   simdjson::dom::parser parser;
439   simdjson::dom::element element = parser.parse(json, json_len);
440   // Next line is to avoid unused warning.
441   (void)element;
442 }
443 
444 
parse_documentation_lowlevel()445 void parse_documentation_lowlevel() {
446   // Such low-level code is not generally recommended. Please
447   // see parse_documentation() instead.
448   // Motivation: https://github.com/simdjson/simdjson/issues/1175
449   const char *json      = R"({"key":"value"})";
450   const size_t json_len = std::strlen(json);
451   std::unique_ptr<char[]> padded_json_copy{new char[json_len + SIMDJSON_PADDING]};
452   std::memcpy(padded_json_copy.get(), json, json_len);
453   std::memset(padded_json_copy.get() + json_len, '\0', SIMDJSON_PADDING);
454   simdjson::dom::parser parser;
455   simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
456   // Next line is to avoid unused warning.
457   (void)element;
458 }
459 
main()460 int main() {
461   basics_dom_1();
462   basics_dom_2();
463   basics_dom_3();
464   basics_dom_4();
465   minify();
466   return 0;
467 }
468