Implement support for string_view (attempt no. 3) (#3423)

* Add key_compare member to ordered_map

* Replace == with key_compare in ordered_map

* Expose the actual comparison function used by object_t

nlohmann::ordered_map uses a different comparison function than the one
provided via template parameter.
* Introduce a type trait to detect if object_t has a key_compare member.
* Rename object_comparator_t to default_object_comparator_t.
* Add object_comparator_t to be conditionally defined as
  object_t::key_compare, if available, or default_object_comparator_t
  otherwise.
* Update the documentation accordingly.

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>

* Add type traits to check if a type is usable as object key

Add type trait to check:
* if a type is a specialization of a template.
* if a type is a json_pointer.
* if a type is a basic_json::{const_,}iterator.
* if two types are comparable using a given comparison functor.
* if a type is comparable to basic_json::object_t::key_type.
* if a type has a member type is_transparent.
* if a type is usable as object key.
* if a type has an erase() function accepting a given KeyType.

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>

* Rework basic_json element access to accept more key types

Rework basic_json element access member functions and operators to
accept any type that meets the requirements defined by type trait
detail::is_usable_as_key_type.

Member functions and operators:
* at()
* operator[]
* value()
* erase()
* find()
* count()
* contains()

Update documentation to reflect these changes.

Add unit tests to excercise the new functions using std::string_view.

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
This commit is contained in:
Florian Albrechtskirchinger
2022-04-29 21:40:02 +02:00
committed by GitHub
parent ee51661481
commit 5352856f04
26 changed files with 1517 additions and 305 deletions

View File

@@ -60,12 +60,38 @@ TEST_CASE("element access 2")
CHECK(j_const.at("floating") == json(42.23));
CHECK(j_const.at("object") == json::object());
CHECK(j_const.at("array") == json({1, 2, 3}));
#ifdef JSON_HAS_CPP_17
CHECK(j.at(std::string_view("integer")) == json(1));
CHECK(j.at(std::string_view("unsigned")) == json(1u));
CHECK(j.at(std::string_view("boolean")) == json(true));
CHECK(j.at(std::string_view("null")) == json(nullptr));
CHECK(j.at(std::string_view("string")) == json("hello world"));
CHECK(j.at(std::string_view("floating")) == json(42.23));
CHECK(j.at(std::string_view("object")) == json::object());
CHECK(j.at(std::string_view("array")) == json({1, 2, 3}));
CHECK(j_const.at(std::string_view("integer")) == json(1));
CHECK(j_const.at(std::string_view("unsigned")) == json(1u));
CHECK(j_const.at(std::string_view("boolean")) == json(true));
CHECK(j_const.at(std::string_view("null")) == json(nullptr));
CHECK(j_const.at(std::string_view("string")) == json("hello world"));
CHECK(j_const.at(std::string_view("floating")) == json(42.23));
CHECK(j_const.at(std::string_view("object")) == json::object());
CHECK(j_const.at(std::string_view("array")) == json({1, 2, 3}));
#endif
}
SECTION("access outside bounds")
{
CHECK_THROWS_WITH_AS(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
CHECK_THROWS_WITH_AS(j_const.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
CHECK_THROWS_WITH_AS(j_const.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&);
#endif
}
SECTION("access on non-object type")
@@ -76,6 +102,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", json::type_error&);
#endif
}
SECTION("boolean")
@@ -84,6 +115,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&);
#endif
}
SECTION("string")
@@ -92,6 +128,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", json::type_error&);
#endif
}
SECTION("array")
@@ -100,6 +141,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", json::type_error&);
#endif
}
SECTION("number (integer)")
@@ -108,6 +154,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#endif
}
SECTION("number (unsigned)")
@@ -116,6 +167,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#endif
}
SECTION("number (floating-point)")
@@ -124,6 +180,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&);
#endif
}
}
}
@@ -158,6 +219,33 @@ TEST_CASE("element access 2")
CHECK(j_const.value("floating", 12) == 42);
CHECK(j_const.value("object", json({{"foo", "bar"}})) == json::object());
CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3}));
#ifdef JSON_HAS_CPP_17
CHECK(j.value(std::string_view("integer"), 2) == 1);
CHECK(j.value(std::string_view("integer"), 1.0) == Approx(1));
CHECK(j.value(std::string_view("unsigned"), 2) == 1u);
CHECK(j.value(std::string_view("unsigned"), 1.0) == Approx(1u));
CHECK(j.value(std::string_view("null"), json(1)) == json());
CHECK(j.value(std::string_view("boolean"), false) == true);
CHECK(j.value(std::string_view("string"), "bar") == "hello world");
CHECK(j.value(std::string_view("string"), std::string("bar")) == "hello world");
CHECK(j.value(std::string_view("floating"), 12.34) == Approx(42.23));
CHECK(j.value(std::string_view("floating"), 12) == 42);
CHECK(j.value(std::string_view("object"), json({{"foo", "bar"}})) == json::object());
CHECK(j.value(std::string_view("array"), json({10, 100})) == json({1, 2, 3}));
CHECK(j_const.value(std::string_view("integer"), 2) == 1);
CHECK(j_const.value(std::string_view("integer"), 1.0) == Approx(1));
CHECK(j_const.value(std::string_view("unsigned"), 2) == 1u);
CHECK(j_const.value(std::string_view("unsigned"), 1.0) == Approx(1u));
CHECK(j_const.value(std::string_view("boolean"), false) == true);
CHECK(j_const.value(std::string_view("string"), "bar") == "hello world");
CHECK(j_const.value(std::string_view("string"), std::string("bar")) == "hello world");
CHECK(j_const.value(std::string_view("floating"), 12.34) == Approx(42.23));
CHECK(j_const.value(std::string_view("floating"), 12) == 42);
CHECK(j_const.value(std::string_view("object"), json({{"foo", "bar"}})) == json::object());
CHECK(j_const.value(std::string_view("array"), json({10, 100})) == json({1, 2, 3}));
#endif
}
SECTION("access non-existing value")
@@ -177,6 +265,24 @@ TEST_CASE("element access 2")
CHECK(j_const.value("_", 12.34) == Approx(12.34));
CHECK(j_const.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j_const.value("_", json({10, 100})) == json({10, 100}));
#ifdef JSON_HAS_CPP_17
CHECK(j.value(std::string_view("_"), 2) == 2);
CHECK(j.value(std::string_view("_"), 2u) == 2u);
CHECK(j.value(std::string_view("_"), false) == false);
CHECK(j.value(std::string_view("_"), "bar") == "bar");
CHECK(j.value(std::string_view("_"), 12.34) == Approx(12.34));
CHECK(j.value(std::string_view("_"), json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j.value(std::string_view("_"), json({10, 100})) == json({10, 100}));
CHECK(j_const.value(std::string_view("_"), 2) == 2);
CHECK(j_const.value(std::string_view("_"), 2u) == 2u);
CHECK(j_const.value(std::string_view("_"), false) == false);
CHECK(j_const.value(std::string_view("_"), "bar") == "bar");
CHECK(j_const.value(std::string_view("_"), 12.34) == Approx(12.34));
CHECK(j_const.value(std::string_view("_"), json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j_const.value(std::string_view("_"), json({10, 100})) == json({10, 100}));
#endif
}
SECTION("access on non-object type")
@@ -187,6 +293,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::null);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&);
#endif
}
SECTION("boolean")
@@ -195,6 +306,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::boolean);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&);
#endif
}
SECTION("string")
@@ -203,6 +319,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::string);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&);
#endif
}
SECTION("array")
@@ -211,6 +332,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::array);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&);
#endif
}
SECTION("number (integer)")
@@ -219,6 +345,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_integer);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#endif
}
SECTION("number (unsigned)")
@@ -227,6 +358,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_unsigned);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#endif
}
SECTION("number (floating-point)")
@@ -235,6 +371,11 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_float);
CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&);
#endif
}
}
}
@@ -330,6 +471,31 @@ TEST_CASE("element access 2")
}
}
SECTION("non-const operator[]")
{
{
json j_null;
CHECK(j_null.is_null());
j_null["key"] = 1;
CHECK(j_null.is_object());
CHECK(j_null.size() == 1);
j_null["key"] = 2;
CHECK(j_null.size() == 1);
}
#ifdef JSON_HAS_CPP_17
{
std::string_view key = "key";
json j_null;
CHECK(j_null.is_null());
j_null[key] = 1;
CHECK(j_null.is_object());
CHECK(j_null.size() == 1);
j_null[key] = 2;
CHECK(j_null.size() == 1);
}
#endif
}
SECTION("front and back")
{
// "array" is the smallest key
@@ -390,6 +556,56 @@ TEST_CASE("element access 2")
CHECK(j_const[json::object_t::key_type("array")] == j["array"]);
}
#ifdef JSON_HAS_CPP_17
SECTION("access within bounds (string_view)")
{
CHECK(j["integer"] == json(1));
CHECK(j[std::string_view("integer")] == j["integer"]);
CHECK(j["unsigned"] == json(1u));
CHECK(j[std::string_view("unsigned")] == j["unsigned"]);
CHECK(j["boolean"] == json(true));
CHECK(j[std::string_view("boolean")] == j["boolean"]);
CHECK(j["null"] == json(nullptr));
CHECK(j[std::string_view("null")] == j["null"]);
CHECK(j["string"] == json("hello world"));
CHECK(j[std::string_view("string")] == j["string"]);
CHECK(j["floating"] == json(42.23));
CHECK(j[std::string_view("floating")] == j["floating"]);
CHECK(j["object"] == json::object());
CHECK(j[std::string_view("object")] == j["object"]);
CHECK(j["array"] == json({1, 2, 3}));
CHECK(j[std::string_view("array")] == j["array"]);
CHECK(j_const["integer"] == json(1));
CHECK(j_const[std::string_view("integer")] == j["integer"]);
CHECK(j_const["boolean"] == json(true));
CHECK(j_const[std::string_view("boolean")] == j["boolean"]);
CHECK(j_const["null"] == json(nullptr));
CHECK(j_const[std::string_view("null")] == j["null"]);
CHECK(j_const["string"] == json("hello world"));
CHECK(j_const[std::string_view("string")] == j["string"]);
CHECK(j_const["floating"] == json(42.23));
CHECK(j_const[std::string_view("floating")] == j["floating"]);
CHECK(j_const["object"] == json::object());
CHECK(j_const[std::string_view("object")] == j["object"]);
CHECK(j_const["array"] == json({1, 2, 3}));
CHECK(j_const[std::string_view("array")] == j["array"]);
}
#endif
SECTION("access on non-object type")
{
SECTION("null")
@@ -397,10 +613,16 @@ TEST_CASE("element access 2")
json j_nonobject(json::value_t::null);
json j_nonobject2(json::value_t::null);
const json j_const_nonobject(j_nonobject);
CHECK_NOTHROW(j_nonobject["foo"]);
CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]);
CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_NOTHROW(j_nonobject2[std::string_view("foo")]);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&);
#endif
}
SECTION("boolean")
@@ -415,6 +637,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&);
#endif
}
SECTION("string")
@@ -429,6 +656,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&);
#endif
}
SECTION("array")
@@ -442,6 +674,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&);
#endif
}
SECTION("number (integer)")
@@ -456,6 +693,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#endif
}
SECTION("number (unsigned)")
@@ -470,6 +712,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#endif
}
SECTION("number (floating-point)")
@@ -484,6 +731,11 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&);
#endif
}
}
}
@@ -533,6 +785,51 @@ TEST_CASE("element access 2")
CHECK(j.erase("array") == 0);
}
#ifdef JSON_HAS_CPP_17
SECTION("remove element by key (string_view)")
{
CHECK(j.find(std::string_view("integer")) != j.end());
CHECK(j.erase(std::string_view("integer")) == 1);
CHECK(j.find(std::string_view("integer")) == j.end());
CHECK(j.erase(std::string_view("integer")) == 0);
CHECK(j.find(std::string_view("unsigned")) != j.end());
CHECK(j.erase(std::string_view("unsigned")) == 1);
CHECK(j.find(std::string_view("unsigned")) == j.end());
CHECK(j.erase(std::string_view("unsigned")) == 0);
CHECK(j.find(std::string_view("boolean")) != j.end());
CHECK(j.erase(std::string_view("boolean")) == 1);
CHECK(j.find(std::string_view("boolean")) == j.end());
CHECK(j.erase(std::string_view("boolean")) == 0);
CHECK(j.find(std::string_view("null")) != j.end());
CHECK(j.erase(std::string_view("null")) == 1);
CHECK(j.find(std::string_view("null")) == j.end());
CHECK(j.erase(std::string_view("null")) == 0);
CHECK(j.find(std::string_view("string")) != j.end());
CHECK(j.erase(std::string_view("string")) == 1);
CHECK(j.find(std::string_view("string")) == j.end());
CHECK(j.erase(std::string_view("string")) == 0);
CHECK(j.find(std::string_view("floating")) != j.end());
CHECK(j.erase(std::string_view("floating")) == 1);
CHECK(j.find(std::string_view("floating")) == j.end());
CHECK(j.erase(std::string_view("floating")) == 0);
CHECK(j.find(std::string_view("object")) != j.end());
CHECK(j.erase(std::string_view("object")) == 1);
CHECK(j.find(std::string_view("object")) == j.end());
CHECK(j.erase(std::string_view("object")) == 0);
CHECK(j.find(std::string_view("array")) != j.end());
CHECK(j.erase(std::string_view("array")) == 1);
CHECK(j.find(std::string_view("array")) == j.end());
CHECK(j.erase(std::string_view("array")) == 0);
}
#endif
SECTION("remove element by iterator")
{
SECTION("erase(begin())")
@@ -652,36 +949,60 @@ TEST_CASE("element access 2")
{
json j_nonobject(json::value_t::null);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&);
#endif
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&);
#endif
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&);
#endif
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with array", json::type_error&);
#endif
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#endif
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&);
#endif
}
}
}
@@ -699,12 +1020,28 @@ TEST_CASE("element access 2")
CHECK(j_const.find(key) != j_const.end());
CHECK(*j_const.find(key) == j_const.at(key));
}
#ifdef JSON_HAS_CPP_17
for (const std::string_view key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.find(key) != j.end());
CHECK(*j.find(key) == j.at(key));
CHECK(j_const.find(key) != j_const.end());
CHECK(*j_const.find(key) == j_const.at(key));
}
#endif
}
SECTION("nonexisting element")
{
CHECK(j.find("foo") == j.end());
CHECK(j_const.find("foo") == j_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j.find(std::string_view("foo")) == j.end());
CHECK(j_const.find(std::string_view("foo")) == j_const.end());
#endif
}
SECTION("all types")
@@ -713,64 +1050,112 @@ TEST_CASE("element access 2")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
SECTION("string")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
SECTION("object")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
SECTION("array")
{
json j_nonarray(json::value_t::array);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
SECTION("boolean")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
SECTION("number (integer)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
SECTION("number (unsigned)")
{
json j_nonarray(json::value_t::number_unsigned);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
SECTION("number (floating-point)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
#ifdef JSON_HAS_CPP_17
CHECK(j_nonarray.find(std::string_view("foo")) == j_nonarray.end());
CHECK(j_nonarray_const.find(std::string_view("foo")) == j_nonarray_const.end());
#endif
}
}
}
@@ -786,12 +1171,26 @@ TEST_CASE("element access 2")
CHECK(j.count(key) == 1);
CHECK(j_const.count(key) == 1);
}
#ifdef JSON_HAS_CPP_17
for (const std::string_view key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.count(key) == 1);
CHECK(j_const.count(key) == 1);
}
#endif
}
SECTION("nonexisting element")
{
CHECK(j.count("foo") == 0);
CHECK(j_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("all types")
@@ -800,64 +1199,112 @@ TEST_CASE("element access 2")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(json::value_t::null);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(json::value_t::string);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("object")
{
json j_nonobject(json::value_t::object);
const json j_nonobject_const(json::value_t::object);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(json::value_t::array);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(json::value_t::boolean);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(json::value_t::number_integer);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(json::value_t::number_unsigned);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(json::value_t::number_float);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
#ifdef JSON_HAS_CPP_17
CHECK(j.count(std::string_view("foo")) == 0);
CHECK(j_const.count(std::string_view("foo")) == 0);
#endif
}
}
}
@@ -873,12 +1320,27 @@ TEST_CASE("element access 2")
CHECK(j.contains(key) == true);
CHECK(j_const.contains(key) == true);
}
#ifdef JSON_HAS_CPP_17
for (const std::string_view key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.contains(key) == true);
CHECK(j_const.contains(key) == true);
}
#endif
}
SECTION("nonexisting element")
{
CHECK(j.contains("foo") == false);
CHECK(j_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j.contains(std::string_view("foo")) == false);
CHECK(j_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("all types")
@@ -887,56 +1349,98 @@ TEST_CASE("element access 2")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(json::value_t::null);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(json::value_t::string);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("object")
{
json j_nonobject(json::value_t::object);
const json j_nonobject_const(json::value_t::object);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(json::value_t::array);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(json::value_t::boolean);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(json::value_t::number_integer);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(json::value_t::number_unsigned);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
SECTION("number (floating-point)")
@@ -945,6 +1449,10 @@ TEST_CASE("element access 2")
const json j_nonobject_const(json::value_t::number_float);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
#ifdef JSON_HAS_CPP_17
CHECK(j_nonobject.contains(std::string_view("foo")) == false);
CHECK(j_nonobject_const.contains(std::string_view("foo")) == false);
#endif
}
}
}