1 #ifndef ENTT_CORE_TYPE_TRAITS_HPP
2 #define ENTT_CORE_TYPE_TRAITS_HPP
3
4
5 #include <cstddef>
6 #include <iterator>
7 #include <type_traits>
8 #include <utility>
9 #include "../config/config.h"
10 #include "fwd.hpp"
11
12
13 namespace entt {
14
15
16 /**
17 * @brief Utility class to disambiguate overloaded functions.
18 * @tparam N Number of choices available.
19 */
20 template<std::size_t N>
21 struct choice_t
22 // Unfortunately, doxygen cannot parse such a construct.
23 /*! @cond TURN_OFF_DOXYGEN */
24 : choice_t<N-1>
25 /*! @endcond */
26 {};
27
28
29 /*! @copybrief choice_t */
30 template<>
31 struct choice_t<0> {};
32
33
34 /**
35 * @brief Variable template for the choice trick.
36 * @tparam N Number of choices available.
37 */
38 template<std::size_t N>
39 inline constexpr choice_t<N> choice{};
40
41
42 /**
43 * @brief Identity type trait.
44 *
45 * Useful to establish non-deduced contexts in template argument deduction
46 * (waiting for C++20) or to provide types through function arguments.
47 *
48 * @tparam Type A type.
49 */
50 template<typename Type>
51 struct type_identity {
52 /*! @brief Identity type. */
53 using type = Type;
54 };
55
56
57 /**
58 * @brief Helper type.
59 * @tparam Type A type.
60 */
61 template<typename Type>
62 using type_identity_t = typename type_identity<Type>::type;
63
64
65 /**
66 * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
67 * @tparam Type The type of which to return the size.
68 * @tparam The size of the type if `sizeof` accepts it, 0 otherwise.
69 */
70 template<typename Type, typename = void>
71 struct size_of: std::integral_constant<std::size_t, 0u> {};
72
73
74 /*! @copydoc size_of */
75 template<typename Type>
76 struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
77 : std::integral_constant<std::size_t, sizeof(Type)>
78 {};
79
80
81 /**
82 * @brief Helper variable template.
83 * @tparam Type The type of which to return the size.
84 */
85 template<class Type>
86 inline constexpr std::size_t size_of_v = size_of<Type>::value;
87
88
89 /**
90 * @brief Using declaration to be used to _repeat_ the same type a number of
91 * times equal to the size of a given parameter pack.
92 * @tparam Type A type to repeat.
93 */
94 template<typename Type, typename>
95 using unpack_as_t = Type;
96
97
98 /**
99 * @brief Helper variable template to be used to _repeat_ the same value a
100 * number of times equal to the size of a given parameter pack.
101 * @tparam Value A value to repeat.
102 */
103 template<auto Value, typename>
104 inline constexpr auto unpack_as_v = Value;
105
106
107 /**
108 * @brief Wraps a static constant.
109 * @tparam Value A static constant.
110 */
111 template<auto Value>
112 using integral_constant = std::integral_constant<decltype(Value), Value>;
113
114
115 /**
116 * @brief Alias template to facilitate the creation of named values.
117 * @tparam Value A constant value at least convertible to `id_type`.
118 */
119 template<id_type Value>
120 using tag = integral_constant<Value>;
121
122
123 /**
124 * @brief A class to use to push around lists of types, nothing more.
125 * @tparam Type Types provided by the type list.
126 */
127 template<typename... Type>
128 struct type_list {
129 /*! @brief Type list type. */
130 using type = type_list;
131 /*! @brief Compile-time number of elements in the type list. */
132 static constexpr auto size = sizeof...(Type);
133 };
134
135
136 /*! @brief Primary template isn't defined on purpose. */
137 template<std::size_t, typename>
138 struct type_list_element;
139
140
141 /**
142 * @brief Provides compile-time indexed access to the types of a type list.
143 * @tparam Index Index of the type to return.
144 * @tparam Type First type provided by the type list.
145 * @tparam Other Other types provided by the type list.
146 */
147 template<std::size_t Index, typename Type, typename... Other>
148 struct type_list_element<Index, type_list<Type, Other...>>
149 : type_list_element<Index - 1u, type_list<Other...>>
150 {};
151
152
153 /**
154 * @brief Provides compile-time indexed access to the types of a type list.
155 * @tparam Type First type provided by the type list.
156 * @tparam Other Other types provided by the type list.
157 */
158 template<typename Type, typename... Other>
159 struct type_list_element<0u, type_list<Type, Other...>> {
160 /*! @brief Searched type. */
161 using type = Type;
162 };
163
164
165 /**
166 * @brief Helper type.
167 * @tparam Index Index of the type to return.
168 * @tparam List Type list to search into.
169 */
170 template<std::size_t Index, typename List>
171 using type_list_element_t = typename type_list_element<Index, List>::type;
172
173
174 /**
175 * @brief Concatenates multiple type lists.
176 * @tparam Type Types provided by the first type list.
177 * @tparam Other Types provided by the second type list.
178 * @return A type list composed by the types of both the type lists.
179 */
180 template<typename... Type, typename... Other>
operator +(type_list<Type...>,type_list<Other...>)181 constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) { return {}; }
182
183
184 /*! @brief Primary template isn't defined on purpose. */
185 template<typename...>
186 struct type_list_cat;
187
188
189 /*! @brief Concatenates multiple type lists. */
190 template<>
191 struct type_list_cat<> {
192 /*! @brief A type list composed by the types of all the type lists. */
193 using type = type_list<>;
194 };
195
196
197 /**
198 * @brief Concatenates multiple type lists.
199 * @tparam Type Types provided by the first type list.
200 * @tparam Other Types provided by the second type list.
201 * @tparam List Other type lists, if any.
202 */
203 template<typename... Type, typename... Other, typename... List>
204 struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> {
205 /*! @brief A type list composed by the types of all the type lists. */
206 using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type;
207 };
208
209
210 /**
211 * @brief Concatenates multiple type lists.
212 * @tparam Type Types provided by the type list.
213 */
214 template<typename... Type>
215 struct type_list_cat<type_list<Type...>> {
216 /*! @brief A type list composed by the types of all the type lists. */
217 using type = type_list<Type...>;
218 };
219
220
221 /**
222 * @brief Helper type.
223 * @tparam List Type lists to concatenate.
224 */
225 template<typename... List>
226 using type_list_cat_t = typename type_list_cat<List...>::type;
227
228
229 /*! @brief Primary template isn't defined on purpose. */
230 template<typename>
231 struct type_list_unique;
232
233
234 /**
235 * @brief Removes duplicates types from a type list.
236 * @tparam Type One of the types provided by the given type list.
237 * @tparam Other The other types provided by the given type list.
238 */
239 template<typename Type, typename... Other>
240 struct type_list_unique<type_list<Type, Other...>> {
241 /*! @brief A type list without duplicate types. */
242 using type = std::conditional_t<
243 std::disjunction_v<std::is_same<Type, Other>...>,
244 typename type_list_unique<type_list<Other...>>::type,
245 type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>
246 >;
247 };
248
249
250 /*! @brief Removes duplicates types from a type list. */
251 template<>
252 struct type_list_unique<type_list<>> {
253 /*! @brief A type list without duplicate types. */
254 using type = type_list<>;
255 };
256
257
258 /**
259 * @brief Helper type.
260 * @tparam Type A type list.
261 */
262 template<typename Type>
263 using type_list_unique_t = typename type_list_unique<Type>::type;
264
265
266 /**
267 * @brief Provides the member constant `value` to true if a type list contains a
268 * given type, false otherwise.
269 * @tparam List Type list.
270 * @tparam Type Type to look for.
271 */
272 template<typename List, typename Type>
273 struct type_list_contains;
274
275
276 /**
277 * @copybrief type_list_contains
278 * @tparam Type Types provided by the type list.
279 * @tparam Other Type to look for.
280 */
281 template<typename... Type, typename Other>
282 struct type_list_contains<type_list<Type...>, Other>: std::disjunction<std::is_same<Type, Other>...> {};
283
284
285 /**
286 * @brief Helper variable template.
287 * @tparam List Type list.
288 * @tparam Type Type to look for.
289 */
290 template<class List, typename Type>
291 inline constexpr bool type_list_contains_v = type_list_contains<List, Type>::value;
292
293
294 /*! @brief Primary template isn't defined on purpose. */
295 template<typename...>
296 struct type_list_diff;
297
298
299 /**
300 * @brief Computes the difference between two type lists.
301 * @tparam Type Types provided by the first type list.
302 * @tparam Other Types provided by the second type list.
303 */
304 template<typename... Type, typename... Other>
305 struct type_list_diff<type_list<Type...>, type_list<Other...>> {
306 /*! @brief A type list that is the difference between the two type lists. */
307 using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
308 };
309
310
311 /**
312 * @brief Helper type.
313 * @tparam List Type lists between which to compute the difference.
314 */
315 template<typename... List>
316 using type_list_diff_t = typename type_list_diff<List...>::type;
317
318
319 /**
320 * @brief A class to use to push around lists of constant values, nothing more.
321 * @tparam Value Values provided by the value list.
322 */
323 template<auto... Value>
324 struct value_list {
325 /*! @brief Value list type. */
326 using type = value_list;
327 /*! @brief Compile-time number of elements in the value list. */
328 static constexpr auto size = sizeof...(Value);
329 };
330
331
332 /*! @brief Primary template isn't defined on purpose. */
333 template<std::size_t, typename>
334 struct value_list_element;
335
336
337 /**
338 * @brief Provides compile-time indexed access to the values of a value list.
339 * @tparam Index Index of the value to return.
340 * @tparam Value First value provided by the value list.
341 * @tparam Other Other values provided by the value list.
342 */
343 template<std::size_t Index, auto Value, auto... Other>
344 struct value_list_element<Index, value_list<Value, Other...>>
345 : value_list_element<Index - 1u, value_list<Other...>>
346 {};
347
348
349 /**
350 * @brief Provides compile-time indexed access to the types of a type list.
351 * @tparam Value First value provided by the value list.
352 * @tparam Other Other values provided by the value list.
353 */
354 template<auto Value, auto... Other>
355 struct value_list_element<0u, value_list<Value, Other...>> {
356 /*! @brief Searched value. */
357 static constexpr auto value = Value;
358 };
359
360
361 /**
362 * @brief Helper type.
363 * @tparam Index Index of the value to return.
364 * @tparam List Value list to search into.
365 */
366 template<std::size_t Index, typename List>
367 inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
368
369
370 /**
371 * @brief Concatenates multiple value lists.
372 * @tparam Value Values provided by the first value list.
373 * @tparam Other Values provided by the second value list.
374 * @return A value list composed by the values of both the value lists.
375 */
376 template<auto... Value, auto... Other>
operator +(value_list<Value...>,value_list<Other...>)377 constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) { return {}; }
378
379
380 /*! @brief Primary template isn't defined on purpose. */
381 template<typename...>
382 struct value_list_cat;
383
384
385 /*! @brief Concatenates multiple value lists. */
386 template<>
387 struct value_list_cat<> {
388 /*! @brief A value list composed by the values of all the value lists. */
389 using type = value_list<>;
390 };
391
392
393 /**
394 * @brief Concatenates multiple value lists.
395 * @tparam Value Values provided by the first value list.
396 * @tparam Other Values provided by the second value list.
397 * @tparam List Other value lists, if any.
398 */
399 template<auto... Value, auto... Other, typename... List>
400 struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> {
401 /*! @brief A value list composed by the values of all the value lists. */
402 using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type;
403 };
404
405
406 /**
407 * @brief Concatenates multiple value lists.
408 * @tparam Value Values provided by the value list.
409 */
410 template<auto... Value>
411 struct value_list_cat<value_list<Value...>> {
412 /*! @brief A value list composed by the values of all the value lists. */
413 using type = value_list<Value...>;
414 };
415
416
417 /**
418 * @brief Helper type.
419 * @tparam List Value lists to concatenate.
420 */
421 template<typename... List>
422 using value_list_cat_t = typename value_list_cat<List...>::type;
423
424
425 /*! @brief Same as std::is_invocable, but with tuples. */
426 template<typename, typename>
427 struct is_applicable: std::false_type {};
428
429
430 /**
431 * @copybrief is_applicable
432 * @tparam Func A valid function type.
433 * @tparam Tuple Tuple-like type.
434 * @tparam Args The list of arguments to use to probe the function type.
435 */
436 template<typename Func, template<typename...> class Tuple, typename... Args>
437 struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
438
439
440 /**
441 * @copybrief is_applicable
442 * @tparam Func A valid function type.
443 * @tparam Tuple Tuple-like type.
444 * @tparam Args The list of arguments to use to probe the function type.
445 */
446 template<typename Func, template<typename...> class Tuple, typename... Args>
447 struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
448
449
450 /**
451 * @brief Helper variable template.
452 * @tparam Func A valid function type.
453 * @tparam Args The list of arguments to use to probe the function type.
454 */
455 template<typename Func, typename Args>
456 inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value;
457
458
459 /*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
460 template<typename, typename, typename>
461 struct is_applicable_r: std::false_type {};
462
463
464 /**
465 * @copybrief is_applicable_r
466 * @tparam Ret The type to which the return type of the function should be
467 * convertible.
468 * @tparam Func A valid function type.
469 * @tparam Args The list of arguments to use to probe the function type.
470 */
471 template<typename Ret, typename Func, typename... Args>
472 struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
473
474
475 /**
476 * @brief Helper variable template.
477 * @tparam Ret The type to which the return type of the function should be
478 * convertible.
479 * @tparam Func A valid function type.
480 * @tparam Args The list of arguments to use to probe the function type.
481 */
482 template<typename Ret, typename Func, typename Args>
483 inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
484
485
486 /**
487 * @brief Provides the member constant `value` to true if a given type is
488 * complete, false otherwise.
489 * @tparam Type The type to test.
490 */
491 template<typename Type, typename = void>
492 struct is_complete: std::false_type {};
493
494
495 /*! @copydoc is_complete */
496 template<typename Type>
497 struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
498
499
500 /**
501 * @brief Helper variable template.
502 * @tparam Type The type to test.
503 */
504 template<typename Type>
505 inline constexpr bool is_complete_v = is_complete<Type>::value;
506
507
508 /**
509 * @brief Provides the member constant `value` to true if a given type is an
510 * iterator, false otherwise.
511 * @tparam Type The type to test.
512 */
513 template<typename Type, typename = void>
514 struct is_iterator: std::false_type {};
515
516
517 /*! @copydoc is_iterator */
518 template<typename Type>
519 struct is_iterator<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>
520 : std::true_type
521 {};
522
523
524 /**
525 * @brief Helper variable template.
526 * @tparam Type The type to test.
527 */
528 template<typename Type>
529 inline constexpr bool is_iterator_v = is_iterator<Type>::value;
530
531
532 /**
533 * @brief Provides the member constant `value` to true if a given type is of the
534 * required iterator type, false otherwise.
535 * @tparam Type The type to test.
536 * @tparam It Required iterator type.
537 */
538 template<typename Type, typename It, typename = void>
539 struct is_iterator_type: std::false_type {};
540
541
542 /*! @copydoc is_iterator_type */
543 template<typename Type, typename It>
544 struct is_iterator_type<Type, It, std::enable_if_t<is_iterator_v<Type> && std::is_same_v<Type, It>>>
545 : std::true_type
546 {};
547
548
549 /*! @copydoc is_iterator_type */
550 template<typename Type, typename It>
551 struct is_iterator_type<Type, It, std::enable_if_t<!std::is_same_v<Type, It>, std::void_t<typename It::iterator_type>>>
552 : is_iterator_type<Type, typename It::iterator_type>
553 {};
554
555
556 /**
557 * @brief Helper variable template.
558 * @tparam Type The type to test.
559 * @tparam It Required iterator type.
560 */
561 template<typename Type, typename It>
562 inline constexpr bool is_iterator_type_v = is_iterator_type<Type, It>::value;
563
564
565 /**
566 * @cond TURN_OFF_DOXYGEN
567 * Internal details not to be documented.
568 */
569
570
571 namespace internal {
572
573
574 template<typename>
is_equality_comparable(...)575 [[nodiscard]] constexpr bool is_equality_comparable(...) { return false; }
576
577
578 template<typename Type>
is_equality_comparable(choice_t<0>)579 [[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>)
580 -> decltype(std::declval<Type>() == std::declval<Type>()) { return true; }
581
582
583 template<typename Type>
is_equality_comparable(choice_t<1>)584 [[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>)
585 -> decltype(std::declval<typename Type::value_type>(), std::declval<Type>() == std::declval<Type>()) {
586 if constexpr(is_iterator_v<Type>) {
587 return true;
588 } else if constexpr(std::is_same_v<typename Type::value_type, Type>) {
589 return is_equality_comparable<Type>(choice<0>);
590 } else {
591 return is_equality_comparable<typename Type::value_type>(choice<2>);
592 }
593 }
594
595
596 template<typename Type>
is_equality_comparable(choice_t<2>)597 [[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>)
598 -> decltype(std::declval<typename Type::mapped_type>(), std::declval<Type>() == std::declval<Type>()) {
599 return is_equality_comparable<typename Type::key_type>(choice<2>) && is_equality_comparable<typename Type::mapped_type>(choice<2>);
600 }
601
602
603 }
604
605
606 /**
607 * Internal details not to be documented.
608 * @endcond
609 */
610
611
612 /**
613 * @brief Provides the member constant `value` to true if a given type is
614 * equality comparable, false otherwise.
615 * @tparam Type The type to test.
616 */
617 template<typename Type, typename = void>
618 struct is_equality_comparable: std::bool_constant<internal::is_equality_comparable<Type>(choice<2>)> {};
619
620
621 /**
622 * @brief Helper variable template.
623 * @tparam Type The type to test.
624 */
625 template<class Type>
626 inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::value;
627
628
629 /**
630 * @brief Transcribes the constness of a type to another type.
631 * @tparam To The type to which to transcribe the constness.
632 * @tparam From The type from which to transcribe the constness.
633 */
634 template<typename To, typename From>
635 struct constness_as {
636 /*! @brief The type resulting from the transcription of the constness. */
637 using type = std::remove_const_t<To>;
638 };
639
640
641 /*! @copydoc constness_as */
642 template<typename To, typename From>
643 struct constness_as<To, const From> {
644 /*! @brief The type resulting from the transcription of the constness. */
645 using type = std::add_const_t<To>;
646 };
647
648
649 /**
650 * @brief Alias template to facilitate the transcription of the constness.
651 * @tparam To The type to which to transcribe the constness.
652 * @tparam From The type from which to transcribe the constness.
653 */
654 template<typename To, typename From>
655 using constness_as_t = typename constness_as<To, From>::type;
656
657
658 /**
659 * @brief Extracts the class of a non-static member object or function.
660 * @tparam Member A pointer to a non-static member object or function.
661 */
662 template<typename Member>
663 class member_class {
664 static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
665
666 template<typename Class, typename Ret, typename... Args>
667 static Class * clazz(Ret(Class:: *)(Args...));
668
669 template<typename Class, typename Ret, typename... Args>
670 static Class * clazz(Ret(Class:: *)(Args...) const);
671
672 template<typename Class, typename Type>
673 static Class * clazz(Type Class:: *);
674
675 public:
676 /*! @brief The class of the given non-static member object or function. */
677 using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>;
678 };
679
680
681 /**
682 * @brief Helper type.
683 * @tparam Member A pointer to a non-static member object or function.
684 */
685 template<typename Member>
686 using member_class_t = typename member_class<Member>::type;
687
688
689 }
690
691
692 #endif
693