value_from.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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_FROM_HPP
  11. #define BOOST_JSON_DETAIL_VALUE_FROM_HPP
  12. #include <boost/json/storage_ptr.hpp>
  13. #include <boost/json/value.hpp>
  14. #include <boost/json/detail/value_traits.hpp>
  15. BOOST_JSON_NS_BEGIN
  16. struct value_from_tag { };
  17. template<class T, class = void>
  18. struct has_value_from;
  19. namespace detail {
  20. // The integral_constant parameter here is an
  21. // rvalue reference to make the standard conversion
  22. // sequence to that parameter better, see
  23. // http://eel.is/c++draft/over.ics.rank#3.2.6
  24. template<std::size_t N, class T>
  25. void
  26. tuple_to_array(
  27. T&&,
  28. array&,
  29. std::integral_constant<std::size_t, N>&&)
  30. {
  31. }
  32. template<std::size_t N, std::size_t I, class T>
  33. void
  34. tuple_to_array(
  35. T&& t,
  36. array& arr,
  37. const std::integral_constant<std::size_t, I>&)
  38. {
  39. using std::get;
  40. arr.emplace_back(value_from(
  41. get<I>(std::forward<T>(t)), arr.storage()));
  42. return detail::tuple_to_array<N>(std::forward<T>(t),
  43. arr, std::integral_constant<std::size_t, I + 1>());
  44. }
  45. //----------------------------------------------------------
  46. // User-provided conversion
  47. template<class T, void_t<decltype(tag_invoke(value_from_tag(),
  48. std::declval<value&>(), std::declval<T&&>()))>* = nullptr>
  49. void
  50. value_from_helper(
  51. value& jv,
  52. T&& from,
  53. priority_tag<5>)
  54. {
  55. tag_invoke(value_from_tag(), jv, std::forward<T>(from));
  56. }
  57. //----------------------------------------------------------
  58. // Native conversion
  59. template<class T, typename std::enable_if<
  60. detail::value_constructible<T>::value>::type* = nullptr>
  61. void
  62. value_from_helper(
  63. value& jv,
  64. T&& from,
  65. priority_tag<4>)
  66. {
  67. jv = std::forward<T>(from);
  68. }
  69. template<class T, typename std::enable_if<
  70. std::is_same<detail::remove_cvref<T>,
  71. std::nullptr_t>::value>::type* = nullptr>
  72. void
  73. value_from_helper(
  74. value& jv,
  75. T&&,
  76. priority_tag<4>)
  77. {
  78. // do nothing
  79. BOOST_ASSERT(jv.is_null());
  80. (void)jv;
  81. }
  82. //----------------------------------------------------------
  83. // Generic conversions
  84. // string-like types
  85. // NOTE: original check for size used is_convertible but
  86. // MSVC-140 selects wrong specialisation if used
  87. template<class T, typename std::enable_if<
  88. std::is_constructible<remove_cvref<T>, const char*, std::size_t>::value &&
  89. std::is_convertible<decltype(std::declval<T&>().data()), const char*>::value &&
  90. std::is_integral<decltype(std::declval<T&>().size())>::value
  91. >::type* = nullptr>
  92. void
  93. value_from_helper(
  94. value& jv,
  95. T&& from,
  96. priority_tag<3>)
  97. {
  98. jv.emplace_string().assign(
  99. from.data(), from.size());
  100. }
  101. // tuple-like types
  102. template<class T, typename std::enable_if<
  103. (std::tuple_size<remove_cvref<T>>::value > 0)>::type* = nullptr>
  104. void
  105. value_from_helper(
  106. value& jv,
  107. T&& from,
  108. priority_tag<2>)
  109. {
  110. constexpr std::size_t n =
  111. std::tuple_size<remove_cvref<T>>::value;
  112. array& arr = jv.emplace_array();
  113. arr.reserve(n);
  114. detail::tuple_to_array<n>(std::forward<T>(from),
  115. arr, std::integral_constant<std::size_t, 0>());
  116. }
  117. // map-like types
  118. template<class T, typename std::enable_if<
  119. map_traits<T>::has_unique_keys &&
  120. has_value_from<typename map_traits<T>::pair_value_type>::value &&
  121. std::is_convertible<typename map_traits<T>::pair_key_type,
  122. string_view>::value>::type* = nullptr>
  123. void
  124. value_from_helper(
  125. value& jv,
  126. T&& from,
  127. priority_tag<1>)
  128. {
  129. using std::get;
  130. object& obj = jv.emplace_object();
  131. obj.reserve(container_traits<T>::try_size(from));
  132. for (auto&& elem : from)
  133. obj.emplace(get<0>(elem), value_from(
  134. get<1>(elem), obj.storage()));
  135. }
  136. // all other containers
  137. template<class T, typename std::enable_if<
  138. has_value_from<typename container_traits<T>::
  139. value_type>::value>::type* = nullptr>
  140. void
  141. value_from_helper(
  142. value& jv,
  143. T&& from,
  144. priority_tag<0>)
  145. {
  146. array& result = jv.emplace_array();
  147. result.reserve(container_traits<T>::try_size(from));
  148. for (auto&& elem : from)
  149. result.emplace_back(
  150. value_from(elem, result.storage()));
  151. }
  152. //----------------------------------------------------------
  153. // Calls to value_from are forwarded to this function
  154. // so we can use ADL and hide the built-in tag_invoke
  155. // overloads in the detail namespace
  156. template<class T, class = void_t<
  157. decltype(detail::value_from_helper(std::declval<value&>(),
  158. std::declval<T&&>(), priority_tag<5>()))>>
  159. value
  160. value_from_impl(
  161. T&& from,
  162. storage_ptr sp)
  163. {
  164. value jv(std::move(sp));
  165. detail::value_from_helper(jv, std::forward<T>(from), priority_tag<5>());
  166. return jv;
  167. }
  168. } // detail
  169. BOOST_JSON_NS_END
  170. #endif