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