Bug 1456906 [wpt PR 10641] - Subtract scrollbar in PerpendicularContainingBlockLogica...
[gecko.git] / mfbt / TypeTraits.h
blobe566a7ce65091b9a10c563de40d86745270da839
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Template-based metaprogramming and type-testing facilities. */
9 #ifndef mozilla_TypeTraits_h
10 #define mozilla_TypeTraits_h
12 #include "mozilla/Types.h"
15 * These traits are approximate copies of the traits and semantics from C++11's
16 * <type_traits> header. Don't add traits not in that header! When all
17 * platforms provide that header, we can convert all users and remove this one.
20 #include <wchar.h>
22 namespace mozilla {
24 /* Forward declarations. */
26 template<typename> struct RemoveCV;
27 template<typename> struct AddRvalueReference;
29 /* 20.2.4 Function template declval [declval] */
31 /**
32 * DeclVal simplifies the definition of expressions which occur as unevaluated
33 * operands. It converts T to a reference type, making it possible to use in
34 * decltype expressions even if T does not have a default constructor, e.g.:
35 * decltype(DeclVal<TWithNoDefaultConstructor>().foo())
37 template<typename T>
38 typename AddRvalueReference<T>::Type DeclVal();
40 /* 20.9.3 Helper classes [meta.help] */
42 /**
43 * Helper class used as a base for various type traits, exposed publicly
44 * because <type_traits> exposes it as well.
46 template<typename T, T Value>
47 struct IntegralConstant
49 static constexpr T value = Value;
50 typedef T ValueType;
51 typedef IntegralConstant<T, Value> Type;
54 /** Convenient aliases. */
55 typedef IntegralConstant<bool, true> TrueType;
56 typedef IntegralConstant<bool, false> FalseType;
58 /* 20.9.4 Unary type traits [meta.unary] */
60 /* 20.9.4.1 Primary type categories [meta.unary.cat] */
62 namespace detail {
64 template<typename T>
65 struct IsVoidHelper : FalseType {};
67 template<>
68 struct IsVoidHelper<void> : TrueType {};
70 } // namespace detail
72 /**
73 * IsVoid determines whether a type is void.
75 * mozilla::IsVoid<int>::value is false;
76 * mozilla::IsVoid<void>::value is true;
77 * mozilla::IsVoid<void*>::value is false;
78 * mozilla::IsVoid<volatile void>::value is true.
80 template<typename T>
81 struct IsVoid : detail::IsVoidHelper<typename RemoveCV<T>::Type> {};
83 namespace detail {
85 template <typename T>
86 struct IsIntegralHelper : FalseType {};
88 template<> struct IsIntegralHelper<char> : TrueType {};
89 template<> struct IsIntegralHelper<signed char> : TrueType {};
90 template<> struct IsIntegralHelper<unsigned char> : TrueType {};
91 template<> struct IsIntegralHelper<short> : TrueType {};
92 template<> struct IsIntegralHelper<unsigned short> : TrueType {};
93 template<> struct IsIntegralHelper<int> : TrueType {};
94 template<> struct IsIntegralHelper<unsigned int> : TrueType {};
95 template<> struct IsIntegralHelper<long> : TrueType {};
96 template<> struct IsIntegralHelper<unsigned long> : TrueType {};
97 template<> struct IsIntegralHelper<long long> : TrueType {};
98 template<> struct IsIntegralHelper<unsigned long long> : TrueType {};
99 template<> struct IsIntegralHelper<bool> : TrueType {};
100 template<> struct IsIntegralHelper<wchar_t> : TrueType {};
101 template<> struct IsIntegralHelper<char16_t> : TrueType {};
103 } /* namespace detail */
106 * IsIntegral determines whether a type is an integral type.
108 * mozilla::IsIntegral<int>::value is true;
109 * mozilla::IsIntegral<unsigned short>::value is true;
110 * mozilla::IsIntegral<const long>::value is true;
111 * mozilla::IsIntegral<int*>::value is false;
112 * mozilla::IsIntegral<double>::value is false;
114 template<typename T>
115 struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type>
118 template<typename T, typename U>
119 struct IsSame;
121 namespace detail {
123 template<typename T>
124 struct IsFloatingPointHelper
125 : IntegralConstant<bool,
126 IsSame<T, float>::value ||
127 IsSame<T, double>::value ||
128 IsSame<T, long double>::value>
131 } // namespace detail
134 * IsFloatingPoint determines whether a type is a floating point type (float,
135 * double, long double).
137 * mozilla::IsFloatingPoint<int>::value is false;
138 * mozilla::IsFloatingPoint<const float>::value is true;
139 * mozilla::IsFloatingPoint<long double>::value is true;
140 * mozilla::IsFloatingPoint<double*>::value is false.
142 template<typename T>
143 struct IsFloatingPoint
144 : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type>
147 namespace detail {
149 template<typename T>
150 struct IsArrayHelper : FalseType {};
152 template<typename T, decltype(sizeof(1)) N>
153 struct IsArrayHelper<T[N]> : TrueType {};
155 template<typename T>
156 struct IsArrayHelper<T[]> : TrueType {};
158 } // namespace detail
161 * IsArray determines whether a type is an array type, of known or unknown
162 * length.
164 * mozilla::IsArray<int>::value is false;
165 * mozilla::IsArray<int[]>::value is true;
166 * mozilla::IsArray<int[5]>::value is true.
168 template<typename T>
169 struct IsArray : detail::IsArrayHelper<typename RemoveCV<T>::Type>
172 namespace detail {
174 template<typename T>
175 struct IsFunPtr;
177 template<typename>
178 struct IsFunPtr
179 : public FalseType
182 template<typename Result, typename... ArgTypes>
183 struct IsFunPtr<Result(*)(ArgTypes...)>
184 : public TrueType
187 }; // namespace detail
190 * IsFunction determines whether a type is a function type. Function pointers
191 * don't qualify here--only the type of an actual function symbol. We do not
192 * correctly handle varags function types because of a bug in MSVC.
194 * Given the function:
195 * void f(int) {}
197 * mozilla::IsFunction<void(int)> is true;
198 * mozilla::IsFunction<void(*)(int)> is false;
199 * mozilla::IsFunction<decltype(f)> is true.
201 template<typename T>
202 struct IsFunction
203 : public detail::IsFunPtr<typename RemoveCV<T>::Type *>
206 namespace detail {
208 template<typename T>
209 struct IsPointerHelper : FalseType {};
211 template<typename T>
212 struct IsPointerHelper<T*> : TrueType {};
214 } // namespace detail
217 * IsPointer determines whether a type is a possibly-CV-qualified pointer type
218 * (but not a pointer-to-member type).
220 * mozilla::IsPointer<struct S*>::value is true;
221 * mozilla::IsPointer<int*>::value is true;
222 * mozilla::IsPointer<int**>::value is true;
223 * mozilla::IsPointer<const int*>::value is true;
224 * mozilla::IsPointer<int* const>::value is true;
225 * mozilla::IsPointer<int* volatile>::value is true;
226 * mozilla::IsPointer<void (*)(void)>::value is true;
227 * mozilla::IsPointer<int>::value is false;
228 * mozilla::IsPointer<struct S>::value is false.
229 * mozilla::IsPointer<int(struct S::*)>::value is false
231 template<typename T>
232 struct IsPointer : detail::IsPointerHelper<typename RemoveCV<T>::Type>
236 * IsLvalueReference determines whether a type is an lvalue reference.
238 * mozilla::IsLvalueReference<struct S*>::value is false;
239 * mozilla::IsLvalueReference<int**>::value is false;
240 * mozilla::IsLvalueReference<void (*)(void)>::value is false;
241 * mozilla::IsLvalueReference<int>::value is false;
242 * mozilla::IsLvalueReference<struct S>::value is false;
243 * mozilla::IsLvalueReference<struct S*&>::value is true;
244 * mozilla::IsLvalueReference<struct S&&>::value is false.
246 template<typename T>
247 struct IsLvalueReference : FalseType {};
249 template<typename T>
250 struct IsLvalueReference<T&> : TrueType {};
253 * IsRvalueReference determines whether a type is an rvalue reference.
255 * mozilla::IsRvalueReference<struct S*>::value is false;
256 * mozilla::IsRvalueReference<int**>::value is false;
257 * mozilla::IsRvalueReference<void (*)(void)>::value is false;
258 * mozilla::IsRvalueReference<int>::value is false;
259 * mozilla::IsRvalueReference<struct S>::value is false;
260 * mozilla::IsRvalueReference<struct S*&>::value is false;
261 * mozilla::IsRvalueReference<struct S&&>::value is true.
263 template<typename T>
264 struct IsRvalueReference : FalseType {};
266 template<typename T>
267 struct IsRvalueReference<T&&> : TrueType {};
269 namespace detail {
271 // __is_enum is a supported extension across all of our supported compilers.
272 template<typename T>
273 struct IsEnumHelper
274 : IntegralConstant<bool, __is_enum(T)>
277 } // namespace detail
280 * IsEnum determines whether a type is an enum type.
282 * mozilla::IsEnum<enum S>::value is true;
283 * mozilla::IsEnum<enum S*>::value is false;
284 * mozilla::IsEnum<int>::value is false;
286 template<typename T>
287 struct IsEnum
288 : detail::IsEnumHelper<typename RemoveCV<T>::Type>
291 namespace detail {
293 // __is_class is a supported extension across all of our supported compilers:
294 // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
295 // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
296 // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
297 template<typename T>
298 struct IsClassHelper
299 : IntegralConstant<bool, __is_class(T)>
302 } // namespace detail
305 * IsClass determines whether a type is a class type (but not a union).
307 * struct S {};
308 * union U {};
309 * mozilla::IsClass<int>::value is false;
310 * mozilla::IsClass<const S>::value is true;
311 * mozilla::IsClass<U>::value is false;
313 template<typename T>
314 struct IsClass
315 : detail::IsClassHelper<typename RemoveCV<T>::Type>
318 /* 20.9.4.2 Composite type traits [meta.unary.comp] */
321 * IsReference determines whether a type is an lvalue or rvalue reference.
323 * mozilla::IsReference<struct S*>::value is false;
324 * mozilla::IsReference<int**>::value is false;
325 * mozilla::IsReference<int&>::value is true;
326 * mozilla::IsReference<void (*)(void)>::value is false;
327 * mozilla::IsReference<const int&>::value is true;
328 * mozilla::IsReference<int>::value is false;
329 * mozilla::IsReference<struct S>::value is false;
330 * mozilla::IsReference<struct S&>::value is true;
331 * mozilla::IsReference<struct S*&>::value is true;
332 * mozilla::IsReference<struct S&&>::value is true.
334 template<typename T>
335 struct IsReference
336 : IntegralConstant<bool,
337 IsLvalueReference<T>::value || IsRvalueReference<T>::value>
341 * IsArithmetic determines whether a type is arithmetic. A type is arithmetic
342 * iff it is an integral type or a floating point type.
344 * mozilla::IsArithmetic<int>::value is true;
345 * mozilla::IsArithmetic<double>::value is true;
346 * mozilla::IsArithmetic<long double*>::value is false.
348 template<typename T>
349 struct IsArithmetic
350 : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value>
353 namespace detail {
355 template<typename T>
356 struct IsMemberPointerHelper : FalseType {};
358 template<typename T, typename U>
359 struct IsMemberPointerHelper<T U::*> : TrueType {};
361 } // namespace detail
364 * IsMemberPointer determines whether a type is pointer to non-static member
365 * object or a pointer to non-static member function.
367 * mozilla::IsMemberPointer<int(cls::*)>::value is true
368 * mozilla::IsMemberPointer<int*>::value is false
370 template<typename T>
371 struct IsMemberPointer
372 : detail::IsMemberPointerHelper<typename RemoveCV<T>::Type>
376 * IsScalar determines whether a type is a scalar type.
378 * mozilla::IsScalar<int>::value is true
379 * mozilla::IsScalar<int*>::value is true
380 * mozilla::IsScalar<cls>::value is false
382 template<typename T>
383 struct IsScalar
384 : IntegralConstant<bool, IsArithmetic<T>::value || IsEnum<T>::value ||
385 IsPointer<T>::value || IsMemberPointer<T>::value>
388 /* 20.9.4.3 Type properties [meta.unary.prop] */
391 * IsConst determines whether a type is const or not.
393 * mozilla::IsConst<int>::value is false;
394 * mozilla::IsConst<void* const>::value is true;
395 * mozilla::IsConst<const char*>::value is false.
397 template<typename T>
398 struct IsConst : FalseType {};
400 template<typename T>
401 struct IsConst<const T> : TrueType {};
404 * IsVolatile determines whether a type is volatile or not.
406 * mozilla::IsVolatile<int>::value is false;
407 * mozilla::IsVolatile<void* volatile>::value is true;
408 * mozilla::IsVolatile<volatile char*>::value is false.
410 template<typename T>
411 struct IsVolatile : FalseType {};
413 template<typename T>
414 struct IsVolatile<volatile T> : TrueType {};
417 * Traits class for identifying POD types. Until C++11 there's no automatic
418 * way to detect PODs, so for the moment this is done manually. Users may
419 * define specializations of this class that inherit from mozilla::TrueType and
420 * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or
421 * false>, or conveniently from mozilla::IsPod for composite types) as needed to
422 * ensure correct IsPod behavior.
424 template<typename T>
425 struct IsPod : public FalseType {};
427 template<> struct IsPod<char> : TrueType {};
428 template<> struct IsPod<signed char> : TrueType {};
429 template<> struct IsPod<unsigned char> : TrueType {};
430 template<> struct IsPod<short> : TrueType {};
431 template<> struct IsPod<unsigned short> : TrueType {};
432 template<> struct IsPod<int> : TrueType {};
433 template<> struct IsPod<unsigned int> : TrueType {};
434 template<> struct IsPod<long> : TrueType {};
435 template<> struct IsPod<unsigned long> : TrueType {};
436 template<> struct IsPod<long long> : TrueType {};
437 template<> struct IsPod<unsigned long long> : TrueType {};
438 template<> struct IsPod<bool> : TrueType {};
439 template<> struct IsPod<float> : TrueType {};
440 template<> struct IsPod<double> : TrueType {};
441 template<> struct IsPod<wchar_t> : TrueType {};
442 template<> struct IsPod<char16_t> : TrueType {};
443 template<typename T> struct IsPod<T*> : TrueType {};
445 namespace detail {
447 // __is_empty is a supported extension across all of our supported compilers:
448 // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
449 // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
450 // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
451 template<typename T>
452 struct IsEmptyHelper
453 : IntegralConstant<bool, IsClass<T>::value && __is_empty(T)>
456 } // namespace detail
459 * IsEmpty determines whether a type is a class (but not a union) that is empty.
461 * A class is empty iff it and all its base classes have no non-static data
462 * members (except bit-fields of length 0) and no virtual member functions, and
463 * no base class is empty or a virtual base class.
465 * Intuitively, empty classes don't have any data that has to be stored in
466 * instances of those classes. (The size of the class must still be non-zero,
467 * because distinct array elements of any type must have different addresses.
468 * However, if the Empty Base Optimization is implemented by the compiler [most
469 * compilers implement it, and in certain cases C++11 requires it], the size of
470 * a class inheriting from an empty |Base| class need not be inflated by
471 * |sizeof(Base)|.) And intuitively, non-empty classes have data members and/or
472 * vtable pointers that must be stored in each instance for proper behavior.
474 * static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty");
475 * union U1 { int x; };
476 * static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty");
477 * struct E1 {};
478 * struct E2 { int : 0 };
479 * struct E3 : E1 {};
480 * struct E4 : E2 {};
481 * static_assert(mozilla::IsEmpty<E1>::value &&
482 * mozilla::IsEmpty<E2>::value &&
483 * mozilla::IsEmpty<E3>::value &&
484 * mozilla::IsEmpty<E4>::value,
485 * "all empty");
486 * union U2 { E1 e1; };
487 * static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty");
488 * struct NE1 { int x; };
489 * struct NE2 : virtual E1 {};
490 * struct NE3 : E2 { virtual ~NE3() {} };
491 * struct NE4 { virtual void f() {} };
492 * static_assert(!mozilla::IsEmpty<NE1>::value &&
493 * !mozilla::IsEmpty<NE2>::value &&
494 * !mozilla::IsEmpty<NE3>::value &&
495 * !mozilla::IsEmpty<NE4>::value,
496 * "all empty");
498 template<typename T>
499 struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type>
503 namespace detail {
505 template<typename T,
506 bool = IsFloatingPoint<T>::value,
507 bool = IsIntegral<T>::value,
508 typename NoCV = typename RemoveCV<T>::Type>
509 struct IsSignedHelper;
511 // Floating point is signed.
512 template<typename T, typename NoCV>
513 struct IsSignedHelper<T, true, false, NoCV> : TrueType {};
515 // Integral is conditionally signed.
516 template<typename T, typename NoCV>
517 struct IsSignedHelper<T, false, true, NoCV>
518 : IntegralConstant<bool, bool(NoCV(-1) < NoCV(1))>
521 // Non-floating point, non-integral is not signed.
522 template<typename T, typename NoCV>
523 struct IsSignedHelper<T, false, false, NoCV> : FalseType {};
525 } // namespace detail
528 * IsSigned determines whether a type is a signed arithmetic type. |char| is
529 * considered a signed type if it has the same representation as |signed char|.
531 * mozilla::IsSigned<int>::value is true;
532 * mozilla::IsSigned<const unsigned int>::value is false;
533 * mozilla::IsSigned<unsigned char>::value is false;
534 * mozilla::IsSigned<float>::value is true.
536 template<typename T>
537 struct IsSigned : detail::IsSignedHelper<T> {};
539 namespace detail {
541 template<typename T,
542 bool = IsFloatingPoint<T>::value,
543 bool = IsIntegral<T>::value,
544 typename NoCV = typename RemoveCV<T>::Type>
545 struct IsUnsignedHelper;
547 // Floating point is not unsigned.
548 template<typename T, typename NoCV>
549 struct IsUnsignedHelper<T, true, false, NoCV> : FalseType {};
551 // Integral is conditionally unsigned.
552 template<typename T, typename NoCV>
553 struct IsUnsignedHelper<T, false, true, NoCV>
554 : IntegralConstant<bool,
555 (IsSame<NoCV, bool>::value || bool(NoCV(1) < NoCV(-1)))>
558 // Non-floating point, non-integral is not unsigned.
559 template<typename T, typename NoCV>
560 struct IsUnsignedHelper<T, false, false, NoCV> : FalseType {};
562 } // namespace detail
565 * IsUnsigned determines whether a type is an unsigned arithmetic type.
567 * mozilla::IsUnsigned<int>::value is false;
568 * mozilla::IsUnsigned<const unsigned int>::value is true;
569 * mozilla::IsUnsigned<unsigned char>::value is true;
570 * mozilla::IsUnsigned<float>::value is false.
572 template<typename T>
573 struct IsUnsigned : detail::IsUnsignedHelper<T> {};
575 namespace detail {
577 struct DoIsDefaultConstructibleImpl
579 template<typename T, typename = decltype(T())>
580 static TrueType test(int);
581 template<typename T>
582 static FalseType test(...);
585 template<typename T>
586 struct IsDefaultConstructibleImpl : public DoIsDefaultConstructibleImpl
588 typedef decltype(test<T>(0)) Type;
591 } // namespace detail
594 * IsDefaultConstructible determines whether a type has a public default
595 * constructor.
597 * struct S0 {}; // Implicit default constructor.
598 * struct S1 { S1(); };
599 * struct S2 { explicit S2(int); }; // No implicit default constructor when
600 * // another one is present.
601 * struct S3 { S3() = delete; };
602 * class C4 { C4(); }; // Default constructor is private.
604 * mozilla::IsDefaultConstructible<int>::value is true;
605 * mozilla::IsDefaultConstructible<S0>::value is true;
606 * mozilla::IsDefaultConstructible<S1>::value is true;
607 * mozilla::IsDefaultConstructible<S2>::value is false;
608 * mozilla::IsDefaultConstructible<S3>::value is false;
609 * mozilla::IsDefaultConstructible<S4>::value is false.
611 template<typename T>
612 struct IsDefaultConstructible
613 : public detail::IsDefaultConstructibleImpl<T>::Type
616 namespace detail {
618 struct DoIsDestructibleImpl
620 template<typename T, typename = decltype(DeclVal<T&>().~T())>
621 static TrueType test(int);
622 template<typename T>
623 static FalseType test(...);
626 template<typename T>
627 struct IsDestructibleImpl : public DoIsDestructibleImpl
629 typedef decltype(test<T>(0)) Type;
632 } // namespace detail
635 * IsDestructible determines whether a type has a public destructor.
637 * struct S0 {}; // Implicit default destructor.
638 * struct S1 { ~S1(); };
639 * class C2 { ~C2(); }; // private destructor.
641 * mozilla::IsDestructible<S0>::value is true;
642 * mozilla::IsDestructible<S1>::value is true;
643 * mozilla::IsDestructible<C2>::value is false.
645 template<typename T>
646 struct IsDestructible : public detail::IsDestructibleImpl<T>::Type {};
648 /* 20.9.5 Type property queries [meta.unary.prop.query] */
650 /* 20.9.6 Relationships between types [meta.rel] */
653 * IsSame tests whether two types are the same type.
655 * mozilla::IsSame<int, int>::value is true;
656 * mozilla::IsSame<int*, int*>::value is true;
657 * mozilla::IsSame<int, unsigned int>::value is false;
658 * mozilla::IsSame<void, void>::value is true;
659 * mozilla::IsSame<const int, int>::value is false;
660 * mozilla::IsSame<struct S, struct S>::value is true.
662 template<typename T, typename U>
663 struct IsSame : FalseType {};
665 template<typename T>
666 struct IsSame<T, T> : TrueType {};
668 namespace detail {
670 #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
672 template<class Base, class Derived>
673 struct BaseOfTester : IntegralConstant<bool, __is_base_of(Base, Derived)> {};
675 #else
677 // The trickery used to implement IsBaseOf here makes it possible to use it for
678 // the cases of private and multiple inheritance. This code was inspired by the
679 // sample code here:
681 // http://stackoverflow.com/questions/2910979/how-is-base-of-works
682 template<class Base, class Derived>
683 struct BaseOfHelper
685 public:
686 operator Base*() const;
687 operator Derived*();
690 template<class Base, class Derived>
691 struct BaseOfTester
693 private:
694 template<class T>
695 static char test(Derived*, T);
696 static int test(Base*, int);
698 public:
699 static const bool value =
700 sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
703 template<class Base, class Derived>
704 struct BaseOfTester<Base, const Derived>
706 private:
707 template<class T>
708 static char test(Derived*, T);
709 static int test(Base*, int);
711 public:
712 static const bool value =
713 sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
716 template<class Base, class Derived>
717 struct BaseOfTester<Base&, Derived&> : FalseType {};
719 template<class Type>
720 struct BaseOfTester<Type, Type> : TrueType {};
722 template<class Type>
723 struct BaseOfTester<Type, const Type> : TrueType {};
725 #endif
727 } /* namespace detail */
730 * IsBaseOf allows to know whether a given class is derived from another.
732 * Consider the following class definitions:
734 * class A {};
735 * class B : public A {};
736 * class C {};
738 * mozilla::IsBaseOf<A, B>::value is true;
739 * mozilla::IsBaseOf<A, C>::value is false;
741 template<class Base, class Derived>
742 struct IsBaseOf
743 : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value>
746 namespace detail {
748 template<typename From, typename To>
749 struct ConvertibleTester
751 private:
752 template<typename To1>
753 static char test_helper(To1);
755 template<typename From1, typename To1>
756 static decltype(test_helper<To1>(DeclVal<From1>())) test(int);
758 template<typename From1, typename To1>
759 static int test(...);
761 public:
762 static const bool value =
763 sizeof(test<From, To>(0)) == sizeof(char);
766 } // namespace detail
769 * IsConvertible determines whether a value of type From will implicitly convert
770 * to a value of type To. For example:
772 * struct A {};
773 * struct B : public A {};
774 * struct C {};
776 * mozilla::IsConvertible<A, A>::value is true;
777 * mozilla::IsConvertible<A*, A*>::value is true;
778 * mozilla::IsConvertible<B, A>::value is true;
779 * mozilla::IsConvertible<B*, A*>::value is true;
780 * mozilla::IsConvertible<C, A>::value is false;
781 * mozilla::IsConvertible<A, C>::value is false;
782 * mozilla::IsConvertible<A*, C*>::value is false;
783 * mozilla::IsConvertible<C*, A*>::value is false.
785 * For obscure reasons, you can't use IsConvertible when the types being tested
786 * are related through private inheritance, and you'll get a compile error if
787 * you try. Just don't do it!
789 * Note - we need special handling for void, which ConvertibleTester doesn't
790 * handle. The void handling here doesn't handle const/volatile void correctly,
791 * which could be easily fixed if the need arises.
793 template<typename From, typename To>
794 struct IsConvertible
795 : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value>
798 template<typename B>
799 struct IsConvertible<void, B>
800 : IntegralConstant<bool, IsVoid<B>::value>
803 template<typename A>
804 struct IsConvertible<A, void>
805 : IntegralConstant<bool, IsVoid<A>::value>
808 template<>
809 struct IsConvertible<void, void>
810 : TrueType
813 /* 20.9.7 Transformations between types [meta.trans] */
815 /* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
818 * RemoveConst removes top-level const qualifications on a type.
820 * mozilla::RemoveConst<int>::Type is int;
821 * mozilla::RemoveConst<const int>::Type is int;
822 * mozilla::RemoveConst<const int*>::Type is const int*;
823 * mozilla::RemoveConst<int* const>::Type is int*.
825 template<typename T>
826 struct RemoveConst
828 typedef T Type;
831 template<typename T>
832 struct RemoveConst<const T>
834 typedef T Type;
838 * RemoveVolatile removes top-level volatile qualifications on a type.
840 * mozilla::RemoveVolatile<int>::Type is int;
841 * mozilla::RemoveVolatile<volatile int>::Type is int;
842 * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*;
843 * mozilla::RemoveVolatile<int* volatile>::Type is int*.
845 template<typename T>
846 struct RemoveVolatile
848 typedef T Type;
851 template<typename T>
852 struct RemoveVolatile<volatile T>
854 typedef T Type;
858 * RemoveCV removes top-level const and volatile qualifications on a type.
860 * mozilla::RemoveCV<int>::Type is int;
861 * mozilla::RemoveCV<const int>::Type is int;
862 * mozilla::RemoveCV<volatile int>::Type is int;
863 * mozilla::RemoveCV<int* const volatile>::Type is int*.
865 template<typename T>
866 struct RemoveCV
868 typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
871 /* 20.9.7.2 Reference modifications [meta.trans.ref] */
874 * Converts reference types to the underlying types.
876 * mozilla::RemoveReference<T>::Type is T;
877 * mozilla::RemoveReference<T&>::Type is T;
878 * mozilla::RemoveReference<T&&>::Type is T;
881 template<typename T>
882 struct RemoveReference
884 typedef T Type;
887 template<typename T>
888 struct RemoveReference<T&>
890 typedef T Type;
893 template<typename T>
894 struct RemoveReference<T&&>
896 typedef T Type;
899 template<bool Condition, typename A, typename B>
900 struct Conditional;
902 namespace detail {
904 enum Voidness { TIsVoid, TIsNotVoid };
906 template<typename T, Voidness V = IsVoid<T>::value ? TIsVoid : TIsNotVoid>
907 struct AddLvalueReferenceHelper;
909 template<typename T>
910 struct AddLvalueReferenceHelper<T, TIsVoid>
912 typedef void Type;
915 template<typename T>
916 struct AddLvalueReferenceHelper<T, TIsNotVoid>
918 typedef T& Type;
921 } // namespace detail
924 * AddLvalueReference adds an lvalue & reference to T if one isn't already
925 * present. (Note: adding an lvalue reference to an rvalue && reference in
926 * essence replaces the && with a &&, per C+11 reference collapsing rules. For
927 * example, int&& would become int&.)
929 * The final computed type will only *not* be an lvalue reference if T is void.
931 * mozilla::AddLvalueReference<int>::Type is int&;
932 * mozilla::AddLvalueRference<volatile int&>::Type is volatile int&;
933 * mozilla::AddLvalueReference<void*>::Type is void*&;
934 * mozilla::AddLvalueReference<void>::Type is void;
935 * mozilla::AddLvalueReference<struct S&&>::Type is struct S&.
937 template<typename T>
938 struct AddLvalueReference
939 : detail::AddLvalueReferenceHelper<T>
942 namespace detail {
944 template<typename T, Voidness V = IsVoid<T>::value ? TIsVoid : TIsNotVoid>
945 struct AddRvalueReferenceHelper;
947 template<typename T>
948 struct AddRvalueReferenceHelper<T, TIsVoid>
950 typedef void Type;
953 template<typename T>
954 struct AddRvalueReferenceHelper<T, TIsNotVoid>
956 typedef T&& Type;
959 } // namespace detail
962 * AddRvalueReference adds an rvalue && reference to T if one isn't already
963 * present. (Note: adding an rvalue reference to an lvalue & reference in
964 * essence keeps the &, per C+11 reference collapsing rules. For example,
965 * int& would remain int&.)
967 * The final computed type will only *not* be a reference if T is void.
969 * mozilla::AddRvalueReference<int>::Type is int&&;
970 * mozilla::AddRvalueRference<volatile int&>::Type is volatile int&;
971 * mozilla::AddRvalueRference<const int&&>::Type is const int&&;
972 * mozilla::AddRvalueReference<void*>::Type is void*&&;
973 * mozilla::AddRvalueReference<void>::Type is void;
974 * mozilla::AddRvalueReference<struct S&>::Type is struct S&.
976 template<typename T>
977 struct AddRvalueReference
978 : detail::AddRvalueReferenceHelper<T>
981 /* 20.9.7.3 Sign modifications [meta.trans.sign] */
983 template<bool B, typename T = void>
984 struct EnableIf;
986 namespace detail {
988 template<bool MakeConst, typename T>
989 struct WithC : Conditional<MakeConst, const T, T>
992 template<bool MakeVolatile, typename T>
993 struct WithV : Conditional<MakeVolatile, volatile T, T>
997 template<bool MakeConst, bool MakeVolatile, typename T>
998 struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type>
1001 template<typename T>
1002 struct CorrespondingSigned;
1004 template<>
1005 struct CorrespondingSigned<char> { typedef signed char Type; };
1006 template<>
1007 struct CorrespondingSigned<unsigned char> { typedef signed char Type; };
1008 template<>
1009 struct CorrespondingSigned<unsigned short> { typedef short Type; };
1010 template<>
1011 struct CorrespondingSigned<unsigned int> { typedef int Type; };
1012 template<>
1013 struct CorrespondingSigned<unsigned long> { typedef long Type; };
1014 template<>
1015 struct CorrespondingSigned<unsigned long long> { typedef long long Type; };
1017 template<typename T,
1018 typename CVRemoved = typename RemoveCV<T>::Type,
1019 bool IsSignedIntegerType = IsSigned<CVRemoved>::value &&
1020 !IsSame<char, CVRemoved>::value>
1021 struct MakeSigned;
1023 template<typename T, typename CVRemoved>
1024 struct MakeSigned<T, CVRemoved, true>
1026 typedef T Type;
1029 template<typename T, typename CVRemoved>
1030 struct MakeSigned<T, CVRemoved, false>
1031 : WithCV<IsConst<T>::value, IsVolatile<T>::value,
1032 typename CorrespondingSigned<CVRemoved>::Type>
1035 } // namespace detail
1038 * MakeSigned produces the corresponding signed integer type for a given
1039 * integral type T, with the const/volatile qualifiers of T. T must be a
1040 * possibly-const/volatile-qualified integral type that isn't bool.
1042 * If T is already a signed integer type (not including char!), then T is
1043 * produced.
1045 * Otherwise, if T is an unsigned integer type, the signed variety of T, with
1046 * T's const/volatile qualifiers, is produced.
1048 * Otherwise, the integral type of the same size as T, with the lowest rank,
1049 * with T's const/volatile qualifiers, is produced. (This basically only acts
1050 * to produce signed char when T = char.)
1052 * mozilla::MakeSigned<unsigned long>::Type is signed long;
1053 * mozilla::MakeSigned<volatile int>::Type is volatile int;
1054 * mozilla::MakeSigned<const unsigned short>::Type is const signed short;
1055 * mozilla::MakeSigned<const char>::Type is const signed char;
1056 * mozilla::MakeSigned<bool> is an error;
1057 * mozilla::MakeSigned<void*> is an error.
1059 template<typename T>
1060 struct MakeSigned
1061 : EnableIf<IsIntegral<T>::value &&
1062 !IsSame<bool, typename RemoveCV<T>::Type>::value,
1063 typename detail::MakeSigned<T>
1064 >::Type
1067 namespace detail {
1069 template<typename T>
1070 struct CorrespondingUnsigned;
1072 template<>
1073 struct CorrespondingUnsigned<char> { typedef unsigned char Type; };
1074 template<>
1075 struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; };
1076 template<>
1077 struct CorrespondingUnsigned<short> { typedef unsigned short Type; };
1078 template<>
1079 struct CorrespondingUnsigned<int> { typedef unsigned int Type; };
1080 template<>
1081 struct CorrespondingUnsigned<long> { typedef unsigned long Type; };
1082 template<>
1083 struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; };
1086 template<typename T,
1087 typename CVRemoved = typename RemoveCV<T>::Type,
1088 bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value &&
1089 !IsSame<char, CVRemoved>::value>
1090 struct MakeUnsigned;
1092 template<typename T, typename CVRemoved>
1093 struct MakeUnsigned<T, CVRemoved, true>
1095 typedef T Type;
1098 template<typename T, typename CVRemoved>
1099 struct MakeUnsigned<T, CVRemoved, false>
1100 : WithCV<IsConst<T>::value, IsVolatile<T>::value,
1101 typename CorrespondingUnsigned<CVRemoved>::Type>
1104 } // namespace detail
1107 * MakeUnsigned produces the corresponding unsigned integer type for a given
1108 * integral type T, with the const/volatile qualifiers of T. T must be a
1109 * possibly-const/volatile-qualified integral type that isn't bool.
1111 * If T is already an unsigned integer type (not including char!), then T is
1112 * produced.
1114 * Otherwise, if T is an signed integer type, the unsigned variety of T, with
1115 * T's const/volatile qualifiers, is produced.
1117 * Otherwise, the unsigned integral type of the same size as T, with the lowest
1118 * rank, with T's const/volatile qualifiers, is produced. (This basically only
1119 * acts to produce unsigned char when T = char.)
1121 * mozilla::MakeUnsigned<signed long>::Type is unsigned long;
1122 * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int;
1123 * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short;
1124 * mozilla::MakeUnsigned<const char>::Type is const unsigned char;
1125 * mozilla::MakeUnsigned<bool> is an error;
1126 * mozilla::MakeUnsigned<void*> is an error.
1128 template<typename T>
1129 struct MakeUnsigned
1130 : EnableIf<IsIntegral<T>::value &&
1131 !IsSame<bool, typename RemoveCV<T>::Type>::value,
1132 typename detail::MakeUnsigned<T>
1133 >::Type
1136 /* 20.9.7.4 Array modifications [meta.trans.arr] */
1139 * RemoveExtent produces either the type of the elements of the array T, or T
1140 * itself.
1142 * mozilla::RemoveExtent<int>::Type is int;
1143 * mozilla::RemoveExtent<const int[]>::Type is const int;
1144 * mozilla::RemoveExtent<volatile int[5]>::Type is volatile int;
1145 * mozilla::RemoveExtent<long[][17]>::Type is long[17].
1147 template<typename T>
1148 struct RemoveExtent
1150 typedef T Type;
1153 template<typename T>
1154 struct RemoveExtent<T[]>
1156 typedef T Type;
1159 template<typename T, decltype(sizeof(1)) N>
1160 struct RemoveExtent<T[N]>
1162 typedef T Type;
1165 /* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
1167 namespace detail {
1169 template<typename T, typename CVRemoved>
1170 struct RemovePointerHelper
1172 typedef T Type;
1175 template<typename T, typename Pointee>
1176 struct RemovePointerHelper<T, Pointee*>
1178 typedef Pointee Type;
1181 } // namespace detail
1184 * Produces the pointed-to type if a pointer is provided, else returns the input
1185 * type. Note that this does not dereference pointer-to-member pointers.
1187 * struct S { bool m; void f(); };
1188 * mozilla::RemovePointer<int>::Type is int;
1189 * mozilla::RemovePointer<int*>::Type is int;
1190 * mozilla::RemovePointer<int* const>::Type is int;
1191 * mozilla::RemovePointer<int* volatile>::Type is int;
1192 * mozilla::RemovePointer<const long*>::Type is const long;
1193 * mozilla::RemovePointer<void* const>::Type is void;
1194 * mozilla::RemovePointer<void (S::*)()>::Type is void (S::*)();
1195 * mozilla::RemovePointer<void (*)()>::Type is void();
1196 * mozilla::RemovePointer<bool S::*>::Type is bool S::*.
1198 template<typename T>
1199 struct RemovePointer
1200 : detail::RemovePointerHelper<T, typename RemoveCV<T>::Type>
1204 * Converts T& to T*. Otherwise returns T* given T. Note that C++17 wants
1205 * std::add_pointer to work differently for function types. We don't implement
1206 * that behavior here.
1208 * mozilla::AddPointer<int> is int*;
1209 * mozilla::AddPointer<int*> is int**;
1210 * mozilla::AddPointer<int&> is int*;
1211 * mozilla::AddPointer<int* const> is int** const.
1213 template<typename T>
1214 struct AddPointer
1216 typedef typename RemoveReference<T>::Type* Type;
1219 /* 20.9.7.6 Other transformations [meta.trans.other] */
1222 * EnableIf is a struct containing a typedef of T if and only if B is true.
1224 * mozilla::EnableIf<true, int>::Type is int;
1225 * mozilla::EnableIf<false, int>::Type is a compile-time error.
1227 * Use this template to implement SFINAE-style (Substitution Failure Is not An
1228 * Error) requirements. For example, you might use it to impose a restriction
1229 * on a template parameter:
1231 * template<typename T>
1232 * class PodVector // vector optimized to store POD (memcpy-able) types
1234 * EnableIf<IsPod<T>::value, T>::Type* vector;
1235 * size_t length;
1236 * ...
1237 * };
1239 template<bool B, typename T>
1240 struct EnableIf
1243 template<typename T>
1244 struct EnableIf<true, T>
1246 typedef T Type;
1250 * Conditional selects a class between two, depending on a given boolean value.
1252 * mozilla::Conditional<true, A, B>::Type is A;
1253 * mozilla::Conditional<false, A, B>::Type is B;
1255 template<bool Condition, typename A, typename B>
1256 struct Conditional
1258 typedef A Type;
1261 template<class A, class B>
1262 struct Conditional<false, A, B>
1264 typedef B Type;
1267 namespace detail {
1269 template<typename U,
1270 bool IsArray = IsArray<U>::value,
1271 bool IsFunction = IsFunction<U>::value>
1272 struct DecaySelector;
1274 template<typename U>
1275 struct DecaySelector<U, false, false>
1277 typedef typename RemoveCV<U>::Type Type;
1280 template<typename U>
1281 struct DecaySelector<U, true, false>
1283 typedef typename RemoveExtent<U>::Type* Type;
1286 template<typename U>
1287 struct DecaySelector<U, false, true>
1289 typedef typename AddPointer<U>::Type Type;
1292 }; // namespace detail
1295 * Strips const/volatile off a type and decays it from an lvalue to an
1296 * rvalue. So function types are converted to function pointers, arrays to
1297 * pointers, and references are removed.
1299 * mozilla::Decay<int>::Type is int
1300 * mozilla::Decay<int&>::Type is int
1301 * mozilla::Decay<int&&>::Type is int
1302 * mozilla::Decay<const int&>::Type is int
1303 * mozilla::Decay<int[2]>::Type is int*
1304 * mozilla::Decay<int(int)>::Type is int(*)(int)
1306 template<typename T>
1307 class Decay
1308 : public detail::DecaySelector<typename RemoveReference<T>::Type>
1312 } /* namespace mozilla */
1314 #endif /* mozilla_TypeTraits_h */