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   39 value_from_impl( user_category, value& jv, T&& from, Ctx const& ) 50   39 value_from_impl( user_category, value& jv, T&& from, Ctx const& )
51   { 51   {
HITCBC 52   39 tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) ); 52   39 tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
HITCBC 53   39 } 53   39 }
54   54  
55   template< class T, class Ctx > 55   template< class T, class Ctx >
56   void 56   void
HITCBC 57   26 value_from_impl( user_context_category, value& jv, T&& from, Ctx const& ctx) 57   26 value_from_impl( user_context_category, 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   user_full_context_category, value& jv, T&& from, Ctx const& ctx) 66   user_full_context_category, 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 Cat, class T, class Ctx > 76   template< class Cat, class T, class Ctx >
77   void 77   void
HITCBC 78   6641 value_from_impl( 78   6641 value_from_impl(
79   Cat, 79   Cat,
80   value& jv, 80   value& jv,
81   T&& from, 81   T&& from,
82   Ctx const&, 82   Ctx const&,
83   typename std::enable_if<is_native_conversion<Cat>::value>* = nullptr) 83   typename std::enable_if<is_native_conversion<Cat>::value>* = nullptr)
84   { 84   {
HITCBC 85   6641 jv = std::forward<T>(from); 85   6641 jv = std::forward<T>(from);
HITCBC 86   6640 } 86   6640 }
87   87  
88   // null-like types 88   // null-like types
89   template< class T, class Ctx > 89   template< class T, class Ctx >
90   void 90   void
HITCBC 91   11 value_from_impl( null_category, value& jv, T&&, Ctx const& ) 91   11 value_from_impl( null_category, value& jv, T&&, Ctx const& )
92   { 92   {
93   // do nothing 93   // do nothing
HITCBC 94   11 BOOST_ASSERT(jv.is_null()); 94   11 BOOST_ASSERT(jv.is_null());
95   (void)jv; 95   (void)jv;
HITCBC 96   11 } 96   11 }
97   97  
98   // string-like types 98   // string-like types
99   template< class T, class Ctx > 99   template< class T, class Ctx >
100   void 100   void
HITCBC 101   75 value_from_impl( string_category, value& jv, T&& from, Ctx const& ) 101   75 value_from_impl( string_category, value& jv, T&& from, Ctx const& )
102   { 102   {
HITCBC 103   75 auto sv = static_cast<string_view>(from); 103   75 auto sv = static_cast<string_view>(from);
HITCBC 104   75 jv.emplace_string().assign(sv); 104   75 jv.emplace_string().assign(sv);
HITCBC 105   75 } 105   75 }
106   106  
107   // map-like types 107   // map-like types
108   template< class T, class Ctx > 108   template< class T, class Ctx >
109   void 109   void
HITCBC 110   47 value_from_impl( map_category, value& jv, T&& from, Ctx const& ctx ) 110   47 value_from_impl( map_category, value& jv, T&& from, Ctx const& ctx )
111   { 111   {
112   using std::get; 112   using std::get;
HITCBC 113   47 object& obj = jv.emplace_object(); 113   47 object& obj = jv.emplace_object();
HITCBC 114   47 obj.reserve(detail::try_size(from, size_implementation<T>())); 114   47 obj.reserve(detail::try_size(from, size_implementation<T>()));
HITCBC 115   148 for (auto&& elem : from) 115   148 for (auto&& elem : from)
HITCBC 116   303 obj.emplace( 116   303 obj.emplace(
HITCBC 117   101 get<0>(elem), 117   101 get<0>(elem),
HITCBC 118   101 value_from( get<1>(elem), ctx, obj.storage() )); 118   101 value_from( get<1>(elem), ctx, obj.storage() ));
HITCBC 119   47 } 119   47 }
120   120  
121   // ranges 121   // ranges
122   template< class T, class Ctx > 122   template< class T, class Ctx >
123   void 123   void
HITCBC 124   108 value_from_impl( sequence_category, value& jv, T&& from, Ctx const& ctx ) 124   108 value_from_impl( sequence_category, value& jv, T&& from, Ctx const& ctx )
125   { 125   {
HITCBC 126   108 array& result = jv.emplace_array(); 126   108 array& result = jv.emplace_array();
HITCBC 127   108 result.reserve(detail::try_size(from, size_implementation<T>())); 127   108 result.reserve(detail::try_size(from, size_implementation<T>()));
128   using ForwardedValue = forwarded_value<T&&>; 128   using ForwardedValue = forwarded_value<T&&>;
HITCBC 129   6382 for (auto&& elem : from) 129   6382 for (auto&& elem : from)
HITCBC 130   6460 result.emplace_back( 130   6460 result.emplace_back(
131   value_from( 131   value_from(
132   // not a static_cast in order to appease clang < 4.0 132   // not a static_cast in order to appease clang < 4.0
HITCBC 133   190 ForwardedValue(elem), 133   190 ForwardedValue(elem),
134   ctx, 134   ctx,
135   result.storage() )); 135   result.storage() ));
HITCBC 136   108 } 136   108 }
137   137  
138   // tuple-like types 138   // tuple-like types
139   template< class T, class Ctx > 139   template< class T, class Ctx >
140   void 140   void
HITCBC 141   139 value_from_impl( tuple_category, value& jv, T&& from, Ctx const& ctx ) 141   139 value_from_impl( tuple_category, value& jv, T&& from, Ctx const& ctx )
142   { 142   {
HITCBC 143   139 constexpr std::size_t n = 143   139 constexpr std::size_t n =
144   std::tuple_size<remove_cvref<T>>::value; 144   std::tuple_size<remove_cvref<T>>::value;
HITCBC 145   139 array& arr = jv.emplace_array(); 145   139 array& arr = jv.emplace_array();
HITCBC 146   139 arr.reserve(n); 146   139 arr.reserve(n);
HITCBC 147   139 mp11::mp_for_each<mp11::mp_iota_c<n>>( 147   139 mp11::mp_for_each<mp11::mp_iota_c<n>>(
HITCBC 148   139 append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) }); 148   139 append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
HITCBC 149   139 } 149   139 }
150   150  
151   // no suitable conversion implementation 151   // no suitable conversion implementation
152   template< class T, class Ctx > 152   template< class T, class Ctx >
153   void 153   void
154   value_from_impl( unknown_category, value&, T&&, Ctx const& ) 154   value_from_impl( unknown_category, value&, T&&, Ctx const& )
155   { 155   {
156   static_assert( 156   static_assert(
157   !std::is_same<T, T>::value, 157   !std::is_same<T, T>::value,
158   "No suitable tag_invoke overload found for the type"); 158   "No suitable tag_invoke overload found for the type");
159   } 159   }
160   160  
161   template< class Ctx, class T > 161   template< class Ctx, class T >
162   struct from_described_member 162   struct from_described_member
163   { 163   {
164   static_assert( 164   static_assert(
165   uniquely_named_members< remove_cvref<T> >::value, 165   uniquely_named_members< remove_cvref<T> >::value,
166   "The type has several described members with the same name."); 166   "The type has several described members with the same name.");
167   167  
168   using Ds = described_members< remove_cvref<T> >; 168   using Ds = described_members< remove_cvref<T> >;
169   169  
170   object& obj; 170   object& obj;
171   Ctx const& ctx; 171   Ctx const& ctx;
172   T&& from; 172   T&& from;
173   173  
174   template< class I > 174   template< class I >
175   void 175   void
176   operator()(I) const 176   operator()(I) const
177   { 177   {
178   using D = mp11::mp_at<Ds, I>; 178   using D = mp11::mp_at<Ds, I>;
179   obj.emplace( 179   obj.emplace(
180   D::name, 180   D::name,
181   value_from( 181   value_from(
182   static_cast<T&&>(from).* D::pointer, 182   static_cast<T&&>(from).* D::pointer,
183   ctx, 183   ctx,
184   obj.storage())); 184   obj.storage()));
185   } 185   }
186   }; 186   };
187   187  
188   // described classes 188   // described classes
189   template< class T, class Ctx > 189   template< class T, class Ctx >
190   void 190   void
191   value_from_impl( 191   value_from_impl(
192   described_class_category, value& jv, T&& from, Ctx const& ctx ) 192   described_class_category, value& jv, T&& from, Ctx const& ctx )
193   { 193   {
194   object& obj = jv.emplace_object(); 194   object& obj = jv.emplace_object();
195   from_described_member<Ctx, T> member_converter{ 195   from_described_member<Ctx, T> member_converter{
196   obj, ctx, static_cast<T&&>(from)}; 196   obj, ctx, static_cast<T&&>(from)};
197   197  
198   using Ds = typename decltype(member_converter)::Ds; 198   using Ds = typename decltype(member_converter)::Ds;
199   constexpr std::size_t N = mp11::mp_size<Ds>::value; 199   constexpr std::size_t N = mp11::mp_size<Ds>::value;
200   obj.reserve(N); 200   obj.reserve(N);
201   mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter); 201   mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
202   } 202   }
203   203  
204   // described enums 204   // described enums
205   template< class T, class Ctx > 205   template< class T, class Ctx >
206   void 206   void
207   value_from_impl( described_enum_category, value& jv, T from, Ctx const& ) 207   value_from_impl( described_enum_category, value& jv, T from, Ctx const& )
208   { 208   {
209   (void)jv; 209   (void)jv;
210   (void)from; 210   (void)from;
211   #ifdef BOOST_DESCRIBE_CXX14 211   #ifdef BOOST_DESCRIBE_CXX14
212   char const* const name = describe::enum_to_string(from, nullptr); 212   char const* const name = describe::enum_to_string(from, nullptr);
213   if( name ) 213   if( name )
214   { 214   {
215   string& str = jv.emplace_string(); 215   string& str = jv.emplace_string();
216   str.assign(name); 216   str.assign(name);
217   } 217   }
218   else 218   else
219   { 219   {
220   using Integer = typename std::underlying_type< remove_cvref<T> >::type; 220   using Integer = typename std::underlying_type< remove_cvref<T> >::type;
221   jv = static_cast<Integer>(from); 221   jv = static_cast<Integer>(from);
222   } 222   }
223   #endif 223   #endif
224   } 224   }
225   225  
226   // optionals 226   // optionals
227   template< class T, class Ctx > 227   template< class T, class Ctx >
228   void 228   void
229   value_from_impl( optional_category, value& jv, T&& from, Ctx const& ctx ) 229   value_from_impl( optional_category, value& jv, T&& from, Ctx const& ctx )
230   { 230   {
231   if( from ) 231   if( from )
232   value_from( *from, ctx, jv ); 232   value_from( *from, ctx, jv );
233   else 233   else
234   jv = nullptr; 234   jv = nullptr;
235   } 235   }
236   236  
237   // variants 237   // variants
238   template< class Ctx > 238   template< class Ctx >
239   struct value_from_visitor 239   struct value_from_visitor
240   { 240   {
241   value& jv; 241   value& jv;
242   Ctx const& ctx; 242   Ctx const& ctx;
243   243  
244   template<class T> 244   template<class T>
245   void 245   void
246   operator()(T&& t) 246   operator()(T&& t)
247   { 247   {
248   value_from( static_cast<T&&>(t), ctx, jv ); 248   value_from( static_cast<T&&>(t), ctx, jv );
249   } 249   }
250   }; 250   };
251   251  
252   template< class Ctx, class T > 252   template< class Ctx, class T >
253   void 253   void
254   value_from_impl( variant_category, value& jv, T&& from, Ctx const& ctx ) 254   value_from_impl( variant_category, value& jv, T&& from, Ctx const& ctx )
255   { 255   {
256   visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) ); 256   visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
257   } 257   }
258   258  
259   template< class Ctx, class T > 259   template< class Ctx, class T >
260   void 260   void
261   value_from_impl( path_category, value& jv, T&& from, Ctx const& ) 261   value_from_impl( path_category, value& jv, T&& from, Ctx const& )
262   { 262   {
263   std::string s = from.generic_string(); 263   std::string s = from.generic_string();
264   string_view sv = s; 264   string_view sv = s;
265   jv.emplace_string().assign(sv); 265   jv.emplace_string().assign(sv);
266   } 266   }
267   267  
268   //---------------------------------------------------------- 268   //----------------------------------------------------------
269   // Contextual conversions 269   // Contextual conversions
270   270  
271   template< class Ctx, class T > 271   template< class Ctx, class T >
272   using value_from_category = get_conversion_category< 272   using value_from_category = get_conversion_category<
273   T, 273   T,
274   Ctx, 274   Ctx,
275   all_custom_checks<value_from_conversion>::fn, 275   all_custom_checks<value_from_conversion>::fn,
276   all_fallback_checks<value_from_conversion>::fn>; 276   all_fallback_checks<value_from_conversion>::fn>;
277   277  
278   } // detail 278   } // detail
279   279  
280   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL 280   #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
281   inline 281   inline
282   void 282   void
283   tag_invoke( 283   tag_invoke(
284   value_from_tag, 284   value_from_tag,
285   value& jv, 285   value& jv,
286   std::nullopt_t) 286   std::nullopt_t)
287   { 287   {
288   // do nothing 288   // do nothing
289   BOOST_ASSERT(jv.is_null()); 289   BOOST_ASSERT(jv.is_null());
290   (void)jv; 290   (void)jv;
291   } 291   }
292   #endif 292   #endif
293   293  
294   } // namespace json 294   } // namespace json
295   } // namespace boost 295   } // namespace boost
296   296  
297   #endif 297   #endif