1 #pragma once 2 3 #include <limits> // numeric_limits 4 #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type 5 #include <utility> // declval 6 7 #include <nlohmann/detail/iterators/iterator_traits.hpp> 8 #include <nlohmann/detail/macro_scope.hpp> 9 #include <nlohmann/detail/meta/cpp_future.hpp> 10 #include <nlohmann/detail/meta/detected.hpp> 11 #include <nlohmann/json_fwd.hpp> 12 13 namespace nlohmann 14 { 15 /*! 16 @brief detail namespace with internal helper functions 17 18 This namespace collects functions that should not be exposed, 19 implementations of some @ref basic_json methods, and meta-programming helpers. 20 21 @since version 2.1.0 22 */ 23 namespace detail 24 { 25 ///////////// 26 // helpers // 27 ///////////// 28 29 // Note to maintainers: 30 // 31 // Every trait in this file expects a non CV-qualified type. 32 // The only exceptions are in the 'aliases for detected' section 33 // (i.e. those of the form: decltype(T::member_function(std::declval<T>()))) 34 // 35 // In this case, T has to be properly CV-qualified to constraint the function arguments 36 // (e.g. to_json(BasicJsonType&, const T&)) 37 38 template<typename> struct is_basic_json : std::false_type {}; 39 40 NLOHMANN_BASIC_JSON_TPL_DECLARATION 41 struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; 42 43 ////////////////////// 44 // json_ref helpers // 45 ////////////////////// 46 47 template<typename> 48 class json_ref; 49 50 template<typename> 51 struct is_json_ref : std::false_type {}; 52 53 template<typename T> 54 struct is_json_ref<json_ref<T>> : std::true_type {}; 55 56 ////////////////////////// 57 // aliases for detected // 58 ////////////////////////// 59 60 template<typename T> 61 using mapped_type_t = typename T::mapped_type; 62 63 template<typename T> 64 using key_type_t = typename T::key_type; 65 66 template<typename T> 67 using value_type_t = typename T::value_type; 68 69 template<typename T> 70 using difference_type_t = typename T::difference_type; 71 72 template<typename T> 73 using pointer_t = typename T::pointer; 74 75 template<typename T> 76 using reference_t = typename T::reference; 77 78 template<typename T> 79 using iterator_category_t = typename T::iterator_category; 80 81 template<typename T> 82 using iterator_t = typename T::iterator; 83 84 template<typename T, typename... Args> 85 using to_json_function = decltype(T::to_json(std::declval<Args>()...)); 86 87 template<typename T, typename... Args> 88 using from_json_function = decltype(T::from_json(std::declval<Args>()...)); 89 90 template<typename T, typename U> 91 using get_template_function = decltype(std::declval<T>().template get<U>()); 92 93 // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists 94 template<typename BasicJsonType, typename T, typename = void> 95 struct has_from_json : std::false_type {}; 96 97 // trait checking if j.get<T> is valid 98 // use this trait instead of std::is_constructible or std::is_convertible, 99 // both rely on, or make use of implicit conversions, and thus fail when T 100 // has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) 101 template <typename BasicJsonType, typename T> 102 struct is_getable 103 { 104 static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value; 105 }; 106 107 template<typename BasicJsonType, typename T> 108 struct has_from_json < BasicJsonType, T, 109 enable_if_t < !is_basic_json<T>::value >> 110 { 111 using serializer = typename BasicJsonType::template json_serializer<T, void>; 112 113 static constexpr bool value = 114 is_detected_exact<void, from_json_function, serializer, 115 const BasicJsonType&, T&>::value; 116 }; 117 118 // This trait checks if JSONSerializer<T>::from_json(json const&) exists 119 // this overload is used for non-default-constructible user-defined-types 120 template<typename BasicJsonType, typename T, typename = void> 121 struct has_non_default_from_json : std::false_type {}; 122 123 template<typename BasicJsonType, typename T> 124 struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> 125 { 126 using serializer = typename BasicJsonType::template json_serializer<T, void>; 127 128 static constexpr bool value = 129 is_detected_exact<T, from_json_function, serializer, 130 const BasicJsonType&>::value; 131 }; 132 133 // This trait checks if BasicJsonType::json_serializer<T>::to_json exists 134 // Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. 135 template<typename BasicJsonType, typename T, typename = void> 136 struct has_to_json : std::false_type {}; 137 138 template<typename BasicJsonType, typename T> 139 struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> 140 { 141 using serializer = typename BasicJsonType::template json_serializer<T, void>; 142 143 static constexpr bool value = 144 is_detected_exact<void, to_json_function, serializer, BasicJsonType&, 145 T>::value; 146 }; 147 148 149 /////////////////// 150 // is_ functions // 151 /////////////////// 152 153 template<typename T, typename = void> 154 struct is_iterator_traits : std::false_type {}; 155 156 template<typename T> 157 struct is_iterator_traits<iterator_traits<T>> 158 { 159 private: 160 using traits = iterator_traits<T>; 161 162 public: 163 static constexpr auto value = 164 is_detected<value_type_t, traits>::value && 165 is_detected<difference_type_t, traits>::value && 166 is_detected<pointer_t, traits>::value && 167 is_detected<iterator_category_t, traits>::value && 168 is_detected<reference_t, traits>::value; 169 }; 170 171 // source: https://stackoverflow.com/a/37193089/4116453 172 173 template<typename T, typename = void> 174 struct is_complete_type : std::false_type {}; 175 176 template<typename T> 177 struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; 178 179 template<typename BasicJsonType, typename CompatibleObjectType, 180 typename = void> 181 struct is_compatible_object_type_impl : std::false_type {}; 182 183 template<typename BasicJsonType, typename CompatibleObjectType> 184 struct is_compatible_object_type_impl < 185 BasicJsonType, CompatibleObjectType, 186 enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&& 187 is_detected<key_type_t, CompatibleObjectType>::value >> 188 { 189 190 using object_t = typename BasicJsonType::object_t; 191 192 // macOS's is_constructible does not play well with nonesuch... 193 static constexpr bool value = 194 std::is_constructible<typename object_t::key_type, 195 typename CompatibleObjectType::key_type>::value && 196 std::is_constructible<typename object_t::mapped_type, 197 typename CompatibleObjectType::mapped_type>::value; 198 }; 199 200 template<typename BasicJsonType, typename CompatibleObjectType> 201 struct is_compatible_object_type 202 : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; 203 204 template<typename BasicJsonType, typename ConstructibleObjectType, 205 typename = void> 206 struct is_constructible_object_type_impl : std::false_type {}; 207 208 template<typename BasicJsonType, typename ConstructibleObjectType> 209 struct is_constructible_object_type_impl < 210 BasicJsonType, ConstructibleObjectType, 211 enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&& 212 is_detected<key_type_t, ConstructibleObjectType>::value >> 213 { 214 using object_t = typename BasicJsonType::object_t; 215 216 static constexpr bool value = 217 (std::is_default_constructible<ConstructibleObjectType>::value && 218 (std::is_move_assignable<ConstructibleObjectType>::value || 219 std::is_copy_assignable<ConstructibleObjectType>::value) && 220 (std::is_constructible<typename ConstructibleObjectType::key_type, 221 typename object_t::key_type>::value && 222 std::is_same < 223 typename object_t::mapped_type, 224 typename ConstructibleObjectType::mapped_type >::value)) || 225 (has_from_json<BasicJsonType, 226 typename ConstructibleObjectType::mapped_type>::value || 227 has_non_default_from_json < 228 BasicJsonType, 229 typename ConstructibleObjectType::mapped_type >::value); 230 }; 231 232 template<typename BasicJsonType, typename ConstructibleObjectType> 233 struct is_constructible_object_type 234 : is_constructible_object_type_impl<BasicJsonType, 235 ConstructibleObjectType> {}; 236 237 template<typename BasicJsonType, typename CompatibleStringType, 238 typename = void> 239 struct is_compatible_string_type_impl : std::false_type {}; 240 241 template<typename BasicJsonType, typename CompatibleStringType> 242 struct is_compatible_string_type_impl < 243 BasicJsonType, CompatibleStringType, 244 enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type, 245 value_type_t, CompatibleStringType>::value >> 246 { 247 static constexpr auto value = 248 std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; 249 }; 250 251 template<typename BasicJsonType, typename ConstructibleStringType> 252 struct is_compatible_string_type 253 : is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {}; 254 255 template<typename BasicJsonType, typename ConstructibleStringType, 256 typename = void> 257 struct is_constructible_string_type_impl : std::false_type {}; 258 259 template<typename BasicJsonType, typename ConstructibleStringType> 260 struct is_constructible_string_type_impl < 261 BasicJsonType, ConstructibleStringType, 262 enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type, 263 value_type_t, ConstructibleStringType>::value >> 264 { 265 static constexpr auto value = 266 std::is_constructible<ConstructibleStringType, 267 typename BasicJsonType::string_t>::value; 268 }; 269 270 template<typename BasicJsonType, typename ConstructibleStringType> 271 struct is_constructible_string_type 272 : is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {}; 273 274 template<typename BasicJsonType, typename CompatibleArrayType, typename = void> 275 struct is_compatible_array_type_impl : std::false_type {}; 276 277 template<typename BasicJsonType, typename CompatibleArrayType> 278 struct is_compatible_array_type_impl < 279 BasicJsonType, CompatibleArrayType, 280 enable_if_t < is_detected<value_type_t, CompatibleArrayType>::value&& 281 is_detected<iterator_t, CompatibleArrayType>::value&& 282 // This is needed because json_reverse_iterator has a ::iterator type... 283 // Therefore it is detected as a CompatibleArrayType. 284 // The real fix would be to have an Iterable concept. 285 !is_iterator_traits < 286 iterator_traits<CompatibleArrayType >>::value >> 287 { 288 static constexpr bool value = 289 std::is_constructible<BasicJsonType, 290 typename CompatibleArrayType::value_type>::value; 291 }; 292 293 template<typename BasicJsonType, typename CompatibleArrayType> 294 struct is_compatible_array_type 295 : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; 296 297 template<typename BasicJsonType, typename ConstructibleArrayType, typename = void> 298 struct is_constructible_array_type_impl : std::false_type {}; 299 300 template<typename BasicJsonType, typename ConstructibleArrayType> 301 struct is_constructible_array_type_impl < 302 BasicJsonType, ConstructibleArrayType, 303 enable_if_t<std::is_same<ConstructibleArrayType, 304 typename BasicJsonType::value_type>::value >> 305 : std::true_type {}; 306 307 template<typename BasicJsonType, typename ConstructibleArrayType> 308 struct is_constructible_array_type_impl < 309 BasicJsonType, ConstructibleArrayType, 310 enable_if_t < !std::is_same<ConstructibleArrayType, 311 typename BasicJsonType::value_type>::value&& 312 std::is_default_constructible<ConstructibleArrayType>::value&& 313 (std::is_move_assignable<ConstructibleArrayType>::value || 314 std::is_copy_assignable<ConstructibleArrayType>::value)&& 315 is_detected<value_type_t, ConstructibleArrayType>::value&& 316 is_detected<iterator_t, ConstructibleArrayType>::value&& 317 is_complete_type < 318 detected_t<value_type_t, ConstructibleArrayType >>::value >> 319 { 320 static constexpr bool value = 321 // This is needed because json_reverse_iterator has a ::iterator type, 322 // furthermore, std::back_insert_iterator (and other iterators) have a 323 // base class `iterator`... Therefore it is detected as a 324 // ConstructibleArrayType. The real fix would be to have an Iterable 325 // concept. 326 !is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value && 327 328 (std::is_same<typename ConstructibleArrayType::value_type, 329 typename BasicJsonType::array_t::value_type>::value || 330 has_from_json<BasicJsonType, 331 typename ConstructibleArrayType::value_type>::value || 332 has_non_default_from_json < 333 BasicJsonType, typename ConstructibleArrayType::value_type >::value); 334 }; 335 336 template<typename BasicJsonType, typename ConstructibleArrayType> 337 struct is_constructible_array_type 338 : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {}; 339 340 template<typename RealIntegerType, typename CompatibleNumberIntegerType, 341 typename = void> 342 struct is_compatible_integer_type_impl : std::false_type {}; 343 344 template<typename RealIntegerType, typename CompatibleNumberIntegerType> 345 struct is_compatible_integer_type_impl < 346 RealIntegerType, CompatibleNumberIntegerType, 347 enable_if_t < std::is_integral<RealIntegerType>::value&& 348 std::is_integral<CompatibleNumberIntegerType>::value&& 349 !std::is_same<bool, CompatibleNumberIntegerType>::value >> 350 { 351 // is there an assert somewhere on overflows? 352 using RealLimits = std::numeric_limits<RealIntegerType>; 353 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; 354 355 static constexpr auto value = 356 std::is_constructible<RealIntegerType, 357 CompatibleNumberIntegerType>::value && 358 CompatibleLimits::is_integer && 359 RealLimits::is_signed == CompatibleLimits::is_signed; 360 }; 361 362 template<typename RealIntegerType, typename CompatibleNumberIntegerType> 363 struct is_compatible_integer_type 364 : is_compatible_integer_type_impl<RealIntegerType, 365 CompatibleNumberIntegerType> {}; 366 367 template<typename BasicJsonType, typename CompatibleType, typename = void> 368 struct is_compatible_type_impl: std::false_type {}; 369 370 template<typename BasicJsonType, typename CompatibleType> 371 struct is_compatible_type_impl < 372 BasicJsonType, CompatibleType, 373 enable_if_t<is_complete_type<CompatibleType>::value >> 374 { 375 static constexpr bool value = 376 has_to_json<BasicJsonType, CompatibleType>::value; 377 }; 378 379 template<typename BasicJsonType, typename CompatibleType> 380 struct is_compatible_type 381 : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; 382 383 // https://en.cppreference.com/w/cpp/types/conjunction 384 template<class...> struct conjunction : std::true_type { }; 385 template<class B1> struct conjunction<B1> : B1 { }; 386 template<class B1, class... Bn> 387 struct conjunction<B1, Bn...> 388 : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; 389 390 template<typename T1, typename T2> 391 struct is_constructible_tuple : std::false_type {}; 392 393 template<typename T1, typename... Args> 394 struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<std::is_constructible<T1, Args>...> {}; 395 } // namespace detail 396 } // namespace nlohmann 397