value_to.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // Official repository: https://github.com/boostorg/json
  9. //
  10. #ifndef BOOST_JSON_DETAIL_VALUE_TO_HPP
  11. #define BOOST_JSON_DETAIL_VALUE_TO_HPP
  12. #include <boost/json/value.hpp>
  13. #include <boost/json/detail/value_traits.hpp>
  14. #include <type_traits>
  15. BOOST_JSON_NS_BEGIN
  16. template<class>
  17. struct value_to_tag { };
  18. template<class, class = void>
  19. struct has_value_to;
  20. template<class T, class U,
  21. typename std::enable_if<
  22. ! std::is_reference<T>::value &&
  23. std::is_same<U, value>::value>::type>
  24. T value_to(U const&);
  25. namespace detail {
  26. //----------------------------------------------------------
  27. // Use native conversion
  28. // identity conversion
  29. inline
  30. value
  31. tag_invoke(
  32. value_to_tag<value>,
  33. value const& jv)
  34. {
  35. return jv;
  36. }
  37. // object
  38. inline
  39. object
  40. tag_invoke(
  41. value_to_tag<object>,
  42. value const& jv)
  43. {
  44. return jv.as_object();
  45. }
  46. // array
  47. inline
  48. array
  49. tag_invoke(
  50. value_to_tag<array>,
  51. value const& jv)
  52. {
  53. return jv.as_array();
  54. }
  55. // string
  56. inline
  57. string
  58. tag_invoke(
  59. value_to_tag<string>,
  60. value const& jv)
  61. {
  62. return jv.as_string();
  63. }
  64. // bool
  65. inline
  66. bool
  67. tag_invoke(
  68. value_to_tag<bool>,
  69. value const& jv)
  70. {
  71. return jv.as_bool();
  72. }
  73. // integral and floating point
  74. template<class T, typename std::enable_if<
  75. std::is_arithmetic<T>::value>::type* = nullptr>
  76. T
  77. tag_invoke(
  78. value_to_tag<T>,
  79. value const& jv)
  80. {
  81. return jv.to_number<T>();
  82. }
  83. //----------------------------------------------------------
  84. // Use generic conversion
  85. // string-like types
  86. // NOTE: original check for size used is_convertible but
  87. // MSVC-140 selects wrong specialisation if used
  88. template<class T, typename std::enable_if<
  89. std::is_constructible<T, const char*, std::size_t>::value &&
  90. std::is_convertible<decltype(std::declval<T&>().data()), const char*>::value &&
  91. std::is_integral<decltype(std::declval<T&>().size())>::value
  92. >::type* = nullptr>
  93. T
  94. value_to_generic(
  95. const value& jv,
  96. priority_tag<2>)
  97. {
  98. auto& str = jv.as_string();
  99. return T(str.data(), str.size());
  100. }
  101. // map like containers
  102. template<class T, typename std::enable_if<
  103. has_value_to<typename map_traits<T>::pair_value_type>::value &&
  104. std::is_constructible<typename map_traits<T>::pair_key_type,
  105. string_view>::value>::type* = nullptr>
  106. T
  107. value_to_generic(
  108. const value& jv,
  109. priority_tag<1>)
  110. {
  111. using value_type = typename
  112. container_traits<T>::value_type;
  113. const object& obj = jv.as_object();
  114. T result;
  115. container_traits<T>::try_reserve(
  116. result, obj.size());
  117. for (const auto& val : obj)
  118. result.insert(value_type{typename map_traits<T>::
  119. pair_key_type(val.key()), value_to<typename
  120. map_traits<T>::pair_value_type>(val.value())});
  121. return result;
  122. }
  123. // all other containers
  124. template<class T, typename std::enable_if<
  125. has_value_to<typename container_traits<T>::
  126. value_type>::value>::type* = nullptr>
  127. T
  128. value_to_generic(
  129. const value& jv,
  130. priority_tag<0>)
  131. {
  132. const array& arr = jv.as_array();
  133. T result;
  134. container_traits<T>::try_reserve(
  135. result, arr.size());
  136. for (const auto& val : arr)
  137. result.insert(end(result), value_to<typename
  138. container_traits<T>::value_type>(val));
  139. return result;
  140. }
  141. // Matches containers
  142. template<class T, void_t<typename std::enable_if<
  143. !std::is_constructible<T, const value&>::value &&
  144. !std::is_arithmetic<T>::value>::type, decltype(
  145. value_to_generic<T>(std::declval<const value&>(),
  146. priority_tag<2>()))>* = nullptr>
  147. T
  148. tag_invoke(
  149. value_to_tag<T>,
  150. value const& jv)
  151. {
  152. return value_to_generic<T>(
  153. jv, priority_tag<2>());
  154. }
  155. //----------------------------------------------------------
  156. // Calls to value_to are forwarded to this function
  157. // so we can use ADL and hide the built-in tag_invoke
  158. // overloads in the detail namespace
  159. template<class T, void_t<
  160. decltype(tag_invoke(std::declval<value_to_tag<T>&>(),
  161. std::declval<const value&>()))>* = nullptr>
  162. T
  163. value_to_impl(
  164. value_to_tag<T> tag,
  165. value const& jv)
  166. {
  167. return tag_invoke(tag, jv);
  168. }
  169. } // detail
  170. BOOST_JSON_NS_END
  171. #endif