mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
056d66926a
* This PR renames a few macros and extends slightly our basic builder * minor tuning
263 lines
6.9 KiB
C++
263 lines
6.9 KiB
C++
#include "simdjson.h"
|
|
#include "test_ondemand.h"
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
using namespace simdjson;
|
|
|
|
/**
|
|
* A custom type that we want to parse.
|
|
*/
|
|
struct Car {
|
|
std::string make{};
|
|
std::string model{};
|
|
int64_t year{};
|
|
std::vector<double> tire_pressure{};
|
|
bool operator==(const Car &other) const {
|
|
return make == other.make && model == other.model && year == other.year &&
|
|
tire_pressure == other.tire_pressure;
|
|
}
|
|
};
|
|
|
|
std::ostream &operator<<(std::ostream &os, const Car &c) {
|
|
os << c.make << " " << c.model << " " << c.year << " ";
|
|
for (auto p : c.tire_pressure) {
|
|
os << p << " ";
|
|
}
|
|
return os;
|
|
}
|
|
|
|
#if !SIMDJSON_SUPPORTS_CONCEPTS
|
|
// This code is not necessary if you have a C++20 compliant system:
|
|
template <>
|
|
simdjson_inline simdjson_result<std::vector<double>>
|
|
simdjson::ondemand::value::get() noexcept {
|
|
ondemand::array array;
|
|
auto error = get_array().get(array);
|
|
if (error) {
|
|
return error;
|
|
}
|
|
std::vector<double> vec;
|
|
for (auto v : array) {
|
|
double val;
|
|
error = v.get_double().get(val);
|
|
if (error) {
|
|
return error;
|
|
}
|
|
vec.push_back(val);
|
|
}
|
|
return vec;
|
|
}
|
|
#endif
|
|
|
|
template <>
|
|
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
|
|
ondemand::object obj;
|
|
auto error = get_object().get(obj);
|
|
if (error) {
|
|
return error;
|
|
}
|
|
Car car;
|
|
if ((error = obj["make"].get_string(car.make))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["model"].get_string(car.model))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["year"].get_int64().get(car.year))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["tire_pressure"].get<std::vector<double>>().get(
|
|
car.tire_pressure))) {
|
|
return error;
|
|
}
|
|
return car;
|
|
}
|
|
|
|
template <>
|
|
simdjson_inline simdjson_result<Car>
|
|
simdjson::ondemand::document::get() &noexcept {
|
|
ondemand::object obj;
|
|
auto error = get_object().get(obj);
|
|
if (error) {
|
|
return error;
|
|
}
|
|
Car car;
|
|
if ((error = obj["make"].get_string(car.make))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["model"].get_string(car.model))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["year"].get_int64().get(car.year))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["tire_pressure"].get<std::vector<double>>().get(
|
|
car.tire_pressure))) {
|
|
return error;
|
|
}
|
|
return car;
|
|
}
|
|
|
|
|
|
template <>
|
|
simdjson_inline simdjson_result<Car>
|
|
simdjson::ondemand::document_reference::get() &noexcept {
|
|
ondemand::object obj;
|
|
auto error = get_object().get(obj);
|
|
if (error) {
|
|
return error;
|
|
}
|
|
Car car;
|
|
if ((error = obj["make"].get_string(car.make))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["model"].get_string(car.model))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["year"].get_int64().get(car.year))) {
|
|
return error;
|
|
}
|
|
if ((error = obj["tire_pressure"].get<std::vector<double>>().get(
|
|
car.tire_pressure))) {
|
|
return error;
|
|
}
|
|
return car;
|
|
}
|
|
|
|
int main_should_compile(void) {
|
|
padded_string json =
|
|
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
|
"tire_pressure": [ 40.1, 39.9 ] },
|
|
{ "make": "Kia", "model": "Soul", "year": 2012,
|
|
"tire_pressure": [ 30.1, 31.0 ] },
|
|
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
|
"tire_pressure": [ 29.8, 30.0 ] }
|
|
])"_padded;
|
|
ondemand::parser parser;
|
|
ondemand::document doc;
|
|
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
|
|
for (auto val : doc) {
|
|
#if SIMDJSON_EXCEPTIONS
|
|
Car c(val); // an exception may be thrown
|
|
#else
|
|
Car c;
|
|
if (auto error = val.get<Car>().get(c)) {
|
|
std::cerr << error << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
#endif
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
namespace car_error_tests {
|
|
bool car_deserialize() {
|
|
TEST_START();
|
|
padded_string json =
|
|
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
|
"tire_pressure": [ 40.1, 39.9 ] },
|
|
{ "make": "Kia", "model": "Soul", "year": 2012,
|
|
"tire_pressure": [ 30.1, 31.0 ] },
|
|
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
|
"tire_pressure": [ 29.8, 30.0 ] }
|
|
])"_padded;
|
|
ondemand::parser parser;
|
|
ondemand::document doc;
|
|
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
|
|
std::vector<Car> cars;
|
|
for (auto val : doc) {
|
|
#if SIMDJSON_EXCEPTIONS
|
|
Car c(val); // an exception may be thrown
|
|
#else
|
|
Car c;
|
|
if (auto error = val.get<Car>().get(c)) {
|
|
std::cerr << error << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
#endif
|
|
cars.push_back(c);
|
|
std::cout << c.make << std::endl;
|
|
}
|
|
std::vector<Car> expected = {{"Toyota", "Camry", 2018, {40.1, 39.9}},
|
|
{"Kia", "Soul", 2012, {30.1, 31.0}},
|
|
{"Toyota", "Tercel", 1999, {29.8, 30.0}}};
|
|
ASSERT_EQUAL(cars.size(), expected.size());
|
|
for (size_t i = 0; i < cars.size(); i++) {
|
|
ASSERT_EQUAL(cars[i], expected[i]);
|
|
}
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool car_doc_deserialize() {
|
|
TEST_START();
|
|
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
|
"tire_pressure": [ 40.1, 39.9 ] }
|
|
)"_padded;
|
|
ondemand::parser parser;
|
|
ondemand::document doc;
|
|
[[maybe_unused]] auto doc_error = parser.iterate(json).get(doc);
|
|
#if SIMDJSON_EXCEPTIONS
|
|
Car c(doc); // an exception may be thrown
|
|
#else
|
|
Car c;
|
|
if (auto error = doc.get<Car>().get(c)) {
|
|
std::cerr << error << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
#endif
|
|
Car expected = {"Toyota", "Camry", 2018, {40.1, 39.9}};
|
|
ASSERT_EQUAL(c, expected);
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool car_stream_deserialize() {
|
|
TEST_START();
|
|
padded_string json =
|
|
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
|
"tire_pressure": [ 40.1, 39.9 ] }
|
|
{ "make": "Kia", "model": "Soul", "year": 2012,
|
|
"tire_pressure": [ 30.1, 31.0 ] }
|
|
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
|
"tire_pressure": [ 29.8, 30.0 ] }
|
|
)"_padded;
|
|
ondemand::parser parser;
|
|
ondemand::document_stream stream;
|
|
auto error = parser.iterate_many(json).get(stream);
|
|
if(error) {
|
|
std::cerr << error << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
std::vector<Car> cars;
|
|
|
|
#if SIMDJSON_EXCEPTIONS
|
|
for(ondemand::document_reference doc : stream) {
|
|
//Car c(doc); // an exception may be thrown
|
|
cars.push_back(Car(doc)); // an exception may be thrown
|
|
}
|
|
#else
|
|
for(auto doc : stream) {
|
|
Car c;
|
|
if ((error = doc.get<Car>().get(c))) {
|
|
std::cerr << error << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
cars.push_back(c);
|
|
}
|
|
#endif
|
|
std::vector<Car> expected = {{"Toyota", "Camry", 2018, {40.1, 39.9}},
|
|
{"Kia", "Soul", 2012, {30.1, 31.0}},
|
|
{"Toyota", "Tercel", 1999, {29.8, 30.0}}};
|
|
ASSERT_EQUAL(cars.size(), expected.size());
|
|
for (size_t i = 0; i < cars.size(); i++) {
|
|
ASSERT_EQUAL(cars[i], expected[i]);
|
|
}
|
|
TEST_SUCCEED();
|
|
}
|
|
|
|
bool run() { return car_stream_deserialize() && car_doc_deserialize() && car_deserialize(); }
|
|
} // namespace car_error_tests
|
|
|
|
int main(int argc, char *argv[]) {
|
|
return test_main(argc, argv, car_error_tests::run);
|
|
} |