Add apply*() functions (visitor pattern)
Add 3 variants of apply*() functions that invoke a given callable with the supplied arguments and the stored JSON value. * void apply(Fn, Args...): ... * void apply_cb(ResultCallback, Fn, Args...): ... * R apply_r(Fn, Args...): ...
This commit is contained in:
parent
0c929e1721
commit
f898c19aca
@ -733,6 +733,28 @@ The dynamic type of the object cannot be represented in the requested serializat
|
||||
|
||||
Encapsulate the JSON value in an object. That is, instead of serializing `#!json true`, serialize `#!json {"value": true}`
|
||||
|
||||
### json.exception.type_error.318
|
||||
|
||||
The given callable cannot be invoked with the stored JSON value and the arguments provided.
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
Calling `apply()` on a numeric JSON value with an unary non-member function accepting a string:
|
||||
```
|
||||
[json.exception.type_error.318] cannot invoke callable with JSON value of type number
|
||||
```
|
||||
|
||||
### json.exception.type_error.319
|
||||
|
||||
The result callback cannot be invoked with the callback argument, in case of a non-static member function pointer callback, and the result of the invocation of the callable.
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
Calling `apply_cb()` with an unary non-member function result callback when the result of the invocation of the callable is not convertible to the argument type of the result callback:
|
||||
```
|
||||
[json.exception.type_error.319] cannot invoke callback
|
||||
```
|
||||
|
||||
## Out of range
|
||||
|
||||
This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance in case of array indices or nonexisting object keys.
|
||||
|
||||
@ -136,6 +136,46 @@ using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
// the following utilities are natively available in C++17
|
||||
using std::conjunction;
|
||||
using std::disjunction;
|
||||
using std::negation;
|
||||
|
||||
using std::as_const;
|
||||
|
||||
#else
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/conjunction
|
||||
template<class...> struct conjunction : std::true_type {};
|
||||
template<class B> struct conjunction<B> : B {};
|
||||
template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<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<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 > {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/utility/as_const
|
||||
template <typename T>
|
||||
constexpr typename std::add_const<T>::type& as_const(T& t) noexcept
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void as_const(const T&&) = delete;
|
||||
|
||||
#endif
|
||||
|
||||
// dispatch utility (taken from ranges-v3)
|
||||
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||
template<> struct priority_tag<0> {};
|
||||
|
||||
120
include/nlohmann/detail/meta/invoke.hpp
Normal file
120
include/nlohmann/detail/meta/invoke.hpp
Normal file
@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <functional> // invoke
|
||||
#endif
|
||||
#include <type_traits> // invoke_result, is_base_of, is_function, is_invocable, is_object, is_same, remove_reference
|
||||
#include <utility> // declval, forward
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta/detected.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
// the following utilities are natively available in C++17
|
||||
using std::invoke;
|
||||
using std::invoke_result;
|
||||
using std::is_invocable;
|
||||
|
||||
#else
|
||||
|
||||
// invoke_impl derived from the C++ standard draft [func.require] for qslib (proprietary)
|
||||
// modified to use standard library type traits and utilities where possible
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template<typename Fn, typename... Args,
|
||||
typename = decltype(std::declval<Fn>()(std::forward<Args>(std::declval<Args>())...))>
|
||||
auto invoke_impl(Fn && f, Args && ...args) -> decltype(f(std::forward<Args>(args)...))
|
||||
{
|
||||
return f(std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_function<T>::value
|
||||
&& std::is_base_of<U, typename std::remove_reference<V>::type>::value, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ...args) -> decltype((v.*f)(std::forward<Args>(args)...))
|
||||
{
|
||||
return (v.*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_function<T>::value
|
||||
&& !std::is_base_of<U, typename std::remove_reference<V>::type>::value, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ...args) -> decltype(((*v).*f)(std::forward<Args>(args)...))
|
||||
{
|
||||
return ((*v).*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_object<T>::value
|
||||
&& sizeof...(Args) == 0, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ... /*unused*/) -> decltype((*v).*f)
|
||||
{
|
||||
return (*v).*f;
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using detect_invocable = decltype(invoke_impl(std::declval<Fn>(), std::declval<Args>()...));
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/result_of
|
||||
template <typename AlwaysVoid, typename, typename...>
|
||||
struct invoke_result {};
|
||||
|
||||
template <typename Fn, typename...Args>
|
||||
struct invoke_result<decltype(void(invoke_impl(std::declval<Fn>(), std::declval<Args>()...))), Fn, Args...>
|
||||
{
|
||||
using type = decltype(invoke_impl(std::declval<Fn>(), std::declval<Args>()...));
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
auto invoke(Fn&& f, Args&& ... args) -> decltype(internal::invoke_impl(std::forward<Fn>(f), std::forward<Args>(args)...))
|
||||
{
|
||||
return internal::invoke_impl(std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using invoke_result = internal::invoke_result<void, Fn, Args...>;
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using is_invocable = typename is_detected<internal::detect_invocable, Fn, Args...>::type;
|
||||
|
||||
#endif
|
||||
|
||||
// used as a dummy argument
|
||||
struct null_arg_t
|
||||
{
|
||||
explicit null_arg_t() = default;
|
||||
};
|
||||
|
||||
static constexpr null_arg_t null_arg{};
|
||||
|
||||
template<typename T>
|
||||
using is_null_arg = typename std::is_same<uncvref_t<T>, null_arg_t>::type;
|
||||
|
||||
template<typename Value, typename Tuple, std::size_t I>
|
||||
struct apply_value_or_arg
|
||||
{
|
||||
using element_type = typename std::tuple_element<I, Tuple>::type;
|
||||
using type = typename std::conditional<detail::is_basic_json_value_placeholder<element_type>::value, Value, element_type>::type;
|
||||
};
|
||||
|
||||
template<typename Value, typename Fn, typename Tuple, std::size_t... I>
|
||||
using apply_invoke_result_t = typename detail::invoke_result<Fn,
|
||||
typename apply_value_or_arg<Value, Tuple, I>::type...>::type;
|
||||
|
||||
template<typename Value, typename Fn, typename Tuple, std::size_t... I>
|
||||
using apply_is_invocable = typename detail::is_invocable<Fn,
|
||||
typename apply_value_or_arg<Value, Tuple, I>::type...>::type;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
@ -12,6 +12,7 @@
|
||||
#include <nlohmann/detail/meta/call_std/end.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/detected.hpp>
|
||||
#include <nlohmann/detail/placeholders.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
@ -178,16 +179,6 @@ using actual_object_comparator_t = typename actual_object_comparator<BasicJsonTy
|
||||
// is_ functions //
|
||||
///////////////////
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/conjunction
|
||||
template<class...> struct conjunction : std::true_type { };
|
||||
template<class B> struct conjunction<B> : B { };
|
||||
template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<bool(B::value), conjunction<Bn...>, B>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/negation
|
||||
template<class B> struct negation : std::integral_constant < bool, !B::value > { };
|
||||
|
||||
// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
|
||||
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
|
||||
// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
|
||||
@ -564,6 +555,11 @@ struct is_ordered_map
|
||||
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
};
|
||||
|
||||
// checks if a type is a basic_json_value placeholder
|
||||
template<typename T>
|
||||
using is_basic_json_value_placeholder = typename std::is_same <
|
||||
uncvref_t<T>, uncvref_t<decltype(::nlohmann::placeholders::basic_json_value) >>::type;
|
||||
|
||||
// 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 >
|
||||
T conditional_static_cast(U value)
|
||||
@ -577,5 +573,17 @@ T conditional_static_cast(U value)
|
||||
return value;
|
||||
}
|
||||
|
||||
// non-standard conditional version of as_const
|
||||
template <bool AsConst, typename T>
|
||||
constexpr typename std::conditional<AsConst,
|
||||
typename std::add_const<T>::type, T>::type&
|
||||
conditional_as_const(T& t) noexcept
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <bool AsConst, typename T>
|
||||
void conditional_as_const(const T&&) = delete;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
24
include/nlohmann/detail/placeholders.hpp
Normal file
24
include/nlohmann/detail/placeholders.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<int I>
|
||||
struct placeholder_t
|
||||
{
|
||||
static constexpr int value = I;
|
||||
|
||||
explicit placeholder_t() = default;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace placeholders
|
||||
{
|
||||
|
||||
static constexpr detail::placeholder_t < -1 > basic_json_value{};
|
||||
|
||||
} // namespace placeholders
|
||||
} // namespace nlohmann
|
||||
@ -62,6 +62,7 @@ SOFTWARE.
|
||||
#include <memory> // unique_ptr
|
||||
#include <numeric> // accumulate
|
||||
#include <string> // string, stoi, to_string
|
||||
#include <tuple> // forward_as_tuple, tuple
|
||||
#include <utility> // declval, forward, move, pair, swap
|
||||
#include <vector> // vector
|
||||
|
||||
@ -86,10 +87,12 @@ SOFTWARE.
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
#include <nlohmann/detail/string_escape.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/invoke.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/output/binary_writer.hpp>
|
||||
#include <nlohmann/detail/output/output_adapters.hpp>
|
||||
#include <nlohmann/detail/output/serializer.hpp>
|
||||
#include <nlohmann/detail/placeholders.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <nlohmann/ordered_map.hpp>
|
||||
@ -207,6 +210,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// SAX interface type, see @ref nlohmann::json_sax
|
||||
using json_sax_t = json_sax<basic_json>;
|
||||
|
||||
// placeholder for the stored JSON value used in apply*() functions
|
||||
static constexpr decltype(::nlohmann::placeholders::basic_json_value) value_placeholder
|
||||
= ::nlohmann::placeholders::basic_json_value;
|
||||
|
||||
////////////////
|
||||
// exceptions //
|
||||
////////////////
|
||||
@ -5120,8 +5127,267 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
template<typename Arg, typename Value,
|
||||
detail::enable_if_t<detail::is_basic_json_value_placeholder<Arg>::value, int> = 0>
|
||||
static auto apply_resolve_placeholder(Arg && /*arg*/, Value && val) -> decltype(std::forward<Value>(val))
|
||||
{
|
||||
return std::forward<Value>(val);
|
||||
}
|
||||
|
||||
template < typename Arg, typename Value,
|
||||
detail::enable_if_t < !detail::is_basic_json_value_placeholder<Arg>::value, int > = 0 >
|
||||
static auto apply_resolve_placeholder(Arg && arg, Value&& /*val*/) -> decltype(std::forward<Arg>(arg))
|
||||
{
|
||||
return std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
// invoke the result callback
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, R&& /*r*/) const
|
||||
{}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
!detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value
|
||||
&& detail::is_invocable<ResultCallback, R>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && cb, CallbackArg && /*cb_arg*/, R && r) const
|
||||
{
|
||||
detail::invoke(std::forward<ResultCallback>(cb), std::forward<R>(r));
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
!detail::is_null_arg<ResultCallback>::value
|
||||
&& !detail::is_null_arg<CallbackArg>::value
|
||||
&& detail::is_invocable<ResultCallback, CallbackArg, R>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && cb, CallbackArg && cb_arg, R && r) const
|
||||
{
|
||||
detail::invoke(std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg), std::forward<R>(r));
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
(!detail::is_null_arg<ResultCallback>::value
|
||||
&& !detail::is_null_arg<CallbackArg>::value
|
||||
&& !detail::is_invocable<ResultCallback, CallbackArg, R>::value)
|
||||
|| (!detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value
|
||||
&& !detail::is_invocable<ResultCallback, R>::value), int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, R&& /*r*/) const
|
||||
{
|
||||
JSON_THROW(type_error::create(319, detail::concat("cannot invoke callback"), this));
|
||||
}
|
||||
|
||||
template<bool ConstThis>
|
||||
void apply_error() const
|
||||
{
|
||||
if (ConstThis)
|
||||
{
|
||||
JSON_THROW(type_error::create(318, detail::concat("cannot invoke callable with const JSON value of type ", type_name()), this));
|
||||
}
|
||||
JSON_THROW(type_error::create(318, detail::concat("cannot invoke callable with JSON value of type ", type_name()), this));
|
||||
}
|
||||
|
||||
// invoke function and possibly delegate result
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < detail::apply_is_invocable<Value, Fn, Tuple, I...>::value
|
||||
&& std::is_same<detail::apply_invoke_result_t<Value, Fn, Tuple, I...>, void>::value, int > = 0 >
|
||||
void apply_invoke(Value && val, ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, Fn && f, Tuple && t, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
detail::invoke(std::forward<Fn>(f), apply_resolve_placeholder(std::get<I>(t), std::forward<Value>(val))...);
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < detail::apply_is_invocable<Value, Fn, Tuple, I...>::value
|
||||
&& !std::is_same<detail::apply_invoke_result_t<Value, Fn, Tuple, I...>, void>::value, int > = 0 >
|
||||
void apply_invoke(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Tuple && t, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
auto&& r = detail::invoke(std::forward<Fn>(f), apply_resolve_placeholder(std::get<I>(t), std::forward<Value>(val))...);
|
||||
apply_invoke_cb(std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg), std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < !detail::apply_is_invocable<Value, Fn, Tuple, I...>::value, int > = 0 >
|
||||
void apply_invoke(Value && /*val*/, ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, Fn && /*f*/, Tuple && /*t*/, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
apply_error<ConstThis>();
|
||||
}
|
||||
|
||||
// convert arguments to tuple; insert basic_json_value placeholder if missing
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename FnArg, typename... Args,
|
||||
detail::enable_if_t < std::is_member_pointer<Fn>::value
|
||||
&& !detail::is_basic_json_value_placeholder<FnArg>::value
|
||||
&& !detail::disjunction<detail::is_basic_json_value_placeholder<Args>...>::value, int > = 0 >
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, FnArg && f_arg, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(f_arg, ::nlohmann::placeholders::basic_json_value, args...),
|
||||
detail::make_index_sequence < 2 + sizeof...(args) > ());
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args,
|
||||
detail::enable_if_t < !std::is_member_pointer<Fn>::value
|
||||
&& !detail::disjunction<detail::is_basic_json_value_placeholder<Args>...>::value, int > = 0 >
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(::nlohmann::placeholders::basic_json_value, args...),
|
||||
detail::make_index_sequence < 1 + sizeof...(args) > ());
|
||||
}
|
||||
|
||||
template<bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args,
|
||||
detail::enable_if_t<detail::disjunction<detail::is_basic_json_value_placeholder<Args>...>::value, int> = 0>
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(args...),
|
||||
detail::make_index_sequence<sizeof...(args)>());
|
||||
}
|
||||
|
||||
// dispatch based on stored value type
|
||||
template<bool ConstThis, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args>
|
||||
void apply_dispatch(ResultCallback&& cb, CallbackArg&& cb_arg, Fn&& f, Args&& ... args) const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case value_t::null:
|
||||
return apply_make_tuple<ConstThis>(nullptr,
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::object:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.object),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::array:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.array),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::string:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.string),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::boolean:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.boolean),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_integer:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_integer),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_unsigned:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_unsigned),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_float:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_float),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::binary:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.binary),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::discarded:
|
||||
return apply_error<ConstThis>();
|
||||
default: // LCOV_EXCL_LINE
|
||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Fn, typename... Args>
|
||||
void apply(Fn&& f, Args&& ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
detail::null_arg, detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Fn, typename... Args>
|
||||
void apply(Fn&& f, Args&& ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
detail::null_arg, detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ResultCallback, typename CallbackArg, typename Fn, typename... Args, detail::enable_if_t<
|
||||
std::is_member_pointer<ResultCallback>::value, int> = 0>
|
||||
void apply_cb(ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ResultCallback, typename CallbackArg, typename Fn, typename... Args, detail::enable_if_t<
|
||||
std::is_member_pointer<ResultCallback>::value, int> = 0>
|
||||
void apply_cb(ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename Fn, typename... Args, detail::enable_if_t <
|
||||
!std::is_member_pointer<ResultCallback>::value, int > = 0 >
|
||||
void apply_cb(ResultCallback && cb, Fn && f, Args && ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
std::forward<ResultCallback>(cb), detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename Fn, typename... Args, detail::enable_if_t <
|
||||
!std::is_member_pointer<ResultCallback>::value, int > = 0 >
|
||||
void apply_cb(ResultCallback && cb, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
std::forward<ResultCallback>(cb), detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename R, typename Fn, typename... Args>
|
||||
R apply_r(Fn&& f, Args&& ... args)
|
||||
{
|
||||
R out;
|
||||
apply_cb([&out](R && r) noexcept(noexcept(out = std::forward<decltype(r)>(r)))
|
||||
{
|
||||
out = std::forward<decltype(r)>(r);
|
||||
}, std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename R, typename Fn, typename... Args>
|
||||
R apply_r(Fn&& f, Args&& ... args) const
|
||||
{
|
||||
R out;
|
||||
apply_cb([&out](R && r) noexcept(noexcept(out = std::forward<decltype(r)>(r)))
|
||||
{
|
||||
out = std::forward<decltype(r)>(r);
|
||||
}, std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
constexpr decltype(::nlohmann::placeholders::basic_json_value) NLOHMANN_BASIC_JSON_TPL::value_placeholder; // NOLINT(readability-redundant-declaration)
|
||||
|
||||
#endif
|
||||
|
||||
/// @brief user-defined to_string function for JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
|
||||
@ -62,6 +62,7 @@ SOFTWARE.
|
||||
#include <memory> // unique_ptr
|
||||
#include <numeric> // accumulate
|
||||
#include <string> // string, stoi, to_string
|
||||
#include <tuple> // forward_as_tuple, tuple
|
||||
#include <utility> // declval, forward, move, pair, swap
|
||||
#include <vector> // vector
|
||||
|
||||
@ -3023,6 +3024,46 @@ using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
// the following utilities are natively available in C++17
|
||||
using std::conjunction;
|
||||
using std::disjunction;
|
||||
using std::negation;
|
||||
|
||||
using std::as_const;
|
||||
|
||||
#else
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/conjunction
|
||||
template<class...> struct conjunction : std::true_type {};
|
||||
template<class B> struct conjunction<B> : B {};
|
||||
template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<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<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 > {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/utility/as_const
|
||||
template <typename T>
|
||||
constexpr typename std::add_const<T>::type& as_const(T& t) noexcept
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void as_const(const T&&) = delete;
|
||||
|
||||
#endif
|
||||
|
||||
// dispatch utility (taken from ranges-v3)
|
||||
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||
template<> struct priority_tag<0> {};
|
||||
@ -3136,6 +3177,32 @@ NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
|
||||
|
||||
// #include <nlohmann/detail/meta/detected.hpp>
|
||||
|
||||
// #include <nlohmann/detail/placeholders.hpp>
|
||||
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<int I>
|
||||
struct placeholder_t
|
||||
{
|
||||
static constexpr int value = I;
|
||||
|
||||
explicit placeholder_t() = default;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace placeholders
|
||||
{
|
||||
|
||||
static constexpr detail::placeholder_t < -1 > basic_json_value{};
|
||||
|
||||
} // namespace placeholders
|
||||
} // namespace nlohmann
|
||||
|
||||
// #include <nlohmann/json_fwd.hpp>
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
@ -3367,16 +3434,6 @@ using actual_object_comparator_t = typename actual_object_comparator<BasicJsonTy
|
||||
// is_ functions //
|
||||
///////////////////
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/conjunction
|
||||
template<class...> struct conjunction : std::true_type { };
|
||||
template<class B> struct conjunction<B> : B { };
|
||||
template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<bool(B::value), conjunction<Bn...>, B>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/negation
|
||||
template<class B> struct negation : std::integral_constant < bool, !B::value > { };
|
||||
|
||||
// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
|
||||
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
|
||||
// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
|
||||
@ -3753,6 +3810,11 @@ struct is_ordered_map
|
||||
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
};
|
||||
|
||||
// checks if a type is a basic_json_value placeholder
|
||||
template<typename T>
|
||||
using is_basic_json_value_placeholder = typename std::is_same <
|
||||
uncvref_t<T>, uncvref_t<decltype(::nlohmann::placeholders::basic_json_value) >>::type;
|
||||
|
||||
// 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 >
|
||||
T conditional_static_cast(U value)
|
||||
@ -3766,6 +3828,18 @@ T conditional_static_cast(U value)
|
||||
return value;
|
||||
}
|
||||
|
||||
// non-standard conditional version of as_const
|
||||
template <bool AsConst, typename T>
|
||||
constexpr typename std::conditional<AsConst,
|
||||
typename std::add_const<T>::type, T>::type&
|
||||
conditional_as_const(T& t) noexcept
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <bool AsConst, typename T>
|
||||
void conditional_as_const(const T&&) = delete;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
@ -13953,6 +14027,131 @@ class json_ref
|
||||
|
||||
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/invoke.hpp>
|
||||
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <functional> // invoke
|
||||
#endif
|
||||
#include <type_traits> // invoke_result, is_base_of, is_function, is_invocable, is_object, is_same, remove_reference
|
||||
#include <utility> // declval, forward
|
||||
|
||||
// #include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/detected.hpp>
|
||||
|
||||
// #include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
// the following utilities are natively available in C++17
|
||||
using std::invoke;
|
||||
using std::invoke_result;
|
||||
using std::is_invocable;
|
||||
|
||||
#else
|
||||
|
||||
// invoke_impl derived from the C++ standard draft [func.require] for qslib (proprietary)
|
||||
// modified to use standard library type traits and utilities where possible
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template<typename Fn, typename... Args,
|
||||
typename = decltype(std::declval<Fn>()(std::forward<Args>(std::declval<Args>())...))>
|
||||
auto invoke_impl(Fn && f, Args && ...args) -> decltype(f(std::forward<Args>(args)...))
|
||||
{
|
||||
return f(std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_function<T>::value
|
||||
&& std::is_base_of<U, typename std::remove_reference<V>::type>::value, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ...args) -> decltype((v.*f)(std::forward<Args>(args)...))
|
||||
{
|
||||
return (v.*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_function<T>::value
|
||||
&& !std::is_base_of<U, typename std::remove_reference<V>::type>::value, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ...args) -> decltype(((*v).*f)(std::forward<Args>(args)...))
|
||||
{
|
||||
return ((*v).*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_object<T>::value
|
||||
&& sizeof...(Args) == 0, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ... /*unused*/) -> decltype((*v).*f)
|
||||
{
|
||||
return (*v).*f;
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using detect_invocable = decltype(invoke_impl(std::declval<Fn>(), std::declval<Args>()...));
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/result_of
|
||||
template <typename AlwaysVoid, typename, typename...>
|
||||
struct invoke_result {};
|
||||
|
||||
template <typename Fn, typename...Args>
|
||||
struct invoke_result<decltype(void(invoke_impl(std::declval<Fn>(), std::declval<Args>()...))), Fn, Args...>
|
||||
{
|
||||
using type = decltype(invoke_impl(std::declval<Fn>(), std::declval<Args>()...));
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
auto invoke(Fn&& f, Args&& ... args) -> decltype(internal::invoke_impl(std::forward<Fn>(f), std::forward<Args>(args)...))
|
||||
{
|
||||
return internal::invoke_impl(std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using invoke_result = internal::invoke_result<void, Fn, Args...>;
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using is_invocable = typename is_detected<internal::detect_invocable, Fn, Args...>::type;
|
||||
|
||||
#endif
|
||||
|
||||
// used as a dummy argument
|
||||
struct null_arg_t
|
||||
{
|
||||
explicit null_arg_t() = default;
|
||||
};
|
||||
|
||||
static constexpr null_arg_t null_arg{};
|
||||
|
||||
template<typename T>
|
||||
using is_null_arg = typename std::is_same<uncvref_t<T>, null_arg_t>::type;
|
||||
|
||||
template<typename Value, typename Tuple, std::size_t I>
|
||||
struct apply_value_or_arg
|
||||
{
|
||||
using element_type = typename std::tuple_element<I, Tuple>::type;
|
||||
using type = typename std::conditional<detail::is_basic_json_value_placeholder<element_type>::value, Value, element_type>::type;
|
||||
};
|
||||
|
||||
template<typename Value, typename Fn, typename Tuple, std::size_t... I>
|
||||
using apply_invoke_result_t = typename detail::invoke_result<Fn,
|
||||
typename apply_value_or_arg<Value, Tuple, I>::type...>::type;
|
||||
|
||||
template<typename Value, typename Fn, typename Tuple, std::size_t... I>
|
||||
using apply_is_invocable = typename detail::is_invocable<Fn,
|
||||
typename apply_value_or_arg<Value, Tuple, I>::type...>::type;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
// #include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
// #include <nlohmann/detail/output/binary_writer.hpp>
|
||||
@ -18030,6 +18229,8 @@ class serializer
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
// #include <nlohmann/detail/placeholders.hpp>
|
||||
|
||||
// #include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
// #include <nlohmann/json_fwd.hpp>
|
||||
@ -18389,6 +18590,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// SAX interface type, see @ref nlohmann::json_sax
|
||||
using json_sax_t = json_sax<basic_json>;
|
||||
|
||||
// placeholder for the stored JSON value used in apply*() functions
|
||||
static constexpr decltype(::nlohmann::placeholders::basic_json_value) value_placeholder
|
||||
= ::nlohmann::placeholders::basic_json_value;
|
||||
|
||||
////////////////
|
||||
// exceptions //
|
||||
////////////////
|
||||
@ -23302,8 +23507,267 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
template<typename Arg, typename Value,
|
||||
detail::enable_if_t<detail::is_basic_json_value_placeholder<Arg>::value, int> = 0>
|
||||
static auto apply_resolve_placeholder(Arg && /*arg*/, Value && val) -> decltype(std::forward<Value>(val))
|
||||
{
|
||||
return std::forward<Value>(val);
|
||||
}
|
||||
|
||||
template < typename Arg, typename Value,
|
||||
detail::enable_if_t < !detail::is_basic_json_value_placeholder<Arg>::value, int > = 0 >
|
||||
static auto apply_resolve_placeholder(Arg && arg, Value&& /*val*/) -> decltype(std::forward<Arg>(arg))
|
||||
{
|
||||
return std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
// invoke the result callback
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, R&& /*r*/) const
|
||||
{}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
!detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value
|
||||
&& detail::is_invocable<ResultCallback, R>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && cb, CallbackArg && /*cb_arg*/, R && r) const
|
||||
{
|
||||
detail::invoke(std::forward<ResultCallback>(cb), std::forward<R>(r));
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
!detail::is_null_arg<ResultCallback>::value
|
||||
&& !detail::is_null_arg<CallbackArg>::value
|
||||
&& detail::is_invocable<ResultCallback, CallbackArg, R>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && cb, CallbackArg && cb_arg, R && r) const
|
||||
{
|
||||
detail::invoke(std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg), std::forward<R>(r));
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
(!detail::is_null_arg<ResultCallback>::value
|
||||
&& !detail::is_null_arg<CallbackArg>::value
|
||||
&& !detail::is_invocable<ResultCallback, CallbackArg, R>::value)
|
||||
|| (!detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value
|
||||
&& !detail::is_invocable<ResultCallback, R>::value), int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, R&& /*r*/) const
|
||||
{
|
||||
JSON_THROW(type_error::create(319, detail::concat("cannot invoke callback"), this));
|
||||
}
|
||||
|
||||
template<bool ConstThis>
|
||||
void apply_error() const
|
||||
{
|
||||
if (ConstThis)
|
||||
{
|
||||
JSON_THROW(type_error::create(318, detail::concat("cannot invoke callable with const JSON value of type ", type_name()), this));
|
||||
}
|
||||
JSON_THROW(type_error::create(318, detail::concat("cannot invoke callable with JSON value of type ", type_name()), this));
|
||||
}
|
||||
|
||||
// invoke function and possibly delegate result
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < detail::apply_is_invocable<Value, Fn, Tuple, I...>::value
|
||||
&& std::is_same<detail::apply_invoke_result_t<Value, Fn, Tuple, I...>, void>::value, int > = 0 >
|
||||
void apply_invoke(Value && val, ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, Fn && f, Tuple && t, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
detail::invoke(std::forward<Fn>(f), apply_resolve_placeholder(std::get<I>(t), std::forward<Value>(val))...);
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < detail::apply_is_invocable<Value, Fn, Tuple, I...>::value
|
||||
&& !std::is_same<detail::apply_invoke_result_t<Value, Fn, Tuple, I...>, void>::value, int > = 0 >
|
||||
void apply_invoke(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Tuple && t, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
auto&& r = detail::invoke(std::forward<Fn>(f), apply_resolve_placeholder(std::get<I>(t), std::forward<Value>(val))...);
|
||||
apply_invoke_cb(std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg), std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < !detail::apply_is_invocable<Value, Fn, Tuple, I...>::value, int > = 0 >
|
||||
void apply_invoke(Value && /*val*/, ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, Fn && /*f*/, Tuple && /*t*/, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
apply_error<ConstThis>();
|
||||
}
|
||||
|
||||
// convert arguments to tuple; insert basic_json_value placeholder if missing
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename FnArg, typename... Args,
|
||||
detail::enable_if_t < std::is_member_pointer<Fn>::value
|
||||
&& !detail::is_basic_json_value_placeholder<FnArg>::value
|
||||
&& !detail::disjunction<detail::is_basic_json_value_placeholder<Args>...>::value, int > = 0 >
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, FnArg && f_arg, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(f_arg, ::nlohmann::placeholders::basic_json_value, args...),
|
||||
detail::make_index_sequence < 2 + sizeof...(args) > ());
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args,
|
||||
detail::enable_if_t < !std::is_member_pointer<Fn>::value
|
||||
&& !detail::disjunction<detail::is_basic_json_value_placeholder<Args>...>::value, int > = 0 >
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(::nlohmann::placeholders::basic_json_value, args...),
|
||||
detail::make_index_sequence < 1 + sizeof...(args) > ());
|
||||
}
|
||||
|
||||
template<bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args,
|
||||
detail::enable_if_t<detail::disjunction<detail::is_basic_json_value_placeholder<Args>...>::value, int> = 0>
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(args...),
|
||||
detail::make_index_sequence<sizeof...(args)>());
|
||||
}
|
||||
|
||||
// dispatch based on stored value type
|
||||
template<bool ConstThis, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args>
|
||||
void apply_dispatch(ResultCallback&& cb, CallbackArg&& cb_arg, Fn&& f, Args&& ... args) const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case value_t::null:
|
||||
return apply_make_tuple<ConstThis>(nullptr,
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::object:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.object),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::array:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.array),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::string:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.string),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::boolean:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.boolean),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_integer:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_integer),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_unsigned:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_unsigned),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_float:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_float),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::binary:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.binary),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::discarded:
|
||||
return apply_error<ConstThis>();
|
||||
default: // LCOV_EXCL_LINE
|
||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Fn, typename... Args>
|
||||
void apply(Fn&& f, Args&& ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
detail::null_arg, detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Fn, typename... Args>
|
||||
void apply(Fn&& f, Args&& ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
detail::null_arg, detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ResultCallback, typename CallbackArg, typename Fn, typename... Args, detail::enable_if_t<
|
||||
std::is_member_pointer<ResultCallback>::value, int> = 0>
|
||||
void apply_cb(ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ResultCallback, typename CallbackArg, typename Fn, typename... Args, detail::enable_if_t<
|
||||
std::is_member_pointer<ResultCallback>::value, int> = 0>
|
||||
void apply_cb(ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename Fn, typename... Args, detail::enable_if_t <
|
||||
!std::is_member_pointer<ResultCallback>::value, int > = 0 >
|
||||
void apply_cb(ResultCallback && cb, Fn && f, Args && ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
std::forward<ResultCallback>(cb), detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename Fn, typename... Args, detail::enable_if_t <
|
||||
!std::is_member_pointer<ResultCallback>::value, int > = 0 >
|
||||
void apply_cb(ResultCallback && cb, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
std::forward<ResultCallback>(cb), detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename R, typename Fn, typename... Args>
|
||||
R apply_r(Fn&& f, Args&& ... args)
|
||||
{
|
||||
R out;
|
||||
apply_cb([&out](R && r) noexcept(noexcept(out = std::forward<decltype(r)>(r)))
|
||||
{
|
||||
out = std::forward<decltype(r)>(r);
|
||||
}, std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename R, typename Fn, typename... Args>
|
||||
R apply_r(Fn&& f, Args&& ... args) const
|
||||
{
|
||||
R out;
|
||||
apply_cb([&out](R && r) noexcept(noexcept(out = std::forward<decltype(r)>(r)))
|
||||
{
|
||||
out = std::forward<decltype(r)>(r);
|
||||
}, std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
constexpr decltype(::nlohmann::placeholders::basic_json_value) NLOHMANN_BASIC_JSON_TPL::value_placeholder; // NOLINT(readability-redundant-declaration)
|
||||
|
||||
#endif
|
||||
|
||||
/// @brief user-defined to_string function for JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
|
||||
661
tests/src/unit-apply.cpp
Normal file
661
tests/src/unit-apply.cpp
Normal file
@ -0,0 +1,661 @@
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32")
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-conversion")
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wimplicit-int-float-conversion")
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion")
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion")
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-conversion")
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion")
|
||||
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING(4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
// JSON_HAS_CPP_20 (magic keyword; do not remove)
|
||||
#include <ranges>
|
||||
#endif
|
||||
|
||||
// MSSTL defines as_const in the global namespace :facepalm:
|
||||
template<typename... Args>
|
||||
static auto const_(Args&& ... args) -> decltype(nlohmann::detail::as_const(std::forward<Args>(args)...))
|
||||
{
|
||||
return nlohmann::detail::as_const(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static void array_push_back(json::array_t& arr, json val)
|
||||
{
|
||||
arr.emplace_back(std::move(val));
|
||||
}
|
||||
|
||||
static void array_push_front(json val, json::array_t& arr)
|
||||
{
|
||||
arr.emplace(arr.begin(), std::move(val));
|
||||
}
|
||||
|
||||
struct foo
|
||||
{
|
||||
int bar = 0;
|
||||
void set_bar(int i) noexcept
|
||||
{
|
||||
bar = i;
|
||||
}
|
||||
|
||||
static int static_bar;
|
||||
static void static_set_bar(int i) noexcept
|
||||
{
|
||||
static_bar = i;
|
||||
}
|
||||
};
|
||||
|
||||
int foo::static_bar = 0;
|
||||
|
||||
struct functor
|
||||
{
|
||||
int arg;
|
||||
int value = 0;
|
||||
|
||||
explicit functor(int arg_ = 0) noexcept : arg(arg_) {}
|
||||
|
||||
void operator()(int a, int b = 0, int c = 0) noexcept
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
value = a;
|
||||
break;
|
||||
case 1:
|
||||
value = b;
|
||||
break;
|
||||
case 2:
|
||||
value = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static int get_value(int i) noexcept
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
static int callback_value = 0;
|
||||
|
||||
static void callback(int i) noexcept
|
||||
{
|
||||
callback_value = i;
|
||||
}
|
||||
|
||||
struct not_an_int
|
||||
{
|
||||
explicit not_an_int() = default;
|
||||
};
|
||||
|
||||
static not_an_int get_not_an_int(int /*unused*/)
|
||||
{
|
||||
return not_an_int{};
|
||||
}
|
||||
|
||||
TEST_CASE("apply*() functions")
|
||||
{
|
||||
SECTION("placeholder")
|
||||
{
|
||||
using nlohmann::placeholders::basic_json_value;
|
||||
using nlohmann::detail::is_basic_json_value_placeholder;
|
||||
CHECK(std::is_same<decltype(basic_json_value), decltype(json::value_placeholder)>::value);
|
||||
CHECK(is_basic_json_value_placeholder<decltype(json::value_placeholder)>::value);
|
||||
CHECK_FALSE(is_basic_json_value_placeholder<json>::value);
|
||||
}
|
||||
|
||||
SECTION("apply()")
|
||||
{
|
||||
SECTION("plain function")
|
||||
{
|
||||
SECTION("const")
|
||||
{
|
||||
const json j = json::array({"foo"});
|
||||
CHECK_THROWS_WITH_AS(j.apply(array_push_back, 42),
|
||||
"[json.exception.type_error.318] cannot invoke callable with const JSON value of type array",
|
||||
json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
SECTION("without explicit placeholder")
|
||||
{
|
||||
json j = json::array({"foo"});
|
||||
json j_expected = json::array({"foo", 42});
|
||||
|
||||
j.apply(array_push_back, 42);
|
||||
|
||||
CHECK(j == j_expected);
|
||||
}
|
||||
|
||||
SECTION("with explicit placeholder")
|
||||
{
|
||||
json j = json::array({"foo"});
|
||||
json j_expected = json::array({42, "foo"});
|
||||
json j_expected2 = json::array({42, "foo", 24});
|
||||
|
||||
j.apply(array_push_front, 42, json::value_placeholder);
|
||||
|
||||
CHECK(j == j_expected);
|
||||
|
||||
j.apply(array_push_back, json::value_placeholder, 24);
|
||||
|
||||
CHECK(j == j_expected2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
const_(j).apply(&foo::static_set_bar);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
const_(j).apply(&foo::static_set_bar, json::value_placeholder);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
j.apply(&foo::static_set_bar);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
j.apply(&foo::static_set_bar, json::value_placeholder);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("non-static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
const_(j).apply(&foo::set_bar, f);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
const_(j).apply(&foo::set_bar, f, json::value_placeholder);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
j.apply(&foo::set_bar, f);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
j.apply(&foo::set_bar, f, json::value_placeholder);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("non-static function member pointer (json::array_t::resize)")
|
||||
{
|
||||
json j = json::array();
|
||||
json j_expected = json::array({42, 42});
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(const_(j).apply(static_cast<void (json::array_t::*)(json::array_t::size_type, const json&)>(&json::array_t::resize), json::value_placeholder, 2, json(42)),
|
||||
"[json.exception.type_error.318] cannot invoke callable with const JSON value of type array",
|
||||
json::type_error&);
|
||||
CHECK(j.empty());
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
j.apply(static_cast<void (json::array_t::*)(json::array_t::size_type, const json&)>(&json::array_t::resize), 2, json(42)),
|
||||
"[json.exception.type_error.318] cannot invoke callable with JSON value of type array",
|
||||
json::type_error&);
|
||||
CHECK(j.empty());
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
j.apply(static_cast<void (json::array_t::*)(json::array_t::size_type, const json&)>(&json::array_t::resize), json::value_placeholder, 2, json(42));
|
||||
|
||||
CHECK(j == j_expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("functor")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
functor f{0};
|
||||
const_(j).apply(f, -1, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
functor f{1};
|
||||
const_(j).apply(f, 0, json::value_placeholder, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
functor f{0};
|
||||
j.apply(f, -1, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
functor f{1};
|
||||
j.apply(f, 0, json::value_placeholder, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("discarded JSON value")
|
||||
{
|
||||
json j(json::value_t::discarded);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
const_(j).apply(nlohmann::detail::null_arg),
|
||||
"[json.exception.type_error.318] cannot invoke callable with const JSON value of type discarded",
|
||||
json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
j.apply(nlohmann::detail::null_arg),
|
||||
"[json.exception.type_error.318] cannot invoke callable with JSON value of type discarded",
|
||||
json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply_cb() (which apply_r() is based on) fails on Clang
|
||||
// due to is_invocable not yielding true as expected
|
||||
// while testing the invocable implementation Clang 3.5 crashed
|
||||
#if !defined(__clang__) || (defined(__clang__) && __clang_major__ == 3 && __clang_minor__ < 6)
|
||||
SECTION("apply_r()")
|
||||
{
|
||||
SECTION("value types")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
|
||||
auto is_null = [](std::nullptr_t) noexcept
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_null());
|
||||
CHECK(const_(j).apply_r<bool>(is_null));
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_null());
|
||||
CHECK(j.apply_r<bool>(is_null));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j{{"foo", 0}, {"bar", 42}};
|
||||
|
||||
auto get_bar = [](const json::object_t& obj)
|
||||
{
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
return obj.at("bar");
|
||||
#else
|
||||
return obj.at("bar").get<int>();
|
||||
#endif
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_object());
|
||||
CHECK(const_(j).apply_r<int>(get_bar) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_object());
|
||||
CHECK(j.apply_r<int>(get_bar) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j{0, 1, 42, 3, 4};
|
||||
|
||||
auto get_2 = [](const json::array_t& arr)
|
||||
{
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
return arr[2];
|
||||
#else
|
||||
return arr[2].get<int>();
|
||||
#endif
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_array());
|
||||
CHECK(const_(j).apply_r<int>(get_2) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_array());
|
||||
CHECK(j.apply_r<int>(get_2) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j("fourty two");
|
||||
|
||||
auto length = [](const json::string_t& str) noexcept
|
||||
{
|
||||
return str.size();
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_string());
|
||||
CHECK(const_(j).apply_r<std::size_t>(length) == 10);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_string());
|
||||
CHECK(j.apply_r<std::size_t>(length) == 10);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j(false);
|
||||
|
||||
auto negate = [](bool b) noexcept
|
||||
{
|
||||
return !b;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_boolean());
|
||||
CHECK(const_(j).apply_r<bool>(negate));
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_boolean());
|
||||
CHECK(j.apply_r<bool>(negate));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number_integer")
|
||||
{
|
||||
json j(-7);
|
||||
|
||||
auto calc = [](json::number_integer_t i) noexcept
|
||||
{
|
||||
return i * i + i;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(const_(j).apply_r<int>(calc) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(j.apply_r<int>(calc) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number_unsigned")
|
||||
{
|
||||
json j(static_cast<json::number_unsigned_t>(7));
|
||||
|
||||
auto calc = [](json::number_unsigned_t i) noexcept
|
||||
{
|
||||
return i * i - i;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_number_unsigned());
|
||||
CHECK(const_(j).apply_r<int>(calc) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_number_unsigned());
|
||||
CHECK(j.apply_r<int>(calc) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number_float")
|
||||
{
|
||||
json j(6.480741);
|
||||
|
||||
auto square = [](json::number_float_t f) noexcept
|
||||
{
|
||||
return f * f;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_number_float());
|
||||
CHECK(const_(j).apply_r<double>(square) == doctest::Approx(42.0));
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_number_float());
|
||||
CHECK(j.apply_r<double>(square) == doctest::Approx(42.0));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
json j = json::binary(std::vector<std::uint8_t> {0xC0, 0xFF, 0xEE});
|
||||
|
||||
auto get_1 = [](const json::binary_t& bin) noexcept
|
||||
{
|
||||
return bin[1];
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_binary());
|
||||
CHECK(const_(j).apply_r<std::uint8_t>(get_1) == 0xFF);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_binary());
|
||||
CHECK(j.apply_r<std::uint8_t>(get_1) == 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
SECTION("std::ranges::min")
|
||||
{
|
||||
json j = json::array({5, 3, 4, 2});
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
CHECK(const_(j).apply_r<int>(std::ranges::min) == 2);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
CHECK(const_(j).apply_r<int>(std::ranges::min, json::value_placeholder) == 2);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
CHECK(j.apply_r<int>(std::ranges::min) == 2);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
CHECK(j.apply_r<int>(std::ranges::min, json::value_placeholder) == 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("apply_cb()")
|
||||
{
|
||||
SECTION("plain function callback")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
callback_value = 0;
|
||||
const_(j).apply_cb(callback, get_value);
|
||||
|
||||
CHECK(callback_value == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
callback_value = 0;
|
||||
j.apply_cb(callback, get_value);
|
||||
|
||||
CHECK(callback_value == 42);
|
||||
}
|
||||
|
||||
SECTION("exception")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
j.apply_cb(callback, get_not_an_int),
|
||||
"[json.exception.type_error.319] cannot invoke callback",
|
||||
json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
const_(j).apply_cb(&foo::static_set_bar, get_value);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
j.apply_cb(&foo::static_set_bar, get_value);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("non-static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
foo f;
|
||||
|
||||
const_(j).apply_cb(&foo::set_bar, f, get_value);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
foo f;
|
||||
|
||||
j.apply_cb(&foo::set_bar, f, get_value);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
||||
Loading…
Reference in New Issue
Block a user