| // __ _____ _____ _____ |
| // __| | __| | | | JSON for Modern C++ |
| // | | |__ | | | | | | version 3.11.0 |
| // |_____|_____|_____|_|___| https://github.com/nlohmann/json |
| // |
| // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> |
| // SPDX-License-Identifier: MIT |
| |
| #pragma once |
| |
| #include <limits> // numeric_limits |
| #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type |
| #include <utility> // declval |
| #include <tuple> // tuple |
| |
| #include <nlohmann/detail/iterators/iterator_traits.hpp> |
| #include <nlohmann/detail/macro_scope.hpp> |
| #include <nlohmann/detail/meta/call_std/begin.hpp> |
| #include <nlohmann/detail/meta/call_std/end.hpp> |
| #include <nlohmann/detail/meta/cpp_future.hpp> |
| #include <nlohmann/detail/meta/detected.hpp> |
| #include <nlohmann/json_fwd.hpp> |
| |
| NLOHMANN_JSON_NAMESPACE_BEGIN |
| /*! |
| @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 // |
| ///////////// |
| |
| // Note to maintainers: |
| // |
| // Every trait in this file expects a non CV-qualified type. |
| // The only exceptions are in the 'aliases for detected' section |
| // (i.e. those of the form: decltype(T::member_function(std::declval<T>()))) |
| // |
| // In this case, T has to be properly CV-qualified to constraint the function arguments |
| // (e.g. to_json(BasicJsonType&, const T&)) |
| |
| 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 {}; |
| |
| // used by exceptions create() member functions |
| // true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t |
| // false_type otherwise |
| template<typename BasicJsonContext> |
| struct is_basic_json_context : |
| std::integral_constant < bool, |
| is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value |
| || std::is_same<BasicJsonContext, std::nullptr_t>::value > |
| {}; |
| |
| ////////////////////// |
| // json_ref helpers // |
| ////////////////////// |
| |
| template<typename> |
| class json_ref; |
| |
| template<typename> |
| struct is_json_ref : std::false_type {}; |
| |
| template<typename T> |
| struct is_json_ref<json_ref<T>> : std::true_type {}; |
| |
| ////////////////////////// |
| // aliases for detected // |
| ////////////////////////// |
| |
| template<typename T> |
| using mapped_type_t = typename T::mapped_type; |
| |
| template<typename T> |
| using key_type_t = typename T::key_type; |
| |
| template<typename T> |
| using value_type_t = typename T::value_type; |
| |
| template<typename T> |
| using difference_type_t = typename T::difference_type; |
| |
| template<typename T> |
| using pointer_t = typename T::pointer; |
| |
| template<typename T> |
| using reference_t = typename T::reference; |
| |
| template<typename T> |
| using iterator_category_t = typename T::iterator_category; |
| |
| template<typename T, typename... Args> |
| using to_json_function = decltype(T::to_json(std::declval<Args>()...)); |
| |
| template<typename T, typename... Args> |
| using from_json_function = decltype(T::from_json(std::declval<Args>()...)); |
| |
| template<typename T, typename U> |
| using get_template_function = decltype(std::declval<T>().template get<U>()); |
| |
| // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists |
| template<typename BasicJsonType, typename T, typename = void> |
| struct has_from_json : std::false_type {}; |
| |
| // trait checking if j.get<T> is valid |
| // use this trait instead of std::is_constructible or std::is_convertible, |
| // both rely on, or make use of implicit conversions, and thus fail when T |
| // has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) |
| template <typename BasicJsonType, typename T> |
| struct is_getable |
| { |
| static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value; |
| }; |
| |
| template<typename BasicJsonType, typename T> |
| struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> |
| { |
| using serializer = typename BasicJsonType::template json_serializer<T, void>; |
| |
| static constexpr bool value = |
| is_detected_exact<void, from_json_function, serializer, |
| const BasicJsonType&, T&>::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, typename = void> |
| struct has_non_default_from_json : std::false_type {}; |
| |
| template<typename BasicJsonType, typename T> |
| struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> |
| { |
| using serializer = typename BasicJsonType::template json_serializer<T, void>; |
| |
| static constexpr bool value = |
| is_detected_exact<T, from_json_function, serializer, |
| const BasicJsonType&>::value; |
| }; |
| |
| // This trait checks if BasicJsonType::json_serializer<T>::to_json exists |
| // Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. |
| template<typename BasicJsonType, typename T, typename = void> |
| struct has_to_json : std::false_type {}; |
| |
| template<typename BasicJsonType, typename T> |
| struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> |
| { |
| using serializer = typename BasicJsonType::template json_serializer<T, void>; |
| |
| static constexpr bool value = |
| is_detected_exact<void, to_json_function, serializer, BasicJsonType&, |
| T>::value; |
| }; |
| |
| template<typename T> |
| using detect_key_compare = typename T::key_compare; |
| |
| template<typename T> |
| struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {}; |
| |
| // obtains the actual object key comparator |
| template<typename BasicJsonType> |
| struct actual_object_comparator |
| { |
| using object_t = typename BasicJsonType::object_t; |
| using object_comparator_t = typename BasicJsonType::default_object_comparator_t; |
| using type = typename std::conditional < has_key_compare<object_t>::value, |
| typename object_t::key_compare, object_comparator_t>::type; |
| }; |
| |
| template<typename BasicJsonType> |
| using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type; |
| |
| /////////////////// |
| // 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<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {}; |
| |
| // https://en.cppreference.com/w/cpp/types/negation |
| template<class B> struct negation : std::integral_constant < bool, !B::value > { }; |
| |
| // Reimplementation of is_constructible and is_default_constructible, due to them being broken for |
| // std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). |
| // This causes compile errors in e.g. clang 3.5 or gcc 4.9. |
| template <typename T> |
| struct is_default_constructible : std::is_default_constructible<T> {}; |
| |
| template <typename T1, typename T2> |
| struct is_default_constructible<std::pair<T1, T2>> |
| : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; |
| |
| template <typename T1, typename T2> |
| struct is_default_constructible<const std::pair<T1, T2>> |
| : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; |
| |
| template <typename... Ts> |
| struct is_default_constructible<std::tuple<Ts...>> |
| : conjunction<is_default_constructible<Ts>...> {}; |
| |
| template <typename... Ts> |
| struct is_default_constructible<const std::tuple<Ts...>> |
| : conjunction<is_default_constructible<Ts>...> {}; |
| |
| |
| template <typename T, typename... Args> |
| struct is_constructible : std::is_constructible<T, Args...> {}; |
| |
| template <typename T1, typename T2> |
| struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {}; |
| |
| template <typename T1, typename T2> |
| struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {}; |
| |
| template <typename... Ts> |
| struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {}; |
| |
| template <typename... Ts> |
| struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {}; |
| |
| |
| template<typename T, typename = void> |
| struct is_iterator_traits : std::false_type {}; |
| |
| template<typename T> |
| struct is_iterator_traits<iterator_traits<T>> |
| { |
| private: |
| using traits = iterator_traits<T>; |
| |
| public: |
| static constexpr auto value = |
| is_detected<value_type_t, traits>::value && |
| is_detected<difference_type_t, traits>::value && |
| is_detected<pointer_t, traits>::value && |
| is_detected<iterator_category_t, traits>::value && |
| is_detected<reference_t, traits>::value; |
| }; |
| |
| template<typename T> |
| struct is_range |
| { |
| private: |
| using t_ref = typename std::add_lvalue_reference<T>::type; |
| |
| using iterator = detected_t<result_of_begin, t_ref>; |
| using sentinel = detected_t<result_of_end, t_ref>; |
| |
| // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator |
| // and https://en.cppreference.com/w/cpp/iterator/sentinel_for |
| // but reimplementing these would be too much work, as a lot of other concepts are used underneath |
| static constexpr auto is_iterator_begin = |
| is_iterator_traits<iterator_traits<iterator>>::value; |
| |
| public: |
| static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin; |
| }; |
| |
| template<typename R> |
| using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>; |
| |
| template<typename T> |
| using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>; |
| |
| // The following implementation of is_complete_type is taken from |
| // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ |
| // and is written by Xiang Fan who agreed to using it in this library. |
| |
| template<typename T, typename = void> |
| struct is_complete_type : std::false_type {}; |
| |
| template<typename T> |
| struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; |
| |
| template<typename BasicJsonType, typename CompatibleObjectType, |
| typename = void> |
| struct is_compatible_object_type_impl : std::false_type {}; |
| |
| template<typename BasicJsonType, typename CompatibleObjectType> |
| struct is_compatible_object_type_impl < |
| BasicJsonType, CompatibleObjectType, |
| enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&& |
| is_detected<key_type_t, CompatibleObjectType>::value >> |
| { |
| using object_t = typename BasicJsonType::object_t; |
| |
| // macOS's is_constructible does not play well with nonesuch... |
| static constexpr bool value = |
| is_constructible<typename object_t::key_type, |
| typename CompatibleObjectType::key_type>::value && |
| is_constructible<typename object_t::mapped_type, |
| typename CompatibleObjectType::mapped_type>::value; |
| }; |
| |
| template<typename BasicJsonType, typename CompatibleObjectType> |
| struct is_compatible_object_type |
| : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; |
| |
| template<typename BasicJsonType, typename ConstructibleObjectType, |
| typename = void> |
| struct is_constructible_object_type_impl : std::false_type {}; |
| |
| template<typename BasicJsonType, typename ConstructibleObjectType> |
| struct is_constructible_object_type_impl < |
| BasicJsonType, ConstructibleObjectType, |
| enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&& |
| is_detected<key_type_t, ConstructibleObjectType>::value >> |
| { |
| using object_t = typename BasicJsonType::object_t; |
| |
| static constexpr bool value = |
| (is_default_constructible<ConstructibleObjectType>::value && |
| (std::is_move_assignable<ConstructibleObjectType>::value || |
| std::is_copy_assignable<ConstructibleObjectType>::value) && |
| (is_constructible<typename ConstructibleObjectType::key_type, |
| typename object_t::key_type>::value && |
| std::is_same < |
| typename object_t::mapped_type, |
| typename ConstructibleObjectType::mapped_type >::value)) || |
| (has_from_json<BasicJsonType, |
| typename ConstructibleObjectType::mapped_type>::value || |
| has_non_default_from_json < |
| BasicJsonType, |
| typename ConstructibleObjectType::mapped_type >::value); |
| }; |
| |
| template<typename BasicJsonType, typename ConstructibleObjectType> |
| struct is_constructible_object_type |
| : is_constructible_object_type_impl<BasicJsonType, |
| ConstructibleObjectType> {}; |
| |
| template<typename BasicJsonType, typename CompatibleStringType> |
| struct is_compatible_string_type |
| { |
| static constexpr auto value = |
| is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; |
| }; |
| |
| template<typename BasicJsonType, typename ConstructibleStringType> |
| struct is_constructible_string_type |
| { |
| // launder type through decltype() to fix compilation failure on ICPC |
| #ifdef __INTEL_COMPILER |
| using laundered_type = decltype(std::declval<ConstructibleStringType>()); |
| #else |
| using laundered_type = ConstructibleStringType; |
| #endif |
| |
| static constexpr auto value = |
| conjunction < |
| is_constructible<laundered_type, typename BasicJsonType::string_t>, |
| is_detected_exact<typename BasicJsonType::string_t::value_type, |
| value_type_t, laundered_type >>::value; |
| }; |
| |
| template<typename BasicJsonType, typename CompatibleArrayType, typename = void> |
| struct is_compatible_array_type_impl : std::false_type {}; |
| |
| template<typename BasicJsonType, typename CompatibleArrayType> |
| struct is_compatible_array_type_impl < |
| BasicJsonType, CompatibleArrayType, |
| enable_if_t < |
| is_detected<iterator_t, CompatibleArrayType>::value&& |
| is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&& |
| // special case for types like std::filesystem::path whose iterator's value_type are themselves |
| // c.f. https://github.com/nlohmann/json/pull/3073 |
| !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >> |
| { |
| static constexpr bool value = |
| is_constructible<BasicJsonType, |
| range_value_t<CompatibleArrayType>>::value; |
| }; |
| |
| template<typename BasicJsonType, typename CompatibleArrayType> |
| struct is_compatible_array_type |
| : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; |
| |
| template<typename BasicJsonType, typename ConstructibleArrayType, typename = void> |
| struct is_constructible_array_type_impl : std::false_type {}; |
| |
| template<typename BasicJsonType, typename ConstructibleArrayType> |
| struct is_constructible_array_type_impl < |
| BasicJsonType, ConstructibleArrayType, |
| enable_if_t<std::is_same<ConstructibleArrayType, |
| typename BasicJsonType::value_type>::value >> |
| : std::true_type {}; |
| |
| template<typename BasicJsonType, typename ConstructibleArrayType> |
| struct is_constructible_array_type_impl < |
| BasicJsonType, ConstructibleArrayType, |
| enable_if_t < !std::is_same<ConstructibleArrayType, |
| typename BasicJsonType::value_type>::value&& |
| !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&& |
| is_default_constructible<ConstructibleArrayType>::value&& |
| (std::is_move_assignable<ConstructibleArrayType>::value || |
| std::is_copy_assignable<ConstructibleArrayType>::value)&& |
| is_detected<iterator_t, ConstructibleArrayType>::value&& |
| is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& |
| is_detected<range_value_t, ConstructibleArrayType>::value&& |
| // special case for types like std::filesystem::path whose iterator's value_type are themselves |
| // c.f. https://github.com/nlohmann/json/pull/3073 |
| !std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&& |
| is_complete_type < |
| detected_t<range_value_t, ConstructibleArrayType >>::value >> |
| { |
| using value_type = range_value_t<ConstructibleArrayType>; |
| |
| static constexpr bool value = |
| std::is_same<value_type, |
| typename BasicJsonType::array_t::value_type>::value || |
| has_from_json<BasicJsonType, |
| value_type>::value || |
| has_non_default_from_json < |
| BasicJsonType, |
| value_type >::value; |
| }; |
| |
| template<typename BasicJsonType, typename ConstructibleArrayType> |
| struct is_constructible_array_type |
| : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {}; |
| |
| template<typename RealIntegerType, typename CompatibleNumberIntegerType, |
| typename = void> |
| struct is_compatible_integer_type_impl : std::false_type {}; |
| |
| template<typename RealIntegerType, typename CompatibleNumberIntegerType> |
| struct is_compatible_integer_type_impl < |
| RealIntegerType, CompatibleNumberIntegerType, |
| enable_if_t < std::is_integral<RealIntegerType>::value&& |
| std::is_integral<CompatibleNumberIntegerType>::value&& |
| !std::is_same<bool, CompatibleNumberIntegerType>::value >> |
| { |
| // is there an assert somewhere on overflows? |
| using RealLimits = std::numeric_limits<RealIntegerType>; |
| using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; |
| |
| static constexpr auto value = |
| is_constructible<RealIntegerType, |
| CompatibleNumberIntegerType>::value && |
| CompatibleLimits::is_integer && |
| RealLimits::is_signed == CompatibleLimits::is_signed; |
| }; |
| |
| template<typename RealIntegerType, typename CompatibleNumberIntegerType> |
| struct is_compatible_integer_type |
| : is_compatible_integer_type_impl<RealIntegerType, |
| CompatibleNumberIntegerType> {}; |
| |
| template<typename BasicJsonType, typename CompatibleType, typename = void> |
| struct is_compatible_type_impl: std::false_type {}; |
| |
| template<typename BasicJsonType, typename CompatibleType> |
| struct is_compatible_type_impl < |
| BasicJsonType, CompatibleType, |
| enable_if_t<is_complete_type<CompatibleType>::value >> |
| { |
| static constexpr bool value = |
| has_to_json<BasicJsonType, CompatibleType>::value; |
| }; |
| |
| template<typename BasicJsonType, typename CompatibleType> |
| struct is_compatible_type |
| : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; |
| |
| template<typename T1, typename T2> |
| 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 {}; |
| |
| template<typename T> |
| using detect_is_transparent = typename T::is_transparent; |
| |
| // type trait to check if KeyType can be used as object key (without a BasicJsonType) |
| // see is_usable_as_basic_json_key_type below |
| template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, |
| bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> |
| using is_usable_as_key_type = typename std::conditional < |
| is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value |
| && !(ExcludeObjectKeyType && std::is_same<KeyType, |
| ObjectKeyType>::value) |
| && (!RequireTransparentComparator |
| || is_detected <detect_is_transparent, Comparator>::value) |
| && !is_json_pointer<KeyType>::value, |
| std::true_type, |
| std::false_type >::type; |
| |
| // 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_basic_json_key_type = typename std::conditional < |
| is_usable_as_key_type<typename BasicJsonType::object_comparator_t, |
| typename BasicJsonType::object_t::key_type, KeyTypeCVRef, |
| RequireTransparentComparator, ExcludeObjectKeyType>::value |
| && !is_json_iterator_of<BasicJsonType, 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> |
| struct is_ordered_map |
| { |
| using one = char; |
| |
| struct two |
| { |
| char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) |
| }; |
| |
| template <typename C> static one test( decltype(&C::capacity) ) ; |
| template <typename C> static two test(...); |
| |
| enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) |
| }; |
| |
| // to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) |
| template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 > |
| T conditional_static_cast(U value) |
| { |
| return static_cast<T>(value); |
| } |
| |
| template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0> |
| T conditional_static_cast(U value) |
| { |
| return value; |
| } |
| |
| template<typename... Types> |
| using all_integral = conjunction<std::is_integral<Types>...>; |
| |
| template<typename... Types> |
| using all_signed = conjunction<std::is_signed<Types>...>; |
| |
| template<typename... Types> |
| using all_unsigned = conjunction<std::is_unsigned<Types>...>; |
| |
| // there's a disjunction trait in another PR; replace when merged |
| template<typename... Types> |
| using same_sign = std::integral_constant < bool, |
| all_signed<Types...>::value || all_unsigned<Types...>::value >; |
| |
| template<typename OfType, typename T> |
| using never_out_of_range = std::integral_constant < bool, |
| (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType))) |
| || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >; |
| |
| template<typename OfType, typename T, |
| bool OfTypeSigned = std::is_signed<OfType>::value, |
| bool TSigned = std::is_signed<T>::value> |
| struct value_in_range_of_impl2; |
| |
| template<typename OfType, typename T> |
| struct value_in_range_of_impl2<OfType, T, false, false> |
| { |
| static constexpr bool test(T val) |
| { |
| using CommonType = typename std::common_type<OfType, T>::type; |
| return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); |
| } |
| }; |
| |
| template<typename OfType, typename T> |
| struct value_in_range_of_impl2<OfType, T, true, false> |
| { |
| static constexpr bool test(T val) |
| { |
| using CommonType = typename std::common_type<OfType, T>::type; |
| return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); |
| } |
| }; |
| |
| template<typename OfType, typename T> |
| struct value_in_range_of_impl2<OfType, T, false, true> |
| { |
| static constexpr bool test(T val) |
| { |
| using CommonType = typename std::common_type<OfType, T>::type; |
| return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); |
| } |
| }; |
| |
| |
| template<typename OfType, typename T> |
| struct value_in_range_of_impl2<OfType, T, true, true> |
| { |
| static constexpr bool test(T val) |
| { |
| using CommonType = typename std::common_type<OfType, T>::type; |
| return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)()) |
| && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)()); |
| } |
| }; |
| |
| template<typename OfType, typename T, |
| bool NeverOutOfRange = never_out_of_range<OfType, T>::value, |
| typename = detail::enable_if_t<all_integral<OfType, T>::value>> |
| struct value_in_range_of_impl1; |
| |
| template<typename OfType, typename T> |
| struct value_in_range_of_impl1<OfType, T, false> |
| { |
| static constexpr bool test(T val) |
| { |
| return value_in_range_of_impl2<OfType, T>::test(val); |
| } |
| }; |
| |
| template<typename OfType, typename T> |
| struct value_in_range_of_impl1<OfType, T, true> |
| { |
| static constexpr bool test(T /*val*/) |
| { |
| return true; |
| } |
| }; |
| |
| template<typename OfType, typename T> |
| inline constexpr bool value_in_range_of(T val) |
| { |
| return value_in_range_of_impl1<OfType, T>::test(val); |
| } |
| |
| } // namespace detail |
| NLOHMANN_JSON_NAMESPACE_END |