Bug 777574 - Skip quickCheckAPI-B2.html on Linux. r=bjacob, a=test-only
[gecko.git] / mfbt / TypeTraits.h
blob1ccd0c85d17f7eff086fc16b4043718d05514843
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
13 * These traits are approximate copies of the traits and semantics from C++11's
14 * <type_traits> header. Don't add traits not in that header! When all
15 * platforms provide that header, we can convert all users and remove this one.
18 #include <wchar.h>
20 namespace mozilla {
22 /* Forward declarations. */
24 template<typename> struct RemoveCV;
26 /* 20.9.3 Helper classes [meta.help] */
28 /**
29 * Helper class used as a base for various type traits, exposed publicly
30 * because <type_traits> exposes it as well.
32 template<typename T, T Value>
33 struct IntegralConstant
35 static const T value = Value;
36 typedef T ValueType;
37 typedef IntegralConstant<T, Value> Type;
40 /** Convenient aliases. */
41 typedef IntegralConstant<bool, true> TrueType;
42 typedef IntegralConstant<bool, false> FalseType;
44 /* 20.9.4 Unary type traits [meta.unary] */
46 /* 20.9.4.1 Primary type categories [meta.unary.cat] */
48 namespace detail {
50 template <typename T>
51 struct IsIntegralHelper : FalseType {};
53 template<> struct IsIntegralHelper<char> : TrueType {};
54 template<> struct IsIntegralHelper<signed char> : TrueType {};
55 template<> struct IsIntegralHelper<unsigned char> : TrueType {};
56 template<> struct IsIntegralHelper<short> : TrueType {};
57 template<> struct IsIntegralHelper<unsigned short> : TrueType {};
58 template<> struct IsIntegralHelper<int> : TrueType {};
59 template<> struct IsIntegralHelper<unsigned int> : TrueType {};
60 template<> struct IsIntegralHelper<long> : TrueType {};
61 template<> struct IsIntegralHelper<unsigned long> : TrueType {};
62 template<> struct IsIntegralHelper<long long> : TrueType {};
63 template<> struct IsIntegralHelper<unsigned long long> : TrueType {};
64 template<> struct IsIntegralHelper<bool> : TrueType {};
65 template<> struct IsIntegralHelper<wchar_t> : TrueType {};
66 #ifdef MOZ_CHAR16_IS_NOT_WCHAR
67 template<> struct IsIntegralHelper<char16_t> : TrueType {};
68 #endif
70 } /* namespace detail */
72 /**
73 * IsIntegral determines whether a type is an integral type.
75 * mozilla::IsIntegral<int>::value is true;
76 * mozilla::IsIntegral<unsigned short>::value is true;
77 * mozilla::IsIntegral<const long>::value is true;
78 * mozilla::IsIntegral<int*>::value is false;
79 * mozilla::IsIntegral<double>::value is false;
81 * Note that the behavior of IsIntegral on char16_t and char32_t is
82 * unspecified.
84 template<typename T>
85 struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type>
86 {};
88 template<typename T, typename U>
89 struct IsSame;
91 namespace detail {
93 template<typename T>
94 struct IsFloatingPointHelper
95 : IntegralConstant<bool,
96 IsSame<T, float>::value ||
97 IsSame<T, double>::value ||
98 IsSame<T, long double>::value>
99 {};
101 } // namespace detail
104 * IsFloatingPoint determines whether a type is a floating point type (float,
105 * double, long double).
107 * mozilla::IsFloatingPoint<int>::value is false;
108 * mozilla::IsFloatingPoint<const float>::value is true;
109 * mozilla::IsFloatingPoint<long double>::value is true;
110 * mozilla::IsFloatingPoint<double*>::value is false.
112 template<typename T>
113 struct IsFloatingPoint
114 : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type>
118 * IsPointer determines whether a type is a pointer type (but not a pointer-to-
119 * member type).
121 * mozilla::IsPointer<struct S*>::value is true;
122 * mozilla::IsPointer<int**>::value is true;
123 * mozilla::IsPointer<void (*)(void)>::value is true;
124 * mozilla::IsPointer<int>::value is false;
125 * mozilla::IsPointer<struct S>::value is false.
127 template<typename T>
128 struct IsPointer : FalseType {};
130 template<typename T>
131 struct IsPointer<T*> : TrueType {};
133 namespace detail {
135 // __is_enum is a supported extension across all of our supported compilers.
136 template<typename T>
137 struct IsEnumHelper
138 : IntegralConstant<bool, __is_enum(T)>
141 } // namespace detail
144 * IsEnum determines whether a type is an enum type.
146 * mozilla::IsEnum<enum S>::value is true;
147 * mozilla::IsEnum<enum S*>::value is false;
148 * mozilla::IsEnum<int>::value is false;
150 template<typename T>
151 struct IsEnum
152 : detail::IsEnumHelper<typename RemoveCV<T>::Type>
155 /* 20.9.4.2 Composite type traits [meta.unary.comp] */
158 * IsArithmetic determines whether a type is arithmetic. A type is arithmetic
159 * iff it is an integral type or a floating point type.
161 * mozilla::IsArithmetic<int>::value is true;
162 * mozilla::IsArithmetic<double>::value is true;
163 * mozilla::IsArithmetic<long double*>::value is false.
165 template<typename T>
166 struct IsArithmetic
167 : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value>
170 /* 20.9.4.3 Type properties [meta.unary.prop] */
173 * IsConst determines whether a type is const or not.
175 * mozilla::IsConst<int>::value is false;
176 * mozilla::IsConst<void* const>::value is true;
177 * mozilla::IsConst<const char*>::value is false.
179 template<typename T>
180 struct IsConst : FalseType {};
182 template<typename T>
183 struct IsConst<const T> : TrueType {};
186 * IsVolatile determines whether a type is volatile or not.
188 * mozilla::IsVolatile<int>::value is false;
189 * mozilla::IsVolatile<void* volatile>::value is true;
190 * mozilla::IsVolatile<volatile char*>::value is false.
192 template<typename T>
193 struct IsVolatile : FalseType {};
195 template<typename T>
196 struct IsVolatile<volatile T> : TrueType {};
199 * Traits class for identifying POD types. Until C++11 there's no automatic
200 * way to detect PODs, so for the moment this is done manually. Users may
201 * define specializations of this class that inherit from mozilla::TrueType and
202 * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or
203 * false>, or conveniently from mozilla::IsPod for composite types) as needed to
204 * ensure correct IsPod behavior.
206 template<typename T>
207 struct IsPod : public FalseType {};
209 template<> struct IsPod<char> : TrueType {};
210 template<> struct IsPod<signed char> : TrueType {};
211 template<> struct IsPod<unsigned char> : TrueType {};
212 template<> struct IsPod<short> : TrueType {};
213 template<> struct IsPod<unsigned short> : TrueType {};
214 template<> struct IsPod<int> : TrueType {};
215 template<> struct IsPod<unsigned int> : TrueType {};
216 template<> struct IsPod<long> : TrueType {};
217 template<> struct IsPod<unsigned long> : TrueType {};
218 template<> struct IsPod<long long> : TrueType {};
219 template<> struct IsPod<unsigned long long> : TrueType {};
220 template<> struct IsPod<bool> : TrueType {};
221 template<> struct IsPod<float> : TrueType {};
222 template<> struct IsPod<double> : TrueType {};
223 template<> struct IsPod<wchar_t> : TrueType {};
224 #ifdef MOZ_CHAR16_IS_NOT_WCHAR
225 template<> struct IsPod<char16_t> : TrueType {};
226 #endif
227 template<typename T> struct IsPod<T*> : TrueType {};
229 namespace detail {
231 template<typename T, bool = IsFloatingPoint<T>::value>
232 struct IsSignedHelper;
234 template<typename T>
235 struct IsSignedHelper<T, true> : TrueType {};
237 template<typename T>
238 struct IsSignedHelper<T, false>
239 : IntegralConstant<bool, IsArithmetic<T>::value && T(-1) < T(1)>
242 } // namespace detail
245 * IsSigned determines whether a type is a signed arithmetic type. |char| is
246 * considered a signed type if it has the same representation as |signed char|.
248 * Don't use this if the type might be user-defined! You might or might not get
249 * a compile error, depending.
251 * mozilla::IsSigned<int>::value is true;
252 * mozilla::IsSigned<const unsigned int>::value is false;
253 * mozilla::IsSigned<unsigned char>::value is false;
254 * mozilla::IsSigned<float>::value is true.
256 template<typename T>
257 struct IsSigned : detail::IsSignedHelper<T> {};
259 namespace detail {
261 template<typename T, bool = IsFloatingPoint<T>::value>
262 struct IsUnsignedHelper;
264 template<typename T>
265 struct IsUnsignedHelper<T, true> : FalseType {};
267 template<typename T>
268 struct IsUnsignedHelper<T, false>
269 : IntegralConstant<bool,
270 IsArithmetic<T>::value &&
271 (IsSame<typename RemoveCV<T>::Type, bool>::value ||
272 T(1) < T(-1))>
275 } // namespace detail
278 * IsUnsigned determines whether a type is an unsigned arithmetic type.
280 * Don't use this if the type might be user-defined! You might or might not get
281 * a compile error, depending.
283 * mozilla::IsUnsigned<int>::value is false;
284 * mozilla::IsUnsigned<const unsigned int>::value is true;
285 * mozilla::IsUnsigned<unsigned char>::value is true;
286 * mozilla::IsUnsigned<float>::value is false.
288 template<typename T>
289 struct IsUnsigned : detail::IsUnsignedHelper<T> {};
291 /* 20.9.5 Type property queries [meta.unary.prop.query] */
293 /* 20.9.6 Relationships between types [meta.rel] */
296 * IsSame tests whether two types are the same type.
298 * mozilla::IsSame<int, int>::value is true;
299 * mozilla::IsSame<int*, int*>::value is true;
300 * mozilla::IsSame<int, unsigned int>::value is false;
301 * mozilla::IsSame<void, void>::value is true;
302 * mozilla::IsSame<const int, int>::value is false;
303 * mozilla::IsSame<struct S, struct S>::value is true.
305 template<typename T, typename U>
306 struct IsSame : FalseType {};
308 template<typename T>
309 struct IsSame<T, T> : TrueType {};
311 namespace detail {
313 // The trickery used to implement IsBaseOf here makes it possible to use it for
314 // the cases of private and multiple inheritance. This code was inspired by the
315 // sample code here:
317 // http://stackoverflow.com/questions/2910979/how-is-base-of-works
318 template<class Base, class Derived>
319 struct BaseOfHelper
321 public:
322 operator Base*() const;
323 operator Derived*();
326 template<class Base, class Derived>
327 struct BaseOfTester
329 private:
330 template<class T>
331 static char test(Derived*, T);
332 static int test(Base*, int);
334 public:
335 static const bool value =
336 sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
339 template<class Base, class Derived>
340 struct BaseOfTester<Base, const Derived>
342 private:
343 template<class T>
344 static char test(Derived*, T);
345 static int test(Base*, int);
347 public:
348 static const bool value =
349 sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
352 template<class Base, class Derived>
353 struct BaseOfTester<Base&, Derived&> : FalseType {};
355 template<class Type>
356 struct BaseOfTester<Type, Type> : TrueType {};
358 template<class Type>
359 struct BaseOfTester<Type, const Type> : TrueType {};
361 } /* namespace detail */
364 * IsBaseOf allows to know whether a given class is derived from another.
366 * Consider the following class definitions:
368 * class A {};
369 * class B : public A {};
370 * class C {};
372 * mozilla::IsBaseOf<A, B>::value is true;
373 * mozilla::IsBaseOf<A, C>::value is false;
375 template<class Base, class Derived>
376 struct IsBaseOf
377 : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value>
380 namespace detail {
382 template<typename From, typename To>
383 struct ConvertibleTester
385 private:
386 static From create();
388 template<typename From1, typename To1>
389 static char test(To to);
391 template<typename From1, typename To1>
392 static int test(...);
394 public:
395 static const bool value =
396 sizeof(test<From, To>(create())) == sizeof(char);
399 } // namespace detail
402 * IsConvertible determines whether a value of type From will implicitly convert
403 * to a value of type To. For example:
405 * struct A {};
406 * struct B : public A {};
407 * struct C {};
409 * mozilla::IsConvertible<A, A>::value is true;
410 * mozilla::IsConvertible<A*, A*>::value is true;
411 * mozilla::IsConvertible<B, A>::value is true;
412 * mozilla::IsConvertible<B*, A*>::value is true;
413 * mozilla::IsConvertible<C, A>::value is false;
414 * mozilla::IsConvertible<A, C>::value is false;
415 * mozilla::IsConvertible<A*, C*>::value is false;
416 * mozilla::IsConvertible<C*, A*>::value is false.
418 * For obscure reasons, you can't use IsConvertible when the types being tested
419 * are related through private inheritance, and you'll get a compile error if
420 * you try. Just don't do it!
422 template<typename From, typename To>
423 struct IsConvertible
424 : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value>
428 * Is IsLvalueReference<T> is true if its template param is T& and is false if
429 * its type is T or T&&.
431 template<typename T>
432 struct IsLvalueReference : FalseType {};
434 template<typename T>
435 struct IsLvalueReference<T&> : TrueType {};
437 /* 20.9.7 Transformations between types [meta.trans] */
439 /* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
442 * RemoveConst removes top-level const qualifications on a type.
444 * mozilla::RemoveConst<int>::Type is int;
445 * mozilla::RemoveConst<const int>::Type is int;
446 * mozilla::RemoveConst<const int*>::Type is const int*;
447 * mozilla::RemoveConst<int* const>::Type is int*.
449 template<typename T>
450 struct RemoveConst
452 typedef T Type;
455 template<typename T>
456 struct RemoveConst<const T>
458 typedef T Type;
462 * RemoveVolatile removes top-level volatile qualifications on a type.
464 * mozilla::RemoveVolatile<int>::Type is int;
465 * mozilla::RemoveVolatile<volatile int>::Type is int;
466 * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*;
467 * mozilla::RemoveVolatile<int* volatile>::Type is int*.
469 template<typename T>
470 struct RemoveVolatile
472 typedef T Type;
475 template<typename T>
476 struct RemoveVolatile<volatile T>
478 typedef T Type;
482 * RemoveCV removes top-level const and volatile qualifications on a type.
484 * mozilla::RemoveCV<int>::Type is int;
485 * mozilla::RemoveCV<const int>::Type is int;
486 * mozilla::RemoveCV<volatile int>::Type is int;
487 * mozilla::RemoveCV<int* const volatile>::Type is int*.
489 template<typename T>
490 struct RemoveCV
492 typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
495 /* 20.9.7.2 Reference modifications [meta.trans.ref] */
498 * Converts reference types to the underlying types.
500 * mozilla::RemoveReference<T>::Type is T;
501 * mozilla::RemoveReference<T&>::Type is T;
502 * mozilla::RemoveReference<T&&>::Type is T;
505 template<typename T>
506 struct RemoveReference
508 typedef T Type;
511 template<typename T>
512 struct RemoveReference<T&>
514 typedef T Type;
517 template<typename T>
518 struct RemoveReference<T&&>
520 typedef T Type;
523 /* 20.9.7.3 Sign modifications [meta.trans.sign] */
525 template<bool B, typename T = void>
526 struct EnableIf;
528 template<bool Condition, typename A, typename B>
529 struct Conditional;
531 namespace detail {
533 template<bool MakeConst, typename T>
534 struct WithC : Conditional<MakeConst, const T, T>
537 template<bool MakeVolatile, typename T>
538 struct WithV : Conditional<MakeVolatile, volatile T, T>
542 template<bool MakeConst, bool MakeVolatile, typename T>
543 struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type>
546 template<typename T>
547 struct CorrespondingSigned;
549 template<>
550 struct CorrespondingSigned<char> { typedef signed char Type; };
551 template<>
552 struct CorrespondingSigned<unsigned char> { typedef signed char Type; };
553 template<>
554 struct CorrespondingSigned<unsigned short> { typedef short Type; };
555 template<>
556 struct CorrespondingSigned<unsigned int> { typedef int Type; };
557 template<>
558 struct CorrespondingSigned<unsigned long> { typedef long Type; };
559 template<>
560 struct CorrespondingSigned<unsigned long long> { typedef long long Type; };
562 template<typename T,
563 typename CVRemoved = typename RemoveCV<T>::Type,
564 bool IsSignedIntegerType = IsSigned<CVRemoved>::value &&
565 !IsSame<char, CVRemoved>::value>
566 struct MakeSigned;
568 template<typename T, typename CVRemoved>
569 struct MakeSigned<T, CVRemoved, true>
571 typedef T Type;
574 template<typename T, typename CVRemoved>
575 struct MakeSigned<T, CVRemoved, false>
576 : WithCV<IsConst<T>::value, IsVolatile<T>::value,
577 typename CorrespondingSigned<CVRemoved>::Type>
580 } // namespace detail
583 * MakeSigned produces the corresponding signed integer type for a given
584 * integral type T, with the const/volatile qualifiers of T. T must be a
585 * possibly-const/volatile-qualified integral type that isn't bool.
587 * If T is already a signed integer type (not including char!), then T is
588 * produced.
590 * Otherwise, if T is an unsigned integer type, the signed variety of T, with
591 * T's const/volatile qualifiers, is produced.
593 * Otherwise, the integral type of the same size as T, with the lowest rank,
594 * with T's const/volatile qualifiers, is produced. (This basically only acts
595 * to produce signed char when T = char.)
597 * mozilla::MakeSigned<unsigned long>::Type is signed long;
598 * mozilla::MakeSigned<volatile int>::Type is volatile int;
599 * mozilla::MakeSigned<const unsigned short>::Type is const signed short;
600 * mozilla::MakeSigned<const char>::Type is const signed char;
601 * mozilla::MakeSigned<bool> is an error;
602 * mozilla::MakeSigned<void*> is an error.
604 template<typename T>
605 struct MakeSigned
606 : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
607 typename detail::MakeSigned<T>
608 >::Type
611 namespace detail {
613 template<typename T>
614 struct CorrespondingUnsigned;
616 template<>
617 struct CorrespondingUnsigned<char> { typedef unsigned char Type; };
618 template<>
619 struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; };
620 template<>
621 struct CorrespondingUnsigned<short> { typedef unsigned short Type; };
622 template<>
623 struct CorrespondingUnsigned<int> { typedef unsigned int Type; };
624 template<>
625 struct CorrespondingUnsigned<long> { typedef unsigned long Type; };
626 template<>
627 struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; };
630 template<typename T,
631 typename CVRemoved = typename RemoveCV<T>::Type,
632 bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value &&
633 !IsSame<char, CVRemoved>::value>
634 struct MakeUnsigned;
636 template<typename T, typename CVRemoved>
637 struct MakeUnsigned<T, CVRemoved, true>
639 typedef T Type;
642 template<typename T, typename CVRemoved>
643 struct MakeUnsigned<T, CVRemoved, false>
644 : WithCV<IsConst<T>::value, IsVolatile<T>::value,
645 typename CorrespondingUnsigned<CVRemoved>::Type>
648 } // namespace detail
651 * MakeUnsigned produces the corresponding unsigned integer type for a given
652 * integral type T, with the const/volatile qualifiers of T. T must be a
653 * possibly-const/volatile-qualified integral type that isn't bool.
655 * If T is already an unsigned integer type (not including char!), then T is
656 * produced.
658 * Otherwise, if T is an signed integer type, the unsigned variety of T, with
659 * T's const/volatile qualifiers, is produced.
661 * Otherwise, the unsigned integral type of the same size as T, with the lowest
662 * rank, with T's const/volatile qualifiers, is produced. (This basically only
663 * acts to produce unsigned char when T = char.)
665 * mozilla::MakeUnsigned<signed long>::Type is unsigned long;
666 * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int;
667 * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short;
668 * mozilla::MakeUnsigned<const char>::Type is const unsigned char;
669 * mozilla::MakeUnsigned<bool> is an error;
670 * mozilla::MakeUnsigned<void*> is an error.
672 template<typename T>
673 struct MakeUnsigned
674 : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
675 typename detail::MakeUnsigned<T>
676 >::Type
679 /* 20.9.7.4 Array modifications [meta.trans.arr] */
681 /* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
683 /* 20.9.7.6 Other transformations [meta.trans.other] */
686 * EnableIf is a struct containing a typedef of T if and only if B is true.
688 * mozilla::EnableIf<true, int>::Type is int;
689 * mozilla::EnableIf<false, int>::Type is a compile-time error.
691 * Use this template to implement SFINAE-style (Substitution Failure Is not An
692 * Error) requirements. For example, you might use it to impose a restriction
693 * on a template parameter:
695 * template<typename T>
696 * class PodVector // vector optimized to store POD (memcpy-able) types
698 * EnableIf<IsPod<T>::value, T>::Type* vector;
699 * size_t length;
700 * ...
701 * };
703 template<bool B, typename T>
704 struct EnableIf
707 template<typename T>
708 struct EnableIf<true, T>
710 typedef T Type;
714 * Conditional selects a class between two, depending on a given boolean value.
716 * mozilla::Conditional<true, A, B>::Type is A;
717 * mozilla::Conditional<false, A, B>::Type is B;
719 template<bool Condition, typename A, typename B>
720 struct Conditional
722 typedef A Type;
725 template<class A, class B>
726 struct Conditional<false, A, B>
728 typedef B Type;
731 } /* namespace mozilla */
733 #endif /* mozilla_TypeTraits_h */