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}`
|
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
|
## 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.
|
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
|
#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)
|
// dispatch utility (taken from ranges-v3)
|
||||||
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||||
template<> struct priority_tag<0> {};
|
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/call_std/end.hpp>
|
||||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
#include <nlohmann/detail/meta/detected.hpp>
|
#include <nlohmann/detail/meta/detected.hpp>
|
||||||
|
#include <nlohmann/detail/placeholders.hpp>
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
|
||||||
namespace nlohmann
|
namespace nlohmann
|
||||||
@ -178,16 +179,6 @@ using actual_object_comparator_t = typename actual_object_comparator<BasicJsonTy
|
|||||||
// is_ functions //
|
// 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
|
// 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).
|
// 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.
|
// 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)
|
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)
|
// 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 >
|
template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
|
||||||
T conditional_static_cast(U value)
|
T conditional_static_cast(U value)
|
||||||
@ -577,5 +573,17 @@ T conditional_static_cast(U value)
|
|||||||
return 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 detail
|
||||||
} // namespace nlohmann
|
} // 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 <memory> // unique_ptr
|
||||||
#include <numeric> // accumulate
|
#include <numeric> // accumulate
|
||||||
#include <string> // string, stoi, to_string
|
#include <string> // string, stoi, to_string
|
||||||
|
#include <tuple> // forward_as_tuple, tuple
|
||||||
#include <utility> // declval, forward, move, pair, swap
|
#include <utility> // declval, forward, move, pair, swap
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
|
|
||||||
@ -86,10 +87,12 @@ SOFTWARE.
|
|||||||
#include <nlohmann/detail/string_concat.hpp>
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
#include <nlohmann/detail/string_escape.hpp>
|
#include <nlohmann/detail/string_escape.hpp>
|
||||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/invoke.hpp>
|
||||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
#include <nlohmann/detail/output/binary_writer.hpp>
|
#include <nlohmann/detail/output/binary_writer.hpp>
|
||||||
#include <nlohmann/detail/output/output_adapters.hpp>
|
#include <nlohmann/detail/output/output_adapters.hpp>
|
||||||
#include <nlohmann/detail/output/serializer.hpp>
|
#include <nlohmann/detail/output/serializer.hpp>
|
||||||
|
#include <nlohmann/detail/placeholders.hpp>
|
||||||
#include <nlohmann/detail/value_t.hpp>
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include <nlohmann/ordered_map.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
|
/// SAX interface type, see @ref nlohmann::json_sax
|
||||||
using json_sax_t = json_sax<basic_json>;
|
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 //
|
// 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
|
/// @brief user-defined to_string function for JSON values
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
|
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
|
||||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||||
|
|||||||
@ -62,6 +62,7 @@ SOFTWARE.
|
|||||||
#include <memory> // unique_ptr
|
#include <memory> // unique_ptr
|
||||||
#include <numeric> // accumulate
|
#include <numeric> // accumulate
|
||||||
#include <string> // string, stoi, to_string
|
#include <string> // string, stoi, to_string
|
||||||
|
#include <tuple> // forward_as_tuple, tuple
|
||||||
#include <utility> // declval, forward, move, pair, swap
|
#include <utility> // declval, forward, move, pair, swap
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
|
|
||||||
@ -3023,6 +3024,46 @@ using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
|
|||||||
|
|
||||||
#endif
|
#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)
|
// dispatch utility (taken from ranges-v3)
|
||||||
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||||
template<> struct priority_tag<0> {};
|
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/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>
|
// #include <nlohmann/json_fwd.hpp>
|
||||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||||
#define 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 //
|
// 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
|
// 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).
|
// 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.
|
// 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)
|
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)
|
// 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 >
|
template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
|
||||||
T conditional_static_cast(U value)
|
T conditional_static_cast(U value)
|
||||||
@ -3766,6 +3828,18 @@ T conditional_static_cast(U value)
|
|||||||
return 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 detail
|
||||||
} // namespace nlohmann
|
} // namespace nlohmann
|
||||||
|
|
||||||
@ -13953,6 +14027,131 @@ class json_ref
|
|||||||
|
|
||||||
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
// #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/meta/type_traits.hpp>
|
||||||
|
|
||||||
// #include <nlohmann/detail/output/binary_writer.hpp>
|
// #include <nlohmann/detail/output/binary_writer.hpp>
|
||||||
@ -18030,6 +18229,8 @@ class serializer
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace nlohmann
|
} // namespace nlohmann
|
||||||
|
|
||||||
|
// #include <nlohmann/detail/placeholders.hpp>
|
||||||
|
|
||||||
// #include <nlohmann/detail/value_t.hpp>
|
// #include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
// #include <nlohmann/json_fwd.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
|
/// SAX interface type, see @ref nlohmann::json_sax
|
||||||
using json_sax_t = json_sax<basic_json>;
|
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 //
|
// 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
|
/// @brief user-defined to_string function for JSON values
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
|
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
|
||||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
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