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