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