Replace x.get<T>() with x.get(v) or T(x)

This commit is contained in:
John Keiser 2020-06-21 14:36:38 -07:00
parent 1b1a122b1f
commit 6fa5abcd7e
12 changed files with 366 additions and 413 deletions

View File

@ -407,7 +407,7 @@ static void iterator_twitter_default_profile(State& state) {
set<string_view> default_users;
ParsedJson::Iterator iter(pj);
// for (dom::object tweet : doc["statuses"].get<dom::array>()) {
// for (dom::object tweet : doc["statuses"]) {
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
if (iter.down()) { // first status
do {
@ -480,7 +480,7 @@ static void iterator_twitter_image_sizes(State& state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
ParsedJson::Iterator iter(pj);
// for (dom::object tweet : doc["statuses"].get<dom::array>()) {
// for (dom::object tweet : doc["statuses"]) {
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
if (iter.down()) { // first status
do {
@ -492,7 +492,7 @@ static void iterator_twitter_image_sizes(State& state) {
if (iter.move_to_key("media")) {
if (!iter.is_array()) { return; }
// for (dom::object image : media.get<dom::array>()) {
// for (dom::object image : media) {
if (iter.down()) { // first media
do {

View File

@ -40,17 +40,18 @@ void print_vec(const std::vector<int64_t> &v) {
// simdjson_recurse below come be implemented like so but it is slow:
/*void simdjson_recurse(std::vector<int64_t> & v, simdjson::dom::element element) {
if (element.is<simdjson::dom::array>()) {
auto [array, array_error] = element.get<simdjson::dom::array>();
error_code error;
if (element.is_array()) {
dom::array array;
error = element.get(array);
for (auto child : array) {
if (child.is<simdjson::dom::array>() || child.is<simdjson::dom::object>()) {
simdjson_recurse(v, child);
}
}
} else if (element.is<simdjson::dom::object>()) {
auto [object, error] = element.get<simdjson::dom::object>();
} else if (element.is_object()) {
int64_t id;
error = object["user"]["id"].get(id);
error = element["user"]["id"].get(id);
if(!error) {
v.push_back(id);
}

View File

@ -154,11 +154,11 @@ static void GenStatPlus(Stat &stat, const dom::element &v) {
break;
case dom::element_type::STRING: {
stat.stringCount++;
std::string_view sv = v.get<std::string_view>();
auto sv = std::string_view(v);
stat.stringLength += sv.size();
} break;
case dom::element_type::BOOL:
if (v.get<bool>()) {
if (bool(v)) {
stat.trueCount++;
} else {
stat.falseCount++;

View File

@ -164,7 +164,7 @@ And another one:
auto abstract_json = R"(
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
dom::parser parser;
double v = parser.parse(abstract_json)["str"]["123"]["abc"].get<double>();
double v = parser.parse(abstract_json)["str"]["123"]["abc"];
cout << "number: " << v << endl;
```
@ -191,14 +191,13 @@ Though it does not validate the JSON input, it will detect when the document end
C++17 Support
-------------
While the simdjson library can be used in any project using C++ 11 and above, it has special support
for C++ 17. The APIs for field iteration and error handling in particular are designed to work
nicely with C++17's destructuring syntax. For example:
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:
```c++
dom::parser parser;
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
auto [object, error] = parser.parse(json).get<dom::object>();
dom::parser parser;
dom::object object;
auto error = parser.parse(json).get(object);
if (error) { cerr << error << endl; return; }
for (auto [key, value] : object) {
cout << key << " = " << value << endl;
@ -209,11 +208,10 @@ For comparison, here is the C++ 11 version of the same code:
```c++
// C++ 11 version for comparison
dom::parser parser;
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
simdjson::error_code error;
dom::parser parser;
dom::object object;
error = parser.parse(json).get(object);
auto error = parser.parse(json).get(object);
if (!error) { cerr << error << endl; return; }
for (dom::key_value_pair field : object) {
cout << field.key << " = " << field.value << endl;
@ -378,8 +376,7 @@ And another one:
cout << "number: " << v << endl;
```
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*.
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*.
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.

View File

@ -336,8 +336,8 @@ public:
* The key will be matched against **unescaped** JSON:
*
* dom::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().first == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
@ -351,8 +351,8 @@ public:
* The key will be matched against **unescaped** JSON:
*
* dom::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().first == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object
@ -391,8 +391,8 @@ public:
* The key will be matched against **unescaped** JSON:
*
* dom::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().first == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
*
* @return The value associated with this field, or:
* - NO_SUCH_FIELD if the field does not exist in the object

View File

@ -101,8 +101,8 @@ public:
* The key will be matched against **unescaped** JSON:
*
* dom::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().first == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
*
* This function has linear-time complexity: the keys are checked one by one.
*
@ -118,8 +118,8 @@ public:
* The key will be matched against **unescaped** JSON:
*
* dom::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().first == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
*
* This function has linear-time complexity: the keys are checked one by one.
*
@ -151,8 +151,8 @@ public:
* The key will be matched against **unescaped** JSON:
*
* dom::parser parser;
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().value == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error == NO_SUCH_FIELD
* parser.parse(R"({ "a\n": 1 })")["a\n"].get<uint64_t>().first == 1
* parser.parse(R"({ "a\n": 1 })")["a\\n"].get<uint64_t>().error() == NO_SUCH_FIELD
*
* This function has linear-time complexity: the keys are checked one by one.
*

View File

@ -17,6 +17,8 @@
#include "cast_tester.h"
#include "test_macros.h"
const size_t AMAZON_CELLPHONES_NDJSON_DOC_COUNT = 793;
namespace number_tests {
// ulp distance
@ -39,8 +41,8 @@ namespace number_tests {
for (int m = 10; m < 20; m++) {
for (int i = -1024; i < 1024; i++) {
auto str = std::to_string(i);
auto [actual, error] = parser.parse(str).get<int64_t>();
if (error) { std::cerr << error << std::endl; return false; }
int64_t actual;
ASSERT_SUCCESS(parser.parse(str).get(actual));
if (actual != i) {
std::cerr << "JSON '" << str << "' parsed to " << actual << " instead of " << i << std::endl;
return false;
@ -60,7 +62,8 @@ namespace number_tests {
size_t n = snprintf(buf, sizeof(buf), "%.*e", std::numeric_limits<double>::max_digits10 - 1, expected);
if (n >= sizeof(buf)) { abort(); }
fflush(NULL);
auto [actual, error] = parser.parse(buf, n).get<double>();
double actual;
auto error = parser.parse(buf, n).get(actual);
if (error) { std::cerr << error << std::endl; return false; }
uint64_t ulp = f64_ulp_dist(actual,expected);
if(ulp > maxulp) maxulp = ulp;
@ -154,7 +157,8 @@ namespace number_tests {
if (n >= sizeof(buf)) { abort(); }
fflush(NULL);
auto [actual, error] = parser.parse(buf, n).get<double>();
double actual;
auto error = parser.parse(buf, n).get(actual);
if (error) { std::cerr << error << std::endl; return false; }
double expected = ((i >= -307) ? testing_power_of_ten[i + 307]: std::pow(10, i));
int ulp = (int) f64_ulp_dist(actual, expected);
@ -229,41 +233,27 @@ namespace document_tests {
std::cout << __func__ << std::endl;
simdjson::padded_string smalljson = "[1,2,3]"_padded;
simdjson::dom::parser parser;
auto [doc, error] = parser.parse(smalljson).get<simdjson::dom::array>();
if (error) {
printf("This json should be valid %s.\n", smalljson.data());
return false;
}
if(doc.size() != 3) {
printf("This json should have size three but found %zu : %s.\n", doc.size(), smalljson.data());
return false;
}
simdjson::dom::array array;
ASSERT_SUCCESS( parser.parse(smalljson).get(array) );
ASSERT_EQUAL( array.size(), 3 );
return true;
}
bool count_object_example() {
std::cout << __func__ << std::endl;
simdjson::padded_string smalljson = "{\"1\":1,\"2\":1,\"3\":1}"_padded;
simdjson::dom::parser parser;
auto [doc, error] = parser.parse(smalljson).get<simdjson::dom::object>();
if (error) {
printf("This json should be valid %s.\n", smalljson.data());
return false;
}
if(doc.size() != 3) {
printf("This json should have size three but found %zu : %s.\n", doc.size(), smalljson.data());
return false;
}
simdjson::dom::object object;
ASSERT_SUCCESS( parser.parse(smalljson).get(object) );
ASSERT_EQUAL( object.size(), 3 );
return true;
}
bool padded_with_open_bracket() {
std::cout << __func__ << std::endl;
simdjson::dom::parser parser;
// This is an invalid document padded with open braces.
auto error1 = parser.parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error();
if (!error1) { std::cerr << "We expected an error but got: " << error1 << std::endl; return false; }
ASSERT_ERROR( parser.parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error(), simdjson::TAPE_ERROR);
// This is a valid document padded with open braces.
auto error2 = parser.parse("[][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error();
if (error2) { std::cerr << "Error: " << error2 << std::endl; return false; }
ASSERT_SUCCESS( parser.parse("[][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[", 2, false).error() );
return true;
}
// returns true if successful
@ -524,16 +514,9 @@ namespace document_stream_tests {
return false;
}
auto [keyid, error2] = doc["id"].get<int64_t>();
if (error2) {
printf("Error getting id as int64 on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error2));
return false;
}
if (keyid != int64_t(count)) {
printf("key does not match %" PRId64 ", expected %zd on document %zd at batch size %zu\n", keyid, count, count, batch_size);
return false;
}
int64_t keyid;
ASSERT_SUCCESS( doc["id"].get(keyid) );
ASSERT_EQUAL( keyid, int64_t(count) );
count++;
}
@ -576,23 +559,13 @@ namespace document_stream_tests {
return false;
}
auto [keyid, error2] = doc["id"].get<int64_t>();
if (error2) {
printf("Error getting id as int64 on document %zd at batch size %zu: %s\n", count, batch_size, simdjson::error_message(error2));
return false;
}
if (keyid != int64_t(count)) {
printf("key does not match %" PRId64 ", expected %zd on document %zd at batch size %zu\n", keyid, count, count, batch_size);
return false;
}
int64_t keyid;
ASSERT_SUCCESS( doc["id"].get(keyid) );
ASSERT_EQUAL( keyid, int64_t(count) );
count++;
}
if(count != n_records) {
printf("Found wrong number of documents %zd, expected %zd at batch size %zu\n", count, n_records, batch_size);
return false;
}
ASSERT_EQUAL( count, n_records )
}
printf("ok\n");
return true;
@ -662,10 +635,10 @@ namespace parse_api_tests {
simdjson::dom::document_stream stream;
ASSERT_SUCCESS( parser.parse_many(EMPTY_NDJSON).get(stream) );
for (auto doc : stream) {
if (doc.error()) { cerr << "Error in parse_many: " << doc.error() << endl; return false; }
ASSERT_SUCCESS(doc.error());
count++;
}
if (count != 0) { cerr << "parse_many returned " << count << " documents, expected 0" << endl; return false; }
ASSERT_EQUAL(count, 0);
return true;
}
@ -682,22 +655,21 @@ namespace parse_api_tests {
simdjson::dom::document_stream stream;
ASSERT_SUCCESS( parser.parse_many(empty_batches_ndjson, BATCH_SIZE*16).get(stream) );
for (auto [doc, error] : stream) {
if (error) { cerr << "Error in parse_many: " << error << endl; return false; }
ASSERT_SUCCESS(error);
count++;
auto [val, val_error] = doc.get<uint64_t>();
if (val_error) { cerr << "Document is not an unsigned int: " << val_error << endl; return false; }
if (val != count) { cerr << "Expected document #" << count << " to equal " << count << ", but got " << val << " instead!" << endl; return false; }
uint64_t val;
ASSERT_SUCCESS( doc.get(val) );
ASSERT_EQUAL( val, count );
}
if (count != 3) { cerr << "parse_many returned " << count << " documents, expected 0" << endl; return false; }
ASSERT_EQUAL(count, 3);
return true;
}
bool parser_load() {
std::cout << "Running " << __func__ << " on " << TWITTER_JSON << std::endl;
dom::parser parser;
auto [doc, error] = parser.load(TWITTER_JSON);
if (error) { cerr << error << endl; return false; }
if (!doc.is<dom::object>()) { cerr << "Document did not parse as an object" << endl; return false; }
dom::object object;
ASSERT_SUCCESS( parser.load(TWITTER_JSON).get(object) );
return true;
}
bool parser_load_many() {
@ -707,21 +679,19 @@ namespace parse_api_tests {
simdjson::dom::document_stream stream;
ASSERT_SUCCESS( parser.load_many(AMAZON_CELLPHONES_NDJSON).get(stream) );
for (auto [doc, error] : stream) {
if (error) { cerr << error << endl; return false; }
ASSERT_SUCCESS( error );
dom::array arr;
error = doc.get(arr); // let us get the array
if (error) { cerr << error << endl; return false; }
ASSERT_SUCCESS( doc.get(arr) ); // let us get the array
ASSERT_EQUAL(arr.size(), 9);
if(arr.size() != 9) { cerr << "bad array size"<< endl; return false; }
size_t c = 0;
for(auto v : arr) { c++; (void)v; }
if(c != 9) { cerr << "mismatched array size"<< endl; return false; }
size_t arr_count = 0;
for (auto v : arr) { arr_count++; (void)v; }
ASSERT_EQUAL(arr_count, 9);
count++;
}
if (count != 793) { cerr << "Expected 793 documents, but load_many loaded " << count << " documents." << endl; return false; }
ASSERT_EQUAL(count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT);
return true;
}
@ -735,18 +705,16 @@ namespace parse_api_tests {
if (error) { cerr << error << endl; return false; }
dom::array arr;
error = doc.get(arr); // let us get the array
if (error) { cerr << error << endl; return false; }
ASSERT_SUCCESS( doc.get(arr) );
ASSERT_EQUAL( arr.size(), 9 );
if(arr.size() != 9) { cerr << "bad array size"<< endl; return false; }
size_t c = 0;
for(auto v : arr) { c++; (void)v; }
if(c != 9) { cerr << "mismatched array size"<< endl; return false; }
size_t arr_count = 0;
for (auto v : arr) { arr_count++; (void)v; }
ASSERT_EQUAL( arr_count, 9 );
count++;
}
if (count != 793) { cerr << "Expected 793 documents, but load_many loaded " << count << " documents." << endl; return false; }
ASSERT_EQUAL( count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT );
return true;
}
SIMDJSON_POP_DISABLE_WARNINGS
@ -756,45 +724,39 @@ namespace parse_api_tests {
bool parser_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(BASIC_JSON);
if (!doc.is<dom::array>()) { cerr << "Document did not parse as an array" << endl; return false; }
UNUSED dom::array array = parser.parse(BASIC_JSON);
return true;
}
bool parser_parse_many_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
int count = 0;
for (const element doc : parser.parse_many(BASIC_NDJSON)) {
if (!doc.is<dom::array>()) { cerr << "Document did not parse as an array" << endl; return false; }
for (UNUSED dom::array doc : parser.parse_many(BASIC_NDJSON)) {
count++;
}
if (count != 2) { cerr << "parse_many returned " << count << " documents, expected 2" << endl; return false; }
ASSERT_EQUAL(count, 2);
return true;
}
bool parser_load_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
const element doc = parser.load(TWITTER_JSON);
if (!doc.is<dom::object>()) { cerr << "Document did not parse as an object" << endl; return false; }
size_t c = 0;
dom::object obj = doc.get<dom::object>().value(); // let us get the object
for (auto x : obj) {
c++;
(void) x;
size_t count = 0;
dom::object object = parser.load(TWITTER_JSON);
for (UNUSED auto field : object) {
count++;
}
if(c != obj.size()) { cerr << "Mismatched size" << endl; return false; }
ASSERT_EQUAL( count, object.size() );
return true;
}
bool parser_load_many_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
int count = 0;
for (const element doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) {
if (!doc.is<dom::array>()) { cerr << "Document did not parse as an array" << endl; return false; }
for (UNUSED dom::array doc : parser.load_many(AMAZON_CELLPHONES_NDJSON)) {
count++;
}
if (count != 793) { cerr << "Expected 1 document, but load_many loaded " << count << " documents." << endl; return false; }
ASSERT_EQUAL( count, AMAZON_CELLPHONES_NDJSON_DOC_COUNT );
return true;
}
#endif
@ -933,16 +895,17 @@ namespace dom_api_tests {
string json(R"({ "a": 1, "b": 2, "c": 3 })");
const char* expected_key[] = { "a", "b", "c" };
uint64_t expected_value[] = { 1, 2, 3 };
int i = 0;
dom::parser parser;
auto [object, error] = parser.parse(json).get<dom::object>();
if (error) { cerr << "Error: " << error << endl; return false; }
dom::object object;
ASSERT_SUCCESS( parser.parse(json).get(object) );
int i = 0;
for (auto [key, value] : object) {
if (key != expected_key[i] || value.get<uint64_t>().first != expected_value[i]) { cerr << "Expected " << expected_key[i] << " = " << expected_value[i] << ", got " << key << "=" << value << endl; return false; }
ASSERT_EQUAL( key, expected_key[i] );
ASSERT_EQUAL( value.get<uint64_t>().value(), expected_value[i] );
i++;
}
if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; }
ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) );
return true;
}
@ -950,16 +913,18 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ 1, 10, 100 ])");
uint64_t expected_value[] = { 1, 10, 100 };
int i=0;
dom::parser parser;
auto [array, error] = parser.parse(json).get<dom::array>();
if (error) { cerr << "Error: " << error << endl; return false; }
dom::array array;
ASSERT_SUCCESS( parser.parse(json).get(array) );
int i=0;
for (auto value : array) {
if (value.get<uint64_t>().first != expected_value[i]) { cerr << "Expected " << expected_value[i] << ", got " << value << endl; return false; }
uint64_t v;
ASSERT_SUCCESS( value.get(v) );
ASSERT_EQUAL( v, expected_value[i] );
i++;
}
if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; }
ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) );
return true;
}
@ -969,13 +934,13 @@ namespace dom_api_tests {
int i = 0;
dom::parser parser;
auto [object, error] = parser.parse(json).get<dom::object>();
if (error) { cerr << "Error: " << error << endl; return false; }
for (auto [key, value] : object) {
cout << "Unexpected " << key << " = " << value << endl;
dom::object object;
ASSERT_SUCCESS( parser.parse(json).get(object) );
for (UNUSED auto field : object) {
TEST_FAIL("Unexpected field");
i++;
}
if (i > 0) { cout << "Expected 0 values, got " << i << endl; return false; }
ASSERT_EQUAL(i, 0);
return true;
}
@ -985,13 +950,13 @@ namespace dom_api_tests {
int i=0;
dom::parser parser;
auto [array, error] = parser.parse(json).get<dom::array>();
if (error) { cerr << "Error: " << error << endl; return false; }
for (auto value : array) {
cout << "Unexpected value " << value << endl;
dom::array array;
ASSERT_SUCCESS( parser.parse(json).get(array) );
for (UNUSED auto value : array) {
TEST_FAIL("Unexpected value");
i++;
}
if (i > 0) { cout << "Expected 0 values, got " << i << endl; return false; }
ASSERT_EQUAL(i, 0);
return true;
}
@ -999,13 +964,18 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ "hi", "has backslash\\" ])");
dom::parser parser;
auto [array, error] = parser.parse(json).get<dom::array>();
if (error) { cerr << "Error: " << error << endl; return false; }
auto val = array.begin();
dom::array array;
ASSERT_SUCCESS( parser.parse(json).get(array) );
auto iter = array.begin();
std::string_view val;
ASSERT_SUCCESS( (*iter).get(val) );
ASSERT_EQUAL( val, "hi" );
++iter;
ASSERT_SUCCESS( (*iter).get(val) );
ASSERT_EQUAL( val, "has backslash\\" );
if ((*val).get<std::string_view>().first != "hi") { cerr << "Expected value to be \"hi\", was " << (*val).get<std::string_view>().first << endl; return false; }
++val;
if ((*val).get<std::string_view>().first != "has backslash\\") { cerr << "Expected string_view(\"has backslash\\\\\") to be \"has backslash\\\", was " << (*val).get<std::string_view>().first << endl; return false; }
return true;
}
@ -1013,22 +983,22 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ 0, 1, -1, 1.1 ])");
dom::parser parser;
auto [array, error] = parser.parse(json).get<dom::array>();
if (error) { cerr << "Error: " << error << endl; return false; }
auto val = array.begin();
dom::array array;
ASSERT_SUCCESS( parser.parse(json).get(array) );
if ((*val).get<uint64_t>().first != 0) { cerr << "Expected uint64_t(0) to be 0, was " << (*val) << endl; return false; }
if ((*val).get<int64_t>().first != 0) { cerr << "Expected int64_t(0) to be 0, was " << (*val).get<int64_t>().first << endl; return false; }
if ((*val).get<double>().first != 0) { cerr << "Expected double(0) to be 0, was " << (*val).get<double>().first << endl; return false; }
++val;
if ((*val).get<uint64_t>().first != 1) { cerr << "Expected uint64_t(1) to be 1, was " << (*val) << endl; return false; }
if ((*val).get<int64_t>().first != 1) { cerr << "Expected int64_t(1) to be 1, was " << (*val).get<int64_t>().first << endl; return false; }
if ((*val).get<double>().first != 1) { cerr << "Expected double(1) to be 1, was " << (*val).get<double>().first << endl; return false; }
++val;
if ((*val).get<int64_t>().first != -1) { cerr << "Expected int64_t(-1) to be -1, was " << (*val).get<int64_t>().first << endl; return false; }
if ((*val).get<double>().first != -1) { cerr << "Expected double(-1) to be -1, was " << (*val).get<double>().first << endl; return false; }
++val;
if ((*val).get<double>().first != 1.1) { cerr << "Expected double(1.1) to be 1.1, was " << (*val).get<double>().first << endl; return false; }
auto iter = array.begin();
ASSERT_EQUAL( (*iter).get<uint64_t>().value(), 0 );
ASSERT_EQUAL( (*iter).get<int64_t>().value(), 0 );
ASSERT_EQUAL( (*iter).get<double>().value(), 0 );
++iter;
ASSERT_EQUAL( (*iter).get<uint64_t>().value(), 1 );
ASSERT_EQUAL( (*iter).get<int64_t>().value(), 1 );
ASSERT_EQUAL( (*iter).get<double>().value(), 1 );
++iter;
ASSERT_EQUAL( (*iter).get<int64_t>().value(), -1 );
ASSERT_EQUAL( (*iter).get<double>().value(), -1 );
++iter;
ASSERT_EQUAL( (*iter).get<double>().value(), 1.1 );
return true;
}
@ -1036,13 +1006,13 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ true, false ])");
dom::parser parser;
auto [array, error] = parser.parse(json).get<dom::array>();
if (error) { cerr << "Error: " << error << endl; return false; }
auto val = array.begin();
dom::array array;
ASSERT_SUCCESS( parser.parse(json).get(array) );
if ((*val).get<bool>().first != true) { cerr << "Expected bool(true) to be true, was " << (*val) << endl; return false; }
auto val = array.begin();
ASSERT_EQUAL( (*val).get<bool>().first, true );
++val;
if ((*val).get<bool>().first != false) { cerr << "Expected bool(false) to be false, was " << (*val) << endl; return false; }
ASSERT_EQUAL( (*val).get<bool>().first, false );
return true;
}
@ -1050,10 +1020,11 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ null ])");
dom::parser parser;
auto [array, error] = parser.parse(json).get<dom::array>();
if (error) { cerr << "Error: " << error << endl; return false; }
dom::array array;
ASSERT_SUCCESS( parser.parse(json).get(array) );
auto val = array.begin();
if (!(*val).is_null()) { cerr << "Expected null to be null!" << endl; return false; }
ASSERT_EQUAL( !(*val).is_null(), 0 );
return true;
}
@ -1061,27 +1032,29 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c/d": 3})");
dom::parser parser;
auto [doc, error] = parser.parse(json);
if (doc["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; }
if (doc["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; }
if (doc["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; }
dom::object object;
ASSERT_SUCCESS( parser.parse(json).get(object) );
ASSERT_EQUAL( object["a"].get<uint64_t>().first, 1 );
ASSERT_EQUAL( object["b"].get<uint64_t>().first, 2 );
ASSERT_EQUAL( object["c/d"].get<uint64_t>().first, 3 );
// Check all three again in backwards order, to ensure we can go backwards
if (doc["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(doc[\"c/d\"]) to be 3, was " << doc["c"].first << endl; return false; }
if (doc["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(doc[\"b\"]) to be 2, was " << doc["b"].first << endl; return false; }
if (doc["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << doc["a"].first << endl; return false; }
ASSERT_EQUAL( object["c/d"].get<uint64_t>().first, 3 );
ASSERT_EQUAL( object["b"].get<uint64_t>().first, 2 );
ASSERT_EQUAL( object["a"].get<uint64_t>().first, 1 );
simdjson::error_code error;
UNUSED element val;
#ifndef _LIBCPP_VERSION // should work everywhere but with libc++, must include the <ciso646> header.
std::tie(val,error) = doc["d"];
if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; }
std::tie(std::ignore,error) = doc["d"];
if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; }
std::tie(val,error) = object["d"];
ASSERT_ERROR( error, NO_SUCH_FIELD );
std::tie(std::ignore,error) = object["d"];
ASSERT_ERROR( error, NO_SUCH_FIELD );
#endif
// tie(val, error) = doc["d"]; fails with "no viable overloaded '='" on Apple clang version 11.0.0 tie(val, error) = doc["d"];
doc["d"].tie(val, error);
if (error != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; }
if (doc["d"].get(val) != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; }
if (doc["d"].error() != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(doc[\"d\"]), got " << error << endl; return false; }
// tie(val, error) = object["d"]; fails with "no viable overloaded '='" on Apple clang version 11.0.0 tie(val, error) = doc["d"];
object["d"].tie(val, error);
ASSERT_ERROR( error, NO_SUCH_FIELD );
ASSERT_ERROR( object["d"].get(val), NO_SUCH_FIELD );
ASSERT_ERROR( object["d"].error(), NO_SUCH_FIELD );
return true;
}
@ -1089,26 +1062,25 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "obj": { "a": 1, "b": 2, "c/d": 3 } })");
dom::parser parser;
auto [doc, error] = parser.parse(json);
if (error) { cerr << "Error: " << error << endl; return false; }
if (doc["obj"]["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(doc[\"obj\"][\"a\"]) to be 1, was " << doc["obj"]["a"].first << endl; return false; }
dom::element doc;
ASSERT_SUCCESS( parser.parse(json).get(doc) );
ASSERT_EQUAL( doc["obj"]["a"].get<uint64_t>().first, 1);
object obj;
error = doc.get(obj);
if (error) { cerr << "Error: " << error << endl; return false; }
if (obj["obj"]["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(doc[\"obj\"][\"a\"]) to be 1, was " << doc["obj"]["a"].first << endl; return false; }
ASSERT_SUCCESS( doc.get(obj) );
ASSERT_EQUAL( obj["obj"]["a"].get<uint64_t>().first, 1);
error = obj["obj"].get(obj);
if (obj["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; }
if (obj["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; }
if (obj["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; }
ASSERT_SUCCESS( obj["obj"].get(obj) );
ASSERT_EQUAL( obj["a"].get<uint64_t>().first, 1 );
ASSERT_EQUAL( obj["b"].get<uint64_t>().first, 2 );
ASSERT_EQUAL( obj["c/d"].get<uint64_t>().first, 3 );
// Check all three again in backwards order, to ensure we can go backwards
if (obj["c/d"].get<uint64_t>().first != 3) { cerr << "Expected uint64_t(obj[\"c\"]) to be 3, was " << obj["c"].first << endl; return false; }
if (obj["b"].get<uint64_t>().first != 2) { cerr << "Expected uint64_t(obj[\"b\"]) to be 2, was " << obj["b"].first << endl; return false; }
if (obj["a"].get<uint64_t>().first != 1) { cerr << "Expected uint64_t(obj[\"a\"]) to be 1, was " << obj["a"].first << endl; return false; }
ASSERT_EQUAL( obj["c/d"].get<uint64_t>().first, 3 );
ASSERT_EQUAL( obj["b"].get<uint64_t>().first, 2 );
ASSERT_EQUAL( obj["a"].get<uint64_t>().first, 1 );
UNUSED element val;
if (doc["d"].get(val) != simdjson::NO_SUCH_FIELD) { cerr << "Expected NO_SUCH_FIELD error for uint64_t(obj[\"d\"]), got " << error << endl; return false; }
ASSERT_ERROR( doc["d"].get(val), NO_SUCH_FIELD);
return true;
}
@ -1116,9 +1088,9 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
// Prints the number of results in twitter.json
dom::parser parser;
auto [result_count, error] = parser.load(TWITTER_JSON)["search_metadata"]["count"].get<uint64_t>();
if (error) { cerr << "Error: " << error << endl; return false; }
if (result_count != 100) { cerr << "Expected twitter.json[metadata_count][count] = 100, got " << result_count << endl; return false; }
uint64_t result_count;
ASSERT_SUCCESS( parser.load(TWITTER_JSON)["search_metadata"]["count"].get(result_count) );
ASSERT_EQUAL( result_count, 100 );
return true;
}
@ -1128,20 +1100,19 @@ namespace dom_api_tests {
set<string_view> default_users;
dom::parser parser;
dom::array tweets;
auto error = parser.load(TWITTER_JSON)["statuses"].get(tweets);
if (error) { cerr << "Error: " << error << endl; return false; }
ASSERT_SUCCESS( parser.load(TWITTER_JSON)["statuses"].get(tweets) );
for (auto tweet : tweets) {
object user;
if ((error = tweet["user"].get(user))) { cerr << "Error: " << error << endl; return false; }
ASSERT_SUCCESS( tweet["user"].get(user) );
bool default_profile;
if ((error = user["default_profile"].get(default_profile))) { cerr << "Error: " << error << endl; return false; }
ASSERT_SUCCESS( user["default_profile"].get(default_profile) );
if (default_profile) {
std::string_view screen_name;
if ((error = user["screen_name"].get(screen_name))) { cerr << "Error: " << error << endl; return false; }
ASSERT_SUCCESS( user["screen_name"].get(screen_name) );
default_users.insert(screen_name);
}
}
if (default_users.size() != 86) { cerr << "Expected twitter.json[statuses][user] to contain 86 default_profile users, got " << default_users.size() << endl; return false; }
ASSERT_EQUAL( default_users.size(), 86 );
return true;
}
@ -1149,26 +1120,26 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
// Print image names and sizes
set<pair<uint64_t, uint64_t>> image_sizes;
simdjson::error_code error;
dom::parser parser;
dom::array tweets;
auto error = parser.load(TWITTER_JSON)["statuses"].get(tweets);
if (error) { cerr << "Error: " << error << endl; return false; }
ASSERT_SUCCESS( parser.load(TWITTER_JSON)["statuses"].get(tweets) );
for (auto tweet : tweets) {
dom::array media;
if (not (error = tweet["entities"]["media"].get(media))) {
for (auto image : media) {
object sizes;
if ((error = image["sizes"].get(sizes))) { cerr << "Error: " << error << endl; return false; }
ASSERT_SUCCESS( image["sizes"].get(sizes) );
for (auto size : sizes) {
uint64_t width, height;
if ((error = size.value["w"].get(width))) { cerr << "Error: " << error << endl; return false; }
if ((error = size.value["h"].get(height))) { cerr << "Error: " << error << endl; return false; }
ASSERT_SUCCESS( size.value["w"].get(width) );
ASSERT_SUCCESS( size.value["h"].get(height) );
image_sizes.insert(make_pair(width, height));
}
}
}
}
if (image_sizes.size() != 15) { cerr << "Expected twitter.json[statuses][entities][media][sizes] to contain 15 different sizes, got " << image_sizes.size() << endl; return false; }
ASSERT_EQUAL( image_sizes.size(), 15 );
return true;
}
@ -1182,12 +1153,12 @@ namespace dom_api_tests {
int i = 0;
dom::parser parser;
element doc = parser.parse(json);
for (auto [key, value] : doc.get<dom::object>()) {
if (key != expected_key[i] || uint64_t(value) != expected_value[i]) { cerr << "Expected " << expected_key[i] << " = " << expected_value[i] << ", got " << key << "=" << uint64_t(value) << endl; return false; }
for (auto [key, value] : dom::object(parser.parse(json))) {
ASSERT_EQUAL( key, expected_key[i]);
ASSERT_EQUAL( uint64_t(value), expected_value[i] );
i++;
}
if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; }
ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) );
return true;
}
@ -1198,69 +1169,61 @@ namespace dom_api_tests {
int i=0;
dom::parser parser;
element doc = parser.parse(json);
for (uint64_t value : doc.get<dom::array>()) {
if (value != expected_value[i]) { cerr << "Expected " << expected_value[i] << ", got " << value << endl; return false; }
for (uint64_t value : parser.parse(json)) {
ASSERT_EQUAL( value, expected_value[i] );
i++;
}
if (i*sizeof(uint64_t) != sizeof(expected_value)) { cout << "Expected " << sizeof(expected_value) << " values, got " << i << endl; return false; }
ASSERT_EQUAL( i*sizeof(uint64_t), sizeof(expected_value) );
return true;
}
bool string_value_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ "hi", "has backslash\\" ])");
dom::parser parser;
auto val = parser.parse(json).get<dom::array>().begin();
if (strcmp((const char*)*val, "hi")) { cerr << "Expected const char*(\"hi\") to be \"hi\", was " << (const char*)*val << endl; return false; }
if (string_view(*val) != "hi") { cerr << "Expected string_view(\"hi\") to be \"hi\", was " << string_view(*val) << endl; return false; }
++val;
if (strcmp((const char*)*val, "has backslash\\")) { cerr << "Expected const char*(\"has backslash\\\\\") to be \"has backslash\\\", was " << (const char*)*val << endl; return false; }
if (string_view(*val) != "has backslash\\") { cerr << "Expected string_view(\"has backslash\\\\\") to be \"has backslash\\\", was " << string_view(*val) << endl; return false; }
ASSERT_EQUAL( (const char *)parser.parse(R"("hi")"_padded), "hi" );
ASSERT_EQUAL( string_view(parser.parse(R"("hi")"_padded)), "hi" );
ASSERT_EQUAL( (const char *)parser.parse(R"("has backslash\\")"_padded), "has backslash\\");
ASSERT_EQUAL( string_view(parser.parse(R"("has backslash\\")"_padded)), "has backslash\\" );
return true;
}
bool numeric_values_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ 0, 1, -1, 1.1 ])");
dom::parser parser;
auto val = parser.parse(json).get<dom::array>().begin();
if (uint64_t(*val) != 0) { cerr << "Expected uint64_t(0) to be 0, was " << uint64_t(*val) << endl; return false; }
if (int64_t(*val) != 0) { cerr << "Expected int64_t(0) to be 0, was " << int64_t(*val) << endl; return false; }
if (double(*val) != 0) { cerr << "Expected double(0) to be 0, was " << double(*val) << endl; return false; }
++val;
if (uint64_t(*val) != 1) { cerr << "Expected uint64_t(1) to be 1, was " << uint64_t(*val) << endl; return false; }
if (int64_t(*val) != 1) { cerr << "Expected int64_t(1) to be 1, was " << int64_t(*val) << endl; return false; }
if (double(*val) != 1) { cerr << "Expected double(1) to be 1, was " << double(*val) << endl; return false; }
++val;
if (int64_t(*val) != -1) { cerr << "Expected int64_t(-1) to be -1, was " << int64_t(*val) << endl; return false; }
if (double(*val) != -1) { cerr << "Expected double(-1) to be -1, was " << double(*val) << endl; return false; }
++val;
if (double(*val) != 1.1) { cerr << "Expected double(1.1) to be 1.1, was " << double(*val) << endl; return false; }
ASSERT_EQUAL( uint64_t(parser.parse("0"_padded)), 0);
ASSERT_EQUAL( int64_t(parser.parse("0"_padded)), 0);
ASSERT_EQUAL( double(parser.parse("0"_padded)), 0);
ASSERT_EQUAL( uint64_t(parser.parse("1"_padded)), 1);
ASSERT_EQUAL( int64_t(parser.parse("1"_padded)), 1);
ASSERT_EQUAL( double(parser.parse("1"_padded)), 1);
ASSERT_EQUAL( int64_t(parser.parse("-1"_padded)), -1);
ASSERT_EQUAL( double(parser.parse("-1"_padded)), -1);
ASSERT_EQUAL( double(parser.parse("1.1"_padded)), 1.1);
return true;
}
bool boolean_values_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ true, false ])");
dom::parser parser;
auto val = parser.parse(json).get<dom::array>().begin();
if (bool(*val) != true) { cerr << "Expected bool(true) to be true, was " << bool(*val) << endl; return false; }
++val;
if (bool(*val) != false) { cerr << "Expected bool(false) to be false, was " << bool(*val) << endl; return false; }
ASSERT_EQUAL( bool(parser.parse("true"_padded)), true);
ASSERT_EQUAL( bool(parser.parse("false"_padded)), false);
return true;
}
bool null_value_exception() {
std::cout << "Running " << __func__ << std::endl;
string json(R"([ null ])");
dom::parser parser;
auto val = parser.parse(json).get<dom::array>().begin();
if (!(*val).is_null()) { cerr << "Expected null to be null!" << endl; return false; }
ASSERT_EQUAL( bool(parser.parse("null"_padded).is_null()), true );
return true;
}
@ -1268,8 +1231,10 @@ namespace dom_api_tests {
std::cout << "Running " << __func__ << std::endl;
string json(R"({ "a": 1, "b": 2, "c": 3})");
dom::parser parser;
element doc = parser.parse(json);
if (uint64_t(doc["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(doc["a"]) << endl; return false; }
auto obj = parser.parse(json);
ASSERT_EQUAL(uint64_t(obj["a"]), 1);
return true;
}
@ -1278,7 +1243,9 @@ namespace dom_api_tests {
string json(R"({ "obj": { "a": 1, "b": 2, "c": 3 } })");
dom::parser parser;
object obj = parser.parse(json)["obj"];
if (uint64_t(obj["a"]) != 1) { cerr << "Expected uint64_t(doc[\"a\"]) to be 1, was " << uint64_t(obj["a"]) << endl; return false; }
ASSERT_EQUAL( uint64_t(obj["a"]), 1);
return true;
}
@ -1313,18 +1280,17 @@ namespace dom_api_tests {
// Print image names and sizes
set<pair<uint64_t, uint64_t>> image_sizes;
dom::parser parser;
element doc = parser.load(TWITTER_JSON);
for (object tweet : doc["statuses"].get<dom::array>()) {
auto [media, not_found] = tweet["entities"]["media"];
if (!not_found) {
for (object image : media.get<dom::array>()) {
for (auto size : image["sizes"].get<dom::object>()) {
for (object tweet : parser.load(TWITTER_JSON)["statuses"]) {
auto media = tweet["entities"]["media"];
if (!media.error()) {
for (object image : media) {
for (auto size : object(image["sizes"])) {
image_sizes.insert(make_pair(size.value["w"], size.value["h"]));
}
}
}
}
if (image_sizes.size() != 15) { cerr << "Expected twitter.json[statuses][entities][media][sizes] to contain 15 different sizes, got " << image_sizes.size() << endl; return false; }
ASSERT_EQUAL( image_sizes.size(), 15 );
return true;
}
@ -1721,21 +1687,10 @@ namespace minify_tests {
return false;
}
size_t newlength{};
auto error = simdjson::minify(input, length, buffer.get(), newlength);
if(error != simdjson::SUCCESS) {
std::cerr << "error " << error << std::endl;
return false;
}
// memcmp
if(newlength != expected_length) {
std::cerr << "lengths do not match " << std::endl;
return false;
}
ASSERT_SUCCESS( simdjson::minify(input, length, buffer.get(), newlength) );
ASSERT_EQUAL( newlength, expected_length);
for(size_t i = 0; i < newlength; i++) {
if(buffer.get()[i] != expected[i]) {
std::cerr << "Inputs do not match (but same length) " << std::endl;
return false;
}
ASSERT_EQUAL( buffer.get()[i], expected[i]);
}
return true;
}
@ -1785,8 +1740,8 @@ namespace format_tests {
bool print_parser_parse() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [doc, error] = parser.parse(DOCUMENT);
if (error) { cerr << error << endl; return false; }
dom::element doc;
ASSERT_SUCCESS( parser.parse(DOCUMENT).get(doc) );
ostringstream s;
s << doc;
return assert_minified(s);
@ -1794,8 +1749,8 @@ namespace format_tests {
bool print_minify_parser_parse() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [doc, error] = parser.parse(DOCUMENT);
if (error) { cerr << error << endl; return false; }
dom::element doc;
ASSERT_SUCCESS( parser.parse(DOCUMENT).get(doc) );
ostringstream s;
s << minify(doc);
return assert_minified(s);
@ -1804,8 +1759,8 @@ namespace format_tests {
bool print_element() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [value, error] = parser.parse(DOCUMENT)["foo"];
if (error) { cerr << error << endl; return false; }
dom::element value;
ASSERT_SUCCESS( parser.parse(DOCUMENT)["foo"].get(value) );
ostringstream s;
s << value;
return assert_minified(s, "1");
@ -1813,8 +1768,8 @@ namespace format_tests {
bool print_minify_element() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [value, error] = parser.parse(DOCUMENT)["foo"];
if (error) { cerr << error << endl; return false; }
dom::element value;
ASSERT_SUCCESS( parser.parse(DOCUMENT)["foo"].get(value) );
ostringstream s;
s << minify(value);
return assert_minified(s, "1");
@ -1823,38 +1778,38 @@ namespace format_tests {
bool print_array() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [value, error] = parser.parse(DOCUMENT)["bar"].get<dom::array>();
if (error) { cerr << error << endl; return false; }
dom::array array;
ASSERT_SUCCESS( parser.parse(DOCUMENT)["bar"].get(array) );
ostringstream s;
s << value;
s << array;
return assert_minified(s, "[1,2,3]");
}
bool print_minify_array() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [value, error] = parser.parse(DOCUMENT)["bar"].get<dom::array>();
if (error) { cerr << error << endl; return false; }
dom::array array;
ASSERT_SUCCESS( parser.parse(DOCUMENT)["bar"].get(array) );
ostringstream s;
s << minify(value);
s << minify(array);
return assert_minified(s, "[1,2,3]");
}
bool print_object() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [value, error] = parser.parse(DOCUMENT)["baz"].get<dom::object>();
if (error) { cerr << error << endl; return false; }
dom::object object;
ASSERT_SUCCESS( parser.parse(DOCUMENT)["baz"].get(object) );
ostringstream s;
s << value;
s << object;
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
}
bool print_minify_object() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
auto [value, error] = parser.parse(DOCUMENT)["baz"].get<dom::object>();
if (error) { cerr << error << endl; return false; }
dom::object object;
ASSERT_SUCCESS( parser.parse(DOCUMENT)["baz"].get(object) );
ostringstream s;
s << minify(value);
s << minify(object);
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
}
@ -1878,25 +1833,22 @@ namespace format_tests {
bool print_element_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["foo"];
s << parser.parse(DOCUMENT)["foo"];
return assert_minified(s, "1");
}
bool print_minify_element_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["foo"]);
s << minify(parser.parse(DOCUMENT)["foo"]);
return assert_minified(s, "1");
}
bool print_element_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
element value = doc["foo"];
element value = parser.parse(DOCUMENT)["foo"];
ostringstream s;
s << value;
return assert_minified(s, "1");
@ -1904,8 +1856,7 @@ namespace format_tests {
bool print_minify_element_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
element value = doc["foo"];
element value = parser.parse(DOCUMENT)["foo"];
ostringstream s;
s << minify(value);
return assert_minified(s, "1");
@ -1914,66 +1865,64 @@ namespace format_tests {
bool print_array_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["bar"].get<dom::array>();
s << parser.parse(DOCUMENT)["bar"].get<dom::array>();
return assert_minified(s, "[1,2,3]");
}
bool print_minify_array_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["bar"].get<dom::array>());
s << minify(parser.parse(DOCUMENT)["bar"].get<dom::array>());
return assert_minified(s, "[1,2,3]");
}
bool print_object_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
ostringstream s;
s << doc["baz"].get<dom::object>();
s << parser.parse(DOCUMENT)["baz"].get<dom::object>();
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
}
bool print_minify_object_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
ostringstream s;
s << minify(doc["baz"].get<dom::object>());
s << minify(parser.parse(DOCUMENT)["baz"].get<dom::object>());
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
}
bool print_array_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
dom::array array = parser.parse(DOCUMENT)["bar"];
ostringstream s;
s << parser.parse(DOCUMENT)["bar"];
s << array;
return assert_minified(s, "[1,2,3]");
}
bool print_minify_array_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
dom::array array = parser.parse(DOCUMENT)["bar"];
ostringstream s;
s << minify(parser.parse(DOCUMENT)["bar"]);
s << minify(array);
return assert_minified(s, "[1,2,3]");
}
bool print_object_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
dom::object object = parser.parse(DOCUMENT)["baz"];
ostringstream s;
s << parser.parse(DOCUMENT)["baz"];
s << object;
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
}
bool print_minify_object_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
element doc = parser.parse(DOCUMENT);
object value = doc["baz"];
dom::object object = parser.parse(DOCUMENT)["baz"];
ostringstream s;
s << minify(value);
s << minify(object);
return assert_minified(s, R"({"a":1,"b":2,"c":3})");
}
#endif // SIMDJSON_EXCEPTIONS

View File

@ -46,15 +46,16 @@ namespace parser_load {
ASSERT_SUCCESS(parser.parse_many(DOC).get(docs));
for (auto doc : docs) {
count++;
auto [val, error] = doc.get<uint64_t>();
uint64_t val;
auto error = doc.get(val);
if (count == 3) {
ASSERT_ERROR(error, TAPE_ERROR);
} else {
if (error) { TEST_FAIL(error); }
if (val != count) { cerr << "FAIL: expected " << count << ", got " << val << endl; return false; }
ASSERT_SUCCESS(error);
ASSERT_EQUAL(val, count);
}
}
if (count != 3) { cerr << "FAIL: expected 2 documents and 1 error, got " << count << " total things" << endl; return false; }
ASSERT_EQUAL(count, 3);
TEST_SUCCEED();
}
@ -69,7 +70,7 @@ namespace parser_load {
count++;
ASSERT_ERROR(doc.error(), TAPE_ERROR);
}
if (count != 1) { cerr << "FAIL: expected no documents and 1 error, got " << count << " total things" << endl; return false; }
ASSERT_EQUAL(count, 1);
TEST_SUCCEED();
}
@ -82,36 +83,34 @@ namespace parser_load {
ASSERT_SUCCESS(parser.parse_many(DOC).get(docs));
for (auto doc : docs) {
count++;
auto [val, error] = doc.get<uint64_t>();
uint64_t val;
auto error = doc.get(val);
if (count == 3) {
ASSERT_ERROR(error, TAPE_ERROR);
} else {
if (error) { TEST_FAIL(error); }
if (val != count) { cerr << "FAIL: expected " << count << ", got " << val << endl; return false; }
ASSERT_SUCCESS(error);
ASSERT_EQUAL(val, count);
}
}
if (count != 3) { cerr << "FAIL: expected 2 documents and 1 error, got " << count << " total things" << endl; return false; }
ASSERT_EQUAL(count, 3);
TEST_SUCCEED();
}
bool parser_load_nonexistent() {
TEST_START();
dom::parser parser;
auto error = parser.load(NONEXISTENT_FILE).error();
ASSERT_ERROR(error, IO_ERROR);
ASSERT_ERROR( parser.load(NONEXISTENT_FILE).error(), IO_ERROR );
TEST_SUCCEED();
}
bool parser_load_many_nonexistent() {
TEST_START();
dom::parser parser;
dom::document_stream stream;
ASSERT_ERROR(parser.load_many(NONEXISTENT_FILE).get(stream), IO_ERROR);
ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).error(), IO_ERROR );
TEST_SUCCEED();
}
bool padded_string_load_nonexistent() {
TEST_START();
auto error = padded_string::load(NONEXISTENT_FILE).error();
ASSERT_ERROR(error, IO_ERROR);
ASSERT_ERROR(padded_string::load(NONEXISTENT_FILE).error(), IO_ERROR);
TEST_SUCCEED();
}
@ -119,16 +118,17 @@ namespace parser_load {
TEST_START();
dom::parser parser;
UNUSED uint64_t foo;
ASSERT_ERROR( parser.load(NONEXISTENT_FILE)["foo"].get(foo) , IO_ERROR);
ASSERT_ERROR( parser.load(NONEXISTENT_FILE)["foo"].get(foo), IO_ERROR);
TEST_SUCCEED();
}
bool parser_load_many_chain() {
TEST_START();
dom::parser parser;
dom::document_stream stream;
ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).get(stream) , IO_ERROR );
UNUSED dom::document_stream stream;
ASSERT_ERROR( parser.load_many(NONEXISTENT_FILE).get(stream), IO_ERROR );
TEST_SUCCEED();
}
bool run() {
return true
&& parser_load_capacity()

View File

@ -3,6 +3,7 @@
#include <limits>
#include "simdjson.h"
#include "test_macros.h"
// we define our own asserts to get around NDEBUG
#ifndef ASSERT
@ -29,44 +30,43 @@ template <typename T> static const std::string make_json(T value) {
}
template <typename T>
static void parse_and_validate(const std::string src, T expected) {
static bool parse_and_validate(const std::string src, T expected) {
std::cout << "src: " << src << ", ";
const padded_string pstr{src};
simdjson::dom::parser parser;
bool result;
if constexpr (std::is_same<int64_t, T>::value) {
auto [actual, error] = parser.parse(pstr).get<dom::object>()["key"].get<int64_t>();
if (error) { std::cerr << error << std::endl; abort(); }
result = (expected == actual);
int64_t actual;
ASSERT_SUCCESS( parser.parse(pstr)["key"].get(actual) );
std::cout << std::boolalpha << "test: " << (expected == actual) << std::endl;
ASSERT_EQUAL( expected, actual );
} else {
auto [actual, error] = parser.parse(pstr).get<dom::object>()["key"].get<uint64_t>();
if (error) { std::cerr << error << std::endl; abort(); }
result = (expected == actual);
}
std::cout << std::boolalpha << "test: " << result << std::endl;
if(!result) {
std::cerr << "bug detected" << std::endl;
exit(EXIT_FAILURE);
uint64_t actual;
ASSERT_SUCCESS( parser.parse(pstr)["key"].get(actual) );
std::cout << std::boolalpha << "test: " << (expected == actual) << std::endl;
ASSERT_EQUAL( expected, actual );
}
return true;
}
static bool parse_and_check_signed(const std::string src) {
std::cout << "src: " << src << ", expecting signed" << std::endl;
const padded_string pstr{src};
simdjson::dom::parser parser;
auto [value, error] = parser.parse(pstr).get<dom::object>()["key"];
if (error) { std::cerr << error << std::endl; abort(); }
return value.is<int64_t>();
simdjson::dom::element value;
ASSERT_SUCCESS( parser.parse(pstr).get<dom::object>()["key"].get(value) );
ASSERT_EQUAL( value.is<int64_t>(), true );
return true;
}
static bool parse_and_check_unsigned(const std::string src) {
std::cout << "src: " << src << ", expecting signed" << std::endl;
const padded_string pstr{src};
simdjson::dom::parser parser;
auto [value, error] = parser.parse(pstr).get<dom::object>()["key"];
if (error) { std::cerr << error << std::endl; abort(); }
return value.is<uint64_t>();
simdjson::dom::element value;
ASSERT_SUCCESS( parser.parse(pstr).get<dom::object>()["key"].get(value) );
ASSERT_EQUAL( value.is<uint64_t>(), true );
return true;
}
int main() {
@ -75,21 +75,21 @@ int main() {
constexpr auto int64_min = numeric_limits<int64_t>::lowest();
constexpr auto uint64_max = numeric_limits<uint64_t>::max();
constexpr auto uint64_min = numeric_limits<uint64_t>::lowest();
parse_and_validate(make_json(int64_max), int64_max);
parse_and_validate(make_json(int64_min), int64_min);
parse_and_validate(make_json(uint64_max), uint64_max);
parse_and_validate(make_json(uint64_min), uint64_min);
constexpr auto int64_max_plus1 = static_cast<uint64_t>(int64_max) + 1;
parse_and_validate(make_json(int64_max_plus1), int64_max_plus1);
if(!parse_and_check_signed(make_json(int64_max))) {
std::cerr << "bug: large signed integers should be represented as signed integers" << std::endl;
return EXIT_FAILURE;
if (true
&& parse_and_validate(make_json(int64_max), int64_max)
&& parse_and_validate(make_json(uint64_max), uint64_max)
&& parse_and_validate(make_json(uint64_min), uint64_min)
&& parse_and_validate(make_json(int64_min), int64_min)
&& parse_and_validate(make_json(uint64_max), uint64_max)
&& parse_and_validate(make_json(uint64_min), uint64_min)
&& parse_and_validate(make_json(int64_max_plus1), int64_max_plus1)
&& parse_and_check_signed(make_json(int64_max))
&& parse_and_check_unsigned(make_json(uint64_max))
) {
std::cout << "All ok." << std::endl;
return EXIT_SUCCESS;
}
if(!parse_and_check_unsigned(make_json(uint64_max))) {
std::cerr << "bug: a large unsigned integers is not represented as an unsigned integer" << std::endl;
return EXIT_FAILURE;
}
std::cout << "All ok." << std::endl;
return EXIT_SUCCESS;
return EXIT_FAILURE;
}

View File

@ -1,6 +1,7 @@
#include <iostream>
#include "simdjson.h"
#include "test_macros.h"
// we define our own asserts to get around NDEBUG
#ifndef ASSERT
@ -35,49 +36,46 @@ const padded_string TEST_JSON = R"(
bool json_pointer_success_test(const char *json_pointer, std::string_view expected_value) {
std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl;
dom::parser parser;
auto [value, error] = parser.parse(TEST_JSON).at(json_pointer).get<std::string_view>();
if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; }
ASSERT(value == expected_value);
std::string_view value;
ASSERT_SUCCESS( parser.parse(TEST_JSON).at(json_pointer).get(value) );
ASSERT_EQUAL(value, expected_value);
return true;
}
bool json_pointer_success_test(const char *json_pointer) {
std::cout << "Running successful JSON pointer test '" << json_pointer << "' ..." << std::endl;
dom::parser parser;
auto error = parser.parse(TEST_JSON).at(json_pointer).error();
if (error) { std::cerr << "Unexpected Error: " << error << std::endl; return false; }
ASSERT_SUCCESS( parser.parse(TEST_JSON).at(json_pointer).error() );
return true;
}
bool json_pointer_failure_test(const char *json_pointer, error_code expected_failure_test) {
bool json_pointer_failure_test(const char *json_pointer, error_code expected_error) {
std::cout << "Running invalid JSON pointer test '" << json_pointer << "' ..." << std::endl;
dom::parser parser;
auto error = parser.parse(TEST_JSON).at(json_pointer).error();
ASSERT(error == expected_failure_test);
ASSERT_ERROR(parser.parse(TEST_JSON).at(json_pointer).error(), expected_error);
return true;
}
int main() {
if (
json_pointer_success_test("") &&
json_pointer_success_test("~1~001abc") &&
json_pointer_success_test("~1~001abc/1") &&
json_pointer_success_test("~1~001abc/1/\\\" 0") &&
json_pointer_success_test("~1~001abc/1/\\\" 0/0", "value0") &&
json_pointer_success_test("~1~001abc/1/\\\" 0/1", "value1") &&
json_pointer_failure_test("~1~001abc/1/\\\" 0/2", INDEX_OUT_OF_BOUNDS) && // index actually out of bounds
json_pointer_success_test("arr") && // get array
json_pointer_failure_test("arr/0", INDEX_OUT_OF_BOUNDS) && // array index 0 out of bounds on empty array
json_pointer_success_test("~1~001abc") && // get object
json_pointer_success_test("0", "0 ok") && // object index with integer-ish key
json_pointer_success_test("01", "01 ok") && // object index with key that would be an invalid integer
json_pointer_success_test("", "empty ok") && // object index with empty key
json_pointer_failure_test("~01abc", NO_SUCH_FIELD) && // Test that we don't try to compare the literal key
json_pointer_failure_test("~1~001abc/01", INVALID_JSON_POINTER) && // Leading 0 in integer index
json_pointer_failure_test("~1~001abc/", INVALID_JSON_POINTER) && // Empty index to array
json_pointer_failure_test("~1~001abc/-", INDEX_OUT_OF_BOUNDS) && // End index is always out of bounds
true
if (true
&& json_pointer_success_test("")
&& json_pointer_success_test("~1~001abc")
&& json_pointer_success_test("~1~001abc/1")
&& json_pointer_success_test("~1~001abc/1/\\\" 0")
&& json_pointer_success_test("~1~001abc/1/\\\" 0/0", "value0")
&& json_pointer_success_test("~1~001abc/1/\\\" 0/1", "value1")
&& json_pointer_failure_test("~1~001abc/1/\\\" 0/2", INDEX_OUT_OF_BOUNDS) // index actually out of bounds
&& json_pointer_success_test("arr") // get array
&& json_pointer_failure_test("arr/0", INDEX_OUT_OF_BOUNDS) // array index 0 out of bounds on empty array
&& json_pointer_success_test("~1~001abc") // get object
&& json_pointer_success_test("0", "0 ok") // object index with integer-ish key
&& json_pointer_success_test("01", "01 ok") // object index with key that would be an invalid integer
&& json_pointer_success_test("", "empty ok") // object index with empty key
&& json_pointer_failure_test("~01abc", NO_SUCH_FIELD) // Test that we don't try to compare the literal key
&& json_pointer_failure_test("~1~001abc/01", INVALID_JSON_POINTER) // Leading 0 in integer index
&& json_pointer_failure_test("~1~001abc/", INVALID_JSON_POINTER) // Empty index to array
&& json_pointer_failure_test("~1~001abc/-", INDEX_OUT_OF_BOUNDS) // End index is always out of bounds
) {
std::cout << "Success!" << std::endl;
return 0;

View File

@ -88,7 +88,7 @@ void basics_dom_4() {
auto abstract_json = R"(
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
dom::parser parser;
double v = parser.parse(abstract_json)["str"]["123"]["abc"].get<double>();
double v = parser.parse(abstract_json)["str"]["123"]["abc"];
cout << "number: " << v << endl;
}
@ -141,9 +141,10 @@ namespace treewalk_1 {
#ifdef SIMDJSON_CPLUSPLUS17
void basics_cpp17_1() {
dom::parser parser;
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
auto [object, error] = parser.parse(json).get<dom::object>();
dom::parser parser;
dom::object object;
auto error = parser.parse(json).get(object);
if (error) { cerr << error << endl; return; }
for (auto [key, value] : object) {
cout << key << " = " << value << endl;
@ -153,11 +154,10 @@ void basics_cpp17_1() {
void basics_cpp17_2() {
// C++ 11 version for comparison
dom::parser parser;
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
simdjson::error_code error;
dom::parser parser;
dom::object object;
error = parser.parse(json).get(object);
auto error = parser.parse(json).get(object);
if (!error) { cerr << error << endl; return; }
for (dom::key_value_pair field : object) {
cout << field.key << " = " << field.value << endl;

View File

@ -18,17 +18,25 @@ const char *SMALLDEMO_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "smalldemo.json";
const char *TRUENULL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "truenull.json";
// For the ASSERT_EQUAL macro
template<typename T>
bool equals_expected(T actual, T expected) {
return actual == expected;
template<typename T, typename S>
bool equals_expected(T actual, S expected) {
return actual == T(expected);
}
template<>
bool equals_expected<const char *>(const char *actual, const char *expected) {
bool equals_expected<const char *, const char *>(const char *actual, const char *expected) {
return !strcmp(actual, expected);
}
#define TEST_START() { cout << "Running " << __func__ << " ..." << endl; }
#define ASSERT_EQUAL(ACTUAL, EXPECTED) do { auto _actual = (ACTUAL); auto _expected = (EXPECTED); if (!equals_expected(_actual, _expected)) { std::cerr << "Expected " << #ACTUAL << " to be " << _expected << ", got " << _actual << " instead!" << std::endl; return false; } } while(0);
#define ASSERT_EQUAL(ACTUAL, EXPECTED) \
do { \
auto _actual = (ACTUAL); \
auto _expected = (EXPECTED); \
if (!equals_expected(_actual, _expected)) { \
std::cerr << "Expected " << (#ACTUAL) << " to be " << _expected << ", got " << _actual << " instead!" << std::endl; \
return false; \
} \
} while(0);
#define ASSERT_ERROR(ACTUAL, EXPECTED) do { auto _actual = (ACTUAL); auto _expected = (EXPECTED); if (_actual != _expected) { std::cerr << "FAIL: Unexpected error \"" << _actual << "\" (expected \"" << _expected << "\")" << std::endl; return false; } } while (0);
#define ASSERT(RESULT, MESSAGE) if (!(RESULT)) { std::cerr << MESSAGE << std::endl; return false; }
#define RUN_TEST(RESULT) if (!RESULT) { return false; }