Bumping manifests a=b2g-bump
[gecko.git] / mfbt / TypeTraits.h
blob515c68d94ec65855799eee8fa1461f45246291df
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;
28 /* 20.9.3 Helper classes [meta.help] */
30 /**
31 * Helper class used as a base for various type traits, exposed publicly
32 * because <type_traits> exposes it as well.
34 template<typename T, T Value>
35 struct IntegralConstant
37 static const T value = Value;
38 typedef T ValueType;
39 typedef IntegralConstant<T, Value> Type;
42 /** Convenient aliases. */
43 typedef IntegralConstant<bool, true> TrueType;
44 typedef IntegralConstant<bool, false> FalseType;
46 /* 20.9.4 Unary type traits [meta.unary] */
48 /* 20.9.4.1 Primary type categories [meta.unary.cat] */
50 namespace detail {
52 template<typename T>
53 struct IsVoidHelper : FalseType {};
55 template<>
56 struct IsVoidHelper<void> : TrueType {};
58 } // namespace detail
60 /**
61 * IsVoid determines whether a type is void.
63 * mozilla::IsVoid<int>::value is false;
64 * mozilla::IsVoid<void>::value is true;
65 * mozilla::IsVoid<void*>::value is false;
66 * mozilla::IsVoid<volatile void>::value is true.
68 template<typename T>
69 struct IsVoid : detail::IsVoidHelper<typename RemoveCV<T>::Type> {};
71 namespace detail {
73 template <typename T>
74 struct IsIntegralHelper : FalseType {};
76 template<> struct IsIntegralHelper<char> : TrueType {};
77 template<> struct IsIntegralHelper<signed char> : TrueType {};
78 template<> struct IsIntegralHelper<unsigned char> : TrueType {};
79 template<> struct IsIntegralHelper<short> : TrueType {};
80 template<> struct IsIntegralHelper<unsigned short> : TrueType {};
81 template<> struct IsIntegralHelper<int> : TrueType {};
82 template<> struct IsIntegralHelper<unsigned int> : TrueType {};
83 template<> struct IsIntegralHelper<long> : TrueType {};
84 template<> struct IsIntegralHelper<unsigned long> : TrueType {};
85 template<> struct IsIntegralHelper<long long> : TrueType {};
86 template<> struct IsIntegralHelper<unsigned long long> : TrueType {};
87 template<> struct IsIntegralHelper<bool> : TrueType {};
88 template<> struct IsIntegralHelper<wchar_t> : TrueType {};
89 #ifdef MOZ_CHAR16_IS_NOT_WCHAR
90 template<> struct IsIntegralHelper<char16_t> : TrueType {};
91 #endif
93 } /* namespace detail */
95 /**
96 * IsIntegral determines whether a type is an integral type.
98 * mozilla::IsIntegral<int>::value is true;
99 * mozilla::IsIntegral<unsigned short>::value is true;
100 * mozilla::IsIntegral<const long>::value is true;
101 * mozilla::IsIntegral<int*>::value is false;
102 * mozilla::IsIntegral<double>::value is false;
104 * Note that the behavior of IsIntegral on char16_t and char32_t is
105 * unspecified.
107 template<typename T>
108 struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type>
111 template<typename T, typename U>
112 struct IsSame;
114 namespace detail {
116 template<typename T>
117 struct IsFloatingPointHelper
118 : IntegralConstant<bool,
119 IsSame<T, float>::value ||
120 IsSame<T, double>::value ||
121 IsSame<T, long double>::value>
124 } // namespace detail
127 * IsFloatingPoint determines whether a type is a floating point type (float,
128 * double, long double).
130 * mozilla::IsFloatingPoint<int>::value is false;
131 * mozilla::IsFloatingPoint<const float>::value is true;
132 * mozilla::IsFloatingPoint<long double>::value is true;
133 * mozilla::IsFloatingPoint<double*>::value is false.
135 template<typename T>
136 struct IsFloatingPoint
137 : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type>
140 namespace detail {
142 template<typename T>
143 struct IsArrayHelper : FalseType {};
145 template<typename T, decltype(sizeof(1)) N>
146 struct IsArrayHelper<T[N]> : TrueType {};
148 template<typename T>
149 struct IsArrayHelper<T[]> : TrueType {};
151 } // namespace detail
154 * IsArray determines whether a type is an array type, of known or unknown
155 * length.
157 * mozilla::IsArray<int>::value is false;
158 * mozilla::IsArray<int[]>::value is true;
159 * mozilla::IsArray<int[5]>::value is true.
161 template<typename T>
162 struct IsArray : detail::IsArrayHelper<typename RemoveCV<T>::Type>
166 * IsPointer determines whether a type is a pointer type (but not a pointer-to-
167 * member type).
169 * mozilla::IsPointer<struct S*>::value is true;
170 * mozilla::IsPointer<int**>::value is true;
171 * mozilla::IsPointer<void (*)(void)>::value is true;
172 * mozilla::IsPointer<int>::value is false;
173 * mozilla::IsPointer<struct S>::value is false.
175 template<typename T>
176 struct IsPointer : FalseType {};
178 template<typename T>
179 struct IsPointer<T*> : TrueType {};
182 * IsLvalueReference determines whether a type is an lvalue reference.
184 * mozilla::IsLvalueReference<struct S*>::value is false;
185 * mozilla::IsLvalueReference<int**>::value is false;
186 * mozilla::IsLvalueReference<void (*)(void)>::value is false;
187 * mozilla::IsLvalueReference<int>::value is false;
188 * mozilla::IsLvalueReference<struct S>::value is false;
189 * mozilla::IsLvalueReference<struct S*&>::value is true;
190 * mozilla::IsLvalueReference<struct S&&>::value is false.
192 template<typename T>
193 struct IsLvalueReference : FalseType {};
195 template<typename T>
196 struct IsLvalueReference<T&> : TrueType {};
199 * IsRvalueReference determines whether a type is an rvalue reference.
201 * mozilla::IsRvalueReference<struct S*>::value is false;
202 * mozilla::IsRvalueReference<int**>::value is false;
203 * mozilla::IsRvalueReference<void (*)(void)>::value is false;
204 * mozilla::IsRvalueReference<int>::value is false;
205 * mozilla::IsRvalueReference<struct S>::value is false;
206 * mozilla::IsRvalueReference<struct S*&>::value is false;
207 * mozilla::IsRvalueReference<struct S&&>::value is true.
209 template<typename T>
210 struct IsRvalueReference : FalseType {};
212 template<typename T>
213 struct IsRvalueReference<T&&> : TrueType {};
215 namespace detail {
217 // __is_enum is a supported extension across all of our supported compilers.
218 template<typename T>
219 struct IsEnumHelper
220 : IntegralConstant<bool, __is_enum(T)>
223 } // namespace detail
226 * IsEnum determines whether a type is an enum type.
228 * mozilla::IsEnum<enum S>::value is true;
229 * mozilla::IsEnum<enum S*>::value is false;
230 * mozilla::IsEnum<int>::value is false;
232 template<typename T>
233 struct IsEnum
234 : detail::IsEnumHelper<typename RemoveCV<T>::Type>
237 namespace detail {
239 // __is_class is a supported extension across all of our supported compilers:
240 // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
241 // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
242 // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
243 template<typename T>
244 struct IsClassHelper
245 : IntegralConstant<bool, __is_class(T)>
248 } // namespace detail
251 * IsClass determines whether a type is a class type (but not a union).
253 * struct S {};
254 * union U {};
255 * mozilla::IsClass<int>::value is false;
256 * mozilla::IsClass<const S>::value is true;
257 * mozilla::IsClass<U>::value is false;
259 template<typename T>
260 struct IsClass
261 : detail::IsClassHelper<typename RemoveCV<T>::Type>
264 /* 20.9.4.2 Composite type traits [meta.unary.comp] */
267 * IsReference determines whether a type is an lvalue or rvalue reference.
269 * mozilla::IsReference<struct S*>::value is false;
270 * mozilla::IsReference<int**>::value is false;
271 * mozilla::IsReference<int&>::value is true;
272 * mozilla::IsReference<void (*)(void)>::value is false;
273 * mozilla::IsReference<const int&>::value is true;
274 * mozilla::IsReference<int>::value is false;
275 * mozilla::IsReference<struct S>::value is false;
276 * mozilla::IsReference<struct S&>::value is true;
277 * mozilla::IsReference<struct S*&>::value is true;
278 * mozilla::IsReference<struct S&&>::value is true.
280 template<typename T>
281 struct IsReference
282 : IntegralConstant<bool,
283 IsLvalueReference<T>::value || IsRvalueReference<T>::value>
287 * IsArithmetic determines whether a type is arithmetic. A type is arithmetic
288 * iff it is an integral type or a floating point type.
290 * mozilla::IsArithmetic<int>::value is true;
291 * mozilla::IsArithmetic<double>::value is true;
292 * mozilla::IsArithmetic<long double*>::value is false.
294 template<typename T>
295 struct IsArithmetic
296 : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value>
299 /* 20.9.4.3 Type properties [meta.unary.prop] */
302 * IsConst determines whether a type is const or not.
304 * mozilla::IsConst<int>::value is false;
305 * mozilla::IsConst<void* const>::value is true;
306 * mozilla::IsConst<const char*>::value is false.
308 template<typename T>
309 struct IsConst : FalseType {};
311 template<typename T>
312 struct IsConst<const T> : TrueType {};
315 * IsVolatile determines whether a type is volatile or not.
317 * mozilla::IsVolatile<int>::value is false;
318 * mozilla::IsVolatile<void* volatile>::value is true;
319 * mozilla::IsVolatile<volatile char*>::value is false.
321 template<typename T>
322 struct IsVolatile : FalseType {};
324 template<typename T>
325 struct IsVolatile<volatile T> : TrueType {};
328 * Traits class for identifying POD types. Until C++11 there's no automatic
329 * way to detect PODs, so for the moment this is done manually. Users may
330 * define specializations of this class that inherit from mozilla::TrueType and
331 * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or
332 * false>, or conveniently from mozilla::IsPod for composite types) as needed to
333 * ensure correct IsPod behavior.
335 template<typename T>
336 struct IsPod : public FalseType {};
338 template<> struct IsPod<char> : TrueType {};
339 template<> struct IsPod<signed char> : TrueType {};
340 template<> struct IsPod<unsigned char> : TrueType {};
341 template<> struct IsPod<short> : TrueType {};
342 template<> struct IsPod<unsigned short> : TrueType {};
343 template<> struct IsPod<int> : TrueType {};
344 template<> struct IsPod<unsigned int> : TrueType {};
345 template<> struct IsPod<long> : TrueType {};
346 template<> struct IsPod<unsigned long> : TrueType {};
347 template<> struct IsPod<long long> : TrueType {};
348 template<> struct IsPod<unsigned long long> : TrueType {};
349 template<> struct IsPod<bool> : TrueType {};
350 template<> struct IsPod<float> : TrueType {};
351 template<> struct IsPod<double> : TrueType {};
352 template<> struct IsPod<wchar_t> : TrueType {};
353 #ifdef MOZ_CHAR16_IS_NOT_WCHAR
354 template<> struct IsPod<char16_t> : TrueType {};
355 #endif
356 template<typename T> struct IsPod<T*> : TrueType {};
358 namespace detail {
360 // __is_empty is a supported extension across all of our supported compilers:
361 // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
362 // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
363 // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
364 template<typename T>
365 struct IsEmptyHelper
366 : IntegralConstant<bool, IsClass<T>::value && __is_empty(T)>
369 } // namespace detail
372 * IsEmpty determines whether a type is a class (but not a union) that is empty.
374 * A class is empty iff it and all its base classes have no non-static data
375 * members (except bit-fields of length 0) and no virtual member functions, and
376 * no base class is empty or a virtual base class.
378 * Intuitively, empty classes don't have any data that has to be stored in
379 * instances of those classes. (The size of the class must still be non-zero,
380 * because distinct array elements of any type must have different addresses.
381 * However, if the Empty Base Optimization is implemented by the compiler [most
382 * compilers implement it, and in certain cases C++11 requires it], the size of
383 * a class inheriting from an empty |Base| class need not be inflated by
384 * |sizeof(Base)|.) And intuitively, non-empty classes have data members and/or
385 * vtable pointers that must be stored in each instance for proper behavior.
387 * static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty");
388 * union U1 { int x; };
389 * static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty");
390 * struct E1 {};
391 * struct E2 { int : 0 };
392 * struct E3 : E1 {};
393 * struct E4 : E2 {};
394 * static_assert(mozilla::IsEmpty<E1>::value &&
395 * mozilla::IsEmpty<E2>::value &&
396 * mozilla::IsEmpty<E3>::value &&
397 * mozilla::IsEmpty<E4>::value,
398 * "all empty");
399 * union U2 { E1 e1; };
400 * static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty");
401 * struct NE1 { int x; };
402 * struct NE2 : virtual E1 {};
403 * struct NE3 : E2 { virtual ~NE3() {} };
404 * struct NE4 { virtual void f() {} };
405 * static_assert(!mozilla::IsEmpty<NE1>::value &&
406 * !mozilla::IsEmpty<NE2>::value &&
407 * !mozilla::IsEmpty<NE3>::value &&
408 * !mozilla::IsEmpty<NE4>::value,
409 * "all empty");
411 template<typename T>
412 struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type>
416 namespace detail {
418 template<typename T,
419 bool = IsFloatingPoint<T>::value,
420 bool = IsIntegral<T>::value,
421 typename NoCV = typename RemoveCV<T>::Type>
422 struct IsSignedHelper;
424 // Floating point is signed.
425 template<typename T, typename NoCV>
426 struct IsSignedHelper<T, true, false, NoCV> : TrueType {};
428 // Integral is conditionally signed.
429 template<typename T, typename NoCV>
430 struct IsSignedHelper<T, false, true, NoCV>
431 : IntegralConstant<bool, bool(NoCV(-1) < NoCV(1))>
434 // Non-floating point, non-integral is not signed.
435 template<typename T, typename NoCV>
436 struct IsSignedHelper<T, false, false, NoCV> : FalseType {};
438 } // namespace detail
441 * IsSigned determines whether a type is a signed arithmetic type. |char| is
442 * considered a signed type if it has the same representation as |signed char|.
444 * mozilla::IsSigned<int>::value is true;
445 * mozilla::IsSigned<const unsigned int>::value is false;
446 * mozilla::IsSigned<unsigned char>::value is false;
447 * mozilla::IsSigned<float>::value is true.
449 template<typename T>
450 struct IsSigned : detail::IsSignedHelper<T> {};
452 namespace detail {
454 template<typename T,
455 bool = IsFloatingPoint<T>::value,
456 bool = IsIntegral<T>::value,
457 typename NoCV = typename RemoveCV<T>::Type>
458 struct IsUnsignedHelper;
460 // Floating point is not unsigned.
461 template<typename T, typename NoCV>
462 struct IsUnsignedHelper<T, true, false, NoCV> : FalseType {};
464 // Integral is conditionally unsigned.
465 template<typename T, typename NoCV>
466 struct IsUnsignedHelper<T, false, true, NoCV>
467 : IntegralConstant<bool,
468 (IsSame<NoCV, bool>::value || bool(NoCV(1) < NoCV(-1)))>
471 // Non-floating point, non-integral is not unsigned.
472 template<typename T, typename NoCV>
473 struct IsUnsignedHelper<T, false, false, NoCV> : FalseType {};
475 } // namespace detail
478 * IsUnsigned determines whether a type is an unsigned arithmetic type.
480 * mozilla::IsUnsigned<int>::value is false;
481 * mozilla::IsUnsigned<const unsigned int>::value is true;
482 * mozilla::IsUnsigned<unsigned char>::value is true;
483 * mozilla::IsUnsigned<float>::value is false.
485 template<typename T>
486 struct IsUnsigned : detail::IsUnsignedHelper<T> {};
488 /* 20.9.5 Type property queries [meta.unary.prop.query] */
490 /* 20.9.6 Relationships between types [meta.rel] */
493 * IsSame tests whether two types are the same type.
495 * mozilla::IsSame<int, int>::value is true;
496 * mozilla::IsSame<int*, int*>::value is true;
497 * mozilla::IsSame<int, unsigned int>::value is false;
498 * mozilla::IsSame<void, void>::value is true;
499 * mozilla::IsSame<const int, int>::value is false;
500 * mozilla::IsSame<struct S, struct S>::value is true.
502 template<typename T, typename U>
503 struct IsSame : FalseType {};
505 template<typename T>
506 struct IsSame<T, T> : TrueType {};
508 namespace detail {
510 #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
512 template<class Base, class Derived>
513 struct BaseOfTester : IntegralConstant<bool, __is_base_of(Base, Derived)> {};
515 #else
517 // The trickery used to implement IsBaseOf here makes it possible to use it for
518 // the cases of private and multiple inheritance. This code was inspired by the
519 // sample code here:
521 // http://stackoverflow.com/questions/2910979/how-is-base-of-works
522 template<class Base, class Derived>
523 struct BaseOfHelper
525 public:
526 operator Base*() const;
527 operator Derived*();
530 template<class Base, class Derived>
531 struct BaseOfTester
533 private:
534 template<class T>
535 static char test(Derived*, T);
536 static int test(Base*, int);
538 public:
539 static const bool value =
540 sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
543 template<class Base, class Derived>
544 struct BaseOfTester<Base, const Derived>
546 private:
547 template<class T>
548 static char test(Derived*, T);
549 static int test(Base*, int);
551 public:
552 static const bool value =
553 sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
556 template<class Base, class Derived>
557 struct BaseOfTester<Base&, Derived&> : FalseType {};
559 template<class Type>
560 struct BaseOfTester<Type, Type> : TrueType {};
562 template<class Type>
563 struct BaseOfTester<Type, const Type> : TrueType {};
565 #endif
567 } /* namespace detail */
570 * IsBaseOf allows to know whether a given class is derived from another.
572 * Consider the following class definitions:
574 * class A {};
575 * class B : public A {};
576 * class C {};
578 * mozilla::IsBaseOf<A, B>::value is true;
579 * mozilla::IsBaseOf<A, C>::value is false;
581 template<class Base, class Derived>
582 struct IsBaseOf
583 : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value>
586 namespace detail {
588 template<typename From, typename To>
589 struct ConvertibleTester
591 private:
592 static From create();
594 template<typename From1, typename To1>
595 static char test(To to);
597 template<typename From1, typename To1>
598 static int test(...);
600 public:
601 static const bool value =
602 sizeof(test<From, To>(create())) == sizeof(char);
605 } // namespace detail
608 * IsConvertible determines whether a value of type From will implicitly convert
609 * to a value of type To. For example:
611 * struct A {};
612 * struct B : public A {};
613 * struct C {};
615 * mozilla::IsConvertible<A, A>::value is true;
616 * mozilla::IsConvertible<A*, A*>::value is true;
617 * mozilla::IsConvertible<B, A>::value is true;
618 * mozilla::IsConvertible<B*, A*>::value is true;
619 * mozilla::IsConvertible<C, A>::value is false;
620 * mozilla::IsConvertible<A, C>::value is false;
621 * mozilla::IsConvertible<A*, C*>::value is false;
622 * mozilla::IsConvertible<C*, A*>::value is false.
624 * For obscure reasons, you can't use IsConvertible when the types being tested
625 * are related through private inheritance, and you'll get a compile error if
626 * you try. Just don't do it!
628 template<typename From, typename To>
629 struct IsConvertible
630 : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value>
633 /* 20.9.7 Transformations between types [meta.trans] */
635 /* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
638 * RemoveConst removes top-level const qualifications on a type.
640 * mozilla::RemoveConst<int>::Type is int;
641 * mozilla::RemoveConst<const int>::Type is int;
642 * mozilla::RemoveConst<const int*>::Type is const int*;
643 * mozilla::RemoveConst<int* const>::Type is int*.
645 template<typename T>
646 struct RemoveConst
648 typedef T Type;
651 template<typename T>
652 struct RemoveConst<const T>
654 typedef T Type;
658 * RemoveVolatile removes top-level volatile qualifications on a type.
660 * mozilla::RemoveVolatile<int>::Type is int;
661 * mozilla::RemoveVolatile<volatile int>::Type is int;
662 * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*;
663 * mozilla::RemoveVolatile<int* volatile>::Type is int*.
665 template<typename T>
666 struct RemoveVolatile
668 typedef T Type;
671 template<typename T>
672 struct RemoveVolatile<volatile T>
674 typedef T Type;
678 * RemoveCV removes top-level const and volatile qualifications on a type.
680 * mozilla::RemoveCV<int>::Type is int;
681 * mozilla::RemoveCV<const int>::Type is int;
682 * mozilla::RemoveCV<volatile int>::Type is int;
683 * mozilla::RemoveCV<int* const volatile>::Type is int*.
685 template<typename T>
686 struct RemoveCV
688 typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
691 /* 20.9.7.2 Reference modifications [meta.trans.ref] */
694 * Converts reference types to the underlying types.
696 * mozilla::RemoveReference<T>::Type is T;
697 * mozilla::RemoveReference<T&>::Type is T;
698 * mozilla::RemoveReference<T&&>::Type is T;
701 template<typename T>
702 struct RemoveReference
704 typedef T Type;
707 template<typename T>
708 struct RemoveReference<T&>
710 typedef T Type;
713 template<typename T>
714 struct RemoveReference<T&&>
716 typedef T Type;
719 template<bool Condition, typename A, typename B>
720 struct Conditional;
722 namespace detail {
724 enum Voidness { TIsVoid, TIsNotVoid };
726 template<typename T, Voidness V = IsVoid<T>::value ? TIsVoid : TIsNotVoid>
727 struct AddLvalueReferenceHelper;
729 template<typename T>
730 struct AddLvalueReferenceHelper<T, TIsVoid>
732 typedef void Type;
735 template<typename T>
736 struct AddLvalueReferenceHelper<T, TIsNotVoid>
738 typedef T& Type;
741 } // namespace detail
744 * AddLvalueReference adds an lvalue & reference to T if one isn't already
745 * present. (Note: adding an lvalue reference to an rvalue && reference in
746 * essence replaces the && with a &&, per C+11 reference collapsing rules. For
747 * example, int&& would become int&.)
749 * The final computed type will only *not* be an lvalue reference if T is void.
751 * mozilla::AddLvalueReference<int>::Type is int&;
752 * mozilla::AddLvalueRference<volatile int&>::Type is volatile int&;
753 * mozilla::AddLvalueReference<void*>::Type is void*&;
754 * mozilla::AddLvalueReference<void>::Type is void;
755 * mozilla::AddLvalueReference<struct S&&>::Type is struct S&.
757 template<typename T>
758 struct AddLvalueReference
759 : detail::AddLvalueReferenceHelper<T>
762 /* 20.9.7.3 Sign modifications [meta.trans.sign] */
764 template<bool B, typename T = void>
765 struct EnableIf;
767 namespace detail {
769 template<bool MakeConst, typename T>
770 struct WithC : Conditional<MakeConst, const T, T>
773 template<bool MakeVolatile, typename T>
774 struct WithV : Conditional<MakeVolatile, volatile T, T>
778 template<bool MakeConst, bool MakeVolatile, typename T>
779 struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type>
782 template<typename T>
783 struct CorrespondingSigned;
785 template<>
786 struct CorrespondingSigned<char> { typedef signed char Type; };
787 template<>
788 struct CorrespondingSigned<unsigned char> { typedef signed char Type; };
789 template<>
790 struct CorrespondingSigned<unsigned short> { typedef short Type; };
791 template<>
792 struct CorrespondingSigned<unsigned int> { typedef int Type; };
793 template<>
794 struct CorrespondingSigned<unsigned long> { typedef long Type; };
795 template<>
796 struct CorrespondingSigned<unsigned long long> { typedef long long Type; };
798 template<typename T,
799 typename CVRemoved = typename RemoveCV<T>::Type,
800 bool IsSignedIntegerType = IsSigned<CVRemoved>::value &&
801 !IsSame<char, CVRemoved>::value>
802 struct MakeSigned;
804 template<typename T, typename CVRemoved>
805 struct MakeSigned<T, CVRemoved, true>
807 typedef T Type;
810 template<typename T, typename CVRemoved>
811 struct MakeSigned<T, CVRemoved, false>
812 : WithCV<IsConst<T>::value, IsVolatile<T>::value,
813 typename CorrespondingSigned<CVRemoved>::Type>
816 } // namespace detail
819 * MakeSigned produces the corresponding signed integer type for a given
820 * integral type T, with the const/volatile qualifiers of T. T must be a
821 * possibly-const/volatile-qualified integral type that isn't bool.
823 * If T is already a signed integer type (not including char!), then T is
824 * produced.
826 * Otherwise, if T is an unsigned integer type, the signed variety of T, with
827 * T's const/volatile qualifiers, is produced.
829 * Otherwise, the integral type of the same size as T, with the lowest rank,
830 * with T's const/volatile qualifiers, is produced. (This basically only acts
831 * to produce signed char when T = char.)
833 * mozilla::MakeSigned<unsigned long>::Type is signed long;
834 * mozilla::MakeSigned<volatile int>::Type is volatile int;
835 * mozilla::MakeSigned<const unsigned short>::Type is const signed short;
836 * mozilla::MakeSigned<const char>::Type is const signed char;
837 * mozilla::MakeSigned<bool> is an error;
838 * mozilla::MakeSigned<void*> is an error.
840 template<typename T>
841 struct MakeSigned
842 : EnableIf<IsIntegral<T>::value &&
843 !IsSame<bool, typename RemoveCV<T>::Type>::value,
844 typename detail::MakeSigned<T>
845 >::Type
848 namespace detail {
850 template<typename T>
851 struct CorrespondingUnsigned;
853 template<>
854 struct CorrespondingUnsigned<char> { typedef unsigned char Type; };
855 template<>
856 struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; };
857 template<>
858 struct CorrespondingUnsigned<short> { typedef unsigned short Type; };
859 template<>
860 struct CorrespondingUnsigned<int> { typedef unsigned int Type; };
861 template<>
862 struct CorrespondingUnsigned<long> { typedef unsigned long Type; };
863 template<>
864 struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; };
867 template<typename T,
868 typename CVRemoved = typename RemoveCV<T>::Type,
869 bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value &&
870 !IsSame<char, CVRemoved>::value>
871 struct MakeUnsigned;
873 template<typename T, typename CVRemoved>
874 struct MakeUnsigned<T, CVRemoved, true>
876 typedef T Type;
879 template<typename T, typename CVRemoved>
880 struct MakeUnsigned<T, CVRemoved, false>
881 : WithCV<IsConst<T>::value, IsVolatile<T>::value,
882 typename CorrespondingUnsigned<CVRemoved>::Type>
885 } // namespace detail
888 * MakeUnsigned produces the corresponding unsigned integer type for a given
889 * integral type T, with the const/volatile qualifiers of T. T must be a
890 * possibly-const/volatile-qualified integral type that isn't bool.
892 * If T is already an unsigned integer type (not including char!), then T is
893 * produced.
895 * Otherwise, if T is an signed integer type, the unsigned variety of T, with
896 * T's const/volatile qualifiers, is produced.
898 * Otherwise, the unsigned integral type of the same size as T, with the lowest
899 * rank, with T's const/volatile qualifiers, is produced. (This basically only
900 * acts to produce unsigned char when T = char.)
902 * mozilla::MakeUnsigned<signed long>::Type is unsigned long;
903 * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int;
904 * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short;
905 * mozilla::MakeUnsigned<const char>::Type is const unsigned char;
906 * mozilla::MakeUnsigned<bool> is an error;
907 * mozilla::MakeUnsigned<void*> is an error.
909 template<typename T>
910 struct MakeUnsigned
911 : EnableIf<IsIntegral<T>::value &&
912 !IsSame<bool, typename RemoveCV<T>::Type>::value,
913 typename detail::MakeUnsigned<T>
914 >::Type
917 /* 20.9.7.4 Array modifications [meta.trans.arr] */
920 * RemoveExtent produces either the type of the elements of the array T, or T
921 * itself.
923 * mozilla::RemoveExtent<int>::Type is int;
924 * mozilla::RemoveExtent<const int[]>::Type is const int;
925 * mozilla::RemoveExtent<volatile int[5]>::Type is volatile int;
926 * mozilla::RemoveExtent<long[][17]>::Type is long[17].
928 template<typename T>
929 struct RemoveExtent
931 typedef T Type;
934 template<typename T>
935 struct RemoveExtent<T[]>
937 typedef T Type;
940 template<typename T, decltype(sizeof(1)) N>
941 struct RemoveExtent<T[N]>
943 typedef T Type;
946 /* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
948 /* 20.9.7.6 Other transformations [meta.trans.other] */
951 * EnableIf is a struct containing a typedef of T if and only if B is true.
953 * mozilla::EnableIf<true, int>::Type is int;
954 * mozilla::EnableIf<false, int>::Type is a compile-time error.
956 * Use this template to implement SFINAE-style (Substitution Failure Is not An
957 * Error) requirements. For example, you might use it to impose a restriction
958 * on a template parameter:
960 * template<typename T>
961 * class PodVector // vector optimized to store POD (memcpy-able) types
963 * EnableIf<IsPod<T>::value, T>::Type* vector;
964 * size_t length;
965 * ...
966 * };
968 template<bool B, typename T>
969 struct EnableIf
972 template<typename T>
973 struct EnableIf<true, T>
975 typedef T Type;
979 * Conditional selects a class between two, depending on a given boolean value.
981 * mozilla::Conditional<true, A, B>::Type is A;
982 * mozilla::Conditional<false, A, B>::Type is B;
984 template<bool Condition, typename A, typename B>
985 struct Conditional
987 typedef A Type;
990 template<class A, class B>
991 struct Conditional<false, A, B>
993 typedef B Type;
996 } /* namespace mozilla */
998 #endif /* mozilla_TypeTraits_h */