| 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 | |