mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 11:40:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57890cebad |
@@ -51,6 +51,7 @@ cc_library(
|
||||
"include/nlohmann/detail/meta/detected.hpp",
|
||||
"include/nlohmann/detail/meta/identity_tag.hpp",
|
||||
"include/nlohmann/detail/meta/is_sax.hpp",
|
||||
"include/nlohmann/detail/meta/logic.hpp",
|
||||
"include/nlohmann/detail/meta/std_fs.hpp",
|
||||
"include/nlohmann/detail/meta/type_traits.hpp",
|
||||
"include/nlohmann/detail/meta/void_t.hpp",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <nlohmann/detail/meta/identity_tag.hpp>
|
||||
#include <nlohmann/detail/meta/std_fs.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/meta/logic.hpp>
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
@@ -428,7 +429,9 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
}
|
||||
|
||||
// overload for arithmetic types, not chosen for basic_json template arguments
|
||||
// (BooleanType, etc.)
|
||||
// (BooleanType, etc.); note: Is it really necessary to provide explicit
|
||||
// overloads for boolean_t etc. in case of a custom BooleanType which is not
|
||||
// an arithmetic type?
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t <
|
||||
std::is_arithmetic<ArithmeticType>::value&&
|
||||
@@ -524,7 +527,7 @@ inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priori
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||
{
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, is_compatible_reference_type<BasicJsonType, Args>>...>::value,
|
||||
static_assert(cxpr_and<cxpr_or<cxpr_not<std::is_reference<Args>>, is_compatible_reference_type<BasicJsonType, Args>>...>::value,
|
||||
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
|
||||
return from_json_tuple_impl_base<1, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
}
|
||||
@@ -589,7 +592,7 @@ inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Has
|
||||
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
|
||||
// Workaround for MSVC 19.51 (and possibly later): in large cpp files, the compiler may fail to resolve with generic has_from_json (issue #4996)
|
||||
// Workaround for MSVC 19.51 (and possibly later): in large in large cpp files, the compiler may fail to resolve with generic has_from_json (issue #4996)
|
||||
template<typename BasicJsonType>
|
||||
struct has_from_json<BasicJsonType, std_fs::path, void> : std::true_type {};
|
||||
|
||||
|
||||
@@ -60,11 +60,9 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
|
||||
"iter_impl only accepts (const) basic_json");
|
||||
// superficial check for the LegacyBidirectionalIterator named requirement
|
||||
// note: only array_t::iterator is checked here; object_t::iterator may be
|
||||
// a forward-only iterator as long as reverse iteration and operator--
|
||||
// are never used on it
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
|
||||
"basic_json iterator assumes array type iterators satisfy the LegacyBidirectionalIterator named requirement.");
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
|
||||
&& std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
|
||||
"basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
|
||||
|
||||
public:
|
||||
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
|
||||
|
||||
@@ -583,6 +583,63 @@ class json_pointer
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@throw parse_error.106 if an array index begins with '0'
|
||||
@throw parse_error.109 if an array index was not a number
|
||||
@throw out_of_range.402 if the array index '-' is used
|
||||
@throw out_of_range.404 if the JSON pointer can not be resolved
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
const BasicJsonType& get_checked(const BasicJsonType* ptr) const
|
||||
{
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
{
|
||||
switch (ptr->type())
|
||||
{
|
||||
case detail::value_t::object:
|
||||
{
|
||||
// note: at performs range check
|
||||
ptr = &ptr->at(reference_token);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::array:
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||
{
|
||||
// "-" always fails the range check
|
||||
JSON_THROW(detail::out_of_range::create(402, detail::concat(
|
||||
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
||||
") is out of range"), ptr));
|
||||
}
|
||||
|
||||
const auto idx = array_index<BasicJsonType>(reference_token);
|
||||
// Bounds check before access to avoid exception with JSON_NOEXCEPTION
|
||||
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
||||
{
|
||||
JSON_THROW(detail::out_of_range::create(401, detail::concat(
|
||||
"array index ", std::to_string(idx), " is out of range"), ptr));
|
||||
}
|
||||
ptr = &ptr->operator[](idx);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::null:
|
||||
case detail::value_t::string:
|
||||
case detail::value_t::boolean:
|
||||
case detail::value_t::number_integer:
|
||||
case detail::value_t::number_unsigned:
|
||||
case detail::value_t::number_float:
|
||||
case detail::value_t::binary:
|
||||
case detail::value_t::discarded:
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief return a pointer to the pointed to value, or `nullptr` if the
|
||||
pointer cannot be resolved because a key is missing, an array
|
||||
@@ -621,19 +678,29 @@ class json_pointer
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// may throw parse_error.106/109 for a malformed index; an
|
||||
// index that is syntactically valid but cannot be
|
||||
// represented (out_of_range.404/410) is treated like an
|
||||
// out-of-range index below
|
||||
typename BasicJsonType::size_type idx{};
|
||||
JSON_TRY
|
||||
// tokens that array_index() rejects with parse_error.106/109
|
||||
// are passed on to it; all other tokens that it would reject
|
||||
// with out_of_range.404/410 are detected here, so that this
|
||||
// also works without exceptions
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 && !(reference_token[0] >= '1' && reference_token[0] <= '9')))
|
||||
{
|
||||
idx = array_index<BasicJsonType>(reference_token);
|
||||
static_cast<void>(array_index<BasicJsonType>(reference_token)); // throws parse_error.106/109
|
||||
}
|
||||
JSON_INTERNAL_CATCH (detail::out_of_range&)
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.empty() || !std::all_of(reference_token.begin(), reference_token.end(), [](const char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
})))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
errno = 0; // strtoull() does not reset errno on success
|
||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.data(), &p_end, 10); // NOLINT(runtime/int)
|
||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE || magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
const auto idx = static_cast<typename BasicJsonType::size_type>(magnitude);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility> // declval, pair
|
||||
#include <nlohmann/detail/meta/detected.hpp>
|
||||
#include <nlohmann/thirdparty/hedley/hedley.hpp>
|
||||
|
||||
// This file contains all internal macro definitions (except those affecting ABI)
|
||||
@@ -139,12 +140,10 @@
|
||||
// libstdc++ < 11 has incomplete C++20 ranges (issue #4440)
|
||||
#elif defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE < 11
|
||||
#define JSON_HAS_RANGES 0
|
||||
// clang < 16 with libstdc++ does not implement the ranges customization
|
||||
// points libstdc++ declares, so its C++20 ranges support is incomplete (issue #5161)
|
||||
// libc++ < 16 has incomplete C++20 ranges (issue #4440)
|
||||
#elif defined(__clang__) && !defined(__apple_build_version__) \
|
||||
&& __clang_major__ < 16 && defined(__GLIBCXX__)
|
||||
#define JSON_HAS_RANGES 0
|
||||
// libc++ < 16 has incomplete C++20 ranges (issue #4440)
|
||||
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
|
||||
#define JSON_HAS_RANGES 0
|
||||
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
|
||||
@@ -306,7 +305,7 @@ void templated_json_throw(ExceptionType exception)
|
||||
@brief macro to briefly define a mapping between an enum and JSON with exception
|
||||
on invalid input
|
||||
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
|
||||
@since version 3.13.0
|
||||
@since version 3.12.0
|
||||
*/
|
||||
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
|
||||
template<typename BasicJsonType> \
|
||||
@@ -877,6 +876,30 @@ void templated_json_throw(ExceptionType exception)
|
||||
\
|
||||
template<typename... T> \
|
||||
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
|
||||
} \
|
||||
\
|
||||
namespace detail2 { \
|
||||
struct std_name##_tag \
|
||||
{ \
|
||||
}; \
|
||||
\
|
||||
template<typename... T> \
|
||||
std_name##_tag std_name(T&&...); \
|
||||
\
|
||||
template<typename... T> \
|
||||
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
|
||||
\
|
||||
template<typename... T> \
|
||||
struct would_call_std_##std_name \
|
||||
{ \
|
||||
static constexpr auto const value = ::nlohmann::detail:: \
|
||||
is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
|
||||
}; \
|
||||
} /* namespace detail2 */ \
|
||||
\
|
||||
template<typename... T> \
|
||||
struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \
|
||||
{ \
|
||||
}
|
||||
|
||||
#ifndef JSON_USE_IMPLICIT_CONVERSIONS
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin)
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end)
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -62,5 +62,9 @@ using detected_or_t = typename detected_or<Default, Op, Args...>::type;
|
||||
template<class Expected, template<class...> class Op, class... Args>
|
||||
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
|
||||
|
||||
template<class To, template<class...> class Op, class... Args>
|
||||
using is_detected_convertible =
|
||||
std::is_convertible<detected_t<Op, Args...>, To>;
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // size_t
|
||||
#include <utility> // declval
|
||||
#include <string> // string
|
||||
|
||||
@@ -70,6 +70,37 @@ using parse_error_function_t = decltype(std::declval<T&>().parse_error(
|
||||
std::declval<std::size_t>(), std::declval<const std::string&>(),
|
||||
std::declval<const Exception&>()));
|
||||
|
||||
template<typename SAX, typename BasicJsonType>
|
||||
struct is_sax
|
||||
{
|
||||
private:
|
||||
static_assert(is_basic_json<BasicJsonType>::value,
|
||||
"BasicJsonType must be of type basic_json<...>");
|
||||
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using binary_t = typename BasicJsonType::binary_t;
|
||||
using exception_t = typename BasicJsonType::exception;
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
is_detected_exact<bool, null_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, boolean_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
|
||||
is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
|
||||
is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
|
||||
is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
|
||||
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
|
||||
is_detected_exact<bool, start_object_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
|
||||
is_detected_exact<bool, end_object_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, start_array_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, end_array_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
|
||||
};
|
||||
|
||||
template<typename SAX, typename BasicJsonType>
|
||||
struct is_sax_static_asserts
|
||||
{
|
||||
@@ -89,6 +120,8 @@ struct is_sax_static_asserts
|
||||
"Missing/invalid function: bool null()");
|
||||
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool boolean(bool)");
|
||||
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool boolean(bool)");
|
||||
static_assert(
|
||||
is_detected_exact<bool, number_integer_function_t, SAX,
|
||||
number_integer_t>::value,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::integral_constant < bool, (Booleans || ...) > {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::integral_constant < bool, (Booleans &&...) > {};
|
||||
|
||||
#else
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::false_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<true, Booleans...> : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<false, Booleans...> : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<true, Booleans...> : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<false, Booleans...> : std::false_type {};
|
||||
|
||||
#endif
|
||||
|
||||
template<class Boolean>
|
||||
struct cxpr_not : std::integral_constant < bool, !Boolean::value > {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_or : cxpr_or_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_c : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_and : cxpr_and_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_c : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -283,13 +283,6 @@ template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/disjunction
|
||||
template<class...> struct disjunction : std::false_type { };
|
||||
template<class B> struct disjunction<B> : B { };
|
||||
template<class B, class... Bn>
|
||||
struct disjunction<B, Bn...>
|
||||
: std::conditional<static_cast<bool>(B::value), B, disjunction<Bn...>>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/negation
|
||||
template<class B> struct negation : std::integral_constant < bool, !B::value > { };
|
||||
|
||||
@@ -611,6 +604,7 @@ struct is_compatible_integer_type_impl <
|
||||
std::is_integral<CompatibleNumberIntegerType>::value&&
|
||||
!std::is_same<bool, CompatibleNumberIntegerType>::value >>
|
||||
{
|
||||
// is there an assert somewhere on overflows?
|
||||
using RealLimits = std::numeric_limits<RealIntegerType>;
|
||||
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
|
||||
|
||||
@@ -804,7 +798,20 @@ struct has_capacity : std::integral_constant<bool, is_detected<detect_capacity,
|
||||
// a naive helper to check if a type is an ordered_map (exploits the fact that
|
||||
// ordered_map inherits capacity() from std::vector)
|
||||
template <typename T>
|
||||
struct is_ordered_map : has_capacity<T> {};
|
||||
struct is_ordered_map
|
||||
{
|
||||
using one = char;
|
||||
|
||||
struct two
|
||||
{
|
||||
char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
};
|
||||
|
||||
template <typename C> static one test( decltype(&C::capacity) ) ;
|
||||
template <typename C> static two test(...);
|
||||
|
||||
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg,cppcoreguidelines-use-enum-class)
|
||||
};
|
||||
|
||||
// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
|
||||
template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
|
||||
@@ -828,8 +835,10 @@ using all_signed = conjunction<std::is_signed<Types>...>;
|
||||
template<typename... Types>
|
||||
using all_unsigned = conjunction<std::is_unsigned<Types>...>;
|
||||
|
||||
// there's a disjunction trait in another PR; replace when merged
|
||||
template<typename... Types>
|
||||
using same_sign = disjunction<all_signed<Types...>, all_unsigned<Types...>>;
|
||||
using same_sign = std::integral_constant < bool,
|
||||
all_signed<Types...>::value || all_unsigned<Types...>::value >;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
using never_out_of_range = std::integral_constant < bool,
|
||||
|
||||
+318
-124
@@ -275,6 +275,104 @@
|
||||
|
||||
|
||||
#include <utility> // declval, pair
|
||||
// #include <nlohmann/detail/meta/detected.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// #include <nlohmann/detail/meta/void_t.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename ...Ts> struct make_void
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// https://en.cppreference.com/w/cpp/experimental/is_detected
|
||||
struct nonesuch
|
||||
{
|
||||
nonesuch() = delete;
|
||||
~nonesuch() = delete;
|
||||
nonesuch(nonesuch const&) = delete;
|
||||
nonesuch(nonesuch const&&) = delete;
|
||||
void operator=(nonesuch const&) = delete;
|
||||
void operator=(nonesuch&&) = delete;
|
||||
};
|
||||
|
||||
template<class Default,
|
||||
class AlwaysVoid,
|
||||
template<class...> class Op,
|
||||
class... Args>
|
||||
struct detector
|
||||
{
|
||||
using value_t = std::false_type;
|
||||
using type = Default;
|
||||
};
|
||||
|
||||
template<class Default, template<class...> class Op, class... Args>
|
||||
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
|
||||
{
|
||||
using value_t = std::true_type;
|
||||
using type = Op<Args...>;
|
||||
};
|
||||
|
||||
template<template<class...> class Op, class... Args>
|
||||
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
|
||||
|
||||
template<template<class...> class Op, class... Args>
|
||||
struct is_detected_lazy : is_detected<Op, Args...> { };
|
||||
|
||||
template<template<class...> class Op, class... Args>
|
||||
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
|
||||
|
||||
template<class Default, template<class...> class Op, class... Args>
|
||||
using detected_or = detector<Default, void, Op, Args...>;
|
||||
|
||||
template<class Default, template<class...> class Op, class... Args>
|
||||
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
|
||||
|
||||
template<class Expected, template<class...> class Op, class... Args>
|
||||
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
|
||||
|
||||
template<class To, template<class...> class Op, class... Args>
|
||||
using is_detected_convertible =
|
||||
std::is_convertible<detected_t<Op, Args...>, To>;
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/thirdparty/hedley/hedley.hpp>
|
||||
|
||||
|
||||
@@ -2453,12 +2551,10 @@ JSON_HEDLEY_DIAGNOSTIC_POP
|
||||
// libstdc++ < 11 has incomplete C++20 ranges (issue #4440)
|
||||
#elif defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE < 11
|
||||
#define JSON_HAS_RANGES 0
|
||||
// clang < 16 with libstdc++ does not implement the ranges customization
|
||||
// points libstdc++ declares, so its C++20 ranges support is incomplete (issue #5161)
|
||||
// libc++ < 16 has incomplete C++20 ranges (issue #4440)
|
||||
#elif defined(__clang__) && !defined(__apple_build_version__) \
|
||||
&& __clang_major__ < 16 && defined(__GLIBCXX__)
|
||||
#define JSON_HAS_RANGES 0
|
||||
// libc++ < 16 has incomplete C++20 ranges (issue #4440)
|
||||
#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 160000
|
||||
#define JSON_HAS_RANGES 0
|
||||
// nvcc CUDA 12.0/12.1 chokes on the enable_borrowed_range variable-template
|
||||
@@ -2620,7 +2716,7 @@ void templated_json_throw(ExceptionType exception)
|
||||
@brief macro to briefly define a mapping between an enum and JSON with exception
|
||||
on invalid input
|
||||
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
|
||||
@since version 3.13.0
|
||||
@since version 3.12.0
|
||||
*/
|
||||
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
|
||||
template<typename BasicJsonType> \
|
||||
@@ -3191,6 +3287,30 @@ void templated_json_throw(ExceptionType exception)
|
||||
\
|
||||
template<typename... T> \
|
||||
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
|
||||
} \
|
||||
\
|
||||
namespace detail2 { \
|
||||
struct std_name##_tag \
|
||||
{ \
|
||||
}; \
|
||||
\
|
||||
template<typename... T> \
|
||||
std_name##_tag std_name(T&&...); \
|
||||
\
|
||||
template<typename... T> \
|
||||
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
|
||||
\
|
||||
template<typename... T> \
|
||||
struct would_call_std_##std_name \
|
||||
{ \
|
||||
static constexpr auto const value = ::nlohmann::detail:: \
|
||||
is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
|
||||
}; \
|
||||
} /* namespace detail2 */ \
|
||||
\
|
||||
template<typename... T> \
|
||||
struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \
|
||||
{ \
|
||||
}
|
||||
|
||||
#ifndef JSON_USE_IMPLICIT_CONVERSIONS
|
||||
@@ -3740,31 +3860,6 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/void_t.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename ...Ts> struct make_void
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
|
||||
@@ -3836,7 +3931,7 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin)
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -3856,80 +3951,13 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end)
|
||||
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/detected.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// #include <nlohmann/detail/meta/void_t.hpp>
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// https://en.cppreference.com/w/cpp/experimental/is_detected
|
||||
struct nonesuch
|
||||
{
|
||||
nonesuch() = delete;
|
||||
~nonesuch() = delete;
|
||||
nonesuch(nonesuch const&) = delete;
|
||||
nonesuch(nonesuch const&&) = delete;
|
||||
void operator=(nonesuch const&) = delete;
|
||||
void operator=(nonesuch&&) = delete;
|
||||
};
|
||||
|
||||
template<class Default,
|
||||
class AlwaysVoid,
|
||||
template<class...> class Op,
|
||||
class... Args>
|
||||
struct detector
|
||||
{
|
||||
using value_t = std::false_type;
|
||||
using type = Default;
|
||||
};
|
||||
|
||||
template<class Default, template<class...> class Op, class... Args>
|
||||
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
|
||||
{
|
||||
using value_t = std::true_type;
|
||||
using type = Op<Args...>;
|
||||
};
|
||||
|
||||
template<template<class...> class Op, class... Args>
|
||||
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
|
||||
|
||||
template<template<class...> class Op, class... Args>
|
||||
struct is_detected_lazy : is_detected<Op, Args...> { };
|
||||
|
||||
template<template<class...> class Op, class... Args>
|
||||
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
|
||||
|
||||
template<class Default, template<class...> class Op, class... Args>
|
||||
using detected_or = detector<Default, void, Op, Args...>;
|
||||
|
||||
template<class Default, template<class...> class Op, class... Args>
|
||||
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
|
||||
|
||||
template<class Expected, template<class...> class Op, class... Args>
|
||||
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/json_fwd.hpp>
|
||||
// __ _____ _____ _____
|
||||
@@ -4265,13 +4293,6 @@ template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/disjunction
|
||||
template<class...> struct disjunction : std::false_type { };
|
||||
template<class B> struct disjunction<B> : B { };
|
||||
template<class B, class... Bn>
|
||||
struct disjunction<B, Bn...>
|
||||
: std::conditional<static_cast<bool>(B::value), B, disjunction<Bn...>>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/negation
|
||||
template<class B> struct negation : std::integral_constant < bool, !B::value > { };
|
||||
|
||||
@@ -4593,6 +4614,7 @@ struct is_compatible_integer_type_impl <
|
||||
std::is_integral<CompatibleNumberIntegerType>::value&&
|
||||
!std::is_same<bool, CompatibleNumberIntegerType>::value >>
|
||||
{
|
||||
// is there an assert somewhere on overflows?
|
||||
using RealLimits = std::numeric_limits<RealIntegerType>;
|
||||
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
|
||||
|
||||
@@ -4786,7 +4808,20 @@ struct has_capacity : std::integral_constant<bool, is_detected<detect_capacity,
|
||||
// a naive helper to check if a type is an ordered_map (exploits the fact that
|
||||
// ordered_map inherits capacity() from std::vector)
|
||||
template <typename T>
|
||||
struct is_ordered_map : has_capacity<T> {};
|
||||
struct is_ordered_map
|
||||
{
|
||||
using one = char;
|
||||
|
||||
struct two
|
||||
{
|
||||
char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
};
|
||||
|
||||
template <typename C> static one test( decltype(&C::capacity) ) ;
|
||||
template <typename C> static two test(...);
|
||||
|
||||
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg,cppcoreguidelines-use-enum-class)
|
||||
};
|
||||
|
||||
// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
|
||||
template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
|
||||
@@ -4810,8 +4845,10 @@ using all_signed = conjunction<std::is_signed<Types>...>;
|
||||
template<typename... Types>
|
||||
using all_unsigned = conjunction<std::is_unsigned<Types>...>;
|
||||
|
||||
// there's a disjunction trait in another PR; replace when merged
|
||||
template<typename... Types>
|
||||
using same_sign = disjunction<all_signed<Types...>, all_unsigned<Types...>>;
|
||||
using same_sign = std::integral_constant < bool,
|
||||
all_signed<Types...>::value || all_unsigned<Types...>::value >;
|
||||
|
||||
template<typename OfType, typename T>
|
||||
using never_out_of_range = std::integral_constant < bool,
|
||||
@@ -5429,6 +5466,63 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/logic.hpp>
|
||||
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::integral_constant < bool, (Booleans || ...) > {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::integral_constant < bool, (Booleans &&...) > {};
|
||||
|
||||
#else
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl : std::false_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<true, Booleans...> : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_impl<false, Booleans...> : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl : std::true_type {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<true, Booleans...> : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_impl<false, Booleans...> : std::false_type {};
|
||||
|
||||
#endif
|
||||
|
||||
template<class Boolean>
|
||||
struct cxpr_not : std::integral_constant < bool, !Boolean::value > {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_or : cxpr_or_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_or_c : cxpr_or_impl<Booleans...> {};
|
||||
|
||||
template<class... Booleans>
|
||||
struct cxpr_and : cxpr_and_impl<Booleans::value...> {};
|
||||
|
||||
template<bool... Booleans>
|
||||
struct cxpr_and_c : cxpr_and_impl<Booleans...> {};
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
// #include <nlohmann/detail/string_concat.hpp>
|
||||
|
||||
// #include <nlohmann/detail/value_t.hpp>
|
||||
@@ -5832,7 +5926,9 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
}
|
||||
|
||||
// overload for arithmetic types, not chosen for basic_json template arguments
|
||||
// (BooleanType, etc.)
|
||||
// (BooleanType, etc.); note: Is it really necessary to provide explicit
|
||||
// overloads for boolean_t etc. in case of a custom BooleanType which is not
|
||||
// an arithmetic type?
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t <
|
||||
std::is_arithmetic<ArithmeticType>::value&&
|
||||
@@ -5928,7 +6024,7 @@ inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priori
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||
{
|
||||
static_assert(conjunction<disjunction<negation<std::is_reference<Args>>, is_compatible_reference_type<BasicJsonType, Args>>...>::value,
|
||||
static_assert(cxpr_and<cxpr_or<cxpr_not<std::is_reference<Args>>, is_compatible_reference_type<BasicJsonType, Args>>...>::value,
|
||||
"Can not return a tuple containing references to types not contained in a Json, try Json::get_to()");
|
||||
return from_json_tuple_impl_base<1, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
}
|
||||
@@ -5993,7 +6089,7 @@ inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Has
|
||||
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
|
||||
// Workaround for MSVC 19.51 (and possibly later): in large cpp files, the compiler may fail to resolve with generic has_from_json (issue #4996)
|
||||
// Workaround for MSVC 19.51 (and possibly later): in large in large cpp files, the compiler may fail to resolve with generic has_from_json (issue #4996)
|
||||
template<typename BasicJsonType>
|
||||
struct has_from_json<BasicJsonType, std_fs::path, void> : std::true_type {};
|
||||
|
||||
@@ -12545,7 +12641,7 @@ NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // size_t
|
||||
#include <utility> // declval
|
||||
#include <string> // string
|
||||
|
||||
@@ -12610,6 +12706,37 @@ using parse_error_function_t = decltype(std::declval<T&>().parse_error(
|
||||
std::declval<std::size_t>(), std::declval<const std::string&>(),
|
||||
std::declval<const Exception&>()));
|
||||
|
||||
template<typename SAX, typename BasicJsonType>
|
||||
struct is_sax
|
||||
{
|
||||
private:
|
||||
static_assert(is_basic_json<BasicJsonType>::value,
|
||||
"BasicJsonType must be of type basic_json<...>");
|
||||
|
||||
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||
using number_float_t = typename BasicJsonType::number_float_t;
|
||||
using string_t = typename BasicJsonType::string_t;
|
||||
using binary_t = typename BasicJsonType::binary_t;
|
||||
using exception_t = typename BasicJsonType::exception;
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
is_detected_exact<bool, null_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, boolean_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
|
||||
is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
|
||||
is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
|
||||
is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
|
||||
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
|
||||
is_detected_exact<bool, start_object_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
|
||||
is_detected_exact<bool, end_object_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, start_array_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, end_array_function_t, SAX>::value &&
|
||||
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
|
||||
};
|
||||
|
||||
template<typename SAX, typename BasicJsonType>
|
||||
struct is_sax_static_asserts
|
||||
{
|
||||
@@ -12629,6 +12756,8 @@ struct is_sax_static_asserts
|
||||
"Missing/invalid function: bool null()");
|
||||
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool boolean(bool)");
|
||||
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||
"Missing/invalid function: bool boolean(bool)");
|
||||
static_assert(
|
||||
is_detected_exact<bool, number_integer_function_t, SAX,
|
||||
number_integer_t>::value,
|
||||
@@ -17810,11 +17939,9 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
|
||||
"iter_impl only accepts (const) basic_json");
|
||||
// superficial check for the LegacyBidirectionalIterator named requirement
|
||||
// note: only array_t::iterator is checked here; object_t::iterator may be
|
||||
// a forward-only iterator as long as reverse iteration and operator--
|
||||
// are never used on it
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
|
||||
"basic_json iterator assumes array type iterators satisfy the LegacyBidirectionalIterator named requirement.");
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
|
||||
&& std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
|
||||
"basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
|
||||
|
||||
public:
|
||||
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
|
||||
@@ -19298,6 +19425,63 @@ class json_pointer
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@throw parse_error.106 if an array index begins with '0'
|
||||
@throw parse_error.109 if an array index was not a number
|
||||
@throw out_of_range.402 if the array index '-' is used
|
||||
@throw out_of_range.404 if the JSON pointer can not be resolved
|
||||
*/
|
||||
template<typename BasicJsonType>
|
||||
const BasicJsonType& get_checked(const BasicJsonType* ptr) const
|
||||
{
|
||||
for (const auto& reference_token : reference_tokens)
|
||||
{
|
||||
switch (ptr->type())
|
||||
{
|
||||
case detail::value_t::object:
|
||||
{
|
||||
// note: at performs range check
|
||||
ptr = &ptr->at(reference_token);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::array:
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||
{
|
||||
// "-" always fails the range check
|
||||
JSON_THROW(detail::out_of_range::create(402, detail::concat(
|
||||
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
||||
") is out of range"), ptr));
|
||||
}
|
||||
|
||||
const auto idx = array_index<BasicJsonType>(reference_token);
|
||||
// Bounds check before access to avoid exception with JSON_NOEXCEPTION
|
||||
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
||||
{
|
||||
JSON_THROW(detail::out_of_range::create(401, detail::concat(
|
||||
"array index ", std::to_string(idx), " is out of range"), ptr));
|
||||
}
|
||||
ptr = &ptr->operator[](idx);
|
||||
break;
|
||||
}
|
||||
|
||||
case detail::value_t::null:
|
||||
case detail::value_t::string:
|
||||
case detail::value_t::boolean:
|
||||
case detail::value_t::number_integer:
|
||||
case detail::value_t::number_unsigned:
|
||||
case detail::value_t::number_float:
|
||||
case detail::value_t::binary:
|
||||
case detail::value_t::discarded:
|
||||
default:
|
||||
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief return a pointer to the pointed to value, or `nullptr` if the
|
||||
pointer cannot be resolved because a key is missing, an array
|
||||
@@ -19336,19 +19520,29 @@ class json_pointer
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// may throw parse_error.106/109 for a malformed index; an
|
||||
// index that is syntactically valid but cannot be
|
||||
// represented (out_of_range.404/410) is treated like an
|
||||
// out-of-range index below
|
||||
typename BasicJsonType::size_type idx{};
|
||||
JSON_TRY
|
||||
// tokens that array_index() rejects with parse_error.106/109
|
||||
// are passed on to it; all other tokens that it would reject
|
||||
// with out_of_range.404/410 are detected here, so that this
|
||||
// also works without exceptions
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 && !(reference_token[0] >= '1' && reference_token[0] <= '9')))
|
||||
{
|
||||
idx = array_index<BasicJsonType>(reference_token);
|
||||
static_cast<void>(array_index<BasicJsonType>(reference_token)); // throws parse_error.106/109
|
||||
}
|
||||
JSON_INTERNAL_CATCH (detail::out_of_range&)
|
||||
if (JSON_HEDLEY_UNLIKELY(reference_token.empty() || !std::all_of(reference_token.begin(), reference_token.end(), [](const char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
})))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
errno = 0; // strtoull() does not reset errno on success
|
||||
char* p_end = nullptr; // NOLINT(misc-const-correctness)
|
||||
const unsigned long long magnitude = std::strtoull(reference_token.data(), &p_end, 10); // NOLINT(runtime/int)
|
||||
if (JSON_HEDLEY_UNLIKELY(errno == ERANGE || magnitude >= static_cast<unsigned long long>((std::numeric_limits<typename BasicJsonType::size_type>::max)()))) // NOLINT(runtime/int)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
const auto idx = static_cast<typename BasicJsonType::size_type>(magnitude);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
||||
{
|
||||
|
||||
@@ -46,6 +46,21 @@ TEST_CASE("Tests with disabled exceptions")
|
||||
CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'");
|
||||
delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
SECTION("issue #5672 - value(json_pointer, default) must not abort for array tokens that are not a valid index")
|
||||
{
|
||||
const json j = {1, 2, 3};
|
||||
|
||||
// a syntactically valid index that is out of range for this array
|
||||
CHECK(j.value("/7"_json_pointer, 42) == 42);
|
||||
// a reference token that is not a number at all
|
||||
CHECK(j.value("/1a"_json_pointer, 42) == 42);
|
||||
// the empty reference token (JSON pointer "/")
|
||||
CHECK(j.value("/"_json_pointer, 42) == 42);
|
||||
// an index whose magnitude does not fit into size_type
|
||||
CHECK(j.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
||||
CHECK(j.value("/18446744073709551615"_json_pointer, 42) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
|
||||
@@ -482,6 +482,21 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
|
||||
CHECK(j_array.value("/-"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/-"_json_pointer, 42) == 42);
|
||||
|
||||
// Test an index with a non-digit after a valid leading digit; this is
|
||||
// out_of_range (not parse_error) and must not throw (see #5672)
|
||||
CHECK(j_array.value("/1a"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/1a"_json_pointer, 42) == 42);
|
||||
|
||||
// Test the empty reference token (JSON pointer "/"); see #5672
|
||||
CHECK(j_array.value("/"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/"_json_pointer, 42) == 42);
|
||||
|
||||
// Test an index whose magnitude does not fit into size_type (see #5672)
|
||||
CHECK(j_array.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/99999999999999999999999"_json_pointer, 42) == 42);
|
||||
CHECK(j_array.value("/18446744073709551615"_json_pointer, 42) == 42);
|
||||
CHECK(j_array_const.value("/18446744073709551615"_json_pointer, 42) == 42);
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
// Test malformed index (non-numeric) throws parse_error
|
||||
CHECK_THROWS_WITH_AS(j_array.value("/foo"_json_pointer, 1), "[json.exception.parse_error.109] parse error: array index 'foo' is not a number", typename Json::parse_error&);
|
||||
|
||||
@@ -10,14 +10,10 @@
|
||||
|
||||
#if JSON_TEST_USING_MULTIPLE_HEADERS
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/ordered_map.hpp>
|
||||
#else
|
||||
#include <nlohmann/json.hpp>
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("type traits")
|
||||
{
|
||||
SECTION("is_c_string")
|
||||
@@ -87,12 +83,4 @@ TEST_CASE("type traits")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("is_ordered_map")
|
||||
{
|
||||
using nlohmann::detail::is_ordered_map;
|
||||
|
||||
CHECK(is_ordered_map<nlohmann::ordered_map<std::string, int>>::value);
|
||||
CHECK_FALSE(is_ordered_map<std::map<std::string, int>>::value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user