mirror of
https://github.com/nlohmann/json.git
synced 2026-10-15 18:57:13 +00:00
Make the value lifecycle inline-friendly
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
4 files changed
+586
-104
No files matched your search
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -1149,3 +1150,157 @@ TEST_CASE("operator<=> of binary values with a different subtype does not depend
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("comparison of scalars (inline fast path)")
|
||||
{
|
||||
const json::number_integer_t neg = -1;
|
||||
const json::number_integer_t pos = 5;
|
||||
const json::number_unsigned_t big = (std::numeric_limits<json::number_unsigned_t>::max)();
|
||||
|
||||
SECTION("same type")
|
||||
{
|
||||
CHECK(json(pos) == json(pos));
|
||||
CHECK(json(pos) != json(neg));
|
||||
CHECK(json(neg) < json(pos));
|
||||
CHECK_FALSE(json(pos) < json(neg));
|
||||
CHECK_FALSE(json(pos) < json(pos));
|
||||
CHECK(json(pos) <= json(pos));
|
||||
|
||||
CHECK(json(1u) == json(1u));
|
||||
CHECK(json(1u) < json(2u));
|
||||
CHECK_FALSE(json(2u) < json(1u));
|
||||
|
||||
CHECK(json(1.5) == json(1.5));
|
||||
CHECK(json(1.5) < json(2.5));
|
||||
CHECK_FALSE(json(2.5) < json(1.5));
|
||||
CHECK(json(-0.0) == json(0.0));
|
||||
}
|
||||
|
||||
SECTION("mixed number types")
|
||||
{
|
||||
// negative signed vs unsigned must not wrap around
|
||||
CHECK(json(neg) < json(1u));
|
||||
CHECK(json(1u) > json(neg));
|
||||
CHECK(json(neg) != json(big));
|
||||
CHECK(json(neg) < json(big));
|
||||
CHECK_FALSE(json(big) < json(neg));
|
||||
|
||||
CHECK(json(pos) == json(5u));
|
||||
CHECK(json(5u) == json(pos));
|
||||
CHECK(json(pos) < json(6u));
|
||||
CHECK(json(pos) == json(5.0));
|
||||
CHECK(json(5.0) == json(pos));
|
||||
CHECK(json(5u) == json(5.0));
|
||||
CHECK(json(neg) < json(0.5));
|
||||
CHECK(json(0.5) < json(1u));
|
||||
}
|
||||
|
||||
SECTION("boolean and null")
|
||||
{
|
||||
CHECK(json(true) == json(true));
|
||||
CHECK(json(true) != json(false));
|
||||
CHECK(json(false) < json(true));
|
||||
CHECK_FALSE(json(true) < json(false));
|
||||
CHECK_FALSE(json(true) < json(true));
|
||||
|
||||
CHECK(json(nullptr) == json(nullptr));
|
||||
CHECK_FALSE(json(nullptr) < json(nullptr));
|
||||
CHECK(json(nullptr) <= json(nullptr));
|
||||
CHECK(json(nullptr) < json(false));
|
||||
CHECK(json(nullptr) != json(false));
|
||||
CHECK(json(nullptr) != json(0));
|
||||
}
|
||||
|
||||
SECTION("string vs number")
|
||||
{
|
||||
CHECK(json("5") != json(5));
|
||||
CHECK(json(5) != json("5"));
|
||||
CHECK(json(5) < json("5")); // number < string by type order
|
||||
CHECK_FALSE(json("5") < json(5));
|
||||
CHECK(json(1.5) < json(""));
|
||||
CHECK(json("a") == json("a"));
|
||||
CHECK(json("a") < json("b"));
|
||||
}
|
||||
|
||||
SECTION("NaN")
|
||||
{
|
||||
const json nan = std::numeric_limits<json::number_float_t>::quiet_NaN();
|
||||
const json one = 1.0;
|
||||
|
||||
CHECK_FALSE(nan == nan);
|
||||
CHECK(nan != nan);
|
||||
CHECK_FALSE(nan < nan);
|
||||
CHECK_FALSE(nan <= nan);
|
||||
CHECK_FALSE(nan >= nan);
|
||||
CHECK_FALSE(nan > nan);
|
||||
|
||||
CHECK_FALSE(nan == one);
|
||||
CHECK_FALSE(one == nan);
|
||||
CHECK_FALSE(nan < one);
|
||||
CHECK_FALSE(one < nan);
|
||||
CHECK_FALSE(nan <= one);
|
||||
CHECK_FALSE(one <= nan);
|
||||
CHECK_FALSE(nan >= one);
|
||||
CHECK_FALSE(one >= nan);
|
||||
|
||||
// NaN against other number types
|
||||
CHECK_FALSE(nan == json(1));
|
||||
CHECK_FALSE(json(1) == nan);
|
||||
CHECK_FALSE(nan < json(1u));
|
||||
CHECK_FALSE(json(1u) < nan);
|
||||
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
CHECK((nan <=> nan) == std::partial_ordering::unordered); // *NOPAD*
|
||||
CHECK((nan <=> one) == std::partial_ordering::unordered); // *NOPAD*
|
||||
CHECK((one <=> nan) == std::partial_ordering::unordered); // *NOPAD*
|
||||
CHECK((one <=> json(2.0)) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((json(2.0) <=> one) == std::partial_ordering::greater); // *NOPAD*
|
||||
CHECK((one <=> one) == std::partial_ordering::equivalent); // *NOPAD*
|
||||
CHECK((json(neg) <=> json(1u)) == std::partial_ordering::less); // *NOPAD*
|
||||
CHECK((json(nullptr) <=> json(nullptr)) == std::partial_ordering::equivalent); // *NOPAD*
|
||||
CHECK((json(true) <=> json(false)) == std::partial_ordering::greater); // *NOPAD*
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("discarded")
|
||||
{
|
||||
const json d(json::value_t::discarded);
|
||||
|
||||
CHECK_FALSE(d == d);
|
||||
CHECK_FALSE(d < d);
|
||||
CHECK_FALSE(d == json(1));
|
||||
CHECK_FALSE(json(1) == d);
|
||||
CHECK_FALSE(d < json(1));
|
||||
CHECK_FALSE(json(1) < d);
|
||||
CHECK_FALSE(d == json(nullptr));
|
||||
CHECK_FALSE(json(nullptr) == d);
|
||||
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
CHECK((d <=> d) == std::partial_ordering::unordered); // *NOPAD*
|
||||
CHECK((d <=> json(1)) == std::partial_ordering::unordered); // *NOPAD*
|
||||
CHECK((json(1) <=> d) == std::partial_ordering::unordered); // *NOPAD*
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("scalar overloads")
|
||||
{
|
||||
CHECK(json(5) == 5);
|
||||
CHECK(5 == json(5));
|
||||
CHECK(json(5) < 6);
|
||||
CHECK(4 < json(5));
|
||||
CHECK(json(1.5) == 1.5);
|
||||
CHECK(json(true) == true);
|
||||
CHECK(json(5) != 6);
|
||||
CHECK(json(1u) == 1.0);
|
||||
}
|
||||
|
||||
SECTION("structured values still compare")
|
||||
{
|
||||
CHECK(json({1, 2}) == json({1, 2}));
|
||||
CHECK(json({1, 2}) < json({1, 3}));
|
||||
CHECK(json({{"a", 1}}) == json({{"a", 1}}));
|
||||
CHECK(json::binary({1, 2}) == json::binary({1, 2}));
|
||||
CHECK(json(1) < json::array());
|
||||
CHECK(json::object() < json::array());
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
@@ -184,3 +187,139 @@ TEST_CASE("other constructors and destructor")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("copy constructor and destructor across value types")
|
||||
{
|
||||
SECTION("copy of a scalar is independent of the source")
|
||||
{
|
||||
const json src_null = nullptr;
|
||||
const json src_bool = true;
|
||||
const json src_int = -7;
|
||||
const json src_uint = 7u;
|
||||
const json src_float = 2.5;
|
||||
|
||||
json c_null(src_null);
|
||||
json c_bool(src_bool);
|
||||
json c_int(src_int);
|
||||
json c_uint(src_uint);
|
||||
json c_float(src_float);
|
||||
|
||||
CHECK(c_null.is_null());
|
||||
CHECK(c_bool == true);
|
||||
CHECK(c_int == -7);
|
||||
CHECK(c_uint == 7u);
|
||||
CHECK(c_float == 2.5);
|
||||
|
||||
c_int = 8;
|
||||
c_float = 3.5;
|
||||
CHECK(src_int == -7);
|
||||
CHECK(src_float == 2.5);
|
||||
}
|
||||
|
||||
SECTION("copy of an owning value, then mutate the copy")
|
||||
{
|
||||
const json src_string = "hello";
|
||||
const json src_array = {1, 2, 3};
|
||||
const json src_object = {{"a", 1}, {"b", {{"c", 2}}}};
|
||||
const json src_binary = json::binary({1, 2, 3});
|
||||
|
||||
json c_string(src_string);
|
||||
json c_array(src_array);
|
||||
json c_object(src_object);
|
||||
json c_binary(src_binary);
|
||||
|
||||
CHECK(c_string == src_string);
|
||||
CHECK(c_array == src_array);
|
||||
CHECK(c_object == src_object);
|
||||
CHECK(c_binary == src_binary);
|
||||
|
||||
c_string.get_ref<json::string_t&>() += " world";
|
||||
c_array.push_back(4);
|
||||
c_object["b"]["c"] = 3;
|
||||
c_object["d"] = 4;
|
||||
c_binary.get_binary().push_back(4);
|
||||
|
||||
CHECK(src_string == "hello");
|
||||
CHECK(src_array.size() == 3);
|
||||
CHECK(src_object["b"]["c"] == 2);
|
||||
CHECK_FALSE(src_object.contains("d"));
|
||||
CHECK(src_binary.get_binary().size() == 3);
|
||||
|
||||
CHECK(c_string == "hello world");
|
||||
CHECK(c_array.size() == 4);
|
||||
CHECK(c_object["b"]["c"] == 3);
|
||||
CHECK(c_binary.get_binary().size() == 4);
|
||||
}
|
||||
|
||||
SECTION("copy keeps parent pointers valid (JSON_DIAGNOSTICS)")
|
||||
{
|
||||
const json src = {{"a", {1, 2}}, {"b", "x"}};
|
||||
json c(src);
|
||||
c["a"].push_back(3);
|
||||
CHECK(c["a"].size() == 3);
|
||||
CHECK(src["a"].size() == 2);
|
||||
}
|
||||
|
||||
SECTION("vector of mixed types: build, copy, and destroy")
|
||||
{
|
||||
{
|
||||
std::vector<json> v;
|
||||
for (int i = 0; i < 70; ++i)
|
||||
{
|
||||
switch (i % 9)
|
||||
{
|
||||
case 0:
|
||||
v.emplace_back(nullptr);
|
||||
break;
|
||||
case 1:
|
||||
v.emplace_back(i % 2 == 0);
|
||||
break;
|
||||
case 2:
|
||||
v.emplace_back(-i);
|
||||
break;
|
||||
case 3:
|
||||
v.emplace_back(static_cast<json::number_unsigned_t>(i));
|
||||
break;
|
||||
case 4:
|
||||
v.emplace_back(i * 0.5);
|
||||
break;
|
||||
case 5:
|
||||
v.emplace_back(std::string(static_cast<std::size_t>(i), 'x'));
|
||||
break;
|
||||
case 6:
|
||||
v.emplace_back(json::array({i, "s", nullptr}));
|
||||
break;
|
||||
case 7:
|
||||
v.emplace_back(json::object({{"k", i}}));
|
||||
break;
|
||||
default:
|
||||
v.emplace_back(json::binary({1, 2, 3}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
REQUIRE(v.size() == 70);
|
||||
|
||||
std::vector<json> copy(v);
|
||||
CHECK(copy == v);
|
||||
|
||||
// mutating the copy leaves the original alone
|
||||
copy[5] = "changed";
|
||||
copy[6].push_back(1);
|
||||
CHECK(copy != v);
|
||||
CHECK(v[5] == std::string(5, 'x'));
|
||||
CHECK(v[6].size() == 3);
|
||||
|
||||
v.erase(v.begin(), v.begin() + 10);
|
||||
CHECK(v.size() == 60);
|
||||
}
|
||||
|
||||
// destroying the discarded and default-constructed values
|
||||
std::vector<json> w(4);
|
||||
w.emplace_back(json::value_t::discarded);
|
||||
w.emplace_back(json::value_t::object);
|
||||
w.emplace_back(json::value_t::array);
|
||||
w.emplace_back(json::value_t::string);
|
||||
w.emplace_back(json::value_t::binary);
|
||||
CHECK(w.size() == 9);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user