mirror of
https://github.com/nlohmann/json.git
synced 2026-10-08 15:37:13 +00:00
Factor out more repeated error paths and test boilerplate
Library: - add throw_cannot_use_with() for the 34 copies of type_error.304-312 "cannot use X with Y" - iter_impl: add throw_cannot_get_value() (invalid_iterator.214) - parser: add syntax_error() for the 12 parse_error.101 sites - ordered_map: share the four at() bodies via at_impl() - json_sax_dom_callback_parser: add pop_container() for end_object() and end_array() - binary_reader: build the two UBJSON/BJData length-type messages with concat() and last_byte_error() Tests: - move same_value(), the NDEBUG guard, and step 0 (parse without exceptions) of the seven fuzzer drivers into tests/src/fuzzer_common.hpp Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
16 files changed
+337
-481
No files matched your search
@@ -321,6 +321,22 @@ JSON_HEDLEY_NO_RETURN inline void throw_type_must_be(const char* expected, const
|
||||
JSON_THROW(type_error::create(302, concat("type must be ", expected, ", but is ", j.type_name()), &j));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief throws because an operation is not supported for the type of @a j
|
||||
@param[in] id_ the id of the type_error exception (304..312)
|
||||
@param[in] operation the operation, e.g. "erase()"
|
||||
@param[in] j the value the operation was called on
|
||||
@throw type_error always
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
JSON_HEDLEY_NO_RETURN inline void throw_cannot_use_with(const int id_, const char* operation, const BasicJsonType& j)
|
||||
{
|
||||
static_cast<void>(id_); // unused when JSON_NOEXCEPTION is defined
|
||||
static_cast<void>(operation);
|
||||
static_cast<void>(j);
|
||||
JSON_THROW(type_error::create(id_, concat("cannot use ", operation, " with ", j.type_name()), &j));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
|
||||
@@ -2566,18 +2566,10 @@ class binary_reader
|
||||
default:
|
||||
break;
|
||||
}
|
||||
auto last_token = get_token_string();
|
||||
std::string message;
|
||||
|
||||
if (input_format != input_format_t::bjdata)
|
||||
{
|
||||
message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
|
||||
}
|
||||
return last_byte_error(113, message, "string");
|
||||
const char* expected = input_format != input_format_t::bjdata
|
||||
? "expected length type specification (U, i, I, l, L)"
|
||||
: "expected length type specification (U, i, u, I, m, l, M, L)";
|
||||
return last_byte_error(113, concat(expected, "; last byte: 0x", get_token_string()), "string");
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2840,18 +2832,10 @@ class binary_reader
|
||||
default:
|
||||
break;
|
||||
}
|
||||
auto last_token = get_token_string();
|
||||
std::string message;
|
||||
|
||||
if (input_format != input_format_t::bjdata)
|
||||
{
|
||||
message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
|
||||
}
|
||||
return last_byte_error(113, message, "size");
|
||||
const char* expected = input_format != input_format_t::bjdata
|
||||
? "expected length type specification (U, i, I, l, L) after '#'"
|
||||
: "expected length type specification (U, i, u, I, m, l, M, L) after '#'";
|
||||
return last_byte_error(113, concat(expected, "; last byte: 0x", get_token_string()), "size");
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -723,13 +723,7 @@ class json_sax_dom_callback_parser
|
||||
}
|
||||
}
|
||||
|
||||
JSON_ASSERT(!ref_stack.empty());
|
||||
JSON_ASSERT(!keep_stack.empty());
|
||||
JSON_ASSERT(!container_key_stack.empty());
|
||||
ref_stack.pop_back();
|
||||
keep_stack.pop_back();
|
||||
const string_t object_key = std::move(container_key_stack.back());
|
||||
container_key_stack.pop_back();
|
||||
const string_t object_key = pop_container();
|
||||
|
||||
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
|
||||
{
|
||||
@@ -811,13 +805,7 @@ class json_sax_dom_callback_parser
|
||||
}
|
||||
}
|
||||
|
||||
JSON_ASSERT(!ref_stack.empty());
|
||||
JSON_ASSERT(!keep_stack.empty());
|
||||
JSON_ASSERT(!container_key_stack.empty());
|
||||
ref_stack.pop_back();
|
||||
keep_stack.pop_back();
|
||||
const string_t object_key = std::move(container_key_stack.back());
|
||||
container_key_stack.pop_back();
|
||||
const string_t object_key = pop_container();
|
||||
|
||||
// remove discarded value
|
||||
if (!ref_stack.empty() && ref_stack.back())
|
||||
@@ -904,6 +892,23 @@ class json_sax_dom_callback_parser
|
||||
return string_t{};
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief leave the object or array that end_object()/end_array() just closed
|
||||
@return the key the container is stored under in its parent (see
|
||||
container_key_stack)
|
||||
*/
|
||||
string_t pop_container()
|
||||
{
|
||||
JSON_ASSERT(!ref_stack.empty());
|
||||
JSON_ASSERT(!keep_stack.empty());
|
||||
JSON_ASSERT(!container_key_stack.empty());
|
||||
ref_stack.pop_back();
|
||||
keep_stack.pop_back();
|
||||
string_t object_key = std::move(container_key_stack.back());
|
||||
container_key_stack.pop_back();
|
||||
return object_key;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief remove the discarded value the callback rejected from its parent,
|
||||
unless it is a duplicate key's slot with a stashed previous value, in
|
||||
|
||||
@@ -156,9 +156,7 @@ class parser
|
||||
// strict mode: next byte must be EOF
|
||||
if (get_token() != token_type::end_of_input)
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::end_of_input, "value"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -197,10 +195,7 @@ class parser
|
||||
// in strict mode, input must be completely read
|
||||
if (get_token() != token_type::end_of_input)
|
||||
{
|
||||
sdp.parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::end_of_input, "value"), nullptr));
|
||||
syntax_error(sdp, exception_message(token_type::end_of_input, "value"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -250,9 +245,7 @@ class parser
|
||||
// parse key
|
||||
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::value_string, "object key"));
|
||||
}
|
||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||
{
|
||||
@@ -262,9 +255,7 @@ class parser
|
||||
// parse separator (:)
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator)))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::name_separator, "object separator"));
|
||||
}
|
||||
|
||||
// remember we are now inside an object
|
||||
@@ -375,23 +366,16 @@ class parser
|
||||
case token_type::parse_error:
|
||||
{
|
||||
// using "uninitialized" to avoid an "expected" message
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::uninitialized, "value"));
|
||||
}
|
||||
case token_type::end_of_input:
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||
return syntax_error(*sax, "attempting to parse an empty input; check that your input string or stream contains the expected JSON");
|
||||
}
|
||||
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::literal_or_value, "value"));
|
||||
}
|
||||
case token_type::uninitialized:
|
||||
case token_type::end_array:
|
||||
@@ -401,9 +385,7 @@ class parser
|
||||
case token_type::literal_or_value:
|
||||
default: // the last token was unexpected
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::literal_or_value, "value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,9 +436,7 @@ class parser
|
||||
continue;
|
||||
}
|
||||
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::end_array, "array"));
|
||||
}
|
||||
|
||||
// states.back() is false -> object
|
||||
@@ -473,9 +453,7 @@ class parser
|
||||
// parse key
|
||||
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::value_string, "object key"));
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||
@@ -486,9 +464,7 @@ class parser
|
||||
// parse separator (:)
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator)))
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::name_separator, "object separator"));
|
||||
}
|
||||
|
||||
// parse values
|
||||
@@ -516,9 +492,7 @@ class parser
|
||||
continue;
|
||||
}
|
||||
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));
|
||||
return syntax_error(*sax, exception_message(token_type::end_object, "object"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,6 +509,19 @@ class parser
|
||||
return (last_token = m_lexer.scan_expecting(expected_type)) == expected_type;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reports a syntax error at the current token (parse_error.101)
|
||||
@param[in] sax the SAX parser to report the error to
|
||||
@param[in] message the error message
|
||||
@return the result of the SAX parser's parse_error()
|
||||
*/
|
||||
template<typename SAX>
|
||||
bool syntax_error(SAX& sax, const std::string& message)
|
||||
{
|
||||
return sax.parse_error(m_lexer.get_position(), m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), message, nullptr));
|
||||
}
|
||||
|
||||
std::string exception_message(const token_type expected, const std::string& context)
|
||||
{
|
||||
std::string error_msg = "syntax error ";
|
||||
|
||||
@@ -279,6 +279,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
}
|
||||
}
|
||||
|
||||
/// @throw invalid_iterator.214 always
|
||||
JSON_HEDLEY_NO_RETURN void throw_cannot_get_value() const
|
||||
{
|
||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||
}
|
||||
|
||||
public:
|
||||
/*!
|
||||
@brief return a reference to the value pointed to by the iterator
|
||||
@@ -303,7 +309,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
}
|
||||
|
||||
case value_t::null:
|
||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||
throw_cannot_get_value();
|
||||
|
||||
case value_t::string:
|
||||
case value_t::boolean:
|
||||
@@ -319,7 +325,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
return *m_object;
|
||||
}
|
||||
|
||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||
throw_cannot_get_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,7 +367,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
return m_object;
|
||||
}
|
||||
|
||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||
throw_cannot_get_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -710,7 +716,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
return *std::next(m_it.array_iterator, n);
|
||||
|
||||
case value_t::null:
|
||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||
throw_cannot_get_value();
|
||||
|
||||
case value_t::string:
|
||||
case value_t::boolean:
|
||||
@@ -726,7 +732,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
return *m_object;
|
||||
}
|
||||
|
||||
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||
throw_cannot_get_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+34
-34
@@ -3320,7 +3320,7 @@ public:
|
||||
// at only works for objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", j.type_name()), &j));
|
||||
detail::throw_cannot_use_with(304, "at()", j);
|
||||
}
|
||||
|
||||
auto it = object_lookup(j, std::forward<KeyType>(key));
|
||||
@@ -3345,7 +3345,7 @@ public:
|
||||
// at only works for arrays
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", j.type_name()), &j));
|
||||
detail::throw_cannot_use_with(304, "at()", j);
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(idx >= j.m_data.m_value.array->size()))
|
||||
@@ -3487,7 +3487,7 @@ public:
|
||||
return m_data.m_value.array->operator[](idx);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(305, "operator[] with a numeric argument", *this);
|
||||
}
|
||||
|
||||
/// @brief access specified array element
|
||||
@@ -3501,7 +3501,7 @@ public:
|
||||
return m_data.m_value.array->operator[](idx);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(305, "operator[] with a numeric argument", *this);
|
||||
}
|
||||
|
||||
/// @brief access specified object element
|
||||
@@ -3521,7 +3521,7 @@ public:
|
||||
return set_parent(result.first->second);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(305, "operator[] with a string argument", *this);
|
||||
}
|
||||
|
||||
/// @brief access specified object element
|
||||
@@ -3536,7 +3536,7 @@ public:
|
||||
return it->second;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(305, "operator[] with a string argument", *this);
|
||||
}
|
||||
|
||||
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
||||
@@ -3572,7 +3572,7 @@ public:
|
||||
return set_parent(result.first->second);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(305, "operator[] with a string argument", *this);
|
||||
}
|
||||
|
||||
/// @brief access specified object element
|
||||
@@ -3589,7 +3589,7 @@ public:
|
||||
return it->second;
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(305, "operator[] with a string argument", *this);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -3613,7 +3613,7 @@ public:
|
||||
// value only works for objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(306, "value()", *this);
|
||||
}
|
||||
|
||||
const auto it = find(std::forward<KeyType>(key));
|
||||
@@ -3628,7 +3628,7 @@ public:
|
||||
// value only works for arrays and objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_structured()))
|
||||
{
|
||||
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(306, "value()", *this);
|
||||
}
|
||||
|
||||
return ptr.get_checked_or_null(this);
|
||||
@@ -3837,7 +3837,7 @@ public:
|
||||
case value_t::null:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(307, "erase()", *this);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3898,7 +3898,7 @@ public:
|
||||
case value_t::null:
|
||||
case value_t::discarded:
|
||||
default:
|
||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(307, "erase()", *this);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3912,7 +3912,7 @@ public:
|
||||
// this erase only works for objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(307, "erase()", *this);
|
||||
}
|
||||
|
||||
const auto erased = m_data.m_value.object->erase(std::forward<KeyType>(key));
|
||||
@@ -3927,7 +3927,7 @@ public:
|
||||
// this erase only works for objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(307, "erase()", *this);
|
||||
}
|
||||
|
||||
const auto it = object_lookup(*this, std::forward<KeyType>(key));
|
||||
@@ -3976,7 +3976,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(307, "erase()", *this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4465,7 +4465,7 @@ public:
|
||||
// push_back only works for null objects or arrays
|
||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||
{
|
||||
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(308, "push_back()", *this);
|
||||
}
|
||||
|
||||
// transform a null object into an array
|
||||
@@ -4496,7 +4496,7 @@ public:
|
||||
// push_back only works for null objects or arrays
|
||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||
{
|
||||
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(308, "push_back()", *this);
|
||||
}
|
||||
|
||||
// transform a null object into an array
|
||||
@@ -4526,7 +4526,7 @@ public:
|
||||
// push_back only works for null objects or objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
||||
{
|
||||
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(308, "push_back()", *this);
|
||||
}
|
||||
|
||||
// transform a null object into an object
|
||||
@@ -4580,7 +4580,7 @@ public:
|
||||
// emplace_back only works for null objects or arrays
|
||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||
{
|
||||
JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(311, "emplace_back()", *this);
|
||||
}
|
||||
|
||||
// transform a null object into an array
|
||||
@@ -4603,7 +4603,7 @@ public:
|
||||
// emplace only works for null objects or arrays
|
||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
||||
{
|
||||
JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(311, "emplace()", *this);
|
||||
}
|
||||
|
||||
// transform a null object into an object
|
||||
@@ -4662,7 +4662,7 @@ public:
|
||||
return insert_iterator(pos, val);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(309, "insert()", *this);
|
||||
}
|
||||
|
||||
/// @brief inserts element into array
|
||||
@@ -4684,7 +4684,7 @@ public:
|
||||
return insert_iterator(pos, std::move(tmp));
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(309, "insert()", *this);
|
||||
}
|
||||
|
||||
/// @brief inserts copies of element into array
|
||||
@@ -4704,7 +4704,7 @@ public:
|
||||
return insert_iterator(pos, cnt, val);
|
||||
}
|
||||
|
||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(309, "insert()", *this);
|
||||
}
|
||||
|
||||
/// @brief inserts range of elements into array
|
||||
@@ -4714,7 +4714,7 @@ public:
|
||||
// insert only works for arrays
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(309, "insert()", *this);
|
||||
}
|
||||
|
||||
// check if iterator pos fits to this JSON value
|
||||
@@ -4751,7 +4751,7 @@ public:
|
||||
// insert only works for arrays
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||
{
|
||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(309, "insert()", *this);
|
||||
}
|
||||
|
||||
// check if iterator pos fits to this JSON value
|
||||
@@ -4779,7 +4779,7 @@ public:
|
||||
// insert only works for objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(309, "insert()", *this);
|
||||
}
|
||||
|
||||
// check if range iterators belong to the same JSON object
|
||||
@@ -4808,7 +4808,7 @@ public:
|
||||
// j, not the copy made below)
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", j.type_name()), &j));
|
||||
detail::throw_cannot_use_with(312, "update()", j);
|
||||
}
|
||||
|
||||
// copy first: j may be *this or one of its descendants, and is
|
||||
@@ -4832,7 +4832,7 @@ public:
|
||||
// passed iterators must belong to objects
|
||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
|
||||
detail::throw_cannot_use_with(312, "update()", *first.m_object);
|
||||
}
|
||||
|
||||
// copy first: the range may belong to *this or one of its
|
||||
@@ -4868,7 +4868,7 @@ public:
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||
{
|
||||
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(312, "update()", *this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5031,7 +5031,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(310, "swap(array_t&)", *this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5048,7 +5048,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(310, "swap(object_t&)", *this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5064,7 +5064,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(310, "swap(string_t&)", *this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5080,7 +5080,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(310, "swap(binary_t&)", *this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5096,7 +5096,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
|
||||
detail::throw_cannot_use_with(310, "swap(binary_t::container_type&)", *this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,19 @@ private:
|
||||
return self.end();
|
||||
}
|
||||
|
||||
/// @brief shared implementation of the const and non-const at() overloads
|
||||
/// @throw std::out_of_range if @a key is not found
|
||||
template<typename Self, typename KeyType>
|
||||
static auto at_impl(Self& self, const KeyType& key) -> decltype((self.begin()->second))
|
||||
{
|
||||
const auto it = find_impl(self, key);
|
||||
if (it == self.end())
|
||||
{
|
||||
JSON_THROW(std::out_of_range("key not found"));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/// @brief remove the entry @a it points to, preserving order
|
||||
/// @note keys are not movable, so the tail is destroyed and re-constructed in place
|
||||
void erase_at(iterator it)
|
||||
@@ -156,46 +169,26 @@ public:
|
||||
|
||||
T& at(const key_type& key)
|
||||
{
|
||||
const auto it = find_impl(*this, key);
|
||||
if (it == this->end())
|
||||
{
|
||||
JSON_THROW(std::out_of_range("key not found"));
|
||||
}
|
||||
return it->second;
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
|
||||
template<class KeyType, detail::enable_if_t<
|
||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||
{
|
||||
const auto it = find_impl(*this, key);
|
||||
if (it == this->end())
|
||||
{
|
||||
JSON_THROW(std::out_of_range("key not found"));
|
||||
}
|
||||
return it->second;
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
|
||||
const T& at(const key_type& key) const
|
||||
{
|
||||
const auto it = find_impl(*this, key);
|
||||
if (it == this->end())
|
||||
{
|
||||
JSON_THROW(std::out_of_range("key not found"));
|
||||
}
|
||||
return it->second;
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
|
||||
template<class KeyType, detail::enable_if_t<
|
||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||
{
|
||||
const auto it = find_impl(*this, key);
|
||||
if (it == this->end())
|
||||
{
|
||||
JSON_THROW(std::out_of_range("key not found"));
|
||||
}
|
||||
return it->second;
|
||||
return at_impl(*this, key);
|
||||
}
|
||||
|
||||
size_type erase(const key_type& key)
|
||||
|
||||
Reference in new issue
Block a user