#pragma once #include <ciso646> // not #include <cstddef> // size_t #include <limits> // numeric_limits #include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type #include <utility> // declval #include "json_fwd.hpp" #include "detail/macro_scope.hpp" namespace nlohmann { /*! @brief detail namespace with internal helper functions This namespace collects functions that should not be exposed, implementations of some @ref basic_json methods, and meta-programming helpers. @since version 2.1.0 */ namespace detail { ///////////// // helpers // ///////////// template<typename> struct is_basic_json : std::false_type {}; NLOHMANN_BASIC_JSON_TPL_DECLARATION struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; // alias templates to reduce boilerplate template<bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type; template<typename T> using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; // implementation of C++14 index_sequence and affiliates // source: https://stackoverflow.com/a/32223343 template<std::size_t... Ints> struct index_sequence { using type = index_sequence; using value_type = std::size_t; static constexpr std::size_t size() noexcept { return sizeof...(Ints); } }; template<class Sequence1, class Sequence2> struct merge_and_renumber; template<std::size_t... I1, std::size_t... I2> struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>> : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; template<std::size_t N> struct make_index_sequence : merge_and_renumber < typename make_index_sequence < N / 2 >::type, typename make_index_sequence < N - N / 2 >::type > {}; template<> struct make_index_sequence<0> : index_sequence<> {}; template<> struct make_index_sequence<1> : index_sequence<0> {}; template<typename... Ts> using index_sequence_for = make_index_sequence<sizeof...(Ts)>; /* Implementation of two C++17 constructs: conjunction, negation. This is needed to avoid evaluating all the traits in a condition For example: not std::is_same<void, T>::value and has_value_type<T>::value will not compile when T = void (on MSVC at least). Whereas conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will stop evaluating if negation<...>::value == false Please note that those constructs must be used with caution, since symbols can become very long quickly (which can slow down compilation and cause MSVC internal compiler errors). Only use it when you have to (see example ahead). */ template<class...> struct conjunction : std::true_type {}; template<class B1> struct conjunction<B1> : B1 {}; template<class B1, class... Bn> struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; template<class B> struct negation : std::integral_constant<bool, not B::value> {}; // dispatch utility (taken from ranges-v3) template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<> struct priority_tag<0> {}; //////////////////////// // has_/is_ functions // //////////////////////// NLOHMANN_JSON_HAS_HELPER(mapped_type); NLOHMANN_JSON_HAS_HELPER(key_type); NLOHMANN_JSON_HAS_HELPER(value_type); NLOHMANN_JSON_HAS_HELPER(iterator); template<bool B, class RealType, class CompatibleObjectType> struct is_compatible_object_type_impl : std::false_type {}; template<class RealType, class CompatibleObjectType> struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType> { static constexpr auto value = std::is_constructible<typename RealType::key_type, typename CompatibleObjectType::key_type>::value and std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value; }; template<class BasicJsonType, class CompatibleObjectType> struct is_compatible_object_type { static auto constexpr value = is_compatible_object_type_impl < conjunction<negation<std::is_same<void, CompatibleObjectType>>, has_mapped_type<CompatibleObjectType>, has_key_type<CompatibleObjectType>>::value, typename BasicJsonType::object_t, CompatibleObjectType >::value; }; template<typename BasicJsonType, typename T> struct is_basic_json_nested_type { static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or std::is_same<T, typename BasicJsonType::const_iterator>::value or std::is_same<T, typename BasicJsonType::reverse_iterator>::value or std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value; }; template<class BasicJsonType, class CompatibleArrayType> struct is_compatible_array_type { static auto constexpr value = conjunction<negation<std::is_same<void, CompatibleArrayType>>, negation<is_compatible_object_type< BasicJsonType, CompatibleArrayType>>, negation<std::is_constructible<typename BasicJsonType::string_t, CompatibleArrayType>>, negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>, has_value_type<CompatibleArrayType>, has_iterator<CompatibleArrayType>>::value; }; template<bool, typename, typename> struct is_compatible_integer_type_impl : std::false_type {}; template<typename RealIntegerType, typename CompatibleNumberIntegerType> struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType> { // is there an assert somewhere on overflows? using RealLimits = std::numeric_limits<RealIntegerType>; using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; static constexpr auto value = std::is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value and CompatibleLimits::is_integer and RealLimits::is_signed == CompatibleLimits::is_signed; }; template<typename RealIntegerType, typename CompatibleNumberIntegerType> struct is_compatible_integer_type { static constexpr auto value = is_compatible_integer_type_impl < std::is_integral<CompatibleNumberIntegerType>::value and not std::is_same<bool, CompatibleNumberIntegerType>::value, RealIntegerType, CompatibleNumberIntegerType > ::value; }; // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists template<typename BasicJsonType, typename T> struct has_from_json { private: // also check the return type of from_json template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json( std::declval<BasicJsonType>(), std::declval<T&>()))>::value>> static int detect(U&&); static void detect(...); public: static constexpr bool value = std::is_integral<decltype( detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; }; // This trait checks if JSONSerializer<T>::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types template<typename BasicJsonType, typename T> struct has_non_default_from_json { private: template < typename U, typename = enable_if_t<std::is_same< T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >> static int detect(U&&); static void detect(...); public: static constexpr bool value = std::is_integral<decltype(detect( std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; }; // This trait checks if BasicJsonType::json_serializer<T>::to_json exists template<typename BasicJsonType, typename T> struct has_to_json { private: template<typename U, typename = decltype(uncvref_t<U>::to_json( std::declval<BasicJsonType&>(), std::declval<T>()))> static int detect(U&&); static void detect(...); public: static constexpr bool value = std::is_integral<decltype(detect( std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; }; // taken from ranges-v3 template<typename T> struct static_const { static constexpr T value{}; }; template<typename T> constexpr T static_const<T>::value; } }