Horizon
type_traits.hpp
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 #include <tuple> // tuple
7 
8 #include <nlohmann/detail/macro_scope.hpp>
9 
10 #include <nlohmann/detail/iterators/iterator_traits.hpp>
11 #include <nlohmann/detail/meta/call_std/begin.hpp>
12 #include <nlohmann/detail/meta/call_std/end.hpp>
13 #include <nlohmann/detail/meta/cpp_future.hpp>
14 #include <nlohmann/detail/meta/detected.hpp>
15 #include <nlohmann/json_fwd.hpp>
16 
17 namespace nlohmann
18 {
27 namespace detail
28 {
30 // helpers //
32 
33 // Note to maintainers:
34 //
35 // Every trait in this file expects a non CV-qualified type.
36 // The only exceptions are in the 'aliases for detected' section
37 // (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
38 //
39 // In this case, T has to be properly CV-qualified to constraint the function arguments
40 // (e.g. to_json(BasicJsonType&, const T&))
41 
42 template<typename> struct is_basic_json : std::false_type {};
43 
44 NLOHMANN_BASIC_JSON_TPL_DECLARATION
45 struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
46 
48 // json_ref helpers //
50 
51 template<typename>
52 class json_ref;
53 
54 template<typename>
55 struct is_json_ref : std::false_type {};
56 
57 template<typename T>
58 struct is_json_ref<json_ref<T>> : std::true_type {};
59 
61 // aliases for detected //
63 
64 template<typename T>
65 using mapped_type_t = typename T::mapped_type;
66 
67 template<typename T>
68 using key_type_t = typename T::key_type;
69 
70 template<typename T>
71 using value_type_t = typename T::value_type;
72 
73 template<typename T>
74 using difference_type_t = typename T::difference_type;
75 
76 template<typename T>
77 using pointer_t = typename T::pointer;
78 
79 template<typename T>
80 using reference_t = typename T::reference;
81 
82 template<typename T>
83 using iterator_category_t = typename T::iterator_category;
84 
85 template<typename T, typename... Args>
86 using to_json_function = decltype(T::to_json(std::declval<Args>()...));
87 
88 template<typename T, typename... Args>
89 using from_json_function = decltype(T::from_json(std::declval<Args>()...));
90 
91 template<typename T, typename U>
92 using get_template_function = decltype(std::declval<T>().template get<U>());
93 
94 // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
95 template<typename BasicJsonType, typename T, typename = void>
96 struct has_from_json : std::false_type {};
97 
98 // trait checking if j.get<T> is valid
99 // use this trait instead of std::is_constructible or std::is_convertible,
100 // both rely on, or make use of implicit conversions, and thus fail when T
101 // has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
102 template <typename BasicJsonType, typename T>
104 {
105  static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
106 };
107 
108 template<typename BasicJsonType, typename T>
109 struct has_from_json < BasicJsonType, T, 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 
150 // is_ functions //
152 
153 // https://en.cppreference.com/w/cpp/types/conjunction
154 template<class...> struct conjunction : std::true_type { };
155 template<class B1> struct conjunction<B1> : B1 { };
156 template<class B1, class... Bn>
157 struct conjunction<B1, Bn...>
158 : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
159 
160 // https://en.cppreference.com/w/cpp/types/negation
161 template<class B> struct negation : std::integral_constant < bool, !B::value > { };
162 
163 // Reimplementation of is_constructible and is_default_constructible, due to them being broken for
164 // std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
165 // This causes compile errors in e.g. clang 3.5 or gcc 4.9.
166 template <typename T>
167 struct is_default_constructible : std::is_default_constructible<T> {};
168 
169 template <typename T1, typename T2>
170 struct is_default_constructible<std::pair<T1, T2>>
171  : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
172 
173 template <typename T1, typename T2>
174 struct is_default_constructible<const std::pair<T1, T2>>
175  : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
176 
177 template <typename... Ts>
178 struct is_default_constructible<std::tuple<Ts...>>
179  : conjunction<is_default_constructible<Ts>...> {};
180 
181 template <typename... Ts>
182 struct is_default_constructible<const std::tuple<Ts...>>
183  : conjunction<is_default_constructible<Ts>...> {};
184 
185 
186 template <typename T, typename... Args>
187 struct is_constructible : std::is_constructible<T, Args...> {};
188 
189 template <typename T1, typename T2>
190 struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
191 
192 template <typename T1, typename T2>
193 struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
194 
195 template <typename... Ts>
196 struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
197 
198 template <typename... Ts>
199 struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
200 
201 
202 template<typename T, typename = void>
203 struct is_iterator_traits : std::false_type {};
204 
205 template<typename T>
207 {
208  private:
209  using traits = iterator_traits<T>;
210 
211  public:
212  static constexpr auto value =
213  is_detected<value_type_t, traits>::value &&
214  is_detected<difference_type_t, traits>::value &&
215  is_detected<pointer_t, traits>::value &&
216  is_detected<iterator_category_t, traits>::value &&
217  is_detected<reference_t, traits>::value;
218 };
219 
220 template<typename T>
221 struct is_range
222 {
223  private:
224  using t_ref = typename std::add_lvalue_reference<T>::type;
225 
226  using iterator = detected_t<result_of_begin, t_ref>;
227  using sentinel = detected_t<result_of_end, t_ref>;
228 
229  // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
230  // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
231  // but reimplementing these would be too much work, as a lot of other concepts are used underneath
232  static constexpr auto is_iterator_begin =
234 
235  public:
236  static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
237 };
238 
239 template<typename R>
240 using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
241 
242 template<typename T>
243 using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
244 
245 // The following implementation of is_complete_type is taken from
246 // https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
247 // and is written by Xiang Fan who agreed to using it in this library.
248 
249 template<typename T, typename = void>
250 struct is_complete_type : std::false_type {};
251 
252 template<typename T>
253 struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
254 
255 template<typename BasicJsonType, typename CompatibleObjectType,
256  typename = void>
257 struct is_compatible_object_type_impl : std::false_type {};
258 
259 template<typename BasicJsonType, typename CompatibleObjectType>
261  BasicJsonType, CompatibleObjectType,
262  enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
263  is_detected<key_type_t, CompatibleObjectType>::value >>
264 {
265  using object_t = typename BasicJsonType::object_t;
266 
267  // macOS's is_constructible does not play well with nonesuch...
268  static constexpr bool value =
269  is_constructible<typename object_t::key_type,
270  typename CompatibleObjectType::key_type>::value &&
271  is_constructible<typename object_t::mapped_type,
272  typename CompatibleObjectType::mapped_type>::value;
273 };
274 
275 template<typename BasicJsonType, typename CompatibleObjectType>
277  : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
278 
279 template<typename BasicJsonType, typename ConstructibleObjectType,
280  typename = void>
281 struct is_constructible_object_type_impl : std::false_type {};
282 
283 template<typename BasicJsonType, typename ConstructibleObjectType>
285  BasicJsonType, ConstructibleObjectType,
286  enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
287  is_detected<key_type_t, ConstructibleObjectType>::value >>
288 {
289  using object_t = typename BasicJsonType::object_t;
290 
291  static constexpr bool value =
293  (std::is_move_assignable<ConstructibleObjectType>::value ||
294  std::is_copy_assignable<ConstructibleObjectType>::value) &&
295  (is_constructible<typename ConstructibleObjectType::key_type,
296  typename object_t::key_type>::value &&
297  std::is_same <
298  typename object_t::mapped_type,
299  typename ConstructibleObjectType::mapped_type >::value)) ||
300  (has_from_json<BasicJsonType,
301  typename ConstructibleObjectType::mapped_type>::value ||
303  BasicJsonType,
304  typename ConstructibleObjectType::mapped_type >::value);
305 };
306 
307 template<typename BasicJsonType, typename ConstructibleObjectType>
309  : is_constructible_object_type_impl<BasicJsonType,
310  ConstructibleObjectType> {};
311 
312 template<typename BasicJsonType, typename CompatibleStringType,
313  typename = void>
314 struct is_compatible_string_type_impl : std::false_type {};
315 
316 template<typename BasicJsonType, typename CompatibleStringType>
318  BasicJsonType, CompatibleStringType,
319  enable_if_t<is_detected_convertible<typename BasicJsonType::string_t::value_type,
320  range_value_t,
321  CompatibleStringType>::value >>
322 {
323  static constexpr auto value =
325 };
326 
327 template<typename BasicJsonType, typename ConstructibleStringType>
329  : is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
330 
331 template<typename BasicJsonType, typename ConstructibleStringType,
332  typename = void>
333 struct is_constructible_string_type_impl : std::false_type {};
334 
335 template<typename BasicJsonType, typename ConstructibleStringType>
337  BasicJsonType, ConstructibleStringType,
338  enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
339  value_type_t, ConstructibleStringType>::value >>
340 {
341  static constexpr auto value =
342  is_constructible<ConstructibleStringType,
343  typename BasicJsonType::string_t>::value;
344 };
345 
346 template<typename BasicJsonType, typename ConstructibleStringType>
348  : is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
349 
350 template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
351 struct is_compatible_array_type_impl : std::false_type {};
352 
353 template<typename BasicJsonType, typename CompatibleArrayType>
355  BasicJsonType, CompatibleArrayType,
356  enable_if_t <
357  is_detected<iterator_t, CompatibleArrayType>::value&&
358  is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value >>
359 {
360  static constexpr bool value =
361  is_constructible<BasicJsonType,
362  range_value_t<CompatibleArrayType>>::value;
363 };
364 
365 template<typename BasicJsonType, typename CompatibleArrayType>
367  : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
368 
369 template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
370 struct is_constructible_array_type_impl : std::false_type {};
371 
372 template<typename BasicJsonType, typename ConstructibleArrayType>
374  BasicJsonType, ConstructibleArrayType,
375  enable_if_t<std::is_same<ConstructibleArrayType,
376  typename BasicJsonType::value_type>::value >>
377  : std::true_type {};
378 
379 template<typename BasicJsonType, typename ConstructibleArrayType>
381  BasicJsonType, ConstructibleArrayType,
382  enable_if_t < !std::is_same<ConstructibleArrayType,
383  typename BasicJsonType::value_type>::value&&
384  !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
385  is_default_constructible<ConstructibleArrayType>::value&&
386 (std::is_move_assignable<ConstructibleArrayType>::value ||
387  std::is_copy_assignable<ConstructibleArrayType>::value)&&
388 is_detected<iterator_t, ConstructibleArrayType>::value&&
389 is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
390 is_detected<range_value_t, ConstructibleArrayType>::value&&
392 detected_t<range_value_t, ConstructibleArrayType >>::value >>
393 {
394  using value_type = range_value_t<ConstructibleArrayType>;
395 
396  static constexpr bool value =
397  std::is_same<value_type,
398  typename BasicJsonType::array_t::value_type>::value ||
399  has_from_json<BasicJsonType,
400  value_type>::value ||
402  BasicJsonType,
403  value_type >::value;
404 };
405 
406 template<typename BasicJsonType, typename ConstructibleArrayType>
408  : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
409 
410 template<typename RealIntegerType, typename CompatibleNumberIntegerType,
411  typename = void>
412 struct is_compatible_integer_type_impl : std::false_type {};
413 
414 template<typename RealIntegerType, typename CompatibleNumberIntegerType>
416  RealIntegerType, CompatibleNumberIntegerType,
417  enable_if_t < std::is_integral<RealIntegerType>::value&&
418  std::is_integral<CompatibleNumberIntegerType>::value&&
419  !std::is_same<bool, CompatibleNumberIntegerType>::value >>
420 {
421  // is there an assert somewhere on overflows?
422  using RealLimits = std::numeric_limits<RealIntegerType>;
423  using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
424 
425  static constexpr auto value =
426  is_constructible<RealIntegerType,
427  CompatibleNumberIntegerType>::value &&
428  CompatibleLimits::is_integer &&
429  RealLimits::is_signed == CompatibleLimits::is_signed;
430 };
431 
432 template<typename RealIntegerType, typename CompatibleNumberIntegerType>
434  : is_compatible_integer_type_impl<RealIntegerType,
435  CompatibleNumberIntegerType> {};
436 
437 template<typename BasicJsonType, typename CompatibleType, typename = void>
438 struct is_compatible_type_impl: std::false_type {};
439 
440 template<typename BasicJsonType, typename CompatibleType>
442  BasicJsonType, CompatibleType,
443  enable_if_t<is_complete_type<CompatibleType>::value >>
444 {
445  static constexpr bool value =
447 };
448 
449 template<typename BasicJsonType, typename CompatibleType>
451  : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
452 
453 template<typename T1, typename T2>
454 struct is_constructible_tuple : std::false_type {};
455 
456 template<typename T1, typename... Args>
457 struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
458 
459 // a naive helper to check if a type is an ordered_map (exploits the fact that
460 // ordered_map inherits capacity() from std::vector)
461 template <typename T>
463 {
464  using one = char;
465 
466  struct two
467  {
468  char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
469  };
470 
471  template <typename C> static one test( decltype(&C::capacity) ) ;
472  template <typename C> static two test(...);
473 
474  enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
475 };
476 
477 // to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
478 template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
479 T conditional_static_cast(U value)
480 {
481  return static_cast<T>(value);
482 }
483 
484 template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
485 T conditional_static_cast(U value)
486 {
487  return value;
488 }
489 
490 } // namespace detail
491 } // namespace nlohmann
Definition: json_ref.hpp:14
@ value
the parser finished reading a JSON value
namespace for Niels Lohmann
Definition: adl_serializer.hpp:12
Definition: type_traits.hpp:155
Definition: type_traits.hpp:154
Definition: type_traits.hpp:96
Definition: type_traits.hpp:121
Definition: type_traits.hpp:136
Definition: type_traits.hpp:42
Definition: type_traits.hpp:367
Definition: type_traits.hpp:435
Definition: type_traits.hpp:277
Definition: type_traits.hpp:329
Definition: type_traits.hpp:438
Definition: type_traits.hpp:451
Definition: type_traits.hpp:250
Definition: type_traits.hpp:408
Definition: type_traits.hpp:310
Definition: type_traits.hpp:348
Definition: type_traits.hpp:454
Definition: type_traits.hpp:187
Definition: type_traits.hpp:167
Definition: type_traits.hpp:104
Definition: type_traits.hpp:203
Definition: type_traits.hpp:55
Definition: type_traits.hpp:467
Definition: type_traits.hpp:463
Definition: type_traits.hpp:222
Definition: iterator_traits.hpp:32
Definition: type_traits.hpp:161