1// __ _____ _____ _____
2// __| | __| | | | JSON for Modern C++
3// | | |__ | | | | | | version 3.11.3
4// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#pragma once
10
11#include <limits> // numeric_limits
12#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
13#include <utility> // declval
14#include <tuple> // tuple
15#include <string> // char_traits
16
17#include <nlohmann/detail/iterators/iterator_traits.hpp>
18#include <nlohmann/detail/macro_scope.hpp>
19#include <nlohmann/detail/meta/call_std/begin.hpp>
20#include <nlohmann/detail/meta/call_std/end.hpp>
21#include <nlohmann/detail/meta/cpp_future.hpp>
22#include <nlohmann/detail/meta/detected.hpp>
23#include <nlohmann/json_fwd.hpp>
24
25NLOHMANN_JSON_NAMESPACE_BEGIN
26/*!
27@brief detail namespace with internal helper functions
28
29This namespace collects functions that should not be exposed,
30implementations of some @ref basic_json methods, and meta-programming helpers.
31
32@since version 2.1.0
33*/
34namespace detail
35{
36
37/////////////
38// helpers //
39/////////////
40
41// Note to maintainers:
42//
43// Every trait in this file expects a non CV-qualified type.
44// The only exceptions are in the 'aliases for detected' section
45// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
46//
47// In this case, T has to be properly CV-qualified to constraint the function arguments
48// (e.g. to_json(BasicJsonType&, const T&))
49
50template<typename> struct is_basic_json : std::false_type {};
51
52NLOHMANN_BASIC_JSON_TPL_DECLARATION
53struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
54
55// used by exceptions create() member functions
56// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
57// false_type otherwise
58template<typename BasicJsonContext>
59struct is_basic_json_context :
60 std::integral_constant < bool,
61 is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value
62 || std::is_same<BasicJsonContext, std::nullptr_t>::value >
63{};
64
65//////////////////////
66// json_ref helpers //
67//////////////////////
68
69template<typename>
70class json_ref;
71
72template<typename>
73struct is_json_ref : std::false_type {};
74
75template<typename T>
76struct is_json_ref<json_ref<T>> : std::true_type {};
77
78//////////////////////////
79// aliases for detected //
80//////////////////////////
81
82template<typename T>
83using mapped_type_t = typename T::mapped_type;
84
85template<typename T>
86using key_type_t = typename T::key_type;
87
88template<typename T>
89using value_type_t = typename T::value_type;
90
91template<typename T>
92using difference_type_t = typename T::difference_type;
93
94template<typename T>
95using pointer_t = typename T::pointer;
96
97template<typename T>
98using reference_t = typename T::reference;
99
100template<typename T>
101using iterator_category_t = typename T::iterator_category;
102
103template<typename T, typename... Args>
104using to_json_function = decltype(T::to_json(std::declval<Args>()...));
105
106template<typename T, typename... Args>
107using from_json_function = decltype(T::from_json(std::declval<Args>()...));
108
109template<typename T, typename U>
110using get_template_function = decltype(std::declval<T>().template get<U>());
111
112// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
113template<typename BasicJsonType, typename T, typename = void>
114struct has_from_json : std::false_type {};
115
116// trait checking if j.get<T> is valid
117// use this trait instead of std::is_constructible or std::is_convertible,
118// both rely on, or make use of implicit conversions, and thus fail when T
119// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
120template <typename BasicJsonType, typename T>
121struct is_getable
122{
123 static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
124};
125
126template<typename BasicJsonType, typename T>
127struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
128{
129 using serializer = typename BasicJsonType::template json_serializer<T, void>;
130
131 static constexpr bool value =
132 is_detected_exact<void, from_json_function, serializer,
133 const BasicJsonType&, T&>::value;
134};
135
136// This trait checks if JSONSerializer<T>::from_json(json const&) exists
137// this overload is used for non-default-constructible user-defined-types
138template<typename BasicJsonType, typename T, typename = void>
139struct has_non_default_from_json : std::false_type {};
140
141template<typename BasicJsonType, typename T>
142struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
143{
144 using serializer = typename BasicJsonType::template json_serializer<T, void>;
145
146 static constexpr bool value =
147 is_detected_exact<T, from_json_function, serializer,
148 const BasicJsonType&>::value;
149};
150
151// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
152// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
153template<typename BasicJsonType, typename T, typename = void>
154struct has_to_json : std::false_type {};
155
156template<typename BasicJsonType, typename T>
157struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
158{
159 using serializer = typename BasicJsonType::template json_serializer<T, void>;
160
161 static constexpr bool value =
162 is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
163 T>::value;
164};
165
166template<typename T>
167using detect_key_compare = typename T::key_compare;
168
169template<typename T>
170struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
171
172// obtains the actual object key comparator
173template<typename BasicJsonType>
174struct actual_object_comparator
175{
176 using object_t = typename BasicJsonType::object_t;
177 using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
178 using type = typename std::conditional < has_key_compare<object_t>::value,
179 typename object_t::key_compare, object_comparator_t>::type;
180};
181
182template<typename BasicJsonType>
183using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
184
185/////////////////
186// char_traits //
187/////////////////
188
189// Primary template of char_traits calls std char_traits
190template<typename T>
191struct char_traits : std::char_traits<T>
192{};
193
194// Explicitly define char traits for unsigned char since it is not standard
195template<>
196struct char_traits<unsigned char> : std::char_traits<char>
197{
198 using char_type = unsigned char;
199 using int_type = uint64_t;
200
201 // Redefine to_int_type function
202 static int_type to_int_type(char_type c) noexcept
203 {
204 return static_cast<int_type>(c);
205 }
206
207 static char_type to_char_type(int_type i) noexcept
208 {
209 return static_cast<char_type>(i);
210 }
211
212 static constexpr int_type eof() noexcept
213 {
214 return static_cast<int_type>(EOF);
215 }
216};
217
218// Explicitly define char traits for signed char since it is not standard
219template<>
220struct char_traits<signed char> : std::char_traits<char>
221{
222 using char_type = signed char;
223 using int_type = uint64_t;
224
225 // Redefine to_int_type function
226 static int_type to_int_type(char_type c) noexcept
227 {
228 return static_cast<int_type>(c);
229 }
230
231 static char_type to_char_type(int_type i) noexcept
232 {
233 return static_cast<char_type>(i);
234 }
235
236 static constexpr int_type eof() noexcept
237 {
238 return static_cast<int_type>(EOF);
239 }
240};
241
242///////////////////
243// is_ functions //
244///////////////////
245
246// https://en.cppreference.com/w/cpp/types/conjunction
247template<class...> struct conjunction : std::true_type { };
248template<class B> struct conjunction<B> : B { };
249template<class B, class... Bn>
250struct conjunction<B, Bn...>
251: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
252
253// https://en.cppreference.com/w/cpp/types/negation
254template<class B> struct negation : std::integral_constant < bool, !B::value > { };
255
256// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
257// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
258// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
259template <typename T>
260struct is_default_constructible : std::is_default_constructible<T> {};
261
262template <typename T1, typename T2>
263struct is_default_constructible<std::pair<T1, T2>>
264 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
265
266template <typename T1, typename T2>
267struct is_default_constructible<const std::pair<T1, T2>>
268 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
269
270template <typename... Ts>
271struct is_default_constructible<std::tuple<Ts...>>
272 : conjunction<is_default_constructible<Ts>...> {};
273
274template <typename... Ts>
275struct is_default_constructible<const std::tuple<Ts...>>
276 : conjunction<is_default_constructible<Ts>...> {};
277
278template <typename T, typename... Args>
279struct is_constructible : std::is_constructible<T, Args...> {};
280
281template <typename T1, typename T2>
282struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
283
284template <typename T1, typename T2>
285struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
286
287template <typename... Ts>
288struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
289
290template <typename... Ts>
291struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
292
293template<typename T, typename = void>
294struct is_iterator_traits : std::false_type {};
295
296template<typename T>
297struct is_iterator_traits<iterator_traits<T>>
298{
299 private:
300 using traits = iterator_traits<T>;
301
302 public:
303 static constexpr auto value =
304 is_detected<value_type_t, traits>::value &&
305 is_detected<difference_type_t, traits>::value &&
306 is_detected<pointer_t, traits>::value &&
307 is_detected<iterator_category_t, traits>::value &&
308 is_detected<reference_t, traits>::value;
309};
310
311template<typename T>
312struct is_range
313{
314 private:
315 using t_ref = typename std::add_lvalue_reference<T>::type;
316
317 using iterator = detected_t<result_of_begin, t_ref>;
318 using sentinel = detected_t<result_of_end, t_ref>;
319
320 // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
321 // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
322 // but reimplementing these would be too much work, as a lot of other concepts are used underneath
323 static constexpr auto is_iterator_begin =
324 is_iterator_traits<iterator_traits<iterator>>::value;
325
326 public:
327 static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
328};
329
330template<typename R>
331using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
332
333template<typename T>
334using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
335
336// The following implementation of is_complete_type is taken from
337// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
338// and is written by Xiang Fan who agreed to using it in this library.
339
340template<typename T, typename = void>
341struct is_complete_type : std::false_type {};
342
343template<typename T>
344struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
345
346template<typename BasicJsonType, typename CompatibleObjectType,
347 typename = void>
348struct is_compatible_object_type_impl : std::false_type {};
349
350template<typename BasicJsonType, typename CompatibleObjectType>
351struct is_compatible_object_type_impl <
352 BasicJsonType, CompatibleObjectType,
353 enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
354 is_detected<key_type_t, CompatibleObjectType>::value >>
355{
356 using object_t = typename BasicJsonType::object_t;
357
358 // macOS's is_constructible does not play well with nonesuch...
359 static constexpr bool value =
360 is_constructible<typename object_t::key_type,
361 typename CompatibleObjectType::key_type>::value &&
362 is_constructible<typename object_t::mapped_type,
363 typename CompatibleObjectType::mapped_type>::value;
364};
365
366template<typename BasicJsonType, typename CompatibleObjectType>
367struct is_compatible_object_type
368 : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
369
370template<typename BasicJsonType, typename ConstructibleObjectType,
371 typename = void>
372struct is_constructible_object_type_impl : std::false_type {};
373
374template<typename BasicJsonType, typename ConstructibleObjectType>
375struct is_constructible_object_type_impl <
376 BasicJsonType, ConstructibleObjectType,
377 enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
378 is_detected<key_type_t, ConstructibleObjectType>::value >>
379{
380 using object_t = typename BasicJsonType::object_t;
381
382 static constexpr bool value =
383 (is_default_constructible<ConstructibleObjectType>::value &&
384 (std::is_move_assignable<ConstructibleObjectType>::value ||
385 std::is_copy_assignable<ConstructibleObjectType>::value) &&
386 (is_constructible<typename ConstructibleObjectType::key_type,
387 typename object_t::key_type>::value &&
388 std::is_same <
389 typename object_t::mapped_type,
390 typename ConstructibleObjectType::mapped_type >::value)) ||
391 (has_from_json<BasicJsonType,
392 typename ConstructibleObjectType::mapped_type>::value ||
393 has_non_default_from_json <
394 BasicJsonType,
395 typename ConstructibleObjectType::mapped_type >::value);
396};
397
398template<typename BasicJsonType, typename ConstructibleObjectType>
399struct is_constructible_object_type
400 : is_constructible_object_type_impl<BasicJsonType,
401 ConstructibleObjectType> {};
402
403template<typename BasicJsonType, typename CompatibleStringType>
404struct is_compatible_string_type
405{
406 static constexpr auto value =
407 is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
408};
409
410template<typename BasicJsonType, typename ConstructibleStringType>
411struct is_constructible_string_type
412{
413 // launder type through decltype() to fix compilation failure on ICPC
414#ifdef __INTEL_COMPILER
415 using laundered_type = decltype(std::declval<ConstructibleStringType>());
416#else
417 using laundered_type = ConstructibleStringType;
418#endif
419
420 static constexpr auto value =
421 conjunction <
422 is_constructible<laundered_type, typename BasicJsonType::string_t>,
423 is_detected_exact<typename BasicJsonType::string_t::value_type,
424 value_type_t, laundered_type >>::value;
425};
426
427template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
428struct is_compatible_array_type_impl : std::false_type {};
429
430template<typename BasicJsonType, typename CompatibleArrayType>
431struct is_compatible_array_type_impl <
432 BasicJsonType, CompatibleArrayType,
433 enable_if_t <
434 is_detected<iterator_t, CompatibleArrayType>::value&&
435 is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
436// special case for types like std::filesystem::path whose iterator's value_type are themselves
437// c.f. https://github.com/nlohmann/json/pull/3073
438 !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
439{
440 static constexpr bool value =
441 is_constructible<BasicJsonType,
442 range_value_t<CompatibleArrayType>>::value;
443};
444
445template<typename BasicJsonType, typename CompatibleArrayType>
446struct is_compatible_array_type
447 : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
448
449template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
450struct is_constructible_array_type_impl : std::false_type {};
451
452template<typename BasicJsonType, typename ConstructibleArrayType>
453struct is_constructible_array_type_impl <
454 BasicJsonType, ConstructibleArrayType,
455 enable_if_t<std::is_same<ConstructibleArrayType,
456 typename BasicJsonType::value_type>::value >>
457 : std::true_type {};
458
459template<typename BasicJsonType, typename ConstructibleArrayType>
460struct is_constructible_array_type_impl <
461 BasicJsonType, ConstructibleArrayType,
462 enable_if_t < !std::is_same<ConstructibleArrayType,
463 typename BasicJsonType::value_type>::value&&
464 !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
465 is_default_constructible<ConstructibleArrayType>::value&&
466(std::is_move_assignable<ConstructibleArrayType>::value ||
467 std::is_copy_assignable<ConstructibleArrayType>::value)&&
468is_detected<iterator_t, ConstructibleArrayType>::value&&
469is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
470is_detected<range_value_t, ConstructibleArrayType>::value&&
471// special case for types like std::filesystem::path whose iterator's value_type are themselves
472// c.f. https://github.com/nlohmann/json/pull/3073
473!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
474 is_complete_type <
475 detected_t<range_value_t, ConstructibleArrayType >>::value >>
476{
477 using value_type = range_value_t<ConstructibleArrayType>;
478
479 static constexpr bool value =
480 std::is_same<value_type,
481 typename BasicJsonType::array_t::value_type>::value ||
482 has_from_json<BasicJsonType,
483 value_type>::value ||
484 has_non_default_from_json <
485 BasicJsonType,
486 value_type >::value;
487};
488
489template<typename BasicJsonType, typename ConstructibleArrayType>
490struct is_constructible_array_type
491 : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
492
493template<typename RealIntegerType, typename CompatibleNumberIntegerType,
494 typename = void>
495struct is_compatible_integer_type_impl : std::false_type {};
496
497template<typename RealIntegerType, typename CompatibleNumberIntegerType>
498struct is_compatible_integer_type_impl <
499 RealIntegerType, CompatibleNumberIntegerType,
500 enable_if_t < std::is_integral<RealIntegerType>::value&&
501 std::is_integral<CompatibleNumberIntegerType>::value&&
502 !std::is_same<bool, CompatibleNumberIntegerType>::value >>
503{
504 // is there an assert somewhere on overflows?
505 using RealLimits = std::numeric_limits<RealIntegerType>;
506 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
507
508 static constexpr auto value =
509 is_constructible<RealIntegerType,
510 CompatibleNumberIntegerType>::value &&
511 CompatibleLimits::is_integer &&
512 RealLimits::is_signed == CompatibleLimits::is_signed;
513};
514
515template<typename RealIntegerType, typename CompatibleNumberIntegerType>
516struct is_compatible_integer_type
517 : is_compatible_integer_type_impl<RealIntegerType,
518 CompatibleNumberIntegerType> {};
519
520template<typename BasicJsonType, typename CompatibleType, typename = void>
521struct is_compatible_type_impl: std::false_type {};
522
523template<typename BasicJsonType, typename CompatibleType>
524struct is_compatible_type_impl <
525 BasicJsonType, CompatibleType,
526 enable_if_t<is_complete_type<CompatibleType>::value >>
527{
528 static constexpr bool value =
529 has_to_json<BasicJsonType, CompatibleType>::value;
530};
531
532template<typename BasicJsonType, typename CompatibleType>
533struct is_compatible_type
534 : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
535
536template<typename T1, typename T2>
537struct is_constructible_tuple : std::false_type {};
538
539template<typename T1, typename... Args>
540struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
541
542template<typename BasicJsonType, typename T>
543struct is_json_iterator_of : std::false_type {};
544
545template<typename BasicJsonType>
546struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
547
548template<typename BasicJsonType>
549struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
550{};
551
552// checks if a given type T is a template specialization of Primary
553template<template <typename...> class Primary, typename T>
554struct is_specialization_of : std::false_type {};
555
556template<template <typename...> class Primary, typename... Args>
557struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
558
559template<typename T>
560using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
561
562// checks if A and B are comparable using Compare functor
563template<typename Compare, typename A, typename B, typename = void>
564struct is_comparable : std::false_type {};
565
566template<typename Compare, typename A, typename B>
567struct is_comparable<Compare, A, B, void_t<
568decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
569decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
570>> : std::true_type {};
571
572template<typename T>
573using detect_is_transparent = typename T::is_transparent;
574
575// type trait to check if KeyType can be used as object key (without a BasicJsonType)
576// see is_usable_as_basic_json_key_type below
577template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
578 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
579using is_usable_as_key_type = typename std::conditional <
580 is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value
581 && !(ExcludeObjectKeyType && std::is_same<KeyType,
582 ObjectKeyType>::value)
583 && (!RequireTransparentComparator
584 || is_detected <detect_is_transparent, Comparator>::value)
585 && !is_json_pointer<KeyType>::value,
586 std::true_type,
587 std::false_type >::type;
588
589// type trait to check if KeyType can be used as object key
590// true if:
591// - KeyType is comparable with BasicJsonType::object_t::key_type
592// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
593// - the comparator is transparent or RequireTransparentComparator is false
594// - KeyType is not a JSON iterator or json_pointer
595template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
596 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
597using is_usable_as_basic_json_key_type = typename std::conditional <
598 is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
599 typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
600 RequireTransparentComparator, ExcludeObjectKeyType>::value
601 && !is_json_iterator_of<BasicJsonType, KeyType>::value,
602 std::true_type,
603 std::false_type >::type;
604
605template<typename ObjectType, typename KeyType>
606using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
607
608// type trait to check if object_t has an erase() member functions accepting KeyType
609template<typename BasicJsonType, typename KeyType>
610using has_erase_with_key_type = typename std::conditional <
611 is_detected <
612 detect_erase_with_key_type,
613 typename BasicJsonType::object_t, KeyType >::value,
614 std::true_type,
615 std::false_type >::type;
616
617// a naive helper to check if a type is an ordered_map (exploits the fact that
618// ordered_map inherits capacity() from std::vector)
619template <typename T>
620struct is_ordered_map
621{
622 using one = char;
623
624 struct two
625 {
626 char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
627 };
628
629 template <typename C> static one test( decltype(&C::capacity) ) ;
630 template <typename C> static two test(...);
631
632 enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
633};
634
635// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
636template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
637T conditional_static_cast(U value)
638{
639 return static_cast<T>(value);
640}
641
642template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
643T conditional_static_cast(U value)
644{
645 return value;
646}
647
648template<typename... Types>
649using all_integral = conjunction<std::is_integral<Types>...>;
650
651template<typename... Types>
652using all_signed = conjunction<std::is_signed<Types>...>;
653
654template<typename... Types>
655using all_unsigned = conjunction<std::is_unsigned<Types>...>;
656
657// there's a disjunction trait in another PR; replace when merged
658template<typename... Types>
659using same_sign = std::integral_constant < bool,
660 all_signed<Types...>::value || all_unsigned<Types...>::value >;
661
662template<typename OfType, typename T>
663using never_out_of_range = std::integral_constant < bool,
664 (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
665 || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
666
667template<typename OfType, typename T,
668 bool OfTypeSigned = std::is_signed<OfType>::value,
669 bool TSigned = std::is_signed<T>::value>
670struct value_in_range_of_impl2;
671
672template<typename OfType, typename T>
673struct value_in_range_of_impl2<OfType, T, false, false>
674{
675 static constexpr bool test(T val)
676 {
677 using CommonType = typename std::common_type<OfType, T>::type;
678 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
679 }
680};
681
682template<typename OfType, typename T>
683struct value_in_range_of_impl2<OfType, T, true, false>
684{
685 static constexpr bool test(T val)
686 {
687 using CommonType = typename std::common_type<OfType, T>::type;
688 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
689 }
690};
691
692template<typename OfType, typename T>
693struct value_in_range_of_impl2<OfType, T, false, true>
694{
695 static constexpr bool test(T val)
696 {
697 using CommonType = typename std::common_type<OfType, T>::type;
698 return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
699 }
700};
701
702template<typename OfType, typename T>
703struct value_in_range_of_impl2<OfType, T, true, true>
704{
705 static constexpr bool test(T val)
706 {
707 using CommonType = typename std::common_type<OfType, T>::type;
708 return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)())
709 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
710 }
711};
712
713template<typename OfType, typename T,
714 bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
715 typename = detail::enable_if_t<all_integral<OfType, T>::value>>
716struct value_in_range_of_impl1;
717
718template<typename OfType, typename T>
719struct value_in_range_of_impl1<OfType, T, false>
720{
721 static constexpr bool test(T val)
722 {
723 return value_in_range_of_impl2<OfType, T>::test(val);
724 }
725};
726
727template<typename OfType, typename T>
728struct value_in_range_of_impl1<OfType, T, true>
729{
730 static constexpr bool test(T /*val*/)
731 {
732 return true;
733 }
734};
735
736template<typename OfType, typename T>
737inline constexpr bool value_in_range_of(T val)
738{
739 return value_in_range_of_impl1<OfType, T>::test(val);
740}
741
742template<bool Value>
743using bool_constant = std::integral_constant<bool, Value>;
744
745///////////////////////////////////////////////////////////////////////////////
746// is_c_string
747///////////////////////////////////////////////////////////////////////////////
748
749namespace impl
750{
751
752template<typename T>
753inline constexpr bool is_c_string()
754{
755 using TUnExt = typename std::remove_extent<T>::type;
756 using TUnCVExt = typename std::remove_cv<TUnExt>::type;
757 using TUnPtr = typename std::remove_pointer<T>::type;
758 using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
759 return
760 (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
761 || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
762}
763
764} // namespace impl
765
766// checks whether T is a [cv] char */[cv] char[] C string
767template<typename T>
768struct is_c_string : bool_constant<impl::is_c_string<T>()> {};
769
770template<typename T>
771using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
772
773///////////////////////////////////////////////////////////////////////////////
774// is_transparent
775///////////////////////////////////////////////////////////////////////////////
776
777namespace impl
778{
779
780template<typename T>
781inline constexpr bool is_transparent()
782{
783 return is_detected<detect_is_transparent, T>::value;
784}
785
786} // namespace impl
787
788// checks whether T has a member named is_transparent
789template<typename T>
790struct is_transparent : bool_constant<impl::is_transparent<T>()> {};
791
792///////////////////////////////////////////////////////////////////////////////
793
794} // namespace detail
795NLOHMANN_JSON_NAMESPACE_END
796