Merge branch 'develop' of https://github.com/nlohmann/json into release_cleanup
This commit is contained in:
commit
ad32f576bd
5 changed files with 222 additions and 9 deletions
|
@ -1,7 +1,7 @@
|
||||||
find_package(Git)
|
find_package(Git)
|
||||||
|
|
||||||
set(JSON_TEST_DATA_URL https://github.com/nlohmann/json_test_data)
|
set(JSON_TEST_DATA_URL https://github.com/nlohmann/json_test_data)
|
||||||
set(JSON_TEST_DATA_VERSION 1.0.0)
|
set(JSON_TEST_DATA_VERSION 2.0.0)
|
||||||
|
|
||||||
# target to download test data
|
# target to download test data
|
||||||
add_custom_target(download_test_data
|
add_custom_target(download_test_data
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <cstring> // memcpy
|
#include <cstring> // memcpy
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
|
#include <cmath> // isnan, isinf
|
||||||
|
|
||||||
#include <nlohmann/detail/input/binary_reader.hpp>
|
#include <nlohmann/detail/input/binary_reader.hpp>
|
||||||
#include <nlohmann/detail/macro_scope.hpp>
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
@ -176,9 +177,36 @@ class binary_writer
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
if (std::isnan(j.m_value.number_float))
|
||||||
|
{
|
||||||
|
// NaN is 0xf97e00 in CBOR
|
||||||
|
oa->write_character(to_char_type(0xF9));
|
||||||
|
oa->write_character(to_char_type(0x7E));
|
||||||
|
oa->write_character(to_char_type(0x00));
|
||||||
|
}
|
||||||
|
else if (std::isinf(j.m_value.number_float))
|
||||||
|
{
|
||||||
|
// Infinity is 0xf97c00, -Infinity is 0xf9fc00
|
||||||
|
oa->write_character(to_char_type(0xf9));
|
||||||
|
oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
|
||||||
|
oa->write_character(to_char_type(0x00));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (j.m_value.number_float >= std::numeric_limits<float>::lowest() and
|
||||||
|
j.m_value.number_float <= std::numeric_limits<float>::max() and
|
||||||
|
static_cast<double>(static_cast<float>(j.m_value.number_float)) == j.m_value.number_float)
|
||||||
|
{
|
||||||
|
oa->write_character(get_cbor_float_prefix(static_cast<float>(j.m_value.number_float)));
|
||||||
|
write_number(static_cast<float>(j.m_value.number_float));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
|
oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
|
||||||
write_number(j.m_value.number_float);
|
write_number(j.m_value.number_float);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4946,6 +4946,11 @@ class basic_json
|
||||||
element as string (see example). For primitive types (e.g., numbers),
|
element as string (see example). For primitive types (e.g., numbers),
|
||||||
`key()` returns an empty string.
|
`key()` returns an empty string.
|
||||||
|
|
||||||
|
@warning Using `items()` on temporary objects is dangerous. Make sure the
|
||||||
|
object's lifetime exeeds the iteration. See
|
||||||
|
<https://github.com/nlohmann/json/issues/2040> for more
|
||||||
|
information.
|
||||||
|
|
||||||
@return iteration proxy object wrapping @a ref with an interface to use in
|
@return iteration proxy object wrapping @a ref with an interface to use in
|
||||||
range-based for loops
|
range-based for loops
|
||||||
|
|
||||||
|
@ -7106,7 +7111,7 @@ class basic_json
|
||||||
- break (0xFF)
|
- break (0xFF)
|
||||||
|
|
||||||
@param[in] j JSON value to serialize
|
@param[in] j JSON value to serialize
|
||||||
@return MessagePack serialization as byte vector
|
@return CBOR serialization as byte vector
|
||||||
|
|
||||||
@complexity Linear in the size of the JSON value @a j.
|
@complexity Linear in the size of the JSON value @a j.
|
||||||
|
|
||||||
|
|
|
@ -11873,6 +11873,7 @@ class json_ref
|
||||||
#include <cstring> // memcpy
|
#include <cstring> // memcpy
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
|
#include <cmath> // isnan, isinf
|
||||||
|
|
||||||
// #include <nlohmann/detail/input/binary_reader.hpp>
|
// #include <nlohmann/detail/input/binary_reader.hpp>
|
||||||
|
|
||||||
|
@ -12170,9 +12171,36 @@ class binary_writer
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
if (std::isnan(j.m_value.number_float))
|
||||||
|
{
|
||||||
|
// NaN is 0xf97e00 in CBOR
|
||||||
|
oa->write_character(to_char_type(0xF9));
|
||||||
|
oa->write_character(to_char_type(0x7E));
|
||||||
|
oa->write_character(to_char_type(0x00));
|
||||||
|
}
|
||||||
|
else if (std::isinf(j.m_value.number_float))
|
||||||
|
{
|
||||||
|
// Infinity is 0xf97c00, -Infinity is 0xf9fc00
|
||||||
|
oa->write_character(to_char_type(0xf9));
|
||||||
|
oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
|
||||||
|
oa->write_character(to_char_type(0x00));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (j.m_value.number_float >= std::numeric_limits<float>::lowest() and
|
||||||
|
j.m_value.number_float <= std::numeric_limits<float>::max() and
|
||||||
|
static_cast<double>(static_cast<float>(j.m_value.number_float)) == j.m_value.number_float)
|
||||||
|
{
|
||||||
|
oa->write_character(get_cbor_float_prefix(static_cast<float>(j.m_value.number_float)));
|
||||||
|
write_number(static_cast<float>(j.m_value.number_float));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
|
oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
|
||||||
write_number(j.m_value.number_float);
|
write_number(j.m_value.number_float);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20437,6 +20465,11 @@ class basic_json
|
||||||
element as string (see example). For primitive types (e.g., numbers),
|
element as string (see example). For primitive types (e.g., numbers),
|
||||||
`key()` returns an empty string.
|
`key()` returns an empty string.
|
||||||
|
|
||||||
|
@warning Using `items()` on temporary objects is dangerous. Make sure the
|
||||||
|
object's lifetime exeeds the iteration. See
|
||||||
|
<https://github.com/nlohmann/json/issues/2040> for more
|
||||||
|
information.
|
||||||
|
|
||||||
@return iteration proxy object wrapping @a ref with an interface to use in
|
@return iteration proxy object wrapping @a ref with an interface to use in
|
||||||
range-based for loops
|
range-based for loops
|
||||||
|
|
||||||
|
@ -22597,7 +22630,7 @@ class basic_json
|
||||||
- break (0xFF)
|
- break (0xFF)
|
||||||
|
|
||||||
@param[in] j JSON value to serialize
|
@param[in] j JSON value to serialize
|
||||||
@return MessagePack serialization as byte vector
|
@return CBOR serialization as byte vector
|
||||||
|
|
||||||
@complexity Linear in the size of the JSON value @a j.
|
@complexity Linear in the size of the JSON value @a j.
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,24 @@ TEST_CASE("CBOR")
|
||||||
CHECK(result.empty());
|
CHECK(result.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("NaN")
|
||||||
|
{
|
||||||
|
// NaN value
|
||||||
|
json j = std::numeric_limits<json::number_float_t>::quiet_NaN();
|
||||||
|
std::vector<uint8_t> expected = {0xf9, 0x7e, 0x00};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Infinity")
|
||||||
|
{
|
||||||
|
// Infinity value
|
||||||
|
json j = std::numeric_limits<json::number_float_t>::infinity();
|
||||||
|
std::vector<uint8_t> expected = {0xf9, 0x7c, 0x00};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("null")
|
SECTION("null")
|
||||||
{
|
{
|
||||||
json j = nullptr;
|
json j = nullptr;
|
||||||
|
@ -816,7 +834,7 @@ TEST_CASE("CBOR")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("float")
|
SECTION("double-precision float")
|
||||||
{
|
{
|
||||||
SECTION("3.1415925")
|
SECTION("3.1415925")
|
||||||
{
|
{
|
||||||
|
@ -837,6 +855,135 @@ TEST_CASE("CBOR")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("single-precision float")
|
||||||
|
{
|
||||||
|
SECTION("0.5")
|
||||||
|
{
|
||||||
|
double v = 0.5;
|
||||||
|
json j = v;
|
||||||
|
// its double-precision float binary value is
|
||||||
|
// {0xfb, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||||
|
// but to save memory, we can store it as single-precision float.
|
||||||
|
std::vector<uint8_t> expected = {0xfa, 0x3f, 0x00, 0x00, 0x00};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("0.0")
|
||||||
|
{
|
||||||
|
double v = 0.0;
|
||||||
|
json j = v;
|
||||||
|
// its double-precision binary value is:
|
||||||
|
// {0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||||
|
std::vector<uint8_t> expected = {0xfa, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("-0.0")
|
||||||
|
{
|
||||||
|
double v = -0.0;
|
||||||
|
json j = v;
|
||||||
|
// its double-precision binary value is:
|
||||||
|
// {0xfb, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||||
|
std::vector<uint8_t> expected = {0xfa, 0x80, 0x00, 0x00, 0x00};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("100.0")
|
||||||
|
{
|
||||||
|
double v = 100.0;
|
||||||
|
json j = v;
|
||||||
|
// its double-precision binary value is:
|
||||||
|
// {0xfb, 0x40, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||||
|
std::vector<uint8_t> expected = {0xfa, 0x42, 0xc8, 0x00, 0x00};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("200.0")
|
||||||
|
{
|
||||||
|
double v = 200.0;
|
||||||
|
json j = v;
|
||||||
|
// its double-precision binary value is:
|
||||||
|
// {0xfb, 0x40, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||||
|
std::vector<uint8_t> expected = {0xfa, 0x43, 0x48, 0x00, 0x00};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("3.40282e+38(max float)")
|
||||||
|
{
|
||||||
|
float v = std::numeric_limits<float>::max();
|
||||||
|
json j = v;
|
||||||
|
std::vector<uint8_t> expected =
|
||||||
|
{
|
||||||
|
0xfa, 0x7f, 0x7f, 0xff, 0xff
|
||||||
|
};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("-3.40282e+38(lowest float)")
|
||||||
|
{
|
||||||
|
double v = std::numeric_limits<float>::lowest();
|
||||||
|
json j = v;
|
||||||
|
std::vector<uint8_t> expected =
|
||||||
|
{
|
||||||
|
0xfa, 0xff, 0x7f, 0xff, 0xff
|
||||||
|
};
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("1 + 3.40282e+38(more than max float)")
|
||||||
|
{
|
||||||
|
double v = std::numeric_limits<float>::max() + 0.1e+34;
|
||||||
|
json j = v;
|
||||||
|
std::vector<uint8_t> expected =
|
||||||
|
{
|
||||||
|
0xfb, 0x47, 0xf0, 0x00, 0x03, 0x04, 0xdc, 0x64, 0x49
|
||||||
|
};
|
||||||
|
// double
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
SECTION("-1 - 3.40282e+38(less than lowest float)")
|
||||||
|
{
|
||||||
|
double v = std::numeric_limits<float>::lowest() - 1;
|
||||||
|
json j = v;
|
||||||
|
std::vector<uint8_t> expected =
|
||||||
|
{
|
||||||
|
0xfa, 0xff, 0x7f, 0xff, 0xff
|
||||||
|
};
|
||||||
|
// the same with lowest float
|
||||||
|
const auto result = json::to_cbor(j);
|
||||||
|
CHECK(result == expected);
|
||||||
|
// roundtrip
|
||||||
|
CHECK(json::from_cbor(result) == j);
|
||||||
|
CHECK(json::from_cbor(result) == v);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("half-precision float (edge cases)")
|
SECTION("half-precision float (edge cases)")
|
||||||
{
|
{
|
||||||
SECTION("errors")
|
SECTION("errors")
|
||||||
|
@ -936,7 +1083,7 @@ TEST_CASE("CBOR")
|
||||||
|
|
||||||
SECTION("NaN")
|
SECTION("NaN")
|
||||||
{
|
{
|
||||||
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c, 0x01}));
|
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7e, 0x00}));
|
||||||
json::number_float_t d = j;
|
json::number_float_t d = j;
|
||||||
CHECK(std::isnan(d));
|
CHECK(std::isnan(d));
|
||||||
CHECK(j.dump() == "null");
|
CHECK(j.dump() == "null");
|
||||||
|
|
Loading…
Reference in a new issue