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