Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16ed40b2d4 |
No files matched your search
+1
-3
@@ -178,10 +178,8 @@ function(_json_test_add_test test_name file main cxx_standard)
|
|||||||
COMMAND ${memcheck_command} $<TARGET_FILE:${test_target}> ${DOCTEST_TEST_FILTER}
|
COMMAND ${memcheck_command} $<TARGET_FILE:${test_target}> ${DOCTEST_TEST_FILTER}
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
)
|
)
|
||||||
# under Valgrind the slowest tests take close to 25 minutes, so ctest's
|
|
||||||
# default timeout of 1500 seconds leaves no headroom
|
|
||||||
set_tests_properties(${test_target}_valgrind PROPERTIES
|
set_tests_properties(${test_target}_valgrind PROPERTIES
|
||||||
LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA TIMEOUT 3600
|
LABELS "valgrind" FIXTURES_REQUIRED TEST_DATA
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|||||||
@@ -1856,14 +1856,18 @@ class binary_reader
|
|||||||
|
|
||||||
Only the start of an array is tried, which covers arrays of numbers
|
Only the start of an array is tried, which covers arrays of numbers
|
||||||
(e.g. coordinates) but costs arrays of other values only one call, not one
|
(e.g. coordinates) but costs arrays of other values only one call, not one
|
||||||
per element.
|
per element. An array of one element is not tried at all: that element is
|
||||||
|
mostly an object or an array (`[[...]]`, the single ring of a GeoJSON
|
||||||
|
polygon), for which the call would find no scalar, while a single scalar,
|
||||||
|
which the run would read faster, is rare. The benchmarks
|
||||||
|
`FromBinaryShape/nested` and `FromBinaryShape/singles` show both sides.
|
||||||
|
|
||||||
@param[in] len the number of elements
|
@param[in] len the number of elements
|
||||||
@return whether the SAX parser accepted the array and the values read
|
@return whether the SAX parser accepted the array and the values read
|
||||||
*/
|
*/
|
||||||
bool enter_cbor_array(const std::size_t len)
|
bool enter_cbor_array(const std::size_t len)
|
||||||
{
|
{
|
||||||
return enter_array(len) && (len == 0 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
return enter_array(len) && (len <= 1 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// input that is not contiguous: every value is read by parse_cbor_value
|
/// input that is not contiguous: every value is read by parse_cbor_value
|
||||||
@@ -2764,12 +2768,16 @@ class binary_reader
|
|||||||
/*!
|
/*!
|
||||||
@brief open a MessagePack array and read the scalars it begins with (see
|
@brief open a MessagePack array and read the scalars it begins with (see
|
||||||
@ref parse_msgpack_scalar_run)
|
@ref parse_msgpack_scalar_run)
|
||||||
|
|
||||||
|
An array of one element is not tried, for the reason given at
|
||||||
|
@ref enter_cbor_array.
|
||||||
|
|
||||||
@param[in] len the number of elements
|
@param[in] len the number of elements
|
||||||
@return whether the SAX parser accepted the array and the values read
|
@return whether the SAX parser accepted the array and the values read
|
||||||
*/
|
*/
|
||||||
bool enter_msgpack_array(const std::size_t len)
|
bool enter_msgpack_array(const std::size_t len)
|
||||||
{
|
{
|
||||||
return enter_array(len) && (len == 0 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
return enter_array(len) && (len <= 1 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// input that is not contiguous: every value is read by parse_msgpack_value
|
/// input that is not contiguous: every value is read by parse_msgpack_value
|
||||||
|
|||||||
@@ -2422,6 +2422,7 @@ class binary_writer
|
|||||||
nothing large has been written then, and the caller writes the
|
nothing large has been written then, and the caller writes the
|
||||||
document in two passes, which reports that error
|
document in two passes, which reports that error
|
||||||
*/
|
*/
|
||||||
|
template<typename SinkType = OutputSinkType, typename std::enable_if<is_detected<sink_written_t, SinkType>::value, int>::type = 0>
|
||||||
bool write_bson_document_single_pass(const BasicJsonType& document)
|
bool write_bson_document_single_pass(const BasicJsonType& document)
|
||||||
{
|
{
|
||||||
const std::size_t start = oa.written();
|
const std::size_t start = oa.written();
|
||||||
|
|||||||
Generated
+12
-3
@@ -19863,14 +19863,18 @@ class binary_reader
|
|||||||
|
|
||||||
Only the start of an array is tried, which covers arrays of numbers
|
Only the start of an array is tried, which covers arrays of numbers
|
||||||
(e.g. coordinates) but costs arrays of other values only one call, not one
|
(e.g. coordinates) but costs arrays of other values only one call, not one
|
||||||
per element.
|
per element. An array of one element is not tried at all: that element is
|
||||||
|
mostly an object or an array (`[[...]]`, the single ring of a GeoJSON
|
||||||
|
polygon), for which the call would find no scalar, while a single scalar,
|
||||||
|
which the run would read faster, is rare. The benchmarks
|
||||||
|
`FromBinaryShape/nested` and `FromBinaryShape/singles` show both sides.
|
||||||
|
|
||||||
@param[in] len the number of elements
|
@param[in] len the number of elements
|
||||||
@return whether the SAX parser accepted the array and the values read
|
@return whether the SAX parser accepted the array and the values read
|
||||||
*/
|
*/
|
||||||
bool enter_cbor_array(const std::size_t len)
|
bool enter_cbor_array(const std::size_t len)
|
||||||
{
|
{
|
||||||
return enter_array(len) && (len == 0 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
return enter_array(len) && (len <= 1 || parse_cbor_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// input that is not contiguous: every value is read by parse_cbor_value
|
/// input that is not contiguous: every value is read by parse_cbor_value
|
||||||
@@ -20771,12 +20775,16 @@ class binary_reader
|
|||||||
/*!
|
/*!
|
||||||
@brief open a MessagePack array and read the scalars it begins with (see
|
@brief open a MessagePack array and read the scalars it begins with (see
|
||||||
@ref parse_msgpack_scalar_run)
|
@ref parse_msgpack_scalar_run)
|
||||||
|
|
||||||
|
An array of one element is not tried, for the reason given at
|
||||||
|
@ref enter_cbor_array.
|
||||||
|
|
||||||
@param[in] len the number of elements
|
@param[in] len the number of elements
|
||||||
@return whether the SAX parser accepted the array and the values read
|
@return whether the SAX parser accepted the array and the values read
|
||||||
*/
|
*/
|
||||||
bool enter_msgpack_array(const std::size_t len)
|
bool enter_msgpack_array(const std::size_t len)
|
||||||
{
|
{
|
||||||
return enter_array(len) && (len == 0 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
return enter_array(len) && (len <= 1 || parse_msgpack_scalar_run(std::integral_constant<bool, bulk_scan> {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// input that is not contiguous: every value is read by parse_msgpack_value
|
/// input that is not contiguous: every value is read by parse_msgpack_value
|
||||||
@@ -30394,6 +30402,7 @@ class binary_writer
|
|||||||
nothing large has been written then, and the caller writes the
|
nothing large has been written then, and the caller writes the
|
||||||
document in two passes, which reports that error
|
document in two passes, which reports that error
|
||||||
*/
|
*/
|
||||||
|
template<typename SinkType = OutputSinkType, typename std::enable_if<is_detected<sink_written_t, SinkType>::value, int>::type = 0>
|
||||||
bool write_bson_document_single_pass(const BasicJsonType& document)
|
bool write_bson_document_single_pass(const BasicJsonType& document)
|
||||||
{
|
{
|
||||||
const std::size_t start = oa.written();
|
const std::size_t start = oa.written();
|
||||||
|
|||||||
@@ -629,6 +629,22 @@ static json make_containers()
|
|||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// many arrays of one number each: one-element arrays are left to the general
|
||||||
|
/// path (CBOR and MessagePack), which reads a lone number slower than the loop
|
||||||
|
/// for arrays of scalars would
|
||||||
|
static json make_singles()
|
||||||
|
{
|
||||||
|
json data = json::array();
|
||||||
|
for (std::size_t i = 0; i < 100000; ++i)
|
||||||
|
{
|
||||||
|
data.push_back(json::array({i}));
|
||||||
|
}
|
||||||
|
|
||||||
|
json j = json::object();
|
||||||
|
j["data"] = std::move(data);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
/// one flat array of numbers: the scalar decoding path, which must not move
|
/// one flat array of numbers: the scalar decoding path, which must not move
|
||||||
static json make_scalars()
|
static json make_scalars()
|
||||||
{
|
{
|
||||||
@@ -676,6 +692,8 @@ BENCHMARK_CAPTURE(FromBinaryShape, containers / ubjson_optimized, make_container
|
|||||||
BENCHMARK_CAPTURE(FromBinaryShape, containers / bjdata, make_containers, binary_format::bjdata);
|
BENCHMARK_CAPTURE(FromBinaryShape, containers / bjdata, make_containers, binary_format::bjdata);
|
||||||
BENCHMARK_CAPTURE(FromBinaryShape, containers / bson, make_containers, binary_format::bson);
|
BENCHMARK_CAPTURE(FromBinaryShape, containers / bson, make_containers, binary_format::bson);
|
||||||
BENCHMARK_CAPTURE(FromBinaryShape, containers / bon8, make_containers, binary_format::bon8);
|
BENCHMARK_CAPTURE(FromBinaryShape, containers / bon8, make_containers, binary_format::bon8);
|
||||||
|
BENCHMARK_CAPTURE(FromBinaryShape, singles / cbor, make_singles, binary_format::cbor);
|
||||||
|
BENCHMARK_CAPTURE(FromBinaryShape, singles / msgpack, make_singles, binary_format::msgpack);
|
||||||
// BSON names every array element, so a large array measures key generation
|
// BSON names every array element, so a large array measures key generation
|
||||||
// rather than scalar decoding and is left out here
|
// rather than scalar decoding and is left out here
|
||||||
BENCHMARK_CAPTURE(FromBinaryShape, scalars / cbor, make_scalars, binary_format::cbor);
|
BENCHMARK_CAPTURE(FromBinaryShape, scalars / cbor, make_scalars, binary_format::cbor);
|
||||||
|
|||||||
@@ -2520,6 +2520,34 @@ TEST_CASE("CBOR arrays of scalars from contiguous and non-contiguous input")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("CBOR arrays of one element from contiguous and non-contiguous input")
|
||||||
|
{
|
||||||
|
// contiguous input leaves an array of one element to the general path
|
||||||
|
// rather than to the loop that reads arrays of scalars; both inputs must
|
||||||
|
// still give the same events, value, or error for the complete document
|
||||||
|
// and for every truncation of it, with enough bytes after each array that
|
||||||
|
// the loop could have been entered
|
||||||
|
const json j = json::parse(R"({"a": [[[[1.5]]]], "b": [7], "c": [{"x": 2.5}], "d": ["s"], "e": [[1, 2]], "f": [null], "g": 1.25})");
|
||||||
|
const std::vector<std::uint8_t> bytes = json::to_cbor(j);
|
||||||
|
|
||||||
|
CHECK(json::from_cbor(bytes) == j);
|
||||||
|
|
||||||
|
for (std::size_t length = 0; length <= bytes.size(); ++length)
|
||||||
|
{
|
||||||
|
CAPTURE(length)
|
||||||
|
const std::vector<std::uint8_t> contiguous(bytes.begin(), bytes.begin() + static_cast<std::ptrdiff_t>(length));
|
||||||
|
const std::list<std::uint8_t> bytewise(contiguous.begin(), contiguous.end());
|
||||||
|
|
||||||
|
CHECK(json::from_cbor(contiguous, true, false).dump() == json::from_cbor(bytewise.begin(), bytewise.end(), true, false).dump());
|
||||||
|
|
||||||
|
SaxEventLogger from_contiguous;
|
||||||
|
SaxEventLogger from_bytewise;
|
||||||
|
CHECK(json::sax_parse(contiguous, &from_contiguous, json::input_format_t::cbor, true, false)
|
||||||
|
== json::sax_parse(bytewise.begin(), bytewise.end(), &from_bytewise, json::input_format_t::cbor, true, false));
|
||||||
|
CHECK(from_contiguous.events == from_bytewise.events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("CBOR indefinite-length strings do not recurse per chunk")
|
TEST_CASE("CBOR indefinite-length strings do not recurse per chunk")
|
||||||
{
|
{
|
||||||
// Reading an indefinite-length string or byte array used to call itself
|
// Reading an indefinite-length string or byte array used to call itself
|
||||||
|
|||||||
@@ -2311,3 +2311,31 @@ TEST_CASE("MessagePack arrays of scalars from contiguous and non-contiguous inpu
|
|||||||
== json::sax_parse(bytewise.begin(), bytewise.end(), &from_bytewise, json::input_format_t::msgpack));
|
== json::sax_parse(bytewise.begin(), bytewise.end(), &from_bytewise, json::input_format_t::msgpack));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("MessagePack arrays of one element from contiguous and non-contiguous input")
|
||||||
|
{
|
||||||
|
// contiguous input leaves an array of one element to the general path
|
||||||
|
// rather than to the loop that reads arrays of scalars; both inputs must
|
||||||
|
// still give the same events, value, or error for the complete document
|
||||||
|
// and for every truncation of it, with enough bytes after each array that
|
||||||
|
// the loop could have been entered
|
||||||
|
const json j = json::parse(R"({"a": [[[[1.5]]]], "b": [7], "c": [{"x": 2.5}], "d": ["s"], "e": [[1, 2]], "f": [null], "g": 1.25})");
|
||||||
|
const std::vector<std::uint8_t> bytes = json::to_msgpack(j);
|
||||||
|
|
||||||
|
CHECK(json::from_msgpack(bytes) == j);
|
||||||
|
|
||||||
|
for (std::size_t length = 0; length <= bytes.size(); ++length)
|
||||||
|
{
|
||||||
|
CAPTURE(length)
|
||||||
|
const std::vector<std::uint8_t> contiguous(bytes.begin(), bytes.begin() + static_cast<std::ptrdiff_t>(length));
|
||||||
|
const std::list<std::uint8_t> bytewise(contiguous.begin(), contiguous.end());
|
||||||
|
|
||||||
|
CHECK(json::from_msgpack(contiguous, true, false).dump() == json::from_msgpack(bytewise.begin(), bytewise.end(), true, false).dump());
|
||||||
|
|
||||||
|
SaxEventLogger from_contiguous;
|
||||||
|
SaxEventLogger from_bytewise;
|
||||||
|
CHECK(json::sax_parse(contiguous, &from_contiguous, json::input_format_t::msgpack, true, false)
|
||||||
|
== json::sax_parse(bytewise.begin(), bytewise.end(), &from_bytewise, json::input_format_t::msgpack, true, false));
|
||||||
|
CHECK(from_contiguous.events == from_bytewise.events);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user