From 4e7501e59aff4c9dc27b4175bdefb49319d82ed3 Mon Sep 17 00:00:00 2001 From: Niels Date: Fri, 22 Jul 2016 15:34:45 +0200 Subject: [PATCH] minor changes - fixed a bug that did not discard strings with control characters between 0x10 and 0x1f - added termination proofs for two important loops - made get_ref() constexpr --- doc/images/callback_events.png | Bin 0 -> 46039 bytes src/json.hpp | 125 +++++++++++++++++++++++----- src/json.hpp.re2c | 143 ++++++++++++++++++++++++++------- test/src/unit.cpp | 33 ++++++++ 4 files changed, 248 insertions(+), 53 deletions(-) create mode 100644 doc/images/callback_events.png diff --git a/doc/images/callback_events.png b/doc/images/callback_events.png new file mode 100644 index 0000000000000000000000000000000000000000..09aa2b38355a7227b444b5b6779f2c7ca9fa05d6 GIT binary patch literal 46039 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 UkR#h1#Q*>R07*qoM6N<$f`xGfOaK4? literal 0 HcmV?d00001 diff --git a/src/json.hpp b/src/json.hpp index 29155327..00bee970 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -717,7 +717,19 @@ class basic_json This enumeration collects the different JSON types. It is internally used to distinguish the stored values, and the functions @ref is_null(), @ref is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref - is_number(), and @ref is_discarded() rely on it. + is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and + @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and + @ref is_structured() rely on it. + + @note There are three enumeration entries (number_integer, + number_unsigned, and number_float), because the library distinguishes + these three types for numbers: @ref number_unsigned_t is used for unsigned + integers, @ref number_integer_t is used for signed integers, and @ref + number_float_t is used for floating-point numbers or to approximate + integers which do not fit in the limits of their respective type. + + @sa @ref basic_json(const value_t value_type) -- create a JSON value with + the default value for a given type @since version 1.0.0 */ @@ -728,7 +740,7 @@ class basic_json array, ///< array (ordered collection of values) string, ///< string value boolean, ///< boolean value - number_integer, ///< number value (integer) + number_integer, ///< number value (signed integer) number_unsigned, ///< number value (unsigned integer) number_float, ///< number value (floating-point) discarded ///< discarded by the the parser callback function @@ -758,7 +770,24 @@ class basic_json /*! @brief a JSON value - The actual storage for a JSON value of the @ref basic_json class. + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. @since version 1.0.0 */ @@ -874,6 +903,8 @@ class basic_json This enumeration lists the parser events that can trigger calling a callback function of type @ref parser_callback_t during parsing. + @image html callback_events.png "Example when certain parse events are triggered" + @since version 1.0.0 */ enum class parse_event_t : uint8_t @@ -916,6 +947,8 @@ class basic_json parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + @image html callback_events.png "Example when certain parse events are triggered" + Discarding a value (i.e., returning `false`) has different effects depending on the context in which function was called: @@ -2773,21 +2806,16 @@ class basic_json type of the current JSON */ template - static ReferenceType get_ref_impl(ThisType& obj) + static constexpr ReferenceType get_ref_impl(ThisType& obj) { - // delegate the call to get_ptr<>() + // helper type using PointerType = typename std::add_pointer::type; - auto ptr = obj.template get_ptr(); - if (ptr != nullptr) - { - return *ptr; - } - else - { - throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + - obj.type_name()); - } + // delegate the call to get_ptr<>() + return obj.template get_ptr() != nullptr + ? *obj.template get_ptr() + : throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); } public: @@ -3015,7 +3043,7 @@ class basic_json std::is_reference::value and std::is_const::type>::value , int>::type = 0> - ReferenceType get_ref() const + constexpr ReferenceType get_ref() const { // delegate call to get_ref_impl return get_ref_impl(*this); @@ -7286,6 +7314,8 @@ class basic_json @throw std::invalid_argument if the low surrogate is invalid; example: `""missing or wrong low surrogate""` + @complexity Constant. + @see */ static string_t to_unicode(const std::size_t codepoint1, @@ -7402,6 +7432,17 @@ class basic_json function consists of a large block of code with `goto` jumps. @return the class of the next token read from the buffer + + @complexity Linear in the length of the input.\n + + Proposition: The loop below will always terminate for finite input.\n + + Proof (by contradiction): Assume a finite input. To loop forever, the + loop must never hit code with a `break` statement. The only code + snippets without a `break` statement are the continue statements for + whitespace and byte-order-marks. To loop forever, the input must be an + infinite sequence of whitespace or byte-order-marks. This contradicts + the assumption of finite input, q.e.d. */ token_type scan() noexcept { @@ -7422,8 +7463,8 @@ class basic_json { 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 0, 0, 32, 0, 0, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 160, 128, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, @@ -7602,7 +7643,7 @@ basic_json_parser_6: basic_json_parser_9: yyaccept = 0; yych = *(m_marker = ++m_cursor); - if (yych <= 0x0F) + if (yych <= 0x1F) { goto basic_json_parser_5; } @@ -7760,7 +7801,7 @@ basic_json_parser_32: { goto basic_json_parser_31; } - if (yych <= 0x0F) + if (yych <= 0x1F) { goto basic_json_parser_33; } @@ -8233,16 +8274,53 @@ basic_json_parser_63: according to the nature of the escape. Some escapes create new characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape - `"\\uxxxx"` need special care. In this case, to_unicode takes care - of the construction of the values. + `"\\uxxxx"` need special care. In this case, @ref to_unicode takes + care of the construction of the values. 2. Unescaped characters are copied as is. + @pre `m_cursor - m_start >= 2`, meaning the length of the last token + is at least 2 bytes which is trivially true for any string (which + consists of at least two quotes). + + " c1 c2 c3 ... " + ^ ^ + m_start m_cursor + + @complexity Linear in the length of the string.\n + + Lemma: The loop body will always terminate.\n + + Proof (by contradiction): Assume the loop body does not terminate. As + the loop body does not contain another loop, one of the called + functions must never return. The called functions are `std::strtoul` + and @ref to_unicode. Neither function can loop forever, so the loop + body will never loop forever which contradicts the assumption that the + loop body does not terminate, q.e.d.\n + + Lemma: The loop condition for the for loop is eventually false.\n + + Proof (by contradiction): Assume the loop does not terminate. Due to + the above lemma, this can only be due to a tautological loop + condition; that is, the loop condition i < m_cursor - 1 must always be + true. Let x be the change of i for any loop iteration. Then + m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. + This can be rephrased to m_cursor - m_start - 2 > x. With the + precondition, we x <= 0, meaning that the loop condition holds + indefinitly if i is always decreased. However, observe that the + value of i is strictly increasing with each iteration, as it is + incremented by 1 in the iteration expression and never + decremented inside the loop body. Hence, the loop condition + will eventually be false which contradicts the assumption that + the loop condition is a tautology, q.e.d. + @return string value of current token without opening and closing quotes @throw std::out_of_range if to_unicode fails */ string_t get_string() const { + assert(m_cursor - m_start >= 2); + string_t result; result.reserve(static_cast(m_cursor - m_start - 2)); @@ -8915,6 +8993,8 @@ basic_json_parser_63: /*! @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. */ reference get_and_create(reference j) const { @@ -9352,6 +9432,7 @@ basic_json_parser_63: basic_json result; // iterate the JSON object values + assert(value.m_value.object != nullptr); for (const auto& element : *value.m_value.object) { if (not element.second.is_primitive()) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 8eeedefe..05c49ec5 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -717,7 +717,19 @@ class basic_json This enumeration collects the different JSON types. It is internally used to distinguish the stored values, and the functions @ref is_null(), @ref is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref - is_number(), and @ref is_discarded() rely on it. + is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and + @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and + @ref is_structured() rely on it. + + @note There are three enumeration entries (number_integer, + number_unsigned, and number_float), because the library distinguishes + these three types for numbers: @ref number_unsigned_t is used for unsigned + integers, @ref number_integer_t is used for signed integers, and @ref + number_float_t is used for floating-point numbers or to approximate + integers which do not fit in the limits of their respective type. + + @sa @ref basic_json(const value_t value_type) -- create a JSON value with + the default value for a given type @since version 1.0.0 */ @@ -728,7 +740,7 @@ class basic_json array, ///< array (ordered collection of values) string, ///< string value boolean, ///< boolean value - number_integer, ///< number value (integer) + number_integer, ///< number value (signed integer) number_unsigned, ///< number value (unsigned integer) number_float, ///< number value (floating-point) discarded ///< discarded by the the parser callback function @@ -758,7 +770,24 @@ class basic_json /*! @brief a JSON value - The actual storage for a JSON value of the @ref basic_json class. + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. @since version 1.0.0 */ @@ -874,6 +903,8 @@ class basic_json This enumeration lists the parser events that can trigger calling a callback function of type @ref parser_callback_t during parsing. + @image html callback_events.png "Example when certain parse events are triggered" + @since version 1.0.0 */ enum class parse_event_t : uint8_t @@ -916,6 +947,8 @@ class basic_json parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + @image html callback_events.png "Example when certain parse events are triggered" + Discarding a value (i.e., returning `false`) has different effects depending on the context in which function was called: @@ -2773,21 +2806,16 @@ class basic_json type of the current JSON */ template - static ReferenceType get_ref_impl(ThisType& obj) + static constexpr ReferenceType get_ref_impl(ThisType& obj) { - // delegate the call to get_ptr<>() + // helper type using PointerType = typename std::add_pointer::type; - auto ptr = obj.template get_ptr(); - if (ptr != nullptr) - { - return *ptr; - } - else - { - throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + - obj.type_name()); - } + // delegate the call to get_ptr<>() + return obj.template get_ptr() != nullptr + ? *obj.template get_ptr() + : throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); } public: @@ -3015,7 +3043,7 @@ class basic_json std::is_reference::value and std::is_const::type>::value , int>::type = 0> - ReferenceType get_ref() const + constexpr ReferenceType get_ref() const { // delegate call to get_ref_impl return get_ref_impl(*this); @@ -7286,6 +7314,8 @@ class basic_json @throw std::invalid_argument if the low surrogate is invalid; example: `""missing or wrong low surrogate""` + @complexity Constant. + @see */ static string_t to_unicode(const std::size_t codepoint1, @@ -7402,6 +7432,17 @@ class basic_json function consists of a large block of code with `goto` jumps. @return the class of the next token read from the buffer + + @complexity Linear in the length of the input.\n + + Proposition: The loop below will always terminate for finite input.\n + + Proof (by contradiction): Assume a finite input. To loop forever, the + loop must never hit code with a `break` statement. The only code + snippets without a `break` statement are the continue statements for + whitespace and byte-order-marks. To loop forever, the input must be an + infinite sequence of whitespace or byte-order-marks. This contradicts + the assumption of finite input, q.e.d. */ token_type scan() noexcept { @@ -7447,32 +7488,32 @@ class basic_json "false" { last_token_type = token_type::literal_false; break; } // number - decimal_point = [.]; + decimal_point = "."; digit = [0-9]; digit_1_9 = [1-9]; - e = [eE]; - minus = [-]; - plus = [+]; - zero = [0]; - exp = e (minus|plus)? digit+; + e = "e" | "E"; + minus = "-"; + plus = "+"; + zero = "0"; + exp = e (minus | plus)? digit+; frac = decimal_point digit+; - int = (zero|digit_1_9 digit*); + int = (zero | digit_1_9 digit*); number = minus? int frac? exp?; number { last_token_type = token_type::value_number; break; } // string - quotation_mark = ["]; - escape = [\\]; - unescaped = [^"\\\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F]; - single_escaped = ["\\/bfnrt]; - unicode_escaped = [u][0-9a-fA-F]{4}; + quotation_mark = "\""; + escape = "\\"; + unescaped = [^"\\\x00-\x1f]; + single_escaped = "\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t"; + unicode_escaped = "u" [0-9a-fA-F]{4}; escaped = escape (single_escaped | unicode_escaped); char = unescaped | escaped; string = quotation_mark char* quotation_mark; string { last_token_type = token_type::value_string; break; } // end of file - '\000' { last_token_type = token_type::end_of_input; break; } + "\000" { last_token_type = token_type::end_of_input; break; } // anything else is an error . { last_token_type = token_type::parse_error; break; } @@ -7530,16 +7571,53 @@ class basic_json according to the nature of the escape. Some escapes create new characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape - `"\\uxxxx"` need special care. In this case, to_unicode takes care - of the construction of the values. + `"\\uxxxx"` need special care. In this case, @ref to_unicode takes + care of the construction of the values. 2. Unescaped characters are copied as is. + @pre `m_cursor - m_start >= 2`, meaning the length of the last token + is at least 2 bytes which is trivially true for any string (which + consists of at least two quotes). + + " c1 c2 c3 ... " + ^ ^ + m_start m_cursor + + @complexity Linear in the length of the string.\n + + Lemma: The loop body will always terminate.\n + + Proof (by contradiction): Assume the loop body does not terminate. As + the loop body does not contain another loop, one of the called + functions must never return. The called functions are `std::strtoul` + and @ref to_unicode. Neither function can loop forever, so the loop + body will never loop forever which contradicts the assumption that the + loop body does not terminate, q.e.d.\n + + Lemma: The loop condition for the for loop is eventually false.\n + + Proof (by contradiction): Assume the loop does not terminate. Due to + the above lemma, this can only be due to a tautological loop + condition; that is, the loop condition i < m_cursor - 1 must always be + true. Let x be the change of i for any loop iteration. Then + m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. + This can be rephrased to m_cursor - m_start - 2 > x. With the + precondition, we x <= 0, meaning that the loop condition holds + indefinitly if i is always decreased. However, observe that the + value of i is strictly increasing with each iteration, as it is + incremented by 1 in the iteration expression and never + decremented inside the loop body. Hence, the loop condition + will eventually be false which contradicts the assumption that + the loop condition is a tautology, q.e.d. + @return string value of current token without opening and closing quotes @throw std::out_of_range if to_unicode fails */ string_t get_string() const { + assert(m_cursor - m_start >= 2); + string_t result; result.reserve(static_cast(m_cursor - m_start - 2)); @@ -8212,6 +8290,8 @@ class basic_json /*! @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. */ reference get_and_create(reference j) const { @@ -8649,6 +8729,7 @@ class basic_json basic_json result; // iterate the JSON object values + assert(value.m_value.object != nullptr); for (const auto& element : *value.m_value.object) { if (not element.second.is_primitive()) diff --git a/test/src/unit.cpp b/test/src/unit.cpp index a7ca7394..8ca9b01f 100644 --- a/test/src/unit.cpp +++ b/test/src/unit.cpp @@ -9716,6 +9716,39 @@ TEST_CASE("parser class") CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), "parse error - unexpected '\"'"); // improve code coverage CHECK_THROWS_AS(json::parser("\uFF01").parse(), std::invalid_argument); + // unescaped control characters + CHECK_THROWS_AS(json::parser("\"\x00\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x01\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x02\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x03\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x04\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x05\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x06\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x07\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x08\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x09\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x0a\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x0b\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x0c\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x0d\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x0e\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x0f\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x10\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x11\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x12\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x13\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x14\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x15\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x16\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x17\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x18\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x19\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x1a\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x1b\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x1c\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x1d\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x1e\"").parse(), std::invalid_argument); + CHECK_THROWS_AS(json::parser("\"\x1f\"").parse(), std::invalid_argument); } SECTION("escaped")