mirror of
https://github.com/nlohmann/json.git
synced 2026-10-10 00:17:13 +00:00
Avoid allocating temporary basic_json for cbor and msgpack object keys (#5328)
* avoid allocating temporary basic_json for CBOR and MessagePack object keys Signed-off-by: alexprabhat99 <alexpbara@gmail.com> * add size() to the custom object key test type UBJSON and BJData access object keys through size() and c_str() directly, so the key type now provides both and the comment says why. Signed-off-by: alexprabhat99 <alexpbara@gmail.com> * address review: drop key size()/c_str(), test keys below the depth limit Nothing in the library calls size() or c_str() on an object key, so the test key type only keeps data(), which JSON_DIAGNOSTICS needs. The CBOR and MessagePack custom key tests now also nest objects deeper than detail::recursion_depth_limit(), so keys written by write_cbor_iterative and write_msgpack_iterative are covered as well. Signed-off-by: alexprabhat99 <alexpbara@gmail.com> --------- Signed-off-by: alexprabhat99 <alexpbara@gmail.com>
This commit is contained in:
1 parent
d33068da73
commit
69a0c1b82c
6 files changed
+393
-151
No files matched your search
@@ -0,0 +1,75 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace custom_object_key_test
|
||||
{
|
||||
class key
|
||||
{
|
||||
public:
|
||||
key() = default;
|
||||
|
||||
key(const char* value)
|
||||
: m_value(value)
|
||||
{}
|
||||
|
||||
key(std::string value)
|
||||
: m_value(std::move(value))
|
||||
{}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
// Required by JSON_DIAGNOSTICS, which reads object keys through data()
|
||||
// when building the path of an exception.
|
||||
const char* data() const noexcept
|
||||
{
|
||||
return m_value.data();
|
||||
}
|
||||
|
||||
friend bool operator<(const key& lhs, const key& rhs)
|
||||
{
|
||||
return lhs.m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
template<typename Key, typename Value, typename Compare, typename Allocator>
|
||||
class object
|
||||
: public std::map <
|
||||
key,
|
||||
Value,
|
||||
std::less<key>, // NOLINT(modernize-use-transparent-functors)
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc <
|
||||
std::pair<const key, Value >>>
|
||||
{
|
||||
private:
|
||||
using allocator_type =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc <
|
||||
std::pair<const key, Value >>;
|
||||
|
||||
using base_type =
|
||||
std::map<key, Value, std::less<key>, allocator_type>; // NOLINT(modernize-use-transparent-functors)
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
};
|
||||
|
||||
using json = nlohmann::basic_json<object>;
|
||||
} // namespace custom_object_key_test
|
||||
@@ -28,6 +28,7 @@ using nlohmann::json;
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "round_trip_corpus.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "custom_object_key_type.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
@@ -3357,3 +3358,55 @@ TEST_CASE("CBOR large strings and binaries (chunked reader)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CBOR supports custom object key types")
|
||||
{
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{"short"}, 1);
|
||||
object.emplace(
|
||||
custom_key{"a key longer than twenty-three characters"},
|
||||
2);
|
||||
|
||||
const custom_json value(std::move(object));
|
||||
const auto encoded = custom_json::to_cbor(value);
|
||||
|
||||
CHECK(nlohmann::json::from_cbor(encoded) == nlohmann::json
|
||||
{
|
||||
{"short", 1},
|
||||
{"a key longer than twenty-three characters", 2}
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("CBOR supports custom object key types nested deeper than the recursion depth limit")
|
||||
{
|
||||
// below detail::recursion_depth_limit(), keys are written by
|
||||
// write_cbor_iterative instead of write_cbor
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 10;
|
||||
|
||||
custom_json value = 1;
|
||||
nlohmann::json expected = 1;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
// alternate short keys with ones long enough to need a length byte
|
||||
const std::string name = (i % 2 == 0) ? "k" + std::to_string(i)
|
||||
: "a key longer than thirty-one characters " + std::to_string(i);
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{name}, std::move(value));
|
||||
value = custom_json(std::move(object));
|
||||
|
||||
nlohmann::json::object_t expected_object;
|
||||
expected_object.emplace(name, std::move(expected));
|
||||
expected = nlohmann::json(std::move(expected_object));
|
||||
}
|
||||
|
||||
const auto encoded = custom_json::to_cbor(value);
|
||||
CHECK(encoded == nlohmann::json::to_cbor(expected));
|
||||
CHECK(nlohmann::json::from_cbor(encoded) == expected);
|
||||
}
|
||||
@@ -31,6 +31,7 @@ using nlohmann::json;
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "round_trip_corpus.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "custom_object_key_type.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
@@ -2522,3 +2523,55 @@ TEST_CASE("MessagePack large strings and binaries (chunked reader)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MessagePack supports custom object key types")
|
||||
{
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{"short"}, 1);
|
||||
object.emplace(
|
||||
custom_key{"a key longer than thirty-one characters"},
|
||||
2);
|
||||
|
||||
const custom_json value(std::move(object));
|
||||
const auto encoded = custom_json::to_msgpack(value);
|
||||
|
||||
CHECK(nlohmann::json::from_msgpack(encoded) == nlohmann::json
|
||||
{
|
||||
{"short", 1},
|
||||
{"a key longer than thirty-one characters", 2}
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("MessagePack supports custom object key types nested deeper than the recursion depth limit")
|
||||
{
|
||||
// below detail::recursion_depth_limit(), keys are written by
|
||||
// write_msgpack_iterative instead of write_msgpack
|
||||
using custom_json = custom_object_key_test::json;
|
||||
using custom_key = custom_object_key_test::key;
|
||||
|
||||
const std::size_t depth = nlohmann::detail::recursion_depth_limit() + 10;
|
||||
|
||||
custom_json value = 1;
|
||||
nlohmann::json expected = 1;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
// alternate short keys with ones long enough to need a length byte
|
||||
const std::string name = (i % 2 == 0) ? "k" + std::to_string(i)
|
||||
: "a key longer than thirty-one characters " + std::to_string(i);
|
||||
|
||||
custom_json::object_t object;
|
||||
object.emplace(custom_key{name}, std::move(value));
|
||||
value = custom_json(std::move(object));
|
||||
|
||||
nlohmann::json::object_t expected_object;
|
||||
expected_object.emplace(name, std::move(expected));
|
||||
expected = nlohmann::json(std::move(expected_object));
|
||||
}
|
||||
|
||||
const auto encoded = custom_json::to_msgpack(value);
|
||||
CHECK(encoded == nlohmann::json::to_msgpack(expected));
|
||||
CHECK(nlohmann::json::from_msgpack(encoded) == expected);
|
||||
}
|
||||
Reference in new issue
Block a user