From f568d35f868a4ab3f78fab1949b864f6db91f92f Mon Sep 17 00:00:00 2001 From: Francois Mazen Date: Sat, 19 Oct 2024 16:05:20 +0200 Subject: [PATCH] Add yyjson support. --- src/CMakeLists.txt | 5 + src/cmake/Setup3rdParty.cmake | 12 +- src/libs/conduit/CMakeLists.txt | 1 + src/libs/conduit/conduit_generator.cpp | 165 +++++---- src/libs/conduit/conduit_json.hpp | 13 + src/tests/conduit/t_conduit_node.cpp | 4 +- src/tests/conduit/t_conduit_node_set.cpp | 2 +- src/tests/conduit/t_conduit_node_to_array.cpp | 2 +- .../conduit/t_conduit_node_type_dispatch.cpp | 2 +- src/tests/conduit/t_conduit_node_update.cpp | 2 +- .../docs/t_conduit_docs_tutorial_basics.cpp | 2 +- src/tests/thirdparty/t_rapidjson_smoke.cpp | 6 +- .../yyjson/conduit_yyjson.h | 314 ++++++++++++++++++ 13 files changed, 434 insertions(+), 96 deletions(-) create mode 100644 src/libs/conduit/conduit_json.hpp create mode 100644 src/thirdparty_builtin/yyjson/conduit_yyjson.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b443994a5..32a0abc31 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,11 @@ option(ENABLE_FORTRAN "Build Fortran Support" OFF) option(ENABLE_MPI "Build MPI Support" OFF) option(ENABLE_OPENMP "Build OpenMP Support" OFF) +option(USE_SYSTEM_YYJSON "Use yyjson as a replacement for rapidjson." OFF) +if(${USE_SYSTEM_YYJSON}) + add_compile_definitions(USE_YYJSON) +endif() + # Add another option that provides extra # control over conduit tests for cases where # conduit is brought in as a submodule diff --git a/src/cmake/Setup3rdParty.cmake b/src/cmake/Setup3rdParty.cmake index 11171eaf5..60d71b8a8 100644 --- a/src/cmake/Setup3rdParty.cmake +++ b/src/cmake/Setup3rdParty.cmake @@ -27,9 +27,15 @@ endif() ################################ # Setup includes for RapidJSON ################################ -include(cmake/thirdparty/SetupRapidJSON.cmake) -message(STATUS "Using RapidJSON Include: ${RAPIDJSON_INCLUDE_DIR}") -include_directories(${RAPIDJSON_INCLUDE_DIR}) +if(${USE_SYSTEM_YYJSON}) + find_package(yyjson REQUIRED) + link_libraries(yyjson::yyjson) + include_directories(thirdparty_builtin/yyjson) +else() + include(cmake/thirdparty/SetupRapidJSON.cmake) + message(STATUS "Using RapidJSON Include: ${RAPIDJSON_INCLUDE_DIR}") + include_directories(${RAPIDJSON_INCLUDE_DIR}) +endif() ################################ # Setup and build libb64 diff --git a/src/libs/conduit/CMakeLists.txt b/src/libs/conduit/CMakeLists.txt index 19f7afdb5..9941d54d7 100644 --- a/src/libs/conduit/CMakeLists.txt +++ b/src/libs/conduit/CMakeLists.txt @@ -66,6 +66,7 @@ set(conduit_headers ${CMAKE_CURRENT_BINARY_DIR}/conduit_config.h conduit_config.hpp ${CMAKE_CURRENT_BINARY_DIR}/conduit_bitwidth_style_types.h + conduit_json.hpp ) # diff --git a/src/libs/conduit/conduit_generator.cpp b/src/libs/conduit/conduit_generator.cpp index feb5ef385..0c9927d45 100644 --- a/src/libs/conduit/conduit_generator.cpp +++ b/src/libs/conduit/conduit_generator.cpp @@ -19,8 +19,7 @@ //----------------------------------------------------------------------------- // -- rapidjson includes -- //----------------------------------------------------------------------------- -#include "rapidjson/document.h" -#include "rapidjson/error/en.h" +#include "conduit_json.hpp" //----------------------------------------------------------------------------- // -- libyaml includes -- @@ -125,81 +124,81 @@ class Generator::Parser { public: - static const conduit_rapidjson::ParseFlag RAPIDJSON_PARSE_OPTS = conduit_rapidjson::kParseNoFlags; + static const conduit_json::ParseFlag JSON_PARSE_OPTS = conduit_json::kParseNoFlags; - static index_t json_to_numeric_dtype(const conduit_rapidjson::Value &jvalue); + static index_t json_to_numeric_dtype(const conduit_json::Value &jvalue); - static index_t check_homogenous_json_array(const conduit_rapidjson::Value &jvalue); + static index_t check_homogenous_json_array(const conduit_json::Value &jvalue); - static void parse_json_int64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_int64_array(const conduit_json::Value &jvalue, std::vector &res); // for efficiency - assumes res is already alloced to proper size - static void parse_json_int64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_int64_array(const conduit_json::Value &jvalue, int64_array &res); - static void parse_json_int64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_int64_array(const conduit_json::Value &jvalue, Node &node); - static void parse_json_uint64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_uint64_array(const conduit_json::Value &jvalue, std::vector &res); // for efficiency - assumes res is already alloced to proper size - static void parse_json_uint64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_uint64_array(const conduit_json::Value &jvalue, uint64_array &res); - static void parse_json_uint64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_uint64_array(const conduit_json::Value &jvalue, Node &node); - static void parse_json_float64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_float64_array(const conduit_json::Value &jvalue, std::vector &res); // for efficiency - assumes res is already alloced to proper size - static void parse_json_float64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_float64_array(const conduit_json::Value &jvalue, float64_array &res); - static void parse_json_float64_array(const conduit_rapidjson::Value &jvalue, + static void parse_json_float64_array(const conduit_json::Value &jvalue, Node &node); - static void parse_leaf_dtype(const conduit_rapidjson::Value &jvalue, + static void parse_leaf_dtype(const conduit_json::Value &jvalue, index_t offset, DataType &dtype_res); - static void parse_inline_leaf(const conduit_rapidjson::Value &jvalue, + static void parse_inline_leaf(const conduit_json::Value &jvalue, Node &node); - static void* parse_inline_address(const conduit_rapidjson::Value& jvalue); + static void* parse_inline_address(const conduit_json::Value& jvalue); - static void parse_inline_value(const conduit_rapidjson::Value &jvalue, + static void parse_inline_value(const conduit_json::Value &jvalue, Node &node); static void walk_json_schema(Schema *schema, - const conduit_rapidjson::Value &jvalue, + const conduit_json::Value &jvalue, index_t curr_offset); static void walk_pure_json_schema(Node *node, Schema *schema, - const conduit_rapidjson::Value &jvalue); + const conduit_json::Value &jvalue); // if data pointer is provided, data is copied into dest node static void walk_json_schema(Node *node, Schema *schema, void *data, - const conduit_rapidjson::Value &jvalue, + const conduit_json::Value &jvalue, index_t curr_offset); // if data pointer is provided, data is set_external into dest node static void walk_json_schema_external(Node *node, Schema *schema, void *data, - const conduit_rapidjson::Value &jvalue, + const conduit_json::Value &jvalue, index_t curr_offset); static void parse_base64(Node *node, - const conduit_rapidjson::Value &jvalue); + const conduit_json::Value &jvalue); static void parse_error_details(const std::string &json, - const conduit_rapidjson::Document &document, + const conduit_json::Document &document, std::ostream &os); }; //----------------------------------------------------------------------------- @@ -478,7 +477,7 @@ Generator::Parser::parse_leaf_dtype_name(const std::string &dtype_name) //---------------------------------------------------------------------------// index_t -Generator::Parser::JSON::json_to_numeric_dtype(const conduit_rapidjson::Value &jvalue) +Generator::Parser::JSON::json_to_numeric_dtype(const conduit_json::Value &jvalue) { index_t res = DataType::EMPTY_ID; if(jvalue.IsNumber()) @@ -510,7 +509,7 @@ Generator::Parser::JSON::json_to_numeric_dtype(const conduit_rapidjson::Value &j //---------------------------------------------------------------------------// index_t -Generator::Parser::JSON::check_homogenous_json_array(const conduit_rapidjson::Value &jvalue) +Generator::Parser::JSON::check_homogenous_json_array(const conduit_json::Value &jvalue) { // check for homogenous array of ints or floats // promote to float64 as the most wide type @@ -522,10 +521,10 @@ Generator::Parser::JSON::check_homogenous_json_array(const conduit_rapidjson::Va // we could also have string reps of nan, infinity, etc. // json_to_numeric_dtype handles that case fo us - index_t val_type = json_to_numeric_dtype(jvalue[(conduit_rapidjson::SizeType)0]); + index_t val_type = json_to_numeric_dtype(jvalue[(conduit_json::SizeType)0]); bool homogenous = (val_type != DataType::EMPTY_ID); - for (conduit_rapidjson::SizeType i = 1; i < jvalue.Size() && homogenous; i++) + for (conduit_json::SizeType i = 1; i < jvalue.Size() && homogenous; i++) { index_t curr_val_type = json_to_numeric_dtype(jvalue[i]); if(val_type == DataType::INT64_ID && @@ -547,11 +546,11 @@ Generator::Parser::JSON::check_homogenous_json_array(const conduit_rapidjson::Va //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_int64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_int64_array(const conduit_json::Value &jvalue, std::vector &res) { res.resize(jvalue.Size(),0); - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { res[i] = jvalue[i].GetInt64(); } @@ -559,11 +558,11 @@ Generator::Parser::JSON::parse_json_int64_array(const conduit_rapidjson::Value & //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_int64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_int64_array(const conduit_json::Value &jvalue, int64_array &res) { // for efficiency - assumes res is already alloced to proper size - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { res[i] = jvalue[i].GetInt64(); } @@ -572,7 +571,7 @@ Generator::Parser::JSON::parse_json_int64_array(const conduit_rapidjson::Value & //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_int64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_int64_array(const conduit_json::Value &jvalue, Node &node) { // TODO: we can make this more efficient @@ -624,11 +623,11 @@ Generator::Parser::JSON::parse_json_int64_array(const conduit_rapidjson::Value & //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_uint64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_uint64_array(const conduit_json::Value &jvalue, std::vector &res) { res.resize(jvalue.Size(),0); - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { res[i] = jvalue[i].GetUint64(); } @@ -636,11 +635,11 @@ Generator::Parser::JSON::parse_json_uint64_array(const conduit_rapidjson::Value //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_uint64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_uint64_array(const conduit_json::Value &jvalue, uint64_array &res) { // for efficiency - assumes res is already alloced to proper size - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { res[i] = jvalue[i].GetUint64(); } @@ -648,7 +647,7 @@ Generator::Parser::JSON::parse_json_uint64_array(const conduit_rapidjson::Value //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_uint64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_uint64_array(const conduit_json::Value &jvalue, Node &node) { // TODO: we can make this more efficient @@ -700,11 +699,11 @@ Generator::Parser::JSON::parse_json_uint64_array(const conduit_rapidjson::Value //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_float64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_float64_array(const conduit_json::Value &jvalue, std::vector &res) { res.resize(jvalue.Size(),0); - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { if(jvalue[i].IsNumber()) { @@ -725,11 +724,11 @@ Generator::Parser::JSON::parse_json_float64_array(const conduit_rapidjson::Value //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_float64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_float64_array(const conduit_json::Value &jvalue, float64_array &res) { // for efficiency - assumes res is already alloced to proper size - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { if(jvalue[i].IsNumber()) { @@ -751,7 +750,7 @@ Generator::Parser::JSON::parse_json_float64_array(const conduit_rapidjson::Value //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_json_float64_array(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_json_float64_array(const conduit_json::Value &jvalue, Node &node) { // TODO: we can make this more efficient @@ -802,7 +801,7 @@ Generator::Parser::JSON::parse_json_float64_array(const conduit_rapidjson::Value //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_leaf_dtype(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_leaf_dtype(const conduit_json::Value &jvalue, index_t offset, DataType &dtype_res) { @@ -834,7 +833,7 @@ Generator::Parser::JSON::parse_leaf_dtype(const conduit_rapidjson::Value &jvalue { if (jvalue.HasMember(member_name)) { - const conduit_rapidjson::Value &json_value = jvalue[member_name]; + const conduit_json::Value &json_value = jvalue[member_name]; CONDUIT_ASSERT(json_value.IsNumber(), "JSON Generator error:\n" << "'" << member_name << "' must be a number "); @@ -844,7 +843,7 @@ Generator::Parser::JSON::parse_leaf_dtype(const conduit_rapidjson::Value &jvalue if (jvalue.HasMember("number_of_elements")) { - const conduit_rapidjson::Value &json_num_eles = jvalue["number_of_elements"]; + const conduit_json::Value &json_num_eles = jvalue["number_of_elements"]; if(json_num_eles.IsNumber()) { length = json_num_eles.GetUint64(); @@ -861,7 +860,7 @@ Generator::Parser::JSON::parse_leaf_dtype(const conduit_rapidjson::Value &jvalue // length is the old schema style, we should deprecate this path else if (jvalue.HasMember("length")) { - const conduit_rapidjson::Value &json_len = jvalue["length"]; + const conduit_json::Value &json_len = jvalue["length"]; if(json_len.IsNumber()) { length = json_len.GetUint64(); @@ -890,7 +889,7 @@ Generator::Parser::JSON::parse_leaf_dtype(const conduit_rapidjson::Value &jvalue index_t endianness = Endianness::DEFAULT_ID; if(jvalue.HasMember("endianness")) { - const conduit_rapidjson::Value &json_endianness = jvalue["endianness"]; + const conduit_json::Value &json_endianness = jvalue["endianness"]; if(json_endianness.IsString()) { std::string end_val(json_endianness.GetString()); @@ -949,7 +948,7 @@ Generator::Parser::JSON::parse_leaf_dtype(const conduit_rapidjson::Value &jvalue //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_inline_leaf(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_inline_leaf(const conduit_json::Value &jvalue, Node &node) { if(jvalue.IsString()) @@ -1048,7 +1047,7 @@ Generator::Parser::JSON::parse_inline_leaf(const conduit_rapidjson::Value &jvalu //---------------------------------------------------------------------------// void * -Generator::Parser::JSON::parse_inline_address(const conduit_rapidjson::Value &jvalue) +Generator::Parser::JSON::parse_inline_address(const conduit_json::Value &jvalue) { void * res = nullptr; if(jvalue.IsString()) @@ -1070,7 +1069,7 @@ Generator::Parser::JSON::parse_inline_address(const conduit_rapidjson::Value &jv //---------------------------------------------------------------------------// void -Generator::Parser::JSON::parse_inline_value(const conduit_rapidjson::Value &jvalue, +Generator::Parser::JSON::parse_inline_value(const conduit_json::Value &jvalue, Node &node) { if(jvalue.IsArray()) @@ -1122,7 +1121,7 @@ Generator::Parser::JSON::parse_inline_value(const conduit_rapidjson::Value &jval //---------------------------------------------------------------------------// void Generator::Parser::JSON::walk_json_schema(Schema *schema, - const conduit_rapidjson::Value &jvalue, + const conduit_json::Value &jvalue, index_t curr_offset) { // object cases @@ -1131,13 +1130,13 @@ Generator::Parser::JSON::walk_json_schema(Schema *schema, if (jvalue.HasMember("dtype")) { // if dtype is an object, we have a "list_of" case - const conduit_rapidjson::Value &dt_value = jvalue["dtype"]; + const conduit_json::Value &dt_value = jvalue["dtype"]; if(dt_value.IsObject()) { int length =1; if(jvalue.HasMember("length")) { - const conduit_rapidjson::Value &len_value = jvalue["length"]; + const conduit_json::Value &len_value = jvalue["length"]; if(len_value.IsObject() && len_value.HasMember("reference")) { @@ -1185,7 +1184,7 @@ Generator::Parser::JSON::walk_json_schema(Schema *schema, schema->set(DataType::object()); // loop over all entries - for (conduit_rapidjson::Value::ConstMemberIterator itr = + for (conduit_json::Value::ConstMemberIterator itr = jvalue.MemberBegin(); itr != jvalue.MemberEnd(); ++itr) { @@ -1205,7 +1204,7 @@ Generator::Parser::JSON::walk_json_schema(Schema *schema, // list role schema->set(DataType::list()); - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { Schema &curr_schema = schema->append(); curr_schema.set(DataType::list()); @@ -1232,7 +1231,7 @@ Generator::Parser::JSON::walk_json_schema(Schema *schema, void Generator::Parser::JSON::walk_pure_json_schema(Node *node, Schema *schema, - const conduit_rapidjson::Value &jvalue) + const conduit_json::Value &jvalue) { // object cases if(jvalue.IsObject()) @@ -1242,7 +1241,7 @@ Generator::Parser::JSON::walk_pure_json_schema(Node *node, // object role schema->set(DataType::object()); // loop over all entries - for (conduit_rapidjson::Value::ConstMemberIterator itr = jvalue.MemberBegin(); + for (conduit_json::Value::ConstMemberIterator itr = jvalue.MemberBegin(); itr != jvalue.MemberEnd(); ++itr) { std::string entry_name(itr->name.GetString()); @@ -1295,7 +1294,7 @@ Generator::Parser::JSON::walk_pure_json_schema(Node *node, // list role schema->set(DataType::list()); - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { schema->append(); Schema *curr_schema = schema->child_ptr(i); @@ -1361,7 +1360,7 @@ void Generator::Parser::JSON::walk_json_schema(Node *node, Schema *schema, void *data, - const conduit_rapidjson::Value &jvalue, + const conduit_json::Value &jvalue, index_t curr_offset) { // object cases @@ -1370,7 +1369,7 @@ Generator::Parser::JSON::walk_json_schema(Node *node, if (jvalue.HasMember("dtype")) { // if dtype is an object, we have a "list_of" case - const conduit_rapidjson::Value &dt_value = jvalue["dtype"]; + const conduit_json::Value &dt_value = jvalue["dtype"]; if(dt_value.IsObject()) { index_t length =1; @@ -1468,7 +1467,7 @@ Generator::Parser::JSON::walk_json_schema(Node *node, { schema->set(DataType::object()); // standard object case - loop over all entries - for (conduit_rapidjson::Value::ConstMemberIterator itr = + for (conduit_json::Value::ConstMemberIterator itr = jvalue.MemberBegin(); itr != jvalue.MemberEnd(); ++itr) { @@ -1513,7 +1512,7 @@ Generator::Parser::JSON::walk_json_schema(Node *node, { schema->set(DataType::list()); - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { schema->append(); Schema *curr_schema = schema->child_ptr(i); @@ -1565,7 +1564,7 @@ void Generator::Parser::JSON::walk_json_schema_external(Node *node, Schema *schema, void *data, - const conduit_rapidjson::Value &jvalue, + const conduit_json::Value &jvalue, index_t curr_offset) { // object cases @@ -1575,7 +1574,7 @@ Generator::Parser::JSON::walk_json_schema_external(Node *node, if (jvalue.HasMember("dtype")) { // if dtype is an object, we have a "list_of" case - const conduit_rapidjson::Value &dt_value = jvalue["dtype"]; + const conduit_json::Value &dt_value = jvalue["dtype"]; if(dt_value.IsObject()) { index_t length =1; @@ -1664,7 +1663,7 @@ Generator::Parser::JSON::walk_json_schema_external(Node *node, { schema->set(DataType::object()); // standard object case - loop over all entries - for (conduit_rapidjson::Value::ConstMemberIterator itr = + for (conduit_json::Value::ConstMemberIterator itr = jvalue.MemberBegin(); itr != jvalue.MemberEnd(); ++itr) { @@ -1710,7 +1709,7 @@ Generator::Parser::JSON::walk_json_schema_external(Node *node, { schema->set(DataType::list()); - for (conduit_rapidjson::SizeType i = 0; i < jvalue.Size(); i++) + for (conduit_json::SizeType i = 0; i < jvalue.Size(); i++) { schema->append(); Schema *curr_schema = schema->child_ptr(i); @@ -1759,7 +1758,7 @@ Generator::Parser::JSON::walk_json_schema_external(Node *node, //---------------------------------------------------------------------------// void Generator::Parser::JSON::parse_base64(Node *node, - const conduit_rapidjson::Value &jvalue) + const conduit_json::Value &jvalue) { // object case @@ -1814,7 +1813,7 @@ Generator::Parser::JSON::parse_base64(Node *node, //---------------------------------------------------------------------------// void Generator::Parser::JSON::parse_error_details(const std::string &json, - const conduit_rapidjson::Document &document, + const conduit_json::Document &document, std::ostream &os) { // provide message with line + char from rapidjson parse error offset @@ -3329,10 +3328,10 @@ Generator::walk(Schema &schema) const index_t curr_offset = 0; if (m_protocol.find("json") != std::string::npos) { - conduit_rapidjson::Document document; + conduit_json::Document document; std::string res = utils::json_sanitize(m_schema); - if(document.Parse(res.c_str()).HasParseError()) + if(document.Parse(res.c_str()).HasParseError()) { CONDUIT_JSON_PARSE_ERROR(res, document); } @@ -3365,10 +3364,10 @@ Generator::walk(Node &node) const // json, yaml, and conduit_base64_json don't leverage "data" if(m_protocol == "json") { - conduit_rapidjson::Document document; + conduit_json::Document document; std::string res = utils::json_sanitize(m_schema); - if(document.Parse(res.c_str()).HasParseError()) + if(document.Parse(res.c_str()).HasParseError()) { CONDUIT_JSON_PARSE_ERROR(res, document); } @@ -3386,10 +3385,10 @@ Generator::walk(Node &node) const } else if( m_protocol == "conduit_base64_json") { - conduit_rapidjson::Document document; + conduit_json::Document document; std::string res = utils::json_sanitize(m_schema); - if(document.Parse(res.c_str()).HasParseError()) + if(document.Parse(res.c_str()).HasParseError()) { CONDUIT_JSON_PARSE_ERROR(res, document); } @@ -3402,10 +3401,10 @@ Generator::walk(Node &node) const { // Note: conduit_json_external if case here for symmetry with gen / read options // this case is fully handled by conduit_json logic - conduit_rapidjson::Document document; + conduit_json::Document document; std::string res = utils::json_sanitize(m_schema); - if(document.Parse(res.c_str()).HasParseError()) + if(document.Parse(res.c_str()).HasParseError()) { CONDUIT_JSON_PARSE_ERROR(res, document); } @@ -3460,10 +3459,10 @@ Generator::walk_external(Node &node) const // if data is null, we can parse the schema via other 'walk' methods if(m_protocol == "json") { - conduit_rapidjson::Document document; + conduit_json::Document document; std::string res = utils::json_sanitize(m_schema); - if(document.Parse(res.c_str()).HasParseError()) + if(document.Parse(res.c_str()).HasParseError()) { CONDUIT_JSON_PARSE_ERROR(res, document); } @@ -3481,10 +3480,10 @@ Generator::walk_external(Node &node) const } else if( m_protocol == "conduit_base64_json") { - conduit_rapidjson::Document document; + conduit_json::Document document; std::string res = utils::json_sanitize(m_schema); - if(document.Parse(res.c_str()).HasParseError()) + if(document.Parse(res.c_str()).HasParseError()) { CONDUIT_JSON_PARSE_ERROR(res, document); } @@ -3496,10 +3495,10 @@ Generator::walk_external(Node &node) const { // Note: conduit_json_external if case here for symmetry with gen / read options // this case is fully handled by conduit_json logic - conduit_rapidjson::Document document; + conduit_json::Document document; std::string res = utils::json_sanitize(m_schema); - if(document.Parse(res.c_str()).HasParseError()) + if(document.Parse(res.c_str()).HasParseError()) { CONDUIT_JSON_PARSE_ERROR(res, document); } diff --git a/src/libs/conduit/conduit_json.hpp b/src/libs/conduit/conduit_json.hpp new file mode 100644 index 000000000..858922e8e --- /dev/null +++ b/src/libs/conduit/conduit_json.hpp @@ -0,0 +1,13 @@ +#ifndef CONDUIT_JSON_HPP +#define CONDUIT_JSON_HPP + +#ifdef USE_YYJSON + #include "conduit_yyjson.h" + #define conduit_json conduit_yyjson +#else + #include "rapidjson/document.h" + #include "rapidjson/error/en.h" + #define conduit_json conduit_rapidjson +#endif + +#endif diff --git a/src/tests/conduit/t_conduit_node.cpp b/src/tests/conduit/t_conduit_node.cpp index ef25750da..375596e1a 100644 --- a/src/tests/conduit/t_conduit_node.cpp +++ b/src/tests/conduit/t_conduit_node.cpp @@ -12,7 +12,7 @@ #include #include "gtest/gtest.h" -#include "rapidjson/document.h" +#include "conduit_json.hpp" using namespace conduit; //----------------------------------------------------------------------------- @@ -198,7 +198,7 @@ TEST(conduit_node, simple_schema) std::string res = n.schema().to_json(); std::cout << res; - conduit_rapidjson::Document d; + conduit_json::Document d; d.Parse<0>(res.c_str()); EXPECT_TRUE(d.HasMember("a")); diff --git a/src/tests/conduit/t_conduit_node_set.cpp b/src/tests/conduit/t_conduit_node_set.cpp index a5ba6a93d..7d76b6bcc 100644 --- a/src/tests/conduit/t_conduit_node_set.cpp +++ b/src/tests/conduit/t_conduit_node_set.cpp @@ -12,7 +12,7 @@ #include #include "gtest/gtest.h" -#include "rapidjson/document.h" +#include "conduit_json.hpp" using namespace conduit; //----------------------------------------------------------------------------- diff --git a/src/tests/conduit/t_conduit_node_to_array.cpp b/src/tests/conduit/t_conduit_node_to_array.cpp index 604b2f5ad..c34a579f7 100644 --- a/src/tests/conduit/t_conduit_node_to_array.cpp +++ b/src/tests/conduit/t_conduit_node_to_array.cpp @@ -12,7 +12,7 @@ #include #include "gtest/gtest.h" -#include "rapidjson/document.h" +#include "conduit_json.hpp" using namespace conduit; // TODO(JRC): Figure out if there's any better way to facilitate these conversions diff --git a/src/tests/conduit/t_conduit_node_type_dispatch.cpp b/src/tests/conduit/t_conduit_node_type_dispatch.cpp index 341d9c07d..5ca323546 100644 --- a/src/tests/conduit/t_conduit_node_type_dispatch.cpp +++ b/src/tests/conduit/t_conduit_node_type_dispatch.cpp @@ -12,7 +12,7 @@ #include #include "gtest/gtest.h" -#include "rapidjson/document.h" +#include "conduit_json.hpp" using namespace conduit; using namespace conduit::utils; diff --git a/src/tests/conduit/t_conduit_node_update.cpp b/src/tests/conduit/t_conduit_node_update.cpp index 0803804b4..f169250a1 100644 --- a/src/tests/conduit/t_conduit_node_update.cpp +++ b/src/tests/conduit/t_conduit_node_update.cpp @@ -13,7 +13,7 @@ #include #include "gtest/gtest.h" -#include "rapidjson/document.h" +#include "conduit_json.hpp" using namespace conduit; //----------------------------------------------------------------------------- diff --git a/src/tests/docs/t_conduit_docs_tutorial_basics.cpp b/src/tests/docs/t_conduit_docs_tutorial_basics.cpp index 719e7630b..80778051d 100644 --- a/src/tests/docs/t_conduit_docs_tutorial_basics.cpp +++ b/src/tests/docs/t_conduit_docs_tutorial_basics.cpp @@ -15,7 +15,7 @@ #include #include "gtest/gtest.h" -#include "rapidjson/document.h" +#include "conduit_json.hpp" using namespace conduit; diff --git a/src/tests/thirdparty/t_rapidjson_smoke.cpp b/src/tests/thirdparty/t_rapidjson_smoke.cpp index c28798b33..d0abd6cf2 100644 --- a/src/tests/thirdparty/t_rapidjson_smoke.cpp +++ b/src/tests/thirdparty/t_rapidjson_smoke.cpp @@ -8,15 +8,15 @@ /// //----------------------------------------------------------------------------- -#include "rapidjson/document.h" +#include "conduit_json.hpp" #include "gtest/gtest.h" //----------------------------------------------------------------------------- -TEST(rapidjson_smoke, basic_use) +TEST(json_smoke, basic_use) { const char json[] = "{ \"hello\" : \"world\" }"; - conduit_rapidjson::Document d; + conduit_json::Document d; d.Parse<0>(json); ASSERT_STREQ(d["hello"].GetString(),"world"); diff --git a/src/thirdparty_builtin/yyjson/conduit_yyjson.h b/src/thirdparty_builtin/yyjson/conduit_yyjson.h new file mode 100644 index 000000000..36fc4cef6 --- /dev/null +++ b/src/thirdparty_builtin/yyjson/conduit_yyjson.h @@ -0,0 +1,314 @@ +#ifndef CONDUIT_YYJSON_H +#define CONDUIT_YYJSON_H + +#include +#include +#include + +using yyjson_error_code_and_msg = std::pair; +std::string GetParseError_En(yyjson_error_code_and_msg errorCodeAndMessage) +{ + std::stringstream message; + message << "YYJSON error code " << errorCodeAndMessage.first; + std::string errorMessage = "Unknown error code"; + switch(errorCodeAndMessage.first) + { + case YYJSON_READ_SUCCESS: + errorMessage = "Success, no error."; + break; + case YYJSON_READ_ERROR_INVALID_PARAMETER: + errorMessage = "Invalid parameter, such as NULL input string or 0 input length."; + break; + case YYJSON_READ_ERROR_MEMORY_ALLOCATION: + errorMessage = "Memory allocation failure occurs."; + break; + case YYJSON_READ_ERROR_EMPTY_CONTENT: + errorMessage = "Input JSON string is empty."; + break; + case YYJSON_READ_ERROR_UNEXPECTED_CONTENT: + errorMessage = "Unexpected content after document, such as `[123]abc`."; + break; + case YYJSON_READ_ERROR_UNEXPECTED_END: + errorMessage = "Unexpected ending, such as `[123`."; + break; + case YYJSON_READ_ERROR_UNEXPECTED_CHARACTER: + errorMessage = "Unexpected character inside the document, such as `[abc]`."; + break; + case YYJSON_READ_ERROR_JSON_STRUCTURE: + errorMessage = "Invalid JSON structure, such as `[1,]`."; + break; + case YYJSON_READ_ERROR_INVALID_COMMENT: + errorMessage = "Invalid comment, such as unclosed multi-line comment."; + break; + case YYJSON_READ_ERROR_INVALID_NUMBER: + errorMessage = "Invalid number, such as `123.e12`, `000`."; + break; + case YYJSON_READ_ERROR_INVALID_STRING: + errorMessage = "Invalid string, such as invalid escaped character inside a string."; + break; + case YYJSON_READ_ERROR_LITERAL: + errorMessage = "Invalid JSON literal, such as `truu`."; + break; + case YYJSON_READ_ERROR_FILE_OPEN: + errorMessage = "Failed to open a file."; + break; + case YYJSON_READ_ERROR_FILE_READ: + errorMessage = "Failed to read a file."; + break; + default: + break; + } + + message << " (" << errorMessage << "): "; + message << errorCodeAndMessage.second; + return message.str(); +} + +namespace conduit_yyjson +{ +using ParseFlag = int; +static const ParseFlag kParseNoFlags = 0; +using SizeType = size_t; + +/* + * Thin wrapper to adapt the yyjson to the rapidjson API. + */ +class Value +{ +public: + Value(yyjson_val* value) : value(value) + { + } + + bool IsNumber() const + { + return yyjson_is_num(value); + } + + bool IsUint64() const + { + return yyjson_is_uint(value); + } + bool IsInt64() const + { + return yyjson_is_sint(value); + } + bool IsUint() const + { + return yyjson_is_uint(value); + } + bool IsInt() const + { + return yyjson_is_int(value); + } + bool IsDouble() const + { + return yyjson_is_real(value); + } + bool IsString() const + { + return yyjson_is_str(value); + } + bool IsObject() const + { + return yyjson_is_obj(value); + } + bool IsArray() const + { + return yyjson_is_arr(value); + } + bool IsBool() const + { + return yyjson_is_bool(value); + } + bool IsNull() const + { + return yyjson_is_null(value); + } + bool IsTrue() const + { + return yyjson_is_true(value); + } + const char * GetString() const + { + return yyjson_get_str(value); + } + SizeType Size() const + { + return yyjson_get_len(value); + } + int64_t GetInt64() const + { + return yyjson_get_sint(value); + } + uint64_t GetUint64() const + { + return yyjson_get_uint(value); + } + double GetDouble() const + { + return yyjson_get_real(value); + } + bool GetBool() const + { + return yyjson_get_bool(value); + } + int GetInt() const + { + return yyjson_get_int(value); + } + bool HasMember(const char* name) const + { + return yyjson_obj_get(value, name) != nullptr; + } + Value operator[](SizeType index) const + { + return Value(yyjson_arr_get(value, index)); + } + Value operator[](const char* name) const + { + return Value(yyjson_obj_get(value, name)); + } + + class ConstMemberIterator + { + public: + ConstMemberIterator(const yyjson_obj_iter& iter) : + iterator(iter), + content{nullptr, nullptr} + { + Next(); + } + ConstMemberIterator() : + content{nullptr, nullptr} + { + iterator.obj = nullptr; + } + ConstMemberIterator& operator++() + { + Next(); + return *this; + } + bool operator!=(const ConstMemberIterator& other) + { + return other.iterator.obj != iterator.obj; + } + + class Name + { + public: + Name(yyjson_val* value) : value(value){} + std::string GetString() const + { + return yyjson_get_str(value); + } + bool IsValid() const + { + return value != nullptr; + } + private: + yyjson_val* value; + }; + + // Trick to implement the -> operator to fake the iterator. + struct Content + { + Name name; + yyjson_val* value; + }; + const Content* operator->() const + { + return &content; + } + + private: + void Next() + { + auto key = yyjson_obj_iter_next(&iterator); + if(key != nullptr) + { + content.value = yyjson_obj_iter_get_val(key); + content.name = Name(key); + } + else + { + iterator.obj = nullptr; + } + } + yyjson_obj_iter iterator; + Content content; + }; + + ConstMemberIterator MemberBegin() const + { + auto iterator = yyjson_obj_iter_with(value); + return ConstMemberIterator(iterator); + } + ConstMemberIterator MemberEnd() const + { + return ConstMemberIterator(); + } + +protected: + void SetValue(yyjson_val* newValue) + { + value = newValue; + } +private: + yyjson_val* value; +}; + +/* + * Thin wrapper to adapt the yyjson_doc to rapidjson::Document API + */ +class Document : public Value +{ +public: + Document() : Value(nullptr), doc(nullptr), hasParseError(false) + { + } + ~Document() + { + yyjson_doc_free(doc); + } + + template + Document& Parse(const char* text) + { + yyjson_doc_free(doc); + doc = yyjson_read_opts(const_cast(text), strlen(text), flag, nullptr, &errorInformation); + if(doc) + { + auto *root = yyjson_doc_get_root(doc); + this->SetValue(root); + } + else + { + hasParseError = true; + } + return *this; + } + + bool HasParseError() const + { + return hasParseError; + } + size_t GetErrorOffset() const + { + return errorInformation.pos; + } + std::pair GetParseError() const + { + return std::make_pair(errorInformation.code, errorInformation.msg); + } + + +private: + yyjson_doc* doc; + bool hasParseError; + yyjson_read_err errorInformation; +}; + +} + +#endif