🚧 implement operator[] for string_view

parent 4a786898
...@@ -3667,7 +3667,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -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. In case the value was `null` before, it is converted to an object.
@param[in] key key of the element to access @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 @return reference to the element at key @a key
...@@ -3686,11 +3686,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -3686,11 +3686,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0 @since version 1.0.0
*/ */
template < class KeyT, typename std::enable_if < 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) #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 #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) reference operator[](KeyT && key)
{ {
// implicitly convert null value to an empty object // implicitly convert null value to an empty object
...@@ -3710,6 +3710,33 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -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)); 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 @brief read-only access specified object element
...@@ -3720,7 +3747,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -3720,7 +3747,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
undefined. undefined.
@param[in] key key of the element to access @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 @return const reference to the element at key @a key
...@@ -3742,11 +3769,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -3742,11 +3769,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0 @since version 1.0.0
*/ */
template < class KeyT, typename std::enable_if < 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) #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 #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_reference operator[](KeyT && key) const
{ {
// const operator[] only works for objects // const operator[] only works for objects
...@@ -3760,6 +3787,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -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)); 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 @brief access specified object element
......
...@@ -20556,7 +20556,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -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. In case the value was `null` before, it is converted to an object.
@param[in] key key of the element to access @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 @return reference to the element at key @a key
...@@ -20575,11 +20575,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -20575,11 +20575,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0 @since version 1.0.0
*/ */
template < class KeyT, typename std::enable_if < 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) #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 #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) reference operator[](KeyT && key)
{ {
// implicitly convert null value to an empty object // implicitly convert null value to an empty object
...@@ -20599,6 +20599,33 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -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)); 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 @brief read-only access specified object element
...@@ -20609,7 +20636,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -20609,7 +20636,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
undefined. undefined.
@param[in] key key of the element to access @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 @return const reference to the element at key @a key
...@@ -20631,11 +20658,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -20631,11 +20658,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0 @since version 1.0.0
*/ */
template < class KeyT, typename std::enable_if < 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) #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 #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_reference operator[](KeyT && key) const
{ {
// const operator[] only works for objects // const operator[] only works for objects
...@@ -20649,6 +20676,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec ...@@ -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)); 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 @brief access specified object element
......
...@@ -668,6 +668,56 @@ TEST_CASE("element access 2") ...@@ -668,6 +668,56 @@ TEST_CASE("element access 2")
CHECK(j_const[json::object_t::key_type("array")] == j["array"]); 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("access on non-object type")
{ {
SECTION("null") SECTION("null")
...@@ -683,6 +733,13 @@ TEST_CASE("element access 2") ...@@ -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["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")], 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"); "[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") SECTION("boolean")
...@@ -702,6 +759,15 @@ TEST_CASE("element access 2") ...@@ -702,6 +759,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); "[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")], 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"); "[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") SECTION("string")
...@@ -721,6 +787,15 @@ TEST_CASE("element access 2") ...@@ -721,6 +787,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with string"); "[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")], 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"); "[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") SECTION("array")
...@@ -739,6 +814,15 @@ TEST_CASE("element access 2") ...@@ -739,6 +814,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with array"); "[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")], 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"); "[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)") SECTION("number (integer)")
...@@ -758,6 +842,15 @@ TEST_CASE("element access 2") ...@@ -758,6 +842,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number"); "[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")], 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"); "[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)") SECTION("number (unsigned)")
...@@ -777,6 +870,15 @@ TEST_CASE("element access 2") ...@@ -777,6 +870,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number"); "[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")], 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"); "[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)") SECTION("number (floating-point)")
...@@ -796,6 +898,15 @@ TEST_CASE("element access 2") ...@@ -796,6 +898,15 @@ TEST_CASE("element access 2")
"[json.exception.type_error.305] cannot use operator[] with a string argument with number"); "[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")], 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"); "[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
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment