value_from.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
  4. // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
  5. //
  6. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  7. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // Official repository: https://github.com/boostorg/json
  10. //
  11. #ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
  12. #define BOOST_JSON_DETAIL_VALUE_FROM_HPP
  13. #include <boost/json/conversion.hpp>
  14. #include <boost/describe/enum_to_string.hpp>
  15. #include <boost/mp11/algorithm.hpp>
  16. #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
  17. # include <optional>
  18. #endif
  19. namespace boost {
  20. namespace json {
  21. namespace detail {
  22. template <class T>
  23. struct append_tuple_element {
  24. array& arr;
  25. T&& t;
  26. template<std::size_t I>
  27. void
  28. operator()(mp11::mp_size_t<I>) const
  29. {
  30. using std::get;
  31. arr.emplace_back(value_from(
  32. get<I>(std::forward<T>(t)), arr.storage()));
  33. }
  34. };
  35. //----------------------------------------------------------
  36. // User-provided conversion
  37. template<class T>
  38. void
  39. value_from_helper(
  40. value& jv,
  41. T&& from,
  42. user_conversion_tag)
  43. {
  44. tag_invoke(value_from_tag(), jv, std::forward<T>(from));
  45. }
  46. //----------------------------------------------------------
  47. // Native conversion
  48. template<class T>
  49. void
  50. value_from_helper(
  51. value& jv,
  52. T&& from,
  53. native_conversion_tag)
  54. {
  55. jv = std::forward<T>(from);
  56. }
  57. // null-like types
  58. template<class T>
  59. void
  60. value_from_helper(
  61. value& jv,
  62. T&&,
  63. null_like_conversion_tag)
  64. {
  65. // do nothing
  66. BOOST_ASSERT(jv.is_null());
  67. (void)jv;
  68. }
  69. // string-like types
  70. template<class T>
  71. void
  72. value_from_helper(
  73. value& jv,
  74. T&& from,
  75. string_like_conversion_tag)
  76. {
  77. auto sv = static_cast<string_view>(from);
  78. jv.emplace_string().assign(sv);
  79. }
  80. // map-like types
  81. template<class T>
  82. void
  83. value_from_helper(
  84. value& jv,
  85. T&& from,
  86. map_like_conversion_tag)
  87. {
  88. using std::get;
  89. object& obj = jv.emplace_object();
  90. obj.reserve(detail::try_size(from, size_implementation<T>()));
  91. for (auto&& elem : from)
  92. obj.emplace(get<0>(elem), value_from(
  93. get<1>(elem), obj.storage()));
  94. }
  95. // ranges
  96. template<class T>
  97. void
  98. value_from_helper(
  99. value& jv,
  100. T&& from,
  101. sequence_conversion_tag)
  102. {
  103. array& result = jv.emplace_array();
  104. result.reserve(detail::try_size(from, size_implementation<T>()));
  105. for (auto&& elem : from)
  106. result.emplace_back(
  107. value_from(
  108. static_cast< forwarded_value<T&&> >(elem),
  109. result.storage() ));
  110. }
  111. // tuple-like types
  112. template<class T>
  113. void
  114. value_from_helper(
  115. value& jv,
  116. T&& from,
  117. tuple_conversion_tag)
  118. {
  119. constexpr std::size_t n =
  120. std::tuple_size<remove_cvref<T>>::value;
  121. array& arr = jv.emplace_array();
  122. arr.reserve(n);
  123. mp11::mp_for_each<mp11::mp_iota_c<n>>(
  124. append_tuple_element<T>{arr, std::forward<T>(from)});
  125. }
  126. // no suitable conversion implementation
  127. template<class T>
  128. void
  129. value_from_helper(
  130. value&,
  131. T&&,
  132. no_conversion_tag)
  133. {
  134. static_assert(
  135. !std::is_same<T, T>::value,
  136. "No suitable tag_invoke overload found for the type");
  137. }
  138. #ifndef BOOST_NO_CXX17_HDR_VARIANT
  139. struct value_from_visitor
  140. {
  141. value& jv;
  142. template<class T>
  143. void
  144. operator()(T&& t)
  145. {
  146. value_from(static_cast<T&&>(t), jv);
  147. }
  148. };
  149. #endif // BOOST_NO_CXX17_HDR_VARIANT
  150. template< class T >
  151. struct from_described_member
  152. {
  153. using Ds = describe::describe_members<
  154. remove_cvref<T>, describe::mod_public | describe::mod_inherited>;
  155. object& obj;
  156. T&& from;
  157. template< class I >
  158. void
  159. operator()(I) const
  160. {
  161. using D = mp11::mp_at<Ds, I>;
  162. obj.emplace(
  163. D::name,
  164. value_from(
  165. static_cast<T&&>(from).* D::pointer,
  166. obj.storage()));
  167. }
  168. };
  169. // described classes
  170. template<class T>
  171. void
  172. value_from_helper(
  173. value& jv,
  174. T&& from,
  175. described_class_conversion_tag)
  176. {
  177. object& obj = jv.emplace_object();
  178. from_described_member<T> member_converter{obj, static_cast<T&&>(from)};
  179. using Ds = typename decltype(member_converter)::Ds;
  180. constexpr std::size_t N = mp11::mp_size<Ds>::value;
  181. obj.reserve(N);
  182. mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
  183. }
  184. // described enums
  185. template<class T>
  186. void
  187. value_from_helper(
  188. value& jv,
  189. T from,
  190. described_enum_conversion_tag)
  191. {
  192. (void)jv;
  193. (void)from;
  194. #ifdef BOOST_DESCRIBE_CXX14
  195. char const* const name = describe::enum_to_string(from, nullptr);
  196. if( name )
  197. {
  198. string& str = jv.emplace_string();
  199. str.assign(name);
  200. }
  201. else
  202. {
  203. using Integer = typename std::underlying_type< remove_cvref<T> >::type;
  204. jv = static_cast<Integer>(from);
  205. }
  206. #endif
  207. }
  208. } // detail
  209. #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
  210. template<class T>
  211. void
  212. tag_invoke(
  213. value_from_tag,
  214. value& jv,
  215. std::optional<T> const& from)
  216. {
  217. if( from )
  218. value_from(*from, jv);
  219. else
  220. jv = nullptr;
  221. }
  222. template<class T>
  223. void
  224. tag_invoke(
  225. value_from_tag,
  226. value& jv,
  227. std::optional<T>&& from)
  228. {
  229. if( from )
  230. value_from(std::move(*from), jv);
  231. else
  232. jv = nullptr;
  233. }
  234. inline
  235. void
  236. tag_invoke(
  237. value_from_tag,
  238. value& jv,
  239. std::nullopt_t)
  240. {
  241. // do nothing
  242. BOOST_ASSERT(jv.is_null());
  243. (void)jv;
  244. }
  245. #endif
  246. #ifndef BOOST_NO_CXX17_HDR_VARIANT
  247. // std::variant
  248. template<class... Ts>
  249. void
  250. tag_invoke(
  251. value_from_tag,
  252. value& jv,
  253. std::variant<Ts...>&& from)
  254. {
  255. std::visit(detail::value_from_visitor{jv}, std::move(from));
  256. }
  257. template<class... Ts>
  258. void
  259. tag_invoke(
  260. value_from_tag,
  261. value& jv,
  262. std::variant<Ts...> const& from)
  263. {
  264. std::visit(detail::value_from_visitor{jv}, from);
  265. }
  266. #endif // BOOST_NO_CXX17_HDR_VARIANT
  267. } // namespace json
  268. } // namespace boost
  269. #endif