value_traits.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. //
  2. // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/json
  8. //
  9. #ifndef BOOST_JSON_DETAIL_VALUE_TRAITS_HPP
  10. #define BOOST_JSON_DETAIL_VALUE_TRAITS_HPP
  11. #include <boost/json/detail/config.hpp>
  12. #include <type_traits>
  13. #include <tuple>
  14. #include <utility>
  15. BOOST_JSON_NS_BEGIN
  16. namespace detail {
  17. template<std::size_t N>
  18. struct priority_tag
  19. : priority_tag<N - 1> { };
  20. template<>
  21. struct priority_tag<0> { };
  22. using std::begin;
  23. using std::end;
  24. #ifdef __cpp_lib_nonmember_container_access
  25. using std::size;
  26. #endif
  27. template<typename T, typename = void>
  28. struct container_traits
  29. {
  30. static constexpr bool is_container = false;
  31. };
  32. template<typename T>
  33. struct container_traits<T, typename std::enable_if<
  34. std::is_same<decltype(begin(std::declval<T&>())),
  35. decltype(end(std::declval<T&>()))>::value>::type>
  36. {
  37. private:
  38. template<typename U, typename std::enable_if<
  39. std::is_convertible<decltype(std::declval<U&>().size()),
  40. std::size_t>::value>::type* = nullptr>
  41. static
  42. std::size_t
  43. size_impl(
  44. U&& cont,
  45. priority_tag<2>)
  46. {
  47. return cont.size();
  48. }
  49. template<typename U, typename std::enable_if<
  50. std::is_convertible<decltype(size(std::declval<U&>())),
  51. std::size_t>::value>::type* = nullptr>
  52. static
  53. std::size_t
  54. size_impl(
  55. U& cont,
  56. priority_tag<1>)
  57. {
  58. return size(cont);
  59. }
  60. template<typename U, std::size_t N>
  61. static
  62. std::size_t
  63. size_impl(
  64. U(&)[N],
  65. priority_tag<1>)
  66. {
  67. return N;
  68. }
  69. template<typename U>
  70. static
  71. std::size_t
  72. size_impl(U&, priority_tag<0>)
  73. {
  74. return 0;
  75. }
  76. template<typename U>
  77. static
  78. auto
  79. reserve_impl(
  80. U& cont,
  81. std::size_t size,
  82. priority_tag<1>) ->
  83. void_t<decltype(
  84. std::declval<U&>().reserve(0))>
  85. {
  86. cont.reserve(size);
  87. }
  88. template<typename U>
  89. static
  90. void
  91. reserve_impl(
  92. U&,
  93. std::size_t,
  94. priority_tag<0>) { }
  95. public:
  96. static constexpr bool is_container = true;
  97. using value_type = remove_cvref<
  98. decltype(*begin(std::declval<T&>()))>;
  99. template<typename U>
  100. static
  101. std::size_t
  102. try_size(U& cont)
  103. {
  104. return container_traits::size_impl(
  105. cont, priority_tag<2>());
  106. }
  107. template<typename U>
  108. static
  109. void
  110. try_reserve(
  111. U& cont,
  112. std::size_t size)
  113. {
  114. container_traits::reserve_impl(
  115. cont, size, priority_tag<1>());
  116. }
  117. };
  118. template<typename T, typename = void>
  119. struct map_traits
  120. {
  121. static constexpr bool is_map = false;
  122. static constexpr bool has_unique_keys = false;
  123. };
  124. template<typename T>
  125. struct map_traits<T, void_t<typename remove_cvref<T>::key_type,
  126. typename std::enable_if<container_traits<T>::is_container &&
  127. std::tuple_size<typename remove_cvref<T>::
  128. value_type>::value == 2>::type>>
  129. {
  130. private:
  131. template<typename U, typename = void>
  132. struct unique_keys : std::false_type { };
  133. template<typename U>
  134. struct unique_keys<U, typename std::enable_if<
  135. (std::tuple_size<remove_cvref<decltype(std::declval<
  136. remove_cvref<U>&>().emplace(std::declval<typename
  137. remove_cvref<U>::value_type>()))>>::value > 0)>::type>
  138. : std::true_type { };
  139. public:
  140. static constexpr bool is_map = true;
  141. static constexpr bool has_unique_keys = unique_keys<T>::value;
  142. using pair_key_type = typename std::tuple_element<
  143. 0, typename remove_cvref<T>::value_type>::type;
  144. using pair_value_type = typename std::tuple_element<
  145. 1, typename remove_cvref<T>::value_type>::type;
  146. static constexpr bool key_converts_to_string =
  147. std::is_convertible<pair_key_type, string_view>::value;
  148. };
  149. // does not include std::nullptr_t
  150. template<class T>
  151. using value_constructible = std::integral_constant<bool,
  152. std::is_same<detail::remove_cvref<T>, value>::value ||
  153. std::is_same<detail::remove_cvref<T>, object>::value ||
  154. std::is_same<detail::remove_cvref<T>, array>::value ||
  155. std::is_same<detail::remove_cvref<T>, string>::value ||
  156. std::is_same<detail::remove_cvref<T>, string_view>::value ||
  157. std::is_arithmetic<detail::remove_cvref<T>>::value ||
  158. std::is_same<detail::remove_cvref<T>, char const*>::value ||
  159. std::is_same<detail::remove_cvref<T>,
  160. std::initializer_list<value_ref>>::value ||
  161. std::is_same<detail::remove_cvref<T>, value_ref>::value>;
  162. BOOST_STATIC_ASSERT(value_constructible<value>::value);
  163. } // detail
  164. BOOST_JSON_NS_END
  165. #endif