From ed8c4c681dd008812f97fd9c13a45b510760e506 Mon Sep 17 00:00:00 2001 From: Qianqian Fang Date: Sat, 19 Feb 2022 23:11:54 -0500 Subject: [PATCH] move bjdata new markers from default to the same level as ubjson markers --- .../nlohmann/detail/input/binary_reader.hpp | 350 ++++++++++-------- single_include/nlohmann/json.hpp | 350 ++++++++++-------- test/src/unit-bjdata.cpp | 10 +- 3 files changed, 397 insertions(+), 313 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index b16ae5236..fe2b233ad 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -1883,34 +1883,48 @@ class binary_reader return get_number(input_format, len) && get_string(input_format, len, result); } - default: - if (input_format == input_format_t::bjdata) + case 'u': + { + if (input_format != input_format_t::bjdata) { - switch (current) - { - case 'u': - { - uint16_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - case 'm': - { - uint32_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - case 'M': - { - uint64_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - default: - { - } - } + break; } - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format, concat("expected length type specification (U, i, I, l, L); last byte: 0x", last_token), "string"), nullptr)); + std::uint16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + default: + { + } + } + auto last_token = get_token_string(); + if (input_format != input_format_t::bjdata) + { + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"), nullptr)); + } + else + { + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, u, l, m, L, M); last byte: 0x" + last_token, "string"), nullptr)); } } @@ -2039,65 +2053,83 @@ class binary_reader return true; } + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = detail::conditional_static_cast(number); + return true; + } + + case '[': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::vector dim; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) + { + return false; + } + result = 1; + for (auto i : dim) + { + result *= i; + } + return true; + } + default: { - if (input_format == input_format_t::bjdata) - { - switch (prefix) - { - case 'u': - { - uint16_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = static_cast(number); - return true; - } - case 'm': - { - uint32_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = static_cast(number); - return true; - } - case 'M': - { - uint64_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = detail::conditional_static_cast(number); - return true; - } - case '[': - { - std::vector dim; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) - { - return false; - } - result = 1; - for (auto i : dim) - { - result *= i; - } - return true; - } - default: - { - } - } - } } - auto last_token = get_token_string(); + } + auto last_token = get_token_string(); + if (input_format != input_format_t::bjdata) + { return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"), nullptr)); } + else + { + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, u, l, m, L, M) after '#'; last byte: 0x" + last_token, "size"), nullptr)); + } } /*! @@ -2197,6 +2229,88 @@ class binary_reader return get_number(input_format, number) && sax->number_integer(number); } + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'h': + { + if (input_format != input_format_t::bjdata) + { + break; + } + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte2 << 8u) + byte1); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + case 'd': { float number{}; @@ -2245,82 +2359,10 @@ class binary_reader default: // anything else { - if (input_format == input_format_t::bjdata) - { - switch (prefix) - { - case 'u': - { - uint16_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - case 'm': - { - uint32_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - case 'M': - { - uint64_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - case 'h': - { - const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) - { - return false; - } - const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) - { - return false; - } - - const auto byte1 = static_cast(byte1_raw); - const auto byte2 = static_cast(byte2_raw); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const auto half = static_cast((byte2 << 8u) + byte1); - const double val = [&half] - { - const int exp = (half >> 10u) & 0x1Fu; - const unsigned int mant = half & 0x3FFu; - JSON_ASSERT(0 <= exp&& exp <= 32); - JSON_ASSERT(mant <= 1024); - switch (exp) - { - case 0: - return std::ldexp(mant, -24); - case 31: - return (mant == 0) - ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - default: - return std::ldexp(mant + 1024, exp - 25); - } - }(); - return sax->number_float((half & 0x8000u) != 0 - ? static_cast(-val) - : static_cast(val), ""); - } - default: - { - } - } - } - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("invalid byte: 0x", last_token), "value"), nullptr)); } } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); } /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 1091ddf1a..344026d3f 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10259,34 +10259,48 @@ class binary_reader return get_number(input_format, len) && get_string(input_format, len, result); } - default: - if (input_format == input_format_t::bjdata) + case 'u': + { + if (input_format != input_format_t::bjdata) { - switch (current) - { - case 'u': - { - uint16_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - case 'm': - { - uint32_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - case 'M': - { - uint64_t len{}; - return get_number(input_format, len) && get_string(input_format, len, result); - } - default: - { - } - } + break; } - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, - exception_message(input_format, concat("expected length type specification (U, i, I, l, L); last byte: 0x", last_token), "string"), nullptr)); + std::uint16_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t len{}; + return get_number(input_format, len) && get_string(input_format, len, result); + } + + default: + { + } + } + auto last_token = get_token_string(); + if (input_format != input_format_t::bjdata) + { + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"), nullptr)); + } + else + { + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, u, l, m, L, M); last byte: 0x" + last_token, "string"), nullptr)); } } @@ -10415,65 +10429,83 @@ class binary_reader return true; } + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) + { + return false; + } + result = detail::conditional_static_cast(number); + return true; + } + + case '[': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::vector dim; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) + { + return false; + } + result = 1; + for (auto i : dim) + { + result *= i; + } + return true; + } + default: { - if (input_format == input_format_t::bjdata) - { - switch (prefix) - { - case 'u': - { - uint16_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = static_cast(number); - return true; - } - case 'm': - { - uint32_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = static_cast(number); - return true; - } - case 'M': - { - uint64_t number{}; - if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number))) - { - return false; - } - result = detail::conditional_static_cast(number); - return true; - } - case '[': - { - std::vector dim; - if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) - { - return false; - } - result = 1; - for (auto i : dim) - { - result *= i; - } - return true; - } - default: - { - } - } - } } - auto last_token = get_token_string(); + } + auto last_token = get_token_string(); + if (input_format != input_format_t::bjdata) + { return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"), nullptr)); } + else + { + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, "expected length type specification (U, i, I, u, l, m, L, M) after '#'; last byte: 0x" + last_token, "size"), nullptr)); + } } /*! @@ -10573,6 +10605,88 @@ class binary_reader return get_number(input_format, number) && sax->number_integer(number); } + case 'u': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint16_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'm': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint32_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'M': + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint64_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + + case 'h': + { + if (input_format != input_format_t::bjdata) + { + break; + } + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte2 << 8u) + byte1); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + case 'd': { float number{}; @@ -10621,82 +10735,10 @@ class binary_reader default: // anything else { - if (input_format == input_format_t::bjdata) - { - switch (prefix) - { - case 'u': - { - uint16_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - case 'm': - { - uint32_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - case 'M': - { - uint64_t number{}; - return get_number(input_format, number) && sax->number_unsigned(number); - } - case 'h': - { - const auto byte1_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) - { - return false; - } - const auto byte2_raw = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) - { - return false; - } - - const auto byte1 = static_cast(byte1_raw); - const auto byte2 = static_cast(byte2_raw); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const auto half = static_cast((byte2 << 8u) + byte1); - const double val = [&half] - { - const int exp = (half >> 10u) & 0x1Fu; - const unsigned int mant = half & 0x3FFu; - JSON_ASSERT(0 <= exp&& exp <= 32); - JSON_ASSERT(mant <= 1024); - switch (exp) - { - case 0: - return std::ldexp(mant, -24); - case 31: - return (mant == 0) - ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - default: - return std::ldexp(mant + 1024, exp - 25); - } - }(); - return sax->number_float((half & 0x8000u) != 0 - ? static_cast(-val) - : static_cast(val), ""); - } - default: - { - } - } - } - auto last_token = get_token_string(); - return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, - exception_message(input_format, concat("invalid byte: 0x", last_token), "value"), nullptr)); } } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); } /*! diff --git a/test/src/unit-bjdata.cpp b/test/src/unit-bjdata.cpp index 263ad87d0..f6d3dfb05 100644 --- a/test/src/unit-bjdata.cpp +++ b/test/src/unit-bjdata.cpp @@ -1184,7 +1184,7 @@ TEST_CASE("BJData") std::vector vec3 = {'H', 'i', 2, '1', '.'}; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec3), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1.", json::parse_error); std::vector vec4 = {'H', 2, '1', '0'}; - CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec4), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x02", json::parse_error); + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec4), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData size: expected length type specification (U, i, I, u, l, m, L, M) after '#'; last byte: 0x02", json::parse_error); } } } @@ -2534,7 +2534,7 @@ TEST_CASE("BJData") std::vector v = {'S', '1', 'a'}; json _; CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); - CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData string: expected length type specification (U, i, I, l, L); last byte: 0x31"); + CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData string: expected length type specification (U, i, I, u, l, m, L, M); last byte: 0x31"); } } @@ -2613,7 +2613,7 @@ TEST_CASE("BJData") std::vector v0 = {'[', '#', 'T', ']'}; CHECK_THROWS_AS(_ = json::from_bjdata(v0), json::parse_error&); - CHECK_THROWS_WITH(_ = json::from_bjdata(v0), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x54"); + CHECK_THROWS_WITH(_ = json::from_bjdata(v0), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData size: expected length type specification (U, i, I, u, l, m, L, M) after '#'; last byte: 0x54"); CHECK(json::from_bjdata(v0, true, false).is_discarded()); } @@ -2660,7 +2660,7 @@ TEST_CASE("BJData") std::vector vST = {'[', '$', 'i', '#', '[', '$', 'i', '#'}; json _; CHECK_THROWS_AS(_ = json::from_bjdata(vST), json::parse_error&); - CHECK_THROWS_WITH(_ = json::from_bjdata(vST), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0xFF"); + CHECK_THROWS_WITH(_ = json::from_bjdata(vST), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, I, u, l, m, L, M) after '#'; last byte: 0xFF"); CHECK(json::from_bjdata(vST, true, false).is_discarded()); std::vector v = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 1, 2}; @@ -2675,7 +2675,7 @@ TEST_CASE("BJData") std::vector vS = {'[', '$', 'i', '#', '[', '#', 'i', 2, 1, 2, 1}; CHECK_THROWS_AS(_ = json::from_bjdata(vS), json::parse_error&); - CHECK_THROWS_WITH(_ = json::from_bjdata(vS), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x01"); + CHECK_THROWS_WITH(_ = json::from_bjdata(vS), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, I, u, l, m, L, M) after '#'; last byte: 0x01"); CHECK(json::from_bjdata(vS, true, false).is_discarded()); std::vector vT = {'[', '$', 'i', '#', '[', 'i', 2, 'i'};