Skip to content

Commit

Permalink
Add type traits to check if a type is usable as object key
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
falbrechtskirchinger and nlohmann committed Apr 13, 2022
1 parent 771dec4 commit 0e8ff38
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 10 deletions.
71 changes: 66 additions & 5 deletions include/nlohmann/detail/meta/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 //
//////////////////////
Expand Down Expand Up @@ -472,6 +467,72 @@ 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 const&>(), std::declval<B const&>())),
decltype(std::declval<Compare>()(std::declval<B const&>(), std::declval<A const&>()))
>> : 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,
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
// Modify refers to the context in which KeyType is used;
// essentially only true for operator[]
template<typename BasicJsonType, typename KeyType, bool Modify = false, typename UnqualKeyType = uncvref_t<KeyType>>
using is_usable_as_key_type = typename std::conditional <
is_key_type_comparable<BasicJsonType, KeyType>::value
&& (Modify || is_detected <
detect_is_transparent,
typename BasicJsonType::object_comparator_t >::value)
&& !is_json_iterator_of<BasicJsonType, UnqualKeyType>::value
&& !is_json_pointer<UnqualKeyType>::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>
Expand Down
71 changes: 66 additions & 5 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3183,11 +3183,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 //
//////////////////////
Expand Down Expand Up @@ -3601,6 +3596,72 @@ 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 const&>(), std::declval<B const&>())),
decltype(std::declval<Compare>()(std::declval<B const&>(), std::declval<A const&>()))
>> : 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,
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
// Modify refers to the context in which KeyType is used;
// essentially only true for operator[]
template<typename BasicJsonType, typename KeyType, bool Modify = false, typename UnqualKeyType = uncvref_t<KeyType>>
using is_usable_as_key_type = typename std::conditional <
is_key_type_comparable<BasicJsonType, KeyType>::value
&& (Modify || is_detected <
detect_is_transparent,
typename BasicJsonType::object_comparator_t >::value)
&& !is_json_iterator_of<BasicJsonType, UnqualKeyType>::value
&& !is_json_pointer<UnqualKeyType>::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>
Expand Down

0 comments on commit 0e8ff38

Please sign in to comment.