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 | |
25 | NLOHMANN_JSON_NAMESPACE_BEGIN |
26 | /*! |
27 | @brief detail namespace with internal helper functions |
28 | |
29 | This namespace collects functions that should not be exposed, |
30 | implementations of some @ref basic_json methods, and meta-programming helpers. |
31 | |
32 | @since version 2.1.0 |
33 | */ |
34 | namespace 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 | |
50 | template<typename> struct is_basic_json : std::false_type {}; |
51 | |
52 | NLOHMANN_BASIC_JSON_TPL_DECLARATION |
53 | struct 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 |
58 | template<typename BasicJsonContext> |
59 | struct 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 | |
69 | template<typename> |
70 | class json_ref; |
71 | |
72 | template<typename> |
73 | struct is_json_ref : std::false_type {}; |
74 | |
75 | template<typename T> |
76 | struct is_json_ref<json_ref<T>> : std::true_type {}; |
77 | |
78 | ////////////////////////// |
79 | // aliases for detected // |
80 | ////////////////////////// |
81 | |
82 | template<typename T> |
83 | using mapped_type_t = typename T::mapped_type; |
84 | |
85 | template<typename T> |
86 | using key_type_t = typename T::key_type; |
87 | |
88 | template<typename T> |
89 | using value_type_t = typename T::value_type; |
90 | |
91 | template<typename T> |
92 | using difference_type_t = typename T::difference_type; |
93 | |
94 | template<typename T> |
95 | using pointer_t = typename T::pointer; |
96 | |
97 | template<typename T> |
98 | using reference_t = typename T::reference; |
99 | |
100 | template<typename T> |
101 | using iterator_category_t = typename T::iterator_category; |
102 | |
103 | template<typename T, typename... Args> |
104 | using to_json_function = decltype(T::to_json(std::declval<Args>()...)); |
105 | |
106 | template<typename T, typename... Args> |
107 | using from_json_function = decltype(T::from_json(std::declval<Args>()...)); |
108 | |
109 | template<typename T, typename U> |
110 | using get_template_function = decltype(std::declval<T>().template get<U>()); |
111 | |
112 | // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists |
113 | template<typename BasicJsonType, typename T, typename = void> |
114 | struct 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) |
120 | template <typename BasicJsonType, typename T> |
121 | struct is_getable |
122 | { |
123 | static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value; |
124 | }; |
125 | |
126 | template<typename BasicJsonType, typename T> |
127 | struct 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 |
138 | template<typename BasicJsonType, typename T, typename = void> |
139 | struct has_non_default_from_json : std::false_type {}; |
140 | |
141 | template<typename BasicJsonType, typename T> |
142 | struct 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. |
153 | template<typename BasicJsonType, typename T, typename = void> |
154 | struct has_to_json : std::false_type {}; |
155 | |
156 | template<typename BasicJsonType, typename T> |
157 | struct 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 | |
166 | template<typename T> |
167 | using detect_key_compare = typename T::key_compare; |
168 | |
169 | template<typename T> |
170 | struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {}; |
171 | |
172 | // obtains the actual object key comparator |
173 | template<typename BasicJsonType> |
174 | struct 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 | |
182 | template<typename BasicJsonType> |
183 | using 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 |
190 | template<typename T> |
191 | struct char_traits : std::char_traits<T> |
192 | {}; |
193 | |
194 | // Explicitly define char traits for unsigned char since it is not standard |
195 | template<> |
196 | struct 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 |
219 | template<> |
220 | struct 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 |
247 | template<class...> struct conjunction : std::true_type { }; |
248 | template<class B> struct conjunction<B> : B { }; |
249 | template<class B, class... Bn> |
250 | struct 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 |
254 | template<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. |
259 | template <typename T> |
260 | struct is_default_constructible : std::is_default_constructible<T> {}; |
261 | |
262 | template <typename T1, typename T2> |
263 | struct is_default_constructible<std::pair<T1, T2>> |
264 | : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; |
265 | |
266 | template <typename T1, typename T2> |
267 | struct is_default_constructible<const std::pair<T1, T2>> |
268 | : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; |
269 | |
270 | template <typename... Ts> |
271 | struct is_default_constructible<std::tuple<Ts...>> |
272 | : conjunction<is_default_constructible<Ts>...> {}; |
273 | |
274 | template <typename... Ts> |
275 | struct is_default_constructible<const std::tuple<Ts...>> |
276 | : conjunction<is_default_constructible<Ts>...> {}; |
277 | |
278 | template <typename T, typename... Args> |
279 | struct is_constructible : std::is_constructible<T, Args...> {}; |
280 | |
281 | template <typename T1, typename T2> |
282 | struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {}; |
283 | |
284 | template <typename T1, typename T2> |
285 | struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {}; |
286 | |
287 | template <typename... Ts> |
288 | struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {}; |
289 | |
290 | template <typename... Ts> |
291 | struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {}; |
292 | |
293 | template<typename T, typename = void> |
294 | struct is_iterator_traits : std::false_type {}; |
295 | |
296 | template<typename T> |
297 | struct 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 | |
311 | template<typename T> |
312 | struct 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 | |
330 | template<typename R> |
331 | using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>; |
332 | |
333 | template<typename T> |
334 | using 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 | |
340 | template<typename T, typename = void> |
341 | struct is_complete_type : std::false_type {}; |
342 | |
343 | template<typename T> |
344 | struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; |
345 | |
346 | template<typename BasicJsonType, typename CompatibleObjectType, |
347 | typename = void> |
348 | struct is_compatible_object_type_impl : std::false_type {}; |
349 | |
350 | template<typename BasicJsonType, typename CompatibleObjectType> |
351 | struct 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 | |
366 | template<typename BasicJsonType, typename CompatibleObjectType> |
367 | struct is_compatible_object_type |
368 | : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; |
369 | |
370 | template<typename BasicJsonType, typename ConstructibleObjectType, |
371 | typename = void> |
372 | struct is_constructible_object_type_impl : std::false_type {}; |
373 | |
374 | template<typename BasicJsonType, typename ConstructibleObjectType> |
375 | struct 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 | |
398 | template<typename BasicJsonType, typename ConstructibleObjectType> |
399 | struct is_constructible_object_type |
400 | : is_constructible_object_type_impl<BasicJsonType, |
401 | ConstructibleObjectType> {}; |
402 | |
403 | template<typename BasicJsonType, typename CompatibleStringType> |
404 | struct is_compatible_string_type |
405 | { |
406 | static constexpr auto value = |
407 | is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; |
408 | }; |
409 | |
410 | template<typename BasicJsonType, typename ConstructibleStringType> |
411 | struct 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 | |
427 | template<typename BasicJsonType, typename CompatibleArrayType, typename = void> |
428 | struct is_compatible_array_type_impl : std::false_type {}; |
429 | |
430 | template<typename BasicJsonType, typename CompatibleArrayType> |
431 | struct 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 | |
445 | template<typename BasicJsonType, typename CompatibleArrayType> |
446 | struct is_compatible_array_type |
447 | : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; |
448 | |
449 | template<typename BasicJsonType, typename ConstructibleArrayType, typename = void> |
450 | struct is_constructible_array_type_impl : std::false_type {}; |
451 | |
452 | template<typename BasicJsonType, typename ConstructibleArrayType> |
453 | struct 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 | |
459 | template<typename BasicJsonType, typename ConstructibleArrayType> |
460 | struct 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)&& |
468 | is_detected<iterator_t, ConstructibleArrayType>::value&& |
469 | is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& |
470 | is_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 | |
489 | template<typename BasicJsonType, typename ConstructibleArrayType> |
490 | struct is_constructible_array_type |
491 | : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {}; |
492 | |
493 | template<typename RealIntegerType, typename CompatibleNumberIntegerType, |
494 | typename = void> |
495 | struct is_compatible_integer_type_impl : std::false_type {}; |
496 | |
497 | template<typename RealIntegerType, typename CompatibleNumberIntegerType> |
498 | struct 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 | |
515 | template<typename RealIntegerType, typename CompatibleNumberIntegerType> |
516 | struct is_compatible_integer_type |
517 | : is_compatible_integer_type_impl<RealIntegerType, |
518 | CompatibleNumberIntegerType> {}; |
519 | |
520 | template<typename BasicJsonType, typename CompatibleType, typename = void> |
521 | struct is_compatible_type_impl: std::false_type {}; |
522 | |
523 | template<typename BasicJsonType, typename CompatibleType> |
524 | struct 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 | |
532 | template<typename BasicJsonType, typename CompatibleType> |
533 | struct is_compatible_type |
534 | : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; |
535 | |
536 | template<typename T1, typename T2> |
537 | struct is_constructible_tuple : std::false_type {}; |
538 | |
539 | template<typename T1, typename... Args> |
540 | struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {}; |
541 | |
542 | template<typename BasicJsonType, typename T> |
543 | struct is_json_iterator_of : std::false_type {}; |
544 | |
545 | template<typename BasicJsonType> |
546 | struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {}; |
547 | |
548 | template<typename BasicJsonType> |
549 | struct 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 |
553 | template<template <typename...> class Primary, typename T> |
554 | struct is_specialization_of : std::false_type {}; |
555 | |
556 | template<template <typename...> class Primary, typename... Args> |
557 | struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {}; |
558 | |
559 | template<typename T> |
560 | using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>; |
561 | |
562 | // checks if A and B are comparable using Compare functor |
563 | template<typename Compare, typename A, typename B, typename = void> |
564 | struct is_comparable : std::false_type {}; |
565 | |
566 | template<typename Compare, typename A, typename B> |
567 | struct is_comparable<Compare, A, B, void_t< |
568 | decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())), |
569 | decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>())) |
570 | >> : std::true_type {}; |
571 | |
572 | template<typename T> |
573 | using 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 |
577 | template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, |
578 | bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> |
579 | using 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 |
595 | template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, |
596 | bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> |
597 | using 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 | |
605 | template<typename ObjectType, typename KeyType> |
606 | using 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 |
609 | template<typename BasicJsonType, typename KeyType> |
610 | using 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) |
619 | template <typename T> |
620 | struct 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) |
636 | template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 > |
637 | T conditional_static_cast(U value) |
638 | { |
639 | return static_cast<T>(value); |
640 | } |
641 | |
642 | template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0> |
643 | T conditional_static_cast(U value) |
644 | { |
645 | return value; |
646 | } |
647 | |
648 | template<typename... Types> |
649 | using all_integral = conjunction<std::is_integral<Types>...>; |
650 | |
651 | template<typename... Types> |
652 | using all_signed = conjunction<std::is_signed<Types>...>; |
653 | |
654 | template<typename... Types> |
655 | using all_unsigned = conjunction<std::is_unsigned<Types>...>; |
656 | |
657 | // there's a disjunction trait in another PR; replace when merged |
658 | template<typename... Types> |
659 | using same_sign = std::integral_constant < bool, |
660 | all_signed<Types...>::value || all_unsigned<Types...>::value >; |
661 | |
662 | template<typename OfType, typename T> |
663 | using 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 | |
667 | template<typename OfType, typename T, |
668 | bool OfTypeSigned = std::is_signed<OfType>::value, |
669 | bool TSigned = std::is_signed<T>::value> |
670 | struct value_in_range_of_impl2; |
671 | |
672 | template<typename OfType, typename T> |
673 | struct 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 | |
682 | template<typename OfType, typename T> |
683 | struct 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 | |
692 | template<typename OfType, typename T> |
693 | struct 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 | |
702 | template<typename OfType, typename T> |
703 | struct 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 | |
713 | template<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>> |
716 | struct value_in_range_of_impl1; |
717 | |
718 | template<typename OfType, typename T> |
719 | struct 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 | |
727 | template<typename OfType, typename T> |
728 | struct value_in_range_of_impl1<OfType, T, true> |
729 | { |
730 | static constexpr bool test(T /*val*/) |
731 | { |
732 | return true; |
733 | } |
734 | }; |
735 | |
736 | template<typename OfType, typename T> |
737 | inline constexpr bool value_in_range_of(T val) |
738 | { |
739 | return value_in_range_of_impl1<OfType, T>::test(val); |
740 | } |
741 | |
742 | template<bool Value> |
743 | using bool_constant = std::integral_constant<bool, Value>; |
744 | |
745 | /////////////////////////////////////////////////////////////////////////////// |
746 | // is_c_string |
747 | /////////////////////////////////////////////////////////////////////////////// |
748 | |
749 | namespace impl |
750 | { |
751 | |
752 | template<typename T> |
753 | inline 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 |
767 | template<typename T> |
768 | struct is_c_string : bool_constant<impl::is_c_string<T>()> {}; |
769 | |
770 | template<typename T> |
771 | using is_c_string_uncvref = is_c_string<uncvref_t<T>>; |
772 | |
773 | /////////////////////////////////////////////////////////////////////////////// |
774 | // is_transparent |
775 | /////////////////////////////////////////////////////////////////////////////// |
776 | |
777 | namespace impl |
778 | { |
779 | |
780 | template<typename T> |
781 | inline 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 |
789 | template<typename T> |
790 | struct is_transparent : bool_constant<impl::is_transparent<T>()> {}; |
791 | |
792 | /////////////////////////////////////////////////////////////////////////////// |
793 | |
794 | } // namespace detail |
795 | NLOHMANN_JSON_NAMESPACE_END |
796 | |