Add type traits to check if a type is usable as object key

Add type trait to check:
* if a type is a specialization of a template.
* if a type is a json_pointer.
* if a type is a basic_json::{const_,}iterator.
* if two types are comparable using a given comparison functor.
* if a type is comparable to basic_json::object_t::key_type.
* if a type has a member type is_transparent.
* if a type is usable as object key.
* if a type has an erase() function accepting a given KeyType.

Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
This commit is contained in:
Florian Albrechtskirchinger 2022-03-03 13:44:12 +01:00
parent 6df2a1a2cd
commit 0d790397a2
2 changed files with 144 additions and 10 deletions

View File

@ -54,11 +54,6 @@ struct is_basic_json_context :
|| std::is_same<BasicJsonContext, std::nullptr_t>::value >
{};
template<typename> struct is_json_pointer : std::false_type {};
template<typename RefStringType>
struct is_json_pointer<json_pointer<RefStringType>> : std::true_type {};
//////////////////////
// json_ref helpers //
//////////////////////
@ -472,6 +467,78 @@ struct is_constructible_tuple : std::false_type {};
template<typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
template<typename BasicJsonType, typename T>
struct is_json_iterator_of : std::false_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
{};
// checks if a given type T is a template specialization of Primary
template<template <typename...> class Primary, typename T>
struct is_specialization_of : std::false_type {};
template<template <typename...> class Primary, typename... Args>
struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
template<typename T>
using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
// checks if A and B are comparable using Compare functor
template<typename Compare, typename A, typename B, typename = void>
struct is_comparable : std::false_type {};
template<typename Compare, typename A, typename B>
struct is_comparable<Compare, A, B, void_t<
decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
>> : std::true_type {};
// checks if BasicJsonType::object_t::key_type and KeyType are comparable using Compare functor
template<typename BasicJsonType, typename KeyType>
using is_key_type_comparable = typename is_comparable <
typename BasicJsonType::object_comparator_t,
const key_type_t<typename BasicJsonType::object_t>&,
KeyType >::type;
template<typename T>
using detect_is_transparent = typename T::is_transparent;
// type trait to check if KeyType can be used as object key
// true if:
// - KeyType is comparable with BasicJsonType::object_t::key_type
// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
// - the comparator is transparent or RequireTransparentComparator is false
// - KeyType is not a JSON iterator or json_pointer
template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
using is_usable_as_key_type = typename std::conditional <
is_key_type_comparable<BasicJsonType, KeyTypeCVRef>::value
&& !(ExcludeObjectKeyType && std::is_same<KeyType,
typename BasicJsonType::object_t::key_type>::value)
&& (!RequireTransparentComparator || is_detected <
detect_is_transparent,
typename BasicJsonType::object_comparator_t >::value)
&& !is_json_iterator_of<BasicJsonType, KeyType>::value
&& !is_json_pointer<KeyType>::value,
std::true_type,
std::false_type >::type;
template<typename ObjectType, typename KeyType>
using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
// type trait to check if object_t has an erase() member functions accepting KeyType
template<typename BasicJsonType, typename KeyType>
using has_erase_with_key_type = typename std::conditional <
is_detected <
detect_erase_with_key_type,
typename BasicJsonType::object_t, KeyType >::value,
std::true_type,
std::false_type >::type;
// a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector)
template <typename T>

View File

@ -3189,11 +3189,6 @@ struct is_basic_json_context :
|| std::is_same<BasicJsonContext, std::nullptr_t>::value >
{};
template<typename> struct is_json_pointer : std::false_type {};
template<typename RefStringType>
struct is_json_pointer<json_pointer<RefStringType>> : std::true_type {};
//////////////////////
// json_ref helpers //
//////////////////////
@ -3607,6 +3602,78 @@ struct is_constructible_tuple : std::false_type {};
template<typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
template<typename BasicJsonType, typename T>
struct is_json_iterator_of : std::false_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
{};
// checks if a given type T is a template specialization of Primary
template<template <typename...> class Primary, typename T>
struct is_specialization_of : std::false_type {};
template<template <typename...> class Primary, typename... Args>
struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
template<typename T>
using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
// checks if A and B are comparable using Compare functor
template<typename Compare, typename A, typename B, typename = void>
struct is_comparable : std::false_type {};
template<typename Compare, typename A, typename B>
struct is_comparable<Compare, A, B, void_t<
decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
>> : std::true_type {};
// checks if BasicJsonType::object_t::key_type and KeyType are comparable using Compare functor
template<typename BasicJsonType, typename KeyType>
using is_key_type_comparable = typename is_comparable <
typename BasicJsonType::object_comparator_t,
const key_type_t<typename BasicJsonType::object_t>&,
KeyType >::type;
template<typename T>
using detect_is_transparent = typename T::is_transparent;
// type trait to check if KeyType can be used as object key
// true if:
// - KeyType is comparable with BasicJsonType::object_t::key_type
// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
// - the comparator is transparent or RequireTransparentComparator is false
// - KeyType is not a JSON iterator or json_pointer
template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
using is_usable_as_key_type = typename std::conditional <
is_key_type_comparable<BasicJsonType, KeyTypeCVRef>::value
&& !(ExcludeObjectKeyType && std::is_same<KeyType,
typename BasicJsonType::object_t::key_type>::value)
&& (!RequireTransparentComparator || is_detected <
detect_is_transparent,
typename BasicJsonType::object_comparator_t >::value)
&& !is_json_iterator_of<BasicJsonType, KeyType>::value
&& !is_json_pointer<KeyType>::value,
std::true_type,
std::false_type >::type;
template<typename ObjectType, typename KeyType>
using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
// type trait to check if object_t has an erase() member functions accepting KeyType
template<typename BasicJsonType, typename KeyType>
using has_erase_with_key_type = typename std::conditional <
is_detected <
detect_erase_with_key_type,
typename BasicJsonType::object_t, KeyType >::value,
std::true_type,
std::false_type >::type;
// a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector)
template <typename T>