From 5ed80d308d3b33ae251f85c3f799fbbfeb0cc46d Mon Sep 17 00:00:00 2001 From: Niels Date: Sat, 9 May 2015 22:49:21 +0200 Subject: [PATCH] some parsing performance improvements --- src/json.hpp | 158 ++++++++++++++++++++++++---------------------- src/json.hpp.re2c | 158 ++++++++++++++++++++++++---------------------- test/unit.cpp | 2 +- 3 files changed, 167 insertions(+), 151 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 87faa027..30b8f117 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -147,6 +147,23 @@ class basic_json using list_init_t = std::initializer_list; + ///////////////////////////////// + // JSON value type enumeration // + ///////////////////////////////// + + /// JSON value type enumeration + enum class value_t : uint8_t + { + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (integer) + number_float, ///< number value (floating-point) + discarded ///< (internal) indicates the parser callback chose not to keep the value + }; + //////////////////////// // JSON value storage // //////////////////////// @@ -175,24 +192,60 @@ class basic_json json_value(number_integer_t v) : number_integer(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) : number_float(v) {} - }; + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case (value_t::null): + case (value_t::discarded): + { + break; + } + case (value_t::object): + { + AllocatorType alloc; + object = alloc.allocate(1); + alloc.construct(object); + break; + } - ///////////////////////////////// - // JSON value type enumeration // - ///////////////////////////////// + case (value_t::array): + { + AllocatorType alloc; + array = alloc.allocate(1); + alloc.construct(array); + break; + } - /// JSON value type enumeration - enum class value_t : uint8_t - { - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (integer) - number_float, ///< number value (floating-point) - discarded ///< (internal) indicates the parser callback chose not to keep the value + case (value_t::string): + { + AllocatorType alloc; + string = alloc.allocate(1); + alloc.construct(string, ""); + break; + } + + case (value_t::boolean): + { + boolean = boolean_t(false); + break; + } + + case (value_t::number_integer): + { + number_integer = number_integer_t(0); + break; + } + + case (value_t::number_float): + { + number_float = number_float_t(0.0); + break; + } + } + } }; ////////////////////////// @@ -261,59 +314,8 @@ class basic_json @exception std::bad_alloc if allocation for object, array, or string fails. */ inline basic_json(const value_t value) - : m_type(value) - { - switch (m_type) - { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::object): - { - AllocatorType alloc; - m_value.object = alloc.allocate(1); - alloc.construct(m_value.object); - break; - } - - case (value_t::array): - { - AllocatorType alloc; - m_value.array = alloc.allocate(1); - alloc.construct(m_value.array); - break; - } - - case (value_t::string): - { - AllocatorType alloc; - m_value.string = alloc.allocate(1); - alloc.construct(m_value.string, ""); - break; - } - - case (value_t::boolean): - { - m_value.boolean = boolean_t(false); - break; - } - - case (value_t::number_integer): - { - m_value.number_integer = number_integer_t(0); - break; - } - - case (value_t::number_float): - { - m_value.number_float = number_float_t(0.0); - break; - } - } - } + : m_type(value), m_value(value) + {} /*! @brief create a null object (implicitly) @@ -4629,7 +4631,8 @@ basic_json_parser_59: if (keep and (keep = callback(depth++, parse_event_t::object_start, result))) { // explicitly set result to object to cope with {} - result = basic_json(value_t::object); + result.m_type = value_t::object; + result.m_value = json_value(value_t::object); } // read next token @@ -4698,7 +4701,8 @@ basic_json_parser_59: if (keep and (keep = callback(depth++, parse_event_t::array_start, result))) { // explicitly set result to object to cope with [] - result = basic_json(value_t::array); + result.m_type = value_t::array; + result.m_value = json_value(value_t::array); } // read next token @@ -4750,7 +4754,7 @@ basic_json_parser_59: case (lexer::token_type::literal_null): { get_token(); - result = basic_json(nullptr); + result.m_type = value_t::null; break; } @@ -4765,14 +4769,16 @@ basic_json_parser_59: case (lexer::token_type::literal_true): { get_token(); - result = basic_json(true); + result.m_type = value_t::boolean; + result.m_value = true; break; } case (lexer::token_type::literal_false): { get_token(); - result = basic_json(false); + result.m_type = value_t::boolean; + result.m_value = false; break; } @@ -4795,12 +4801,14 @@ basic_json_parser_59: if (approx(float_val, static_cast(int_val))) { // we basic_json not lose precision -> return int - result = basic_json(int_val); + result.m_type = value_t::number_integer; + result.m_value = int_val; } else { // we would lose precision -> returnfloat - result = basic_json(float_val); + result.m_type = value_t::number_float; + result.m_value = float_val; } break; } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index f456e90f..e5534daa 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -147,6 +147,23 @@ class basic_json using list_init_t = std::initializer_list; + ///////////////////////////////// + // JSON value type enumeration // + ///////////////////////////////// + + /// JSON value type enumeration + enum class value_t : uint8_t + { + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (integer) + number_float, ///< number value (floating-point) + discarded ///< (internal) indicates the parser callback chose not to keep the value + }; + //////////////////////// // JSON value storage // //////////////////////// @@ -175,24 +192,60 @@ class basic_json json_value(number_integer_t v) : number_integer(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) : number_float(v) {} - }; + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case (value_t::null): + case (value_t::discarded): + { + break; + } + case (value_t::object): + { + AllocatorType alloc; + object = alloc.allocate(1); + alloc.construct(object); + break; + } - ///////////////////////////////// - // JSON value type enumeration // - ///////////////////////////////// + case (value_t::array): + { + AllocatorType alloc; + array = alloc.allocate(1); + alloc.construct(array); + break; + } - /// JSON value type enumeration - enum class value_t : uint8_t - { - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (integer) - number_float, ///< number value (floating-point) - discarded ///< (internal) indicates the parser callback chose not to keep the value + case (value_t::string): + { + AllocatorType alloc; + string = alloc.allocate(1); + alloc.construct(string, ""); + break; + } + + case (value_t::boolean): + { + boolean = boolean_t(false); + break; + } + + case (value_t::number_integer): + { + number_integer = number_integer_t(0); + break; + } + + case (value_t::number_float): + { + number_float = number_float_t(0.0); + break; + } + } + } }; ////////////////////////// @@ -261,59 +314,8 @@ class basic_json @exception std::bad_alloc if allocation for object, array, or string fails. */ inline basic_json(const value_t value) - : m_type(value) - { - switch (m_type) - { - case (value_t::null): - case (value_t::discarded): - { - break; - } - - case (value_t::object): - { - AllocatorType alloc; - m_value.object = alloc.allocate(1); - alloc.construct(m_value.object); - break; - } - - case (value_t::array): - { - AllocatorType alloc; - m_value.array = alloc.allocate(1); - alloc.construct(m_value.array); - break; - } - - case (value_t::string): - { - AllocatorType alloc; - m_value.string = alloc.allocate(1); - alloc.construct(m_value.string, ""); - break; - } - - case (value_t::boolean): - { - m_value.boolean = boolean_t(false); - break; - } - - case (value_t::number_integer): - { - m_value.number_integer = number_integer_t(0); - break; - } - - case (value_t::number_float): - { - m_value.number_float = number_float_t(0.0); - break; - } - } - } + : m_type(value), m_value(value) + {} /*! @brief create a null object (implicitly) @@ -3935,7 +3937,8 @@ class basic_json if (keep and (keep = callback(depth++, parse_event_t::object_start, result))) { // explicitly set result to object to cope with {} - result = basic_json(value_t::object); + result.m_type = value_t::object; + result.m_value = json_value(value_t::object); } // read next token @@ -4004,7 +4007,8 @@ class basic_json if (keep and (keep = callback(depth++, parse_event_t::array_start, result))) { // explicitly set result to object to cope with [] - result = basic_json(value_t::array); + result.m_type = value_t::array; + result.m_value = json_value(value_t::array); } // read next token @@ -4056,7 +4060,7 @@ class basic_json case (lexer::token_type::literal_null): { get_token(); - result = basic_json(nullptr); + result.m_type = value_t::null; break; } @@ -4071,14 +4075,16 @@ class basic_json case (lexer::token_type::literal_true): { get_token(); - result = basic_json(true); + result.m_type = value_t::boolean; + result.m_value = true; break; } case (lexer::token_type::literal_false): { get_token(); - result = basic_json(false); + result.m_type = value_t::boolean; + result.m_value = false; break; } @@ -4101,12 +4107,14 @@ class basic_json if (approx(float_val, static_cast(int_val))) { // we basic_json not lose precision -> return int - result = basic_json(int_val); + result.m_type = value_t::number_integer; + result.m_value = int_val; } else { // we would lose precision -> returnfloat - result = basic_json(float_val); + result.m_type = value_t::number_float; + result.m_value = float_val; } break; } diff --git a/test/unit.cpp b/test/unit.cpp index b41c3846..d304934c 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -8662,7 +8662,7 @@ TEST_CASE("compliance tests from nativejson-benchmark") TEST_STRING("[\"\\u20AC\"]", "\xE2\x82\xAC"); // Euro sign U+20AC TEST_STRING("[\"\\uD834\\uDD1E\"]", "\xF0\x9D\x84\x9E"); // G clef sign U+1D11E } - + SECTION("roundtrip") { // test cases are from https://github.com/miloyip/nativejson-benchmark/tree/master/data/roundtrip