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 
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 {
23 namespace detail
24 {
26 // helpers //
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 
44 // json_ref helpers //
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 
57 // aliases for detected //
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>
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 
150 // is_ functions //
152 
153 template<typename T, typename = void>
154 struct is_iterator_traits : std::false_type {};
155 
156 template<typename 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>
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>
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>
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 ||
228  BasicJsonType,
229  typename ConstructibleObjectType::mapped_type >::value);
230 };
231 
232 template<typename BasicJsonType, typename ConstructibleObjectType>
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>
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>
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>
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>
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>
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.
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>
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>
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>
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&&
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.
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 ||
333  BasicJsonType, typename ConstructibleArrayType::value_type >::value);
334 };
335 
336 template<typename BasicJsonType, typename ConstructibleArrayType>
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>
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>
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>
372  BasicJsonType, CompatibleType,
373  enable_if_t<is_complete_type<CompatibleType>::value >>
374 {
375  static constexpr bool value =
377 };
378 
379 template<typename BasicJsonType, typename CompatibleType>
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
Definition: json_ref.hpp:14
@ value
the parser finished reading a JSON value
namespace for Niels Lohmann
Definition: adl_serializer.hpp:9
Definition: type_traits.hpp:385
Definition: type_traits.hpp:384
Definition: type_traits.hpp:95
Definition: type_traits.hpp:121
Definition: type_traits.hpp:136
Definition: type_traits.hpp:38
Definition: type_traits.hpp:295
Definition: type_traits.hpp:365
Definition: type_traits.hpp:202
Definition: type_traits.hpp:253
Definition: type_traits.hpp:368
Definition: type_traits.hpp:381
Definition: type_traits.hpp:174
Definition: type_traits.hpp:338
Definition: type_traits.hpp:235
Definition: type_traits.hpp:272
Definition: type_traits.hpp:391
Definition: type_traits.hpp:103
Definition: type_traits.hpp:154
Definition: type_traits.hpp:51
Definition: iterator_traits.hpp:32