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