// Copyright 2013 Daniel Parker // Distributed under the Boost license, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See https://github.com/danielaparker/jsoncons for latest version #ifndef JSONCONS_MORE_TYPE_TRAITS_HPP #define JSONCONS_MORE_TYPE_TRAITS_HPP #include #include #include #include // std::enable_if, std::true_type #include #include // std::iterator_traits #include #include // std::array #include // std::byte #include // std::declval #include // CHAR_BIT #include namespace jsoncons { namespace type_traits { // is_char8 template struct is_char8 : std::false_type {}; template struct is_char8::value && !std::is_same::value && sizeof(uint8_t) == sizeof(CharT)>::type> : std::true_type {}; // is_char16 template struct is_char16 : std::false_type {}; template struct is_char16::value && !std::is_same::value && (std::is_same::value || sizeof(uint16_t) == sizeof(CharT))>::type> : std::true_type {}; // is_char32 template struct is_char32 : std::false_type {}; template struct is_char32::value && !std::is_same::value && (std::is_same::value || (!std::is_same::value && sizeof(uint32_t) == sizeof(CharT)))>::type> : std::true_type {}; // is_int128 template struct is_int128_type : std::false_type {}; #if defined(JSONCONS_HAS_INT128) template struct is_int128_type::value>::type> : std::true_type {}; #endif // is_unsigned_integer template struct is_uint128_type : std::false_type {}; #if defined (JSONCONS_HAS_INT128) template struct is_uint128_type::value>::type> : std::true_type {}; #endif template class integer_limits { public: static constexpr bool is_specialized = false; }; template class integer_limits::value && !std::is_same::value>::type> { public: static constexpr bool is_specialized = true; static constexpr bool is_signed = std::numeric_limits::is_signed; static constexpr int digits = std::numeric_limits::digits; static constexpr std::size_t buffer_size = static_cast(sizeof(T)*CHAR_BIT*0.302) + 3; static constexpr T(max)() noexcept { return (std::numeric_limits::max)(); } static constexpr T(min)() noexcept { return (std::numeric_limits::min)(); } static constexpr T lowest() noexcept { return std::numeric_limits::lowest(); } }; template class integer_limits::value && is_int128_type::value>::type> { public: static constexpr bool is_specialized = true; static constexpr bool is_signed = true; static constexpr int digits = sizeof(T)*CHAR_BIT - 1; static constexpr std::size_t buffer_size = (sizeof(T)*CHAR_BIT*0.302) + 3; static constexpr T(max)() noexcept { return (((((T)1 << (digits - 1)) - 1) << 1) + 1); } static constexpr T(min)() noexcept { return -(max)() - 1; } static constexpr T lowest() noexcept { return (min)(); } }; template class integer_limits::value && is_uint128_type::value>::type> { public: static constexpr bool is_specialized = true; static constexpr bool is_signed = false; static constexpr int digits = sizeof(T)*CHAR_BIT; static constexpr T(max)() noexcept { return T(T(~0)); } static constexpr T(min)() noexcept { return 0; } static constexpr T lowest() noexcept { return std::numeric_limits::lowest(); } }; #ifndef JSONCONS_HAS_VOID_T // follows https://en.cppreference.com/w/cpp/types/void_t template struct make_void { typedef void type;}; template using void_t = typename make_void::type; #else using void_t = std::void_t; #endif // follows http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf // detector // primary template handles all types not supporting the archetypal Op template< class Default, class, // always void; supplied externally template class Op, class... Args > struct detector { constexpr static auto value = false; using type = Default; }; // specialization recognizes and handles only types supporting Op template< class Default, template class Op, class... Args > struct detector>, Op, Args...> { constexpr static auto value = true; using type = Op; }; // is_detected, is_detected_t template< template class Op, class... Args > using is_detected = detector; template< template class Op, class... Args > using is_detected_t = typename is_detected::type; // detected_or, detected_or_t template< class Default, template class Op, class... Args > using detected_or = detector; template< class Default, template class Op, class... Args > using detected_or_t = typename detected_or::type; // is_detected_exact template< class Expected, template class Op, class... Args > using is_detected_exact = std::is_same< Expected, is_detected_t >; // is_detected_convertible template< class To, template class Op, class... Args > using is_detected_convertible = std::is_convertible< is_detected_t, To >; template struct is_stateless : public std::integral_constant::value && std::is_empty::value)> {}; // to_plain_pointer template inline typename std::pointer_traits::element_type* to_plain_pointer(Pointer ptr) { return (std::addressof(*ptr)); } template inline T * to_plain_pointer(T * ptr) { return (ptr); } // is_std_byte template struct is_std_byte : std::false_type {}; #if defined(JSONCONS_HAS_STD_BYTE) template struct is_std_byte::value >::type> : std::true_type {}; #endif // is_byte template struct is_byte : std::false_type {}; template struct is_byte::value || std::is_same::value || std::is_same::value || is_std_byte::value >::type> : std::true_type {}; // is_character template struct is_character : std::false_type {}; template struct is_character::value || std::is_same::value >::type> : std::true_type {}; // is_narrow_character template struct is_narrow_character : std::false_type {}; template struct is_narrow_character::value && (sizeof(T) == sizeof(char)) >::type> : std::true_type {}; // is_wide_character template struct is_wide_character : std::false_type {}; template struct is_wide_character::value && (sizeof(T) != sizeof(char)) >::type> : std::true_type {}; // From boost namespace ut_detail { template struct is_cstring_impl : public std::false_type {}; template struct is_cstring_impl : public is_cstring_impl {}; template struct is_cstring_impl : public is_cstring_impl {}; template<> struct is_cstring_impl : public std::true_type {}; template<> struct is_cstring_impl : public std::true_type {}; } // namespace ut_detail template struct is_cstring : public ut_detail::is_cstring_impl::type> {}; // is_bool template struct is_bool : std::false_type {}; template struct is_bool::value >::type> : std::true_type {}; // is_u8_u16_u32_or_u64 template struct is_u8_u16_u32_or_u64 : std::false_type {}; template struct is_u8_u16_u32_or_u64::value || std::is_same::value || std::is_same::value || std::is_same::value >::type> : std::true_type {}; // is_int template struct is_i8_i16_i32_or_i64 : std::false_type {}; template struct is_i8_i16_i32_or_i64::value || std::is_same::value || std::is_same::value || std::is_same::value >::type> : std::true_type {}; // is_float_or_double template struct is_float_or_double : std::false_type {}; template struct is_float_or_double::value || std::is_same::value >::type> : std::true_type {}; // make_unsigned template struct make_unsigned_impl {using type = typename std::make_unsigned::type;}; #if defined(JSONCONS_HAS_INT128) template <> struct make_unsigned_impl {using type = uint128_type;}; template <> struct make_unsigned_impl {using type = uint128_type;}; #endif template struct make_unsigned : make_unsigned_impl::type> {}; // is_integer template struct is_integer : std::false_type {}; template struct is_integer::is_specialized>::type> : std::true_type {}; // is_signed_integer template struct is_signed_integer : std::false_type {}; template struct is_signed_integer::is_specialized && integer_limits::is_signed>::type> : std::true_type {}; // is_unsigned_integer template struct is_unsigned_integer : std::false_type {}; template struct is_unsigned_integer::is_specialized && !integer_limits::is_signed>::type> : std::true_type {}; // is_primitive template struct is_primitive : std::false_type {}; template struct is_primitive::value || is_bool::value || std::is_floating_point::value >::type> : std::true_type {}; // Containers template using container_npos_t = decltype(Container::npos); template using container_allocator_type_t = typename Container::allocator_type; template using container_mapped_type_t = typename Container::mapped_type; template using container_key_type_t = typename Container::key_type; template using container_value_type_t = typename std::iterator_traits::value_type; template using container_char_traits_t = typename Container::traits_type::char_type; template using container_push_back_t = decltype(std::declval().push_back(std::declval())); template using container_push_front_t = decltype(std::declval().push_front(std::declval())); template using container_insert_t = decltype(std::declval().insert(std::declval())); template using container_reserve_t = decltype(std::declval().reserve(typename Container::size_type())); template using container_data_t = decltype(std::declval().data()); template using container_size_t = decltype(std::declval().size()); // is_string_or_string_view template struct is_string_or_string_view : std::false_type {}; template struct is_string_or_string_view::value && is_detected_exact::value && is_detected::value >::type> : std::true_type {}; // is_basic_string template struct is_basic_string : std::false_type {}; template struct is_basic_string::value && is_detected::value >::type> : std::true_type {}; // is_basic_string_view template struct is_basic_string_view : std::false_type {}; template struct is_basic_string_view::value && !is_detected::value >::type> : std::true_type {}; // is_map_like template struct is_map_like : std::false_type {}; template struct is_map_like::value && is_detected::value && is_detected::value && is_detected::value >::type> : std::true_type {}; // is_std_array template struct is_std_array : std::false_type {}; template struct is_std_array> : std::true_type {}; // is_list_like template struct is_list_like : std::false_type {}; template struct is_list_like::value && is_detected::value && !is_std_array::value && !is_detected_exact::value && !is_map_like::value >::type> : std::true_type {}; // is_constructible_from_const_pointer_and_size template struct is_constructible_from_const_pointer_and_size : std::false_type {}; template struct is_constructible_from_const_pointer_and_size::value >::type> : std::true_type {}; // has_reserve template using has_reserve = is_detected; // is_back_insertable template using is_back_insertable = is_detected; // is_front_insertable template using is_front_insertable = is_detected; // is_insertable template using is_insertable = is_detected; // has_data, has_data_exact template using has_data = is_detected; template using has_data_exact = is_detected_exact; // has_size template using has_size = is_detected; // has_data_and_size template struct has_data_and_size { static constexpr bool value = has_data::value && has_size::value; }; // is_byte_sequence template struct is_byte_sequence : std::false_type {}; template struct is_byte_sequence::value && has_size::value && is_byte::value >::type> : std::true_type {}; // is_char_sequence template struct is_char_sequence : std::false_type {}; template struct is_char_sequence::value && has_size::value && is_character::value >::type> : std::true_type {}; // is_sequence_of template struct is_sequence_of : std::false_type {}; template struct is_sequence_of::value && has_size::value && std::is_same::value >::type> : std::true_type {}; // is_back_insertable_byte_container template struct is_back_insertable_byte_container : std::false_type {}; template struct is_back_insertable_byte_container::value && is_byte::value >::type> : std::true_type {}; // is_back_insertable_char_container template struct is_back_insertable_char_container : std::false_type {}; template struct is_back_insertable_char_container::value && is_character::value >::type> : std::true_type {}; // is_back_insertable_container_of template struct is_back_insertable_container_of : std::false_type {}; template struct is_back_insertable_container_of::value && std::is_same::value >::type> : std::true_type {}; // is_c_array template struct is_c_array : std::false_type {}; template struct is_c_array : std::true_type {}; template struct is_c_array : std::true_type {}; namespace impl { template struct is_typed_array : std::false_type {}; template struct is_typed_array < T, typename std::enable_if::value && (std::is_same::type,uint8_t>::value || std::is_same::type,uint16_t>::value || std::is_same::type,uint32_t>::value || std::is_same::type,uint64_t>::value || std::is_same::type,int8_t>::value || std::is_same::type,int16_t>::value || std::is_same::type,int32_t>::value || std::is_same::type,int64_t>::value || std::is_same::type,float_t>::value || std::is_same::type,double_t>::value)>::type > : std::true_type{}; } // namespace impl template using is_typed_array = impl::is_typed_array::type>; // is_compatible_element template struct is_compatible_element : std::false_type {}; template struct is_compatible_element < Container, Element, typename std::enable_if::value>::type> : std::is_convertible< typename std::remove_pointer().data() )>::type(*)[], Element(*)[]> {}; template using construct_from_string_t = decltype(T(std::string{})); template using is_constructible_from_string = is_detected; template using construct_from_data_size_t = decltype(T(static_cast(nullptr),Size{})); template using is_constructible_from_data_size = is_detected; // is_unary_function_object // is_unary_function_object_exact template using unary_function_object_t = decltype(std::declval()(std::declval())); template using is_unary_function_object = is_detected; template using is_unary_function_object_exact = is_detected_exact; // is_binary_function_object // is_binary_function_object_exact template using binary_function_object_t = decltype(std::declval()(std::declval(),std::declval())); template using is_binary_function_object = is_detected; template using is_binary_function_object_exact = is_detected_exact; template struct is_convertible_to_string_view : std::false_type {}; template struct is_convertible_to_string_view::value || is_cstring::value >::type> : std::true_type {}; #if defined(JSONCONS_HAS_2017) template using is_nothrow_swappable = std::is_nothrow_swappable; #else template struct is_nothrow_swappable { static const bool value = noexcept(swap(std::declval(), std::declval())); }; #endif #if defined(JSONCONS_HAS_2014) template using alignment_of = std::alignment_of; template< class T, T... Ints > using integer_sequence = std::integer_sequence; template using index_sequence = std::index_sequence; template using make_integer_sequence = std::make_integer_sequence; template using make_index_sequence = std::make_index_sequence; template using index_sequence_for = std::index_sequence_for; #else template struct alignment_of : std::integral_constant::type)> {}; template class integer_sequence { public: using value_type = T; static_assert(std::is_integral::value, "not integral type"); static constexpr std::size_t size() noexcept { return sizeof...(Ints); } }; template using index_sequence = integer_sequence; namespace detail_ { template struct IntSeqImpl { using TValue = T; static_assert(std::is_integral::value, "not integral type"); static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)"); template struct IntSeqCombiner; template struct IntSeqCombiner, integer_sequence> { using TResult = integer_sequence; }; using TResult = typename IntSeqCombiner::TResult, typename IntSeqImpl::TResult>::TResult; }; template struct IntSeqImpl { using TValue = T; static_assert(std::is_integral::value, "not integral type"); static_assert(Begin >= 0, "unexpected argument (Begin<0)"); using TResult = integer_sequence; }; template struct IntSeqImpl { using TValue = T; static_assert(std::is_integral::value, "not integral type"); static_assert(Begin >= 0, "unexpected argument (Begin<0)"); using TResult = integer_sequence; }; } // namespace detail_ template using make_integer_sequence = typename detail_::IntSeqImpl::TResult; template using make_index_sequence = make_integer_sequence; template using index_sequence_for = make_index_sequence; #endif } // type_traits } // jsoncons #endif