100.00% Lines (18/18) 100.00% Functions (9/9)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com) 2   // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
3   // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru) 3   // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru)
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/boostorg/json 8   // Official repository: https://github.com/boostorg/json
9   // 9   //
10   10  
11   #ifndef BOOST_JSON_IMPL_CONVERSION_HPP 11   #ifndef BOOST_JSON_IMPL_CONVERSION_HPP
12   #define BOOST_JSON_IMPL_CONVERSION_HPP 12   #define BOOST_JSON_IMPL_CONVERSION_HPP
13   13  
14   #include <boost/json/fwd.hpp> 14   #include <boost/json/fwd.hpp>
15   #include <boost/json/string_view.hpp> 15   #include <boost/json/string_view.hpp>
16   #include <boost/describe/enumerators.hpp> 16   #include <boost/describe/enumerators.hpp>
17   #include <boost/describe/members.hpp> 17   #include <boost/describe/members.hpp>
18   #include <boost/describe/bases.hpp> 18   #include <boost/describe/bases.hpp>
19   #include <boost/mp11/algorithm.hpp> 19   #include <boost/mp11/algorithm.hpp>
20   #include <boost/mp11/utility.hpp> 20   #include <boost/mp11/utility.hpp>
21   #include <boost/system/result.hpp> 21   #include <boost/system/result.hpp>
22   22  
23   #include <iterator> 23   #include <iterator>
24   #include <tuple> 24   #include <tuple>
25   #include <utility> 25   #include <utility>
26   #ifndef BOOST_NO_CXX17_HDR_VARIANT 26   #ifndef BOOST_NO_CXX17_HDR_VARIANT
27   # include <variant> 27   # include <variant>
28   #endif // BOOST_NO_CXX17_HDR_VARIANT 28   #endif // BOOST_NO_CXX17_HDR_VARIANT
29   29  
30   namespace boost { 30   namespace boost {
31   namespace json { 31   namespace json {
32   32  
33   class value_ref; 33   class value_ref;
34   34  
35   namespace detail { 35   namespace detail {
36   36  
37   #ifdef __cpp_lib_nonmember_container_access 37   #ifdef __cpp_lib_nonmember_container_access
38   using std::size; 38   using std::size;
39   #endif 39   #endif
40   40  
41   template<std::size_t I, class T> 41   template<std::size_t I, class T>
42   using tuple_element_t = typename std::tuple_element<I, T>::type; 42   using tuple_element_t = typename std::tuple_element<I, T>::type;
43   43  
44   template<class T> 44   template<class T>
45   using iterator_type = decltype(std::begin(std::declval<T&>())); 45   using iterator_type = decltype(std::begin(std::declval<T&>()));
46   template<class T> 46   template<class T>
47   using iterator_traits = std::iterator_traits< iterator_type<T> >; 47   using iterator_traits = std::iterator_traits< iterator_type<T> >;
48   48  
49   template<class T> 49   template<class T>
50   using value_type = typename iterator_traits<T>::value_type; 50   using value_type = typename iterator_traits<T>::value_type;
51   template<class T> 51   template<class T>
52   using mapped_type = tuple_element_t< 1, value_type<T> >; 52   using mapped_type = tuple_element_t< 1, value_type<T> >;
53   53  
54   // had to make the metafunction always succeeding in order to make it work 54   // had to make the metafunction always succeeding in order to make it work
55   // with msvc 14.0 55   // with msvc 14.0
56   template<class T> 56   template<class T>
57   using key_type_helper = tuple_element_t< 0, value_type<T> >; 57   using key_type_helper = tuple_element_t< 0, value_type<T> >;
58   template<class T> 58   template<class T>
59   using key_type = mp11::mp_eval_or< 59   using key_type = mp11::mp_eval_or<
60   void, 60   void,
61   key_type_helper, 61   key_type_helper,
62   T>; 62   T>;
63   63  
64   template<class T> 64   template<class T>
65   using are_begin_and_end_same = std::is_same< 65   using are_begin_and_end_same = std::is_same<
66   iterator_type<T>, 66   iterator_type<T>,
67   decltype(std::end(std::declval<T&>()))>; 67   decltype(std::end(std::declval<T&>()))>;
68   68  
69   // msvc 14.0 gets confused when std::is_same is used directly 69   // msvc 14.0 gets confused when std::is_same is used directly
70   template<class A, class B> 70   template<class A, class B>
71   using is_same_msvc_140 = std::is_same<A, B>; 71   using is_same_msvc_140 = std::is_same<A, B>;
72   template<class T> 72   template<class T>
73   using is_its_own_value = is_same_msvc_140<value_type<T>, T>; 73   using is_its_own_value = is_same_msvc_140<value_type<T>, T>;
74   74  
75   template<class T> 75   template<class T>
76   using not_its_own_value = mp11::mp_not< is_its_own_value<T> >; 76   using not_its_own_value = mp11::mp_not< is_its_own_value<T> >;
77   77  
78   template<class T> 78   template<class T>
79   using begin_iterator_category = typename std::iterator_traits< 79   using begin_iterator_category = typename std::iterator_traits<
80   iterator_type<T>>::iterator_category; 80   iterator_type<T>>::iterator_category;
81   81  
82   template<class T> 82   template<class T>
83   using has_positive_tuple_size = mp11::mp_bool< 83   using has_positive_tuple_size = mp11::mp_bool<
84   (std::tuple_size<T>::value > 0) >; 84   (std::tuple_size<T>::value > 0) >;
85   85  
86   template<class T> 86   template<class T>
87   using has_unique_keys = has_positive_tuple_size<decltype( 87   using has_unique_keys = has_positive_tuple_size<decltype(
88   std::declval<T&>().emplace( 88   std::declval<T&>().emplace(
89   std::declval<value_type<T>>()))>; 89   std::declval<value_type<T>>()))>;
90   90  
91   template<class T> 91   template<class T>
92   using has_string_type = std::is_same< 92   using has_string_type = std::is_same<
93   typename T::string_type, std::basic_string<typename T::value_type> >; 93   typename T::string_type, std::basic_string<typename T::value_type> >;
94   94  
95   template<class T> 95   template<class T>
96   struct is_value_type_pair_helper : std::false_type 96   struct is_value_type_pair_helper : std::false_type
97   { }; 97   { };
98   template<class T1, class T2> 98   template<class T1, class T2>
99   struct is_value_type_pair_helper<std::pair<T1, T2>> : std::true_type 99   struct is_value_type_pair_helper<std::pair<T1, T2>> : std::true_type
100   { }; 100   { };
101   template<class T> 101   template<class T>
102   using is_value_type_pair = is_value_type_pair_helper<value_type<T>>; 102   using is_value_type_pair = is_value_type_pair_helper<value_type<T>>;
103   103  
104   template<class T> 104   template<class T>
105   using has_size_member_helper 105   using has_size_member_helper
106   = std::is_convertible<decltype(std::declval<T&>().size()), std::size_t>; 106   = std::is_convertible<decltype(std::declval<T&>().size()), std::size_t>;
107   template<class T> 107   template<class T>
108   using has_size_member = mp11::mp_valid_and_true<has_size_member_helper, T>; 108   using has_size_member = mp11::mp_valid_and_true<has_size_member_helper, T>;
109   template<class T> 109   template<class T>
110   using has_free_size_helper 110   using has_free_size_helper
111   = std::is_convertible< 111   = std::is_convertible<
112   decltype(size(std::declval<T const&>())), 112   decltype(size(std::declval<T const&>())),
113   std::size_t>; 113   std::size_t>;
114   template<class T> 114   template<class T>
115   using has_free_size = mp11::mp_valid_and_true<has_free_size_helper, T>; 115   using has_free_size = mp11::mp_valid_and_true<has_free_size_helper, T>;
116   template<class T> 116   template<class T>
117   using size_implementation = mp11::mp_cond< 117   using size_implementation = mp11::mp_cond<
118   has_size_member<T>, mp11::mp_int<3>, 118   has_size_member<T>, mp11::mp_int<3>,
119   has_free_size<T>, mp11::mp_int<2>, 119   has_free_size<T>, mp11::mp_int<2>,
120   std::is_array<T>, mp11::mp_int<1>, 120   std::is_array<T>, mp11::mp_int<1>,
121   mp11::mp_true, mp11::mp_int<0>>; 121   mp11::mp_true, mp11::mp_int<0>>;
122   122  
123   template<class T> 123   template<class T>
124   std::size_t 124   std::size_t
HITCBC 125   150 try_size(T&& cont, mp11::mp_int<3>) 125   150 try_size(T&& cont, mp11::mp_int<3>)
126   { 126   {
HITCBC 127   150 return cont.size(); 127   150 return cont.size();
128   } 128   }
129   129  
130   template<class T> 130   template<class T>
131   std::size_t 131   std::size_t
HITCBC 132   1 try_size(T& cont, mp11::mp_int<2>) 132   1 try_size(T& cont, mp11::mp_int<2>)
133   { 133   {
HITCBC 134   1 return size(cont); 134   1 return size(cont);
135   } 135   }
136   136  
137   template<class T, std::size_t N> 137   template<class T, std::size_t N>
138   std::size_t 138   std::size_t
HITCBC 139   1 try_size(T(&)[N], mp11::mp_int<1>) 139   1 try_size(T(&)[N], mp11::mp_int<1>)
140   { 140   {
HITCBC 141   1 return N; 141   1 return N;
142   } 142   }
143   143  
144   template<class T> 144   template<class T>
145   std::size_t 145   std::size_t
HITCBC 146   7 try_size(T&, mp11::mp_int<0>) 146   7 try_size(T&, mp11::mp_int<0>)
147   { 147   {
HITCBC 148   7 return 0; 148   7 return 0;
149   } 149   }
150   150  
151   template<class T> 151   template<class T>
152   using has_push_back_helper 152   using has_push_back_helper
153   = decltype(std::declval<T&>().push_back(std::declval<value_type<T>>())); 153   = decltype(std::declval<T&>().push_back(std::declval<value_type<T>>()));
154   template<class T> 154   template<class T>
155   using has_push_back = mp11::mp_valid<has_push_back_helper, T>; 155   using has_push_back = mp11::mp_valid<has_push_back_helper, T>;
156   template<class T> 156   template<class T>
157   using inserter_implementation = mp11::mp_cond< 157   using inserter_implementation = mp11::mp_cond<
158   is_tuple_like<T>, mp11::mp_int<2>, 158   is_tuple_like<T>, mp11::mp_int<2>,
159   has_push_back<T>, mp11::mp_int<1>, 159   has_push_back<T>, mp11::mp_int<1>,
160   mp11::mp_true, mp11::mp_int<0>>; 160   mp11::mp_true, mp11::mp_int<0>>;
161   161  
162   template<class T> 162   template<class T>
163   iterator_type<T> 163   iterator_type<T>
HITCBC 164   64 inserter( 164   64 inserter(
165   T& target, 165   T& target,
166   mp11::mp_int<2>) 166   mp11::mp_int<2>)
167   { 167   {
HITCBC 168   64 return target.begin(); 168   64 return target.begin();
169   } 169   }
170   170  
171   template<class T> 171   template<class T>
172   std::back_insert_iterator<T> 172   std::back_insert_iterator<T>
HITCBC 173   659 inserter( 173   659 inserter(
174   T& target, 174   T& target,
175   mp11::mp_int<1>) 175   mp11::mp_int<1>)
176   { 176   {
HITCBC 177   659 return std::back_inserter(target); 177   659 return std::back_inserter(target);
178   } 178   }
179   179  
180   template<class T> 180   template<class T>
181   std::insert_iterator<T> 181   std::insert_iterator<T>
HITCBC 182   104 inserter( 182   104 inserter(
183   T& target, 183   T& target,
184   mp11::mp_int<0>) 184   mp11::mp_int<0>)
185   { 185   {
HITCBC 186   104 return std::inserter( target, target.end() ); 186   104 return std::inserter( target, target.end() );
187   } 187   }
188   188  
189   using boolean_category = std::integral_constant< 189   using boolean_category = std::integral_constant<
190   conversion_category, conversion_category::boolean>; 190   conversion_category, conversion_category::boolean>;
191   191  
192   using integer_category = std::integral_constant< 192   using integer_category = std::integral_constant<
193   conversion_category, conversion_category::integer>; 193   conversion_category, conversion_category::integer>;
194   194  
195   using floating_point_category = std::integral_constant< 195   using floating_point_category = std::integral_constant<
196   conversion_category, conversion_category::floating_point>; 196   conversion_category, conversion_category::floating_point>;
197   197  
198   } // namespace detail 198   } // namespace detail
199   199  
200   200  
201   template<class T, class Ctx, class Enable> 201   template<class T, class Ctx, class Enable>
202   struct use_category : unknown_category {}; 202   struct use_category : unknown_category {};
203   203  
204   namespace detail { 204   namespace detail {
205   205  
206   using value_from_conversion = mp11::mp_true; 206   using value_from_conversion = mp11::mp_true;
207   using value_to_conversion = mp11::mp_false; 207   using value_to_conversion = mp11::mp_false;
208   208  
209   using user_category = std::integral_constant< 209   using user_category = std::integral_constant<
210   conversion_category, conversion_category::user>; 210   conversion_category, conversion_category::user>;
211   using user_context_category = std::integral_constant< 211   using user_context_category = std::integral_constant<
212   conversion_category, conversion_category::user_context>; 212   conversion_category, conversion_category::user_context>;
213   using user_full_context_category = std::integral_constant< 213   using user_full_context_category = std::integral_constant<
214   conversion_category, conversion_category::user_full_context>; 214   conversion_category, conversion_category::user_full_context>;
215   using json_value_category = std::integral_constant< 215   using json_value_category = std::integral_constant<
216   conversion_category, conversion_category::json_value>; 216   conversion_category, conversion_category::json_value>;
217   using json_object_category = std::integral_constant< 217   using json_object_category = std::integral_constant<
218   conversion_category, conversion_category::json_object>; 218   conversion_category, conversion_category::json_object>;
219   using json_array_category = std::integral_constant< 219   using json_array_category = std::integral_constant<
220   conversion_category, conversion_category::json_array>; 220   conversion_category, conversion_category::json_array>;
221   using json_string_category = std::integral_constant< 221   using json_string_category = std::integral_constant<
222   conversion_category, conversion_category::json_string>; 222   conversion_category, conversion_category::json_string>;
223   using json_value_ref_category = std::integral_constant< 223   using json_value_ref_category = std::integral_constant<
224   conversion_category, conversion_category::json_value_ref>; 224   conversion_category, conversion_category::json_value_ref>;
225   225  
226   template< class Cat > 226   template< class Cat >
227   using is_user_conversion = mp11::mp_bool< 227   using is_user_conversion = mp11::mp_bool<
228   Cat::value == conversion_category::user 228   Cat::value == conversion_category::user
229   || Cat::value == conversion_category::user_context 229   || Cat::value == conversion_category::user_context
230   || Cat::value == conversion_category::user_full_context>; 230   || Cat::value == conversion_category::user_full_context>;
231   231  
232   template< class Cat > 232   template< class Cat >
233   using is_native_conversion = mp11::mp_bool< 233   using is_native_conversion = mp11::mp_bool<
234   Cat::value == conversion_category::user 234   Cat::value == conversion_category::user
235   || Cat::value == conversion_category::json_value 235   || Cat::value == conversion_category::json_value
236   || Cat::value == conversion_category::json_object 236   || Cat::value == conversion_category::json_object
237   || Cat::value == conversion_category::json_array 237   || Cat::value == conversion_category::json_array
238   || Cat::value == conversion_category::json_string 238   || Cat::value == conversion_category::json_string
239   || Cat::value == conversion_category::json_value_ref 239   || Cat::value == conversion_category::json_value_ref
240   || Cat::value == conversion_category::boolean 240   || Cat::value == conversion_category::boolean
241   || Cat::value == conversion_category::integer 241   || Cat::value == conversion_category::integer
242   || Cat::value == conversion_category::floating_point>; 242   || Cat::value == conversion_category::floating_point>;
243   243  
244   template<class... Args> 244   template<class... Args>
245   using supports_tag_invoke = decltype(tag_invoke( std::declval<Args>()... )); 245   using supports_tag_invoke = decltype(tag_invoke( std::declval<Args>()... ));
246   246  
247   template<class T> 247   template<class T>
248   using has_user_conversion_from_impl = supports_tag_invoke< 248   using has_user_conversion_from_impl = supports_tag_invoke<
249   value_from_tag, value&, T&& >; 249   value_from_tag, value&, T&& >;
250   template<class T> 250   template<class T>
251   using has_user_conversion_to_impl = supports_tag_invoke< 251   using has_user_conversion_to_impl = supports_tag_invoke<
252   value_to_tag<T>, value const& >; 252   value_to_tag<T>, value const& >;
253   template<class T> 253   template<class T>
254   using has_nonthrowing_user_conversion_to_impl = supports_tag_invoke< 254   using has_nonthrowing_user_conversion_to_impl = supports_tag_invoke<
255   try_value_to_tag<T>, value const& >; 255   try_value_to_tag<T>, value const& >;
256   template< class T, class Dir > 256   template< class T, class Dir >
257   using has_user_conversion1 = mp11::mp_if< 257   using has_user_conversion1 = mp11::mp_if<
258   std::is_same<Dir, value_from_conversion>, 258   std::is_same<Dir, value_from_conversion>,
259   mp11::mp_valid<has_user_conversion_from_impl, T>, 259   mp11::mp_valid<has_user_conversion_from_impl, T>,
260   mp11::mp_or< 260   mp11::mp_or<
261   mp11::mp_valid<has_user_conversion_to_impl, T>, 261   mp11::mp_valid<has_user_conversion_to_impl, T>,
262   mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>>>; 262   mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>>>;
263   263  
264   template< class Ctx, class T > 264   template< class Ctx, class T >
265   using has_context_conversion_from_impl = supports_tag_invoke< 265   using has_context_conversion_from_impl = supports_tag_invoke<
266   value_from_tag, value&, T&&, Ctx const& >; 266   value_from_tag, value&, T&&, Ctx const& >;
267   template< class Ctx, class T > 267   template< class Ctx, class T >
268   using has_context_conversion_to_impl = supports_tag_invoke< 268   using has_context_conversion_to_impl = supports_tag_invoke<
269   value_to_tag<T>, value const&, Ctx const& >; 269   value_to_tag<T>, value const&, Ctx const& >;
270   template< class Ctx, class T > 270   template< class Ctx, class T >
271   using has_nonthrowing_context_conversion_to_impl = supports_tag_invoke< 271   using has_nonthrowing_context_conversion_to_impl = supports_tag_invoke<
272   try_value_to_tag<T>, value const&, Ctx const& >; 272   try_value_to_tag<T>, value const&, Ctx const& >;
273   template< class Ctx, class T, class Dir > 273   template< class Ctx, class T, class Dir >
274   using has_user_conversion2 = mp11::mp_if< 274   using has_user_conversion2 = mp11::mp_if<
275   std::is_same<Dir, value_from_conversion>, 275   std::is_same<Dir, value_from_conversion>,
276   mp11::mp_valid<has_context_conversion_from_impl, Ctx, T>, 276   mp11::mp_valid<has_context_conversion_from_impl, Ctx, T>,
277   mp11::mp_or< 277   mp11::mp_or<
278   mp11::mp_valid<has_context_conversion_to_impl, Ctx, T>, 278   mp11::mp_valid<has_context_conversion_to_impl, Ctx, T>,
279   mp11::mp_valid<has_nonthrowing_context_conversion_to_impl, Ctx, T>>>; 279   mp11::mp_valid<has_nonthrowing_context_conversion_to_impl, Ctx, T>>>;
280   280  
281   template< class Ctx, class T > 281   template< class Ctx, class T >
282   using has_full_context_conversion_from_impl = supports_tag_invoke< 282   using has_full_context_conversion_from_impl = supports_tag_invoke<
283   value_from_tag, value&, T&&, Ctx const&, Ctx const& >; 283   value_from_tag, value&, T&&, Ctx const&, Ctx const& >;
284   template< class Ctx, class T > 284   template< class Ctx, class T >
285   using has_full_context_conversion_to_impl = supports_tag_invoke< 285   using has_full_context_conversion_to_impl = supports_tag_invoke<
286   value_to_tag<T>, value const&, Ctx const&, Ctx const& >; 286   value_to_tag<T>, value const&, Ctx const&, Ctx const& >;
287   template< class Ctx, class T > 287   template< class Ctx, class T >
288   using has_nonthrowing_full_context_conversion_to_impl = supports_tag_invoke< 288   using has_nonthrowing_full_context_conversion_to_impl = supports_tag_invoke<
289   try_value_to_tag<T>, value const&, Ctx const&, Ctx const& >; 289   try_value_to_tag<T>, value const&, Ctx const&, Ctx const& >;
290   template< class Ctx, class T, class Dir > 290   template< class Ctx, class T, class Dir >
291   using has_user_conversion3 = mp11::mp_if< 291   using has_user_conversion3 = mp11::mp_if<
292   std::is_same<Dir, value_from_conversion>, 292   std::is_same<Dir, value_from_conversion>,
293   mp11::mp_valid<has_full_context_conversion_from_impl, Ctx, T>, 293   mp11::mp_valid<has_full_context_conversion_from_impl, Ctx, T>,
294   mp11::mp_or< 294   mp11::mp_or<
295   mp11::mp_valid<has_full_context_conversion_to_impl, Ctx, T>, 295   mp11::mp_valid<has_full_context_conversion_to_impl, Ctx, T>,
296   mp11::mp_valid< 296   mp11::mp_valid<
297   has_nonthrowing_full_context_conversion_to_impl, Ctx, T>>>; 297   has_nonthrowing_full_context_conversion_to_impl, Ctx, T>>>;
298   298  
299   template< class T > 299   template< class T >
300   using described_non_public_members = describe::describe_members< 300   using described_non_public_members = describe::describe_members<
301   T, 301   T,
302   describe::mod_private 302   describe::mod_private
303   | describe::mod_protected 303   | describe::mod_protected
304   | boost::describe::mod_inherited>; 304   | boost::describe::mod_inherited>;
305   305  
306   #if defined(BOOST_MSVC) && BOOST_MSVC < 1920 306   #if defined(BOOST_MSVC) && BOOST_MSVC < 1920
307   307  
308   template< class T > 308   template< class T >
309   struct described_member_t_impl; 309   struct described_member_t_impl;
310   310  
311   template< class T, class C > 311   template< class T, class C >
312   struct described_member_t_impl<T C::*> 312   struct described_member_t_impl<T C::*>
313   { 313   {
314   using type = T; 314   using type = T;
315   }; 315   };
316   316  
317   template< class T, class D > 317   template< class T, class D >
318   using described_member_t = remove_cvref< 318   using described_member_t = remove_cvref<
319   typename described_member_t_impl< 319   typename described_member_t_impl<
320   remove_cvref<decltype(D::pointer)> >::type>; 320   remove_cvref<decltype(D::pointer)> >::type>;
321   321  
322   #else 322   #else
323   323  
324   template< class T, class D > 324   template< class T, class D >
325   using described_member_t = remove_cvref<decltype( 325   using described_member_t = remove_cvref<decltype(
326   std::declval<T&>().* D::pointer )>; 326   std::declval<T&>().* D::pointer )>;
327   327  
328   #endif 328   #endif
329   329  
330   template< class T > 330   template< class T >
331   using described_members = describe::describe_members< 331   using described_members = describe::describe_members<
332   T, describe::mod_any_access | describe::mod_inherited>; 332   T, describe::mod_any_access | describe::mod_inherited>;
333   333  
334   #ifdef BOOST_DESCRIBE_CXX14 334   #ifdef BOOST_DESCRIBE_CXX14
335   335  
336   constexpr 336   constexpr
337   bool 337   bool
338   compare_strings(char const* l, char const* r) 338   compare_strings(char const* l, char const* r)
339   { 339   {
340   #if defined(_MSC_VER) && (_MSC_VER <= 1900) && !defined(__clang__) 340   #if defined(_MSC_VER) && (_MSC_VER <= 1900) && !defined(__clang__)
341   return *l == *r && ( (*l == 0) | compare_strings(l + 1, r + 1) ); 341   return *l == *r && ( (*l == 0) | compare_strings(l + 1, r + 1) );
342   #else 342   #else
343   do 343   do
344   { 344   {
345   if( *l != *r ) 345   if( *l != *r )
346   return false; 346   return false;
347   if( *l == 0 ) 347   if( *l == 0 )
348   return true; 348   return true;
349   ++l; 349   ++l;
350   ++r; 350   ++r;
351   } while(true); 351   } while(true);
352   #endif 352   #endif
353   } 353   }
354   354  
355   template< class L, class R > 355   template< class L, class R >
356   struct equal_member_names 356   struct equal_member_names
357   : mp11::mp_bool< compare_strings(L::name, R::name) > 357   : mp11::mp_bool< compare_strings(L::name, R::name) >
358   {}; 358   {};
359   359  
360   template< class T > 360   template< class T >
361   using uniquely_named_members = mp11::mp_same< 361   using uniquely_named_members = mp11::mp_same<
362   mp11::mp_unique_if< described_members<T>, equal_member_names >, 362   mp11::mp_unique_if< described_members<T>, equal_member_names >,
363   described_members<T> >; 363   described_members<T> >;
364   364  
365   #else 365   #else
366   366  
367   // we only check this in C++14, but the template should exist nevertheless 367   // we only check this in C++14, but the template should exist nevertheless
368   template< class T > 368   template< class T >
369   using uniquely_named_members = std::true_type; 369   using uniquely_named_members = std::true_type;
370   370  
371   #endif // BOOST_DESCRIBE_CXX14 371   #endif // BOOST_DESCRIBE_CXX14
372   372  
373   // user conversion (via tag_invoke) 373   // user conversion (via tag_invoke)
374   template< class T, class Ctx, class Dir > 374   template< class T, class Ctx, class Dir >
375   using tag_invoke_with_context_category = mp11::mp_cond< 375   using tag_invoke_with_context_category = mp11::mp_cond<
376   has_user_conversion3<Ctx, T, Dir>, user_full_context_category, 376   has_user_conversion3<Ctx, T, Dir>, user_full_context_category,
377   has_user_conversion2<Ctx, T, Dir>, user_context_category>; 377   has_user_conversion2<Ctx, T, Dir>, user_context_category>;
378   378  
379   template< class T, class Dir > 379   template< class T, class Dir >
380   using tag_invoke_category = mp11::mp_cond< 380   using tag_invoke_category = mp11::mp_cond<
381   has_user_conversion1<T, Dir>, user_category>; 381   has_user_conversion1<T, Dir>, user_category>;
382   382  
383   // native conversions (constructors and member functions of value) 383   // native conversions (constructors and member functions of value)
384   template< class T > 384   template< class T >
385   using native_conversion_category = mp11::mp_cond< 385   using native_conversion_category = mp11::mp_cond<
386   std::is_same<T, value_ref>, json_value_ref_category, 386   std::is_same<T, value_ref>, json_value_ref_category,
387   std::is_same<T, value>, json_value_category, 387   std::is_same<T, value>, json_value_category,
388   std::is_same<T, array>, json_array_category, 388   std::is_same<T, array>, json_array_category,
389   std::is_same<T, object>, json_object_category, 389   std::is_same<T, object>, json_object_category,
390   std::is_same<T, string>, json_string_category>; 390   std::is_same<T, string>, json_string_category>;
391   391  
392   template<class T> 392   template<class T>
393   struct deduced_category 393   struct deduced_category
394   : mp11::mp_cond< 394   : mp11::mp_cond<
395   std::is_same<T, bool>, detail::boolean_category, 395   std::is_same<T, bool>, detail::boolean_category,
396   std::is_integral<T>, detail::integer_category, 396   std::is_integral<T>, detail::integer_category,
397   std::is_floating_point<T>, detail::floating_point_category, 397   std::is_floating_point<T>, detail::floating_point_category,
398   is_null_like<T>, null_category, 398   is_null_like<T>, null_category,
399   is_string_like<T>, string_category, 399   is_string_like<T>, string_category,
400   is_variant_like<T>, variant_category, 400   is_variant_like<T>, variant_category,
401   is_optional_like<T>, optional_category, 401   is_optional_like<T>, optional_category,
402   is_map_like<T>, map_category, 402   is_map_like<T>, map_category,
403   is_sequence_like<T>, sequence_category, 403   is_sequence_like<T>, sequence_category,
404   is_tuple_like<T>, tuple_category, 404   is_tuple_like<T>, tuple_category,
405   is_path_like<T>, path_category, 405   is_path_like<T>, path_category,
406   is_described_enum<T>, described_enum_category, 406   is_described_enum<T>, described_enum_category,
407   is_described_class<T>, described_class_category, 407   is_described_class<T>, described_class_category,
408   // failed to find a suitable implementation 408   // failed to find a suitable implementation
409   mp11::mp_true, unknown_category> 409   mp11::mp_true, unknown_category>
410   { }; 410   { };
411   411  
412   struct no_context {}; 412   struct no_context {};
413   413  
414   template <class T, class Ctx> 414   template <class T, class Ctx>
415   using use_category_helper = use_category< 415   using use_category_helper = use_category<
416   T, mp11::mp_if<std::is_same<Ctx, no_context>, void, Ctx>>; 416   T, mp11::mp_if<std::is_same<Ctx, no_context>, void, Ctx>>;
417   417  
418   template< class Dir > 418   template< class Dir >
419   struct all_custom_checks 419   struct all_custom_checks
420   { 420   {
421   template <class T, class Ctx> 421   template <class T, class Ctx>
422   using fn = mp11::mp_list< 422   using fn = mp11::mp_list<
423   mp11::mp_defer<use_category_helper, T, Ctx>, 423   mp11::mp_defer<use_category_helper, T, Ctx>,
424   mp11::mp_defer<tag_invoke_with_context_category, T, Ctx, Dir>>; 424   mp11::mp_defer<tag_invoke_with_context_category, T, Ctx, Dir>>;
425   }; 425   };
426   426  
427   template< class Dir > 427   template< class Dir >
428   struct all_fallback_checks 428   struct all_fallback_checks
429   { 429   {
430   template <class T> 430   template <class T>
431   using fn = mp11::mp_list< 431   using fn = mp11::mp_list<
432   mp11::mp_defer<use_category_helper, T, void>, 432   mp11::mp_defer<use_category_helper, T, void>,
433   mp11::mp_defer<tag_invoke_category, T, Dir>, 433   mp11::mp_defer<tag_invoke_category, T, Dir>,
434   mp11::mp_defer<native_conversion_category, T>, 434   mp11::mp_defer<native_conversion_category, T>,
435   mp11::mp_defer<deduced_category, T>>; 435   mp11::mp_defer<deduced_category, T>>;
436   }; 436   };
437   437  
438   template <class T, class Ctx> 438   template <class T, class Ctx>
439   using direct_custom_checks = mp11::mp_list< 439   using direct_custom_checks = mp11::mp_list<
440   mp11::mp_defer<use_category_helper, T, Ctx>>; 440   mp11::mp_defer<use_category_helper, T, Ctx>>;
441   441  
442   template <class T> 442   template <class T>
443   using direct_fallback_checks = mp11::mp_list< 443   using direct_fallback_checks = mp11::mp_list<
444   mp11::mp_defer<use_category_helper, T, void>, 444   mp11::mp_defer<use_category_helper, T, void>,
445   mp11::mp_defer<deduced_category, T>>; 445   mp11::mp_defer<deduced_category, T>>;
446   446  
447   template <class> 447   template <class>
448   using no_checks = mp11::mp_list<>; 448   using no_checks = mp11::mp_list<>;
449   449  
450   template< class T > 450   template< class T >
451   using nested_type = typename T::type; 451   using nested_type = typename T::type;
452   452  
453   template< class T1, class T2 > 453   template< class T1, class T2 >
454   using get_conversion_category_helper = mp11::mp_eval_if_c< 454   using get_conversion_category_helper = mp11::mp_eval_if_c<
455   conversion_category::unknown != T1::value, 455   conversion_category::unknown != T1::value,
456   T1, 456   T1,
457   mp11::mp_eval_or_q, T1, mp11::mp_quote<nested_type>, T2>; 457   mp11::mp_eval_or_q, T1, mp11::mp_quote<nested_type>, T2>;
458   458  
459   template< 459   template<
460   class T, 460   class T,
461   class Ctx, 461   class Ctx,
462   template<class, class> class CustomChecks, 462   template<class, class> class CustomChecks,
463   template<class> class FallbackChecks> 463   template<class> class FallbackChecks>
464   struct get_conversion_category_impl 464   struct get_conversion_category_impl
465   { 465   {
466   using type = std::integral_constant< 466   using type = std::integral_constant<
467   conversion_category, 467   conversion_category,
468   mp11::mp_fold< 468   mp11::mp_fold<
469   mp11::mp_append< CustomChecks<T, Ctx>, FallbackChecks<T> >, 469   mp11::mp_append< CustomChecks<T, Ctx>, FallbackChecks<T> >,
470   unknown_category, 470   unknown_category,
471   get_conversion_category_helper>::value>; 471   get_conversion_category_helper>::value>;
472   }; 472   };
473   473  
474   template< 474   template<
475   class T, 475   class T,
476   class Ctx, 476   class Ctx,
477   template<class, class> class CustomChecks, 477   template<class, class> class CustomChecks,
478   template<class> class FallbackChecks> 478   template<class> class FallbackChecks>
479   using get_conversion_category = typename get_conversion_category_impl< 479   using get_conversion_category = typename get_conversion_category_impl<
480   T, Ctx, CustomChecks, FallbackChecks>::type; 480   T, Ctx, CustomChecks, FallbackChecks>::type;
481   481  
482   template< class T > 482   template< class T >
483   using any_conversion_tag = mp11::mp_not< std::is_same<T, unknown_category> >; 483   using any_conversion_tag = mp11::mp_not< std::is_same<T, unknown_category> >;
484   484  
485   template< 485   template<
486   class T, 486   class T,
487   template<class, class> class CustomChecks, 487   template<class, class> class CustomChecks,
488   template<class> class FallbackChecks, 488   template<class> class FallbackChecks,
489   class... Ctxs > 489   class... Ctxs >
490   struct get_conversion_category_impl< 490   struct get_conversion_category_impl<
491   T, std::tuple<Ctxs...>, CustomChecks, FallbackChecks> 491   T, std::tuple<Ctxs...>, CustomChecks, FallbackChecks>
492   { 492   {
493   using ctxs = mp11::mp_list< remove_cvref<Ctxs>... >; 493   using ctxs = mp11::mp_list< remove_cvref<Ctxs>... >;
494   using cats = mp11::mp_list< 494   using cats = mp11::mp_list<
495   get_conversion_category< 495   get_conversion_category<
496   T, remove_cvref<Ctxs>, CustomChecks, no_checks>... >; 496   T, remove_cvref<Ctxs>, CustomChecks, no_checks>... >;
497   497  
498   using custom_index = mp11::mp_find_if< cats, any_conversion_tag >; 498   using custom_index = mp11::mp_find_if< cats, any_conversion_tag >;
499   using is_custom = mp11::mp_less< custom_index, mp11::mp_size<cats> >; 499   using is_custom = mp11::mp_less< custom_index, mp11::mp_size<cats> >;
500   500  
501   using index = mp11::mp_if< is_custom, custom_index, mp11::mp_size_t<0> >; 501   using index = mp11::mp_if< is_custom, custom_index, mp11::mp_size_t<0> >;
502   502  
503   using fallback_cat = mp11::mp_fold< 503   using fallback_cat = mp11::mp_fold<
504   FallbackChecks<T>, unknown_category, get_conversion_category_helper>; 504   FallbackChecks<T>, unknown_category, get_conversion_category_helper>;
505   505  
506   using type = std::integral_constant< 506   using type = std::integral_constant<
507   conversion_category, 507   conversion_category,
508   mp11::mp_eval_if_not< 508   mp11::mp_eval_if_not<
509   is_custom, fallback_cat, mp11::mp_at, cats, index>::value>; 509   is_custom, fallback_cat, mp11::mp_at, cats, index>::value>;
510   }; 510   };
511   511  
512   template <class T, class Dir> 512   template <class T, class Dir>
513   using can_convert = mp11::mp_not< 513   using can_convert = mp11::mp_not<
514   std::is_same< 514   std::is_same<
515   get_conversion_category< 515   get_conversion_category<
516   T, 516   T,
517   no_context, 517   no_context,
518   all_custom_checks<Dir>::template fn, 518   all_custom_checks<Dir>::template fn,
519   all_fallback_checks<Dir>::template fn>, 519   all_fallback_checks<Dir>::template fn>,
520   unknown_category>>; 520   unknown_category>>;
521   521  
522   template< class T1, class T2 > 522   template< class T1, class T2 >
523   struct copy_cref_helper 523   struct copy_cref_helper
524   { 524   {
525   using type = remove_cvref<T2>; 525   using type = remove_cvref<T2>;
526   }; 526   };
527   template< class T1, class T2 > 527   template< class T1, class T2 >
528   using copy_cref = typename copy_cref_helper< T1, T2 >::type; 528   using copy_cref = typename copy_cref_helper< T1, T2 >::type;
529   529  
530   template< class T1, class T2 > 530   template< class T1, class T2 >
531   struct copy_cref_helper<T1 const, T2> 531   struct copy_cref_helper<T1 const, T2>
532   { 532   {
533   using type = remove_cvref<T2> const; 533   using type = remove_cvref<T2> const;
534   }; 534   };
535   template< class T1, class T2 > 535   template< class T1, class T2 >
536   struct copy_cref_helper<T1&, T2> 536   struct copy_cref_helper<T1&, T2>
537   { 537   {
538   using type = copy_cref<T1, T2>&; 538   using type = copy_cref<T1, T2>&;
539   }; 539   };
540   template< class T1, class T2 > 540   template< class T1, class T2 >
541   struct copy_cref_helper<T1&&, T2> 541   struct copy_cref_helper<T1&&, T2>
542   { 542   {
543   using type = copy_cref<T1, T2>&&; 543   using type = copy_cref<T1, T2>&&;
544   }; 544   };
545   545  
546   template< class Rng, class Traits > 546   template< class Rng, class Traits >
547   using forwarded_value_helper = mp11::mp_if< 547   using forwarded_value_helper = mp11::mp_if<
548   std::is_convertible< 548   std::is_convertible<
549   typename Traits::reference, 549   typename Traits::reference,
550   copy_cref<Rng, typename Traits::value_type> >, 550   copy_cref<Rng, typename Traits::value_type> >,
551   copy_cref<Rng, typename Traits::value_type>, 551   copy_cref<Rng, typename Traits::value_type>,
552   typename Traits::value_type >; 552   typename Traits::value_type >;
553   553  
554   template< class Rng > 554   template< class Rng >
555   using forwarded_value = forwarded_value_helper< 555   using forwarded_value = forwarded_value_helper<
556   Rng, iterator_traits< Rng > >; 556   Rng, iterator_traits< Rng > >;
557   557  
558   template< class Ctx, class T, class Dir > 558   template< class Ctx, class T, class Dir >
559   struct supported_context 559   struct supported_context
560   { 560   {
561   using type = Ctx; 561   using type = Ctx;
562   562  
563   static 563   static
564   type const& 564   type const&
HITCBC 565   32 get( Ctx const& ctx ) noexcept 565   32 get( Ctx const& ctx ) noexcept
566   { 566   {
HITCBC 567   32 return ctx; 567   32 return ctx;
568   } 568   }
569   }; 569   };
570   570  
571   template< class T, class Dir, class... Ctxs > 571   template< class T, class Dir, class... Ctxs >
572   struct supported_context< std::tuple<Ctxs...>, T, Dir > 572   struct supported_context< std::tuple<Ctxs...>, T, Dir >
573   { 573   {
574   using Ctx = std::tuple<Ctxs...>; 574   using Ctx = std::tuple<Ctxs...>;
575   using impl = get_conversion_category_impl< 575   using impl = get_conversion_category_impl<
576   T, 576   T,
577   Ctx, 577   Ctx,
578   all_custom_checks<Dir>::template fn, 578   all_custom_checks<Dir>::template fn,
579   all_fallback_checks<Dir>::template fn>; 579   all_fallback_checks<Dir>::template fn>;
580   using index = typename impl::index; 580   using index = typename impl::index;
581   using next_supported = supported_context< 581   using next_supported = supported_context<
582   mp11::mp_at< typename impl::ctxs, index >, T, Dir >; 582   mp11::mp_at< typename impl::ctxs, index >, T, Dir >;
583   using type = typename next_supported::type; 583   using type = typename next_supported::type;
584   584  
585   static 585   static
586   type const& 586   type const&
HITCBC 587   19 get( Ctx const& ctx ) noexcept 587   19 get( Ctx const& ctx ) noexcept
588   { 588   {
HITCBC 589   19 return next_supported::get( std::get<index::value>( ctx ) ); 589   19 return next_supported::get( std::get<index::value>( ctx ) );
590   } 590   }
591   }; 591   };
592   592  
593   template< class T > 593   template< class T >
594   using value_result_type = typename std::decay< 594   using value_result_type = typename std::decay<
595   decltype( std::declval<T&>().value() )>::type; 595   decltype( std::declval<T&>().value() )>::type;
596   596  
597   template< class T > 597   template< class T >
598   using can_reset = decltype( std::declval<T&>().reset() ); 598   using can_reset = decltype( std::declval<T&>().reset() );
599   599  
600   template< class T > 600   template< class T >
601   using has_valueless_by_exception = 601   using has_valueless_by_exception =
602   decltype( std::declval<T const&>().valueless_by_exception() ); 602   decltype( std::declval<T const&>().valueless_by_exception() );
603   603  
604   } // namespace detail 604   } // namespace detail
605   605  
606   template <class T> 606   template <class T>
607   struct result_for<T, value> 607   struct result_for<T, value>
608   { 608   {
609   using type = system::result< detail::remove_cvref<T> >; 609   using type = system::result< detail::remove_cvref<T> >;
610   }; 610   };
611   611  
612   template<class T> 612   template<class T>
613   struct is_string_like 613   struct is_string_like
614   : std::is_convertible<T, string_view> 614   : std::is_convertible<T, string_view>
615   { }; 615   { };
616   616  
617   template<class T> 617   template<class T>
618   struct is_path_like 618   struct is_path_like
619   : mp11::mp_all< 619   : mp11::mp_all<
620   mp11::mp_valid_and_true<detail::is_its_own_value, T>, 620   mp11::mp_valid_and_true<detail::is_its_own_value, T>,
621   mp11::mp_valid_and_true<detail::has_string_type, T>> 621   mp11::mp_valid_and_true<detail::has_string_type, T>>
622   { }; 622   { };
623   template<class T> 623   template<class T>
624   struct is_sequence_like 624   struct is_sequence_like
625   : mp11::mp_all< 625   : mp11::mp_all<
626   mp11::mp_valid_and_true<detail::are_begin_and_end_same, T>, 626   mp11::mp_valid_and_true<detail::are_begin_and_end_same, T>,
627   mp11::mp_valid_and_true<detail::not_its_own_value, T>, 627   mp11::mp_valid_and_true<detail::not_its_own_value, T>,
628   mp11::mp_valid<detail::begin_iterator_category, T>> 628   mp11::mp_valid<detail::begin_iterator_category, T>>
629   { }; 629   { };
630   630  
631   template<class T> 631   template<class T>
632   struct is_map_like 632   struct is_map_like
633   : mp11::mp_all< 633   : mp11::mp_all<
634   is_sequence_like<T>, 634   is_sequence_like<T>,
635   mp11::mp_valid_and_true<detail::is_value_type_pair, T>, 635   mp11::mp_valid_and_true<detail::is_value_type_pair, T>,
636   is_string_like<detail::key_type<T>>, 636   is_string_like<detail::key_type<T>>,
637   mp11::mp_valid_and_true<detail::has_unique_keys, T>> 637   mp11::mp_valid_and_true<detail::has_unique_keys, T>>
638   { }; 638   { };
639   639  
640   template<class T> 640   template<class T>
641   struct is_tuple_like 641   struct is_tuple_like
642   : mp11::mp_valid_and_true<detail::has_positive_tuple_size, T> 642   : mp11::mp_valid_and_true<detail::has_positive_tuple_size, T>
643   { }; 643   { };
644   644  
645   template<> 645   template<>
646   struct is_null_like<std::nullptr_t> 646   struct is_null_like<std::nullptr_t>
647   : std::true_type 647   : std::true_type
648   { }; 648   { };
649   649  
650   #ifndef BOOST_NO_CXX17_HDR_VARIANT 650   #ifndef BOOST_NO_CXX17_HDR_VARIANT
651   template<> 651   template<>
652   struct is_null_like<std::monostate> 652   struct is_null_like<std::monostate>
653   : std::true_type 653   : std::true_type
654   { }; 654   { };
655   #endif // BOOST_NO_CXX17_HDR_VARIANT 655   #endif // BOOST_NO_CXX17_HDR_VARIANT
656   656  
657   template<class T> 657   template<class T>
658   struct is_described_class 658   struct is_described_class
659   : mp11::mp_and< 659   : mp11::mp_and<
660   describe::has_describe_members<T>, 660   describe::has_describe_members<T>,
661   mp11::mp_not< std::is_union<T> >, 661   mp11::mp_not< std::is_union<T> >,
662   mp11::mp_empty< 662   mp11::mp_empty<
663   mp11::mp_eval_or< 663   mp11::mp_eval_or<
664   mp11::mp_list<>, detail::described_non_public_members, T>>> 664   mp11::mp_list<>, detail::described_non_public_members, T>>>
665   { }; 665   { };
666   666  
667   template<class T> 667   template<class T>
668   struct is_described_enum 668   struct is_described_enum
669   : describe::has_describe_enumerators<T> 669   : describe::has_describe_enumerators<T>
670   { }; 670   { };
671   671  
672   template<class T> 672   template<class T>
673   struct is_variant_like : mp11::mp_valid<detail::has_valueless_by_exception, T> 673   struct is_variant_like : mp11::mp_valid<detail::has_valueless_by_exception, T>
674   { }; 674   { };
675   675  
676   template<class T> 676   template<class T>
677   struct is_optional_like 677   struct is_optional_like
678   : mp11::mp_and< 678   : mp11::mp_and<
679   mp11::mp_not<std::is_void< 679   mp11::mp_not<std::is_void<
680   mp11::mp_eval_or<void, detail::value_result_type, T>>>, 680   mp11::mp_eval_or<void, detail::value_result_type, T>>>,
681   mp11::mp_valid<detail::can_reset, T>> 681   mp11::mp_valid<detail::can_reset, T>>
682   { }; 682   { };
683   683  
684   } // namespace json 684   } // namespace json
685   } // namespace boost 685   } // namespace boost
686   686  
687   #endif // BOOST_JSON_IMPL_CONVERSION_HPP 687   #endif // BOOST_JSON_IMPL_CONVERSION_HPP