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:
Niels Lohmann committed 2026-10-07 17:29:58 +02:00
1 parent 546350440f
commit c3068e9f95
16 files changed
+337 -481

No files matched your search

+17 -24
View File
@@ -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)