🚧 implement operator[] for string_view

This commit is contained in:
Niels Lohmann 2021-03-28 14:34:14 +02:00
parent 4a78689865
commit d42f37a5f8
No known key found for this signature in database
GPG Key ID: 7F3CEA63AE251B69
3 changed files with 213 additions and 16 deletions

View File

@ -3667,7 +3667,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
In case the value was `null` before, it is converted to an object.
@param[in] key key of the element to access
@tparam KeyT a type convertible to an object key or a `std::string_view`
@tparam KeyT a type convertible to an object key, excluding `std::string_view`
@return reference to the element at key @a key
@ -3686,11 +3686,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
template < class KeyT, typename std::enable_if <
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&& (
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&&
#if defined(JSON_HAS_CPP_17)
std::is_same<typename std::decay<KeyT>::type, std::string_view>::value ||
!std::is_same<typename std::decay<KeyT>::type, std::string_view>::value&&
#endif
std::is_convertible<KeyT, typename object_t::key_type>::value), int >::type = 0 >
std::is_convertible<KeyT, typename object_t::key_type>::value, int >::type = 0 >
reference operator[](KeyT && key)
{
// implicitly convert null value to an empty object
@ -3710,6 +3710,33 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#if defined(JSON_HAS_CPP_17)
/// @copydoc operator[](KeyT&&)
reference operator[](const std::string_view& key)
{
// implicitly convert null value to an empty object
if (is_null())
{
m_type = value_t::object;
m_value.object = create<object_t>();
assert_invariant();
}
// operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
if (auto it = m_value.object->find(key); it != m_value.object->end())
{
return it->second;
}
return set_parent(m_value.object->operator[](json::object_t::key_type(key)));
}
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#endif
/*!
@brief read-only access specified object element
@ -3720,7 +3747,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
undefined.
@param[in] key key of the element to access
@tparam KeyT a type convertible to an object key or a `std::string_view`
@tparam KeyT a type convertible to an object key or, excluding `std::string_view`
@return const reference to the element at key @a key
@ -3742,11 +3769,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
template < class KeyT, typename std::enable_if <
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&& (
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&&
#if defined(JSON_HAS_CPP_17)
std::is_same<typename std::decay<KeyT>::type, std::string_view>::value ||
std::is_same<typename std::decay<KeyT>::type, std::string_view>::value&&
#endif
std::is_convertible<KeyT, typename object_t::key_type>::value), int >::type = 0 >
std::is_convertible<KeyT, typename object_t::key_type>::value, int >::type = 0 >
const_reference operator[](KeyT && key) const
{
// const operator[] only works for objects
@ -3760,6 +3787,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#if defined(JSON_HAS_CPP_17)
/// @copydoc operator[](KeyT&&) const
const_reference operator[](const std::string_view& key) const
{
// operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
auto it = m_value.object->find(key);
JSON_ASSERT(it != m_value.object->end());
return it->second;
}
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#endif
/*!
@brief access specified object element

View File

@ -20556,7 +20556,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
In case the value was `null` before, it is converted to an object.
@param[in] key key of the element to access
@tparam KeyT a type convertible to an object key or a `std::string_view`
@tparam KeyT a type convertible to an object key, excluding `std::string_view`
@return reference to the element at key @a key
@ -20575,11 +20575,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
template < class KeyT, typename std::enable_if <
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&& (
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&&
#if defined(JSON_HAS_CPP_17)
std::is_same<typename std::decay<KeyT>::type, std::string_view>::value ||
!std::is_same<typename std::decay<KeyT>::type, std::string_view>::value&&
#endif
std::is_convertible<KeyT, typename object_t::key_type>::value), int >::type = 0 >
std::is_convertible<KeyT, typename object_t::key_type>::value, int >::type = 0 >
reference operator[](KeyT && key)
{
// implicitly convert null value to an empty object
@ -20599,6 +20599,33 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#if defined(JSON_HAS_CPP_17)
/// @copydoc operator[](KeyT&&)
reference operator[](const std::string_view& key)
{
// implicitly convert null value to an empty object
if (is_null())
{
m_type = value_t::object;
m_value.object = create<object_t>();
assert_invariant();
}
// operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
if (auto it = m_value.object->find(key); it != m_value.object->end())
{
return it->second;
}
return set_parent(m_value.object->operator[](json::object_t::key_type(key)));
}
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#endif
/*!
@brief read-only access specified object element
@ -20609,7 +20636,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
undefined.
@param[in] key key of the element to access
@tparam KeyT a type convertible to an object key or a `std::string_view`
@tparam KeyT a type convertible to an object key or, excluding `std::string_view`
@return const reference to the element at key @a key
@ -20631,11 +20658,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
template < class KeyT, typename std::enable_if <
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&& (
!std::is_same<typename std::decay<KeyT>::type, json_pointer>::value&&
#if defined(JSON_HAS_CPP_17)
std::is_same<typename std::decay<KeyT>::type, std::string_view>::value ||
std::is_same<typename std::decay<KeyT>::type, std::string_view>::value&&
#endif
std::is_convertible<KeyT, typename object_t::key_type>::value), int >::type = 0 >
std::is_convertible<KeyT, typename object_t::key_type>::value, int >::type = 0 >
const_reference operator[](KeyT && key) const
{
// const operator[] only works for objects
@ -20649,6 +20676,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#if defined(JSON_HAS_CPP_17)
/// @copydoc operator[](KeyT&&) const
const_reference operator[](const std::string_view& key) const
{
// operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
auto it = m_value.object->find(key);
JSON_ASSERT(it != m_value.object->end());
return it->second;
}
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this));
}
#endif
/*!
@brief access specified object element

View File

@ -668,6 +668,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")
@ -683,6 +733,13 @@ TEST_CASE("element access 2")
CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with null");
#ifdef JSON_HAS_CPP_17
CHECK_NOTHROW(j_nonobject2[std::string_view("foo")]);
CHECK_THROWS_AS(j_const_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_const_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with null");
#endif
}
SECTION("boolean")
@ -702,6 +759,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean");
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_AS(j_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean");
CHECK_THROWS_AS(j_const_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_const_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean");
#endif
}
SECTION("string")
@ -721,6 +787,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with string");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with string");
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_AS(j_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with string");
CHECK_THROWS_AS(j_const_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_const_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with string");
#endif
}
SECTION("array")
@ -739,6 +814,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with array");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with array");
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_AS(j_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with array");
CHECK_THROWS_AS(j_const_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_const_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with array");
#endif
}
SECTION("number (integer)")
@ -758,6 +842,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_AS(j_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
CHECK_THROWS_AS(j_const_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_const_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
#endif
}
SECTION("number (unsigned)")
@ -777,6 +870,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_AS(j_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
CHECK_THROWS_AS(j_const_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_const_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
#endif
}
SECTION("number (floating-point)")
@ -796,6 +898,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
#ifdef JSON_HAS_CPP_17
CHECK_THROWS_AS(j_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
CHECK_THROWS_AS(j_const_nonobject[std::string_view("foo")], json::type_error&);
CHECK_THROWS_WITH(j_const_nonobject[std::string_view("foo")],
"[json.exception.type_error.305] cannot use operator[] with a string argument with number");
#endif
}
}
}