mfbt/TypeTraits.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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"
    14 /*
    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.
    18  */
    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.
    33  */
    34 template<typename T, T Value>
    35 struct IntegralConstant
    36 {
    37     static const T value = Value;
    38     typedef T ValueType;
    39     typedef IntegralConstant<T, Value> Type;
    40 };
    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 IsIntegralHelper : FalseType {};
    55 template<> struct IsIntegralHelper<char>               : TrueType {};
    56 template<> struct IsIntegralHelper<signed char>        : TrueType {};
    57 template<> struct IsIntegralHelper<unsigned char>      : TrueType {};
    58 template<> struct IsIntegralHelper<short>              : TrueType {};
    59 template<> struct IsIntegralHelper<unsigned short>     : TrueType {};
    60 template<> struct IsIntegralHelper<int>                : TrueType {};
    61 template<> struct IsIntegralHelper<unsigned int>       : TrueType {};
    62 template<> struct IsIntegralHelper<long>               : TrueType {};
    63 template<> struct IsIntegralHelper<unsigned long>      : TrueType {};
    64 template<> struct IsIntegralHelper<long long>          : TrueType {};
    65 template<> struct IsIntegralHelper<unsigned long long> : TrueType {};
    66 template<> struct IsIntegralHelper<bool>               : TrueType {};
    67 template<> struct IsIntegralHelper<wchar_t>            : TrueType {};
    68 #ifdef MOZ_CHAR16_IS_NOT_WCHAR
    69 template<> struct IsIntegralHelper<char16_t>           : TrueType {};
    70 #endif
    72 } /* namespace detail */
    74 /**
    75  * IsIntegral determines whether a type is an integral type.
    76  *
    77  * mozilla::IsIntegral<int>::value is true;
    78  * mozilla::IsIntegral<unsigned short>::value is true;
    79  * mozilla::IsIntegral<const long>::value is true;
    80  * mozilla::IsIntegral<int*>::value is false;
    81  * mozilla::IsIntegral<double>::value is false;
    82  *
    83  * Note that the behavior of IsIntegral on char16_t and char32_t is
    84  * unspecified.
    85  */
    86 template<typename T>
    87 struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type>
    88 {};
    90 template<typename T, typename U>
    91 struct IsSame;
    93 namespace detail {
    95 template<typename T>
    96 struct IsFloatingPointHelper
    97   : IntegralConstant<bool,
    98                      IsSame<T, float>::value ||
    99                      IsSame<T, double>::value ||
   100                      IsSame<T, long double>::value>
   101 {};
   103 } // namespace detail
   105 /**
   106  * IsFloatingPoint determines whether a type is a floating point type (float,
   107  * double, long double).
   108  *
   109  * mozilla::IsFloatingPoint<int>::value is false;
   110  * mozilla::IsFloatingPoint<const float>::value is true;
   111  * mozilla::IsFloatingPoint<long double>::value is true;
   112  * mozilla::IsFloatingPoint<double*>::value is false.
   113  */
   114 template<typename T>
   115 struct IsFloatingPoint
   116   : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type>
   117 {};
   119 namespace detail {
   121 template<typename T>
   122 struct IsArrayHelper : FalseType {};
   124 template<typename T, decltype(sizeof(1)) N>
   125 struct IsArrayHelper<T[N]> : TrueType {};
   127 template<typename T>
   128 struct IsArrayHelper<T[]> : TrueType {};
   130 } // namespace detail
   132 /**
   133  * IsArray determines whether a type is an array type, of known or unknown
   134  * length.
   135  *
   136  * mozilla::IsArray<int>::value is false;
   137  * mozilla::IsArray<int[]>::value is true;
   138  * mozilla::IsArray<int[5]>::value is true.
   139  */
   140 template<typename T>
   141 struct IsArray : detail::IsArrayHelper<typename RemoveCV<T>::Type>
   142 {};
   144 /**
   145  * IsPointer determines whether a type is a pointer type (but not a pointer-to-
   146  * member type).
   147  *
   148  * mozilla::IsPointer<struct S*>::value is true;
   149  * mozilla::IsPointer<int**>::value is true;
   150  * mozilla::IsPointer<void (*)(void)>::value is true;
   151  * mozilla::IsPointer<int>::value is false;
   152  * mozilla::IsPointer<struct S>::value is false.
   153  */
   154 template<typename T>
   155 struct IsPointer : FalseType {};
   157 template<typename T>
   158 struct IsPointer<T*> : TrueType {};
   160 /**
   161  * IsLvalueReference determines whether a type is an lvalue reference.
   162  *
   163  * mozilla::IsLvalueReference<struct S*>::value is false;
   164  * mozilla::IsLvalueReference<int**>::value is false;
   165  * mozilla::IsLvalueReference<void (*)(void)>::value is false;
   166  * mozilla::IsLvalueReference<int>::value is false;
   167  * mozilla::IsLvalueReference<struct S>::value is false;
   168  * mozilla::IsLvalueReference<struct S*&>::value is true;
   169  * mozilla::IsLvalueReference<struct S&&>::value is false.
   170  */
   171 template<typename T>
   172 struct IsLvalueReference : FalseType {};
   174 template<typename T>
   175 struct IsLvalueReference<T&> : TrueType {};
   177 /**
   178  * IsRvalueReference determines whether a type is an rvalue reference.
   179  *
   180  * mozilla::IsRvalueReference<struct S*>::value is false;
   181  * mozilla::IsRvalueReference<int**>::value is false;
   182  * mozilla::IsRvalueReference<void (*)(void)>::value is false;
   183  * mozilla::IsRvalueReference<int>::value is false;
   184  * mozilla::IsRvalueReference<struct S>::value is false;
   185  * mozilla::IsRvalueReference<struct S*&>::value is false;
   186  * mozilla::IsRvalueReference<struct S&&>::value is true.
   187  */
   188 template<typename T>
   189 struct IsRvalueReference : FalseType {};
   191 template<typename T>
   192 struct IsRvalueReference<T&&> : TrueType {};
   194 namespace detail {
   196 // __is_enum is a supported extension across all of our supported compilers.
   197 template<typename T>
   198 struct IsEnumHelper
   199   : IntegralConstant<bool, __is_enum(T)>
   200 {};
   202 } // namespace detail
   204 /**
   205  * IsEnum determines whether a type is an enum type.
   206  *
   207  * mozilla::IsEnum<enum S>::value is true;
   208  * mozilla::IsEnum<enum S*>::value is false;
   209  * mozilla::IsEnum<int>::value is false;
   210  */
   211 template<typename T>
   212 struct IsEnum
   213   : detail::IsEnumHelper<typename RemoveCV<T>::Type>
   214 {};
   216 namespace detail {
   218 // __is_class is a supported extension across all of our supported compilers:
   219 // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
   220 // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
   221 // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
   222 template<typename T>
   223 struct IsClassHelper
   224   : IntegralConstant<bool, __is_class(T)>
   225 {};
   227 } // namespace detail
   229 /**
   230  * IsClass determines whether a type is a class type (but not a union).
   231  *
   232  * struct S {};
   233  * union U {};
   234  * mozilla::IsClass<int>::value is false;
   235  * mozilla::IsClass<const S>::value is true;
   236  * mozilla::IsClass<U>::value is false;
   237  */
   238 template<typename T>
   239 struct IsClass
   240   : detail::IsClassHelper<typename RemoveCV<T>::Type>
   241 {};
   243 /* 20.9.4.2 Composite type traits [meta.unary.comp] */
   245 /**
   246  * IsReference determines whether a type is an lvalue or rvalue reference.
   247  *
   248  * mozilla::IsReference<struct S*>::value is false;
   249  * mozilla::IsReference<int**>::value is false;
   250  * mozilla::IsReference<int&>::value is true;
   251  * mozilla::IsReference<void (*)(void)>::value is false;
   252  * mozilla::IsReference<const int&>::value is true;
   253  * mozilla::IsReference<int>::value is false;
   254  * mozilla::IsReference<struct S>::value is false;
   255  * mozilla::IsReference<struct S&>::value is true;
   256  * mozilla::IsReference<struct S*&>::value is true;
   257  * mozilla::IsReference<struct S&&>::value is true.
   258  */
   259 template<typename T>
   260 struct IsReference
   261   : IntegralConstant<bool,
   262                      IsLvalueReference<T>::value || IsRvalueReference<T>::value>
   263 {};
   265 /**
   266  * IsArithmetic determines whether a type is arithmetic.  A type is arithmetic
   267  * iff it is an integral type or a floating point type.
   268  *
   269  * mozilla::IsArithmetic<int>::value is true;
   270  * mozilla::IsArithmetic<double>::value is true;
   271  * mozilla::IsArithmetic<long double*>::value is false.
   272  */
   273 template<typename T>
   274 struct IsArithmetic
   275   : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value>
   276 {};
   278 /* 20.9.4.3 Type properties [meta.unary.prop] */
   280 /**
   281  * IsConst determines whether a type is const or not.
   282  *
   283  * mozilla::IsConst<int>::value is false;
   284  * mozilla::IsConst<void* const>::value is true;
   285  * mozilla::IsConst<const char*>::value is false.
   286  */
   287 template<typename T>
   288 struct IsConst : FalseType {};
   290 template<typename T>
   291 struct IsConst<const T> : TrueType {};
   293 /**
   294  * IsVolatile determines whether a type is volatile or not.
   295  *
   296  * mozilla::IsVolatile<int>::value is false;
   297  * mozilla::IsVolatile<void* volatile>::value is true;
   298  * mozilla::IsVolatile<volatile char*>::value is false.
   299  */
   300 template<typename T>
   301 struct IsVolatile : FalseType {};
   303 template<typename T>
   304 struct IsVolatile<volatile T> : TrueType {};
   306 /**
   307  * Traits class for identifying POD types.  Until C++11 there's no automatic
   308  * way to detect PODs, so for the moment this is done manually.  Users may
   309  * define specializations of this class that inherit from mozilla::TrueType and
   310  * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or
   311  * false>, or conveniently from mozilla::IsPod for composite types) as needed to
   312  * ensure correct IsPod behavior.
   313  */
   314 template<typename T>
   315 struct IsPod : public FalseType {};
   317 template<> struct IsPod<char>               : TrueType {};
   318 template<> struct IsPod<signed char>        : TrueType {};
   319 template<> struct IsPod<unsigned char>      : TrueType {};
   320 template<> struct IsPod<short>              : TrueType {};
   321 template<> struct IsPod<unsigned short>     : TrueType {};
   322 template<> struct IsPod<int>                : TrueType {};
   323 template<> struct IsPod<unsigned int>       : TrueType {};
   324 template<> struct IsPod<long>               : TrueType {};
   325 template<> struct IsPod<unsigned long>      : TrueType {};
   326 template<> struct IsPod<long long>          : TrueType {};
   327 template<> struct IsPod<unsigned long long> : TrueType {};
   328 template<> struct IsPod<bool>               : TrueType {};
   329 template<> struct IsPod<float>              : TrueType {};
   330 template<> struct IsPod<double>             : TrueType {};
   331 template<> struct IsPod<wchar_t>            : TrueType {};
   332 #ifdef MOZ_CHAR16_IS_NOT_WCHAR
   333 template<> struct IsPod<char16_t>           : TrueType {};
   334 #endif
   335 template<typename T> struct IsPod<T*>       : TrueType {};
   337 namespace detail {
   339 // __is_empty is a supported extension across all of our supported compilers:
   340 // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
   341 // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
   342 // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
   343 template<typename T>
   344 struct IsEmptyHelper
   345   : IntegralConstant<bool, IsClass<T>::value && __is_empty(T)>
   346 {};
   348 } // namespace detail
   350 /**
   351  * IsEmpty determines whether a type is a class (but not a union) that is empty.
   352  *
   353  * A class is empty iff it and all its base classes have no non-static data
   354  * members (except bit-fields of length 0) and no virtual member functions, and
   355  * no base class is empty or a virtual base class.
   356  *
   357  * Intuitively, empty classes don't have any data that has to be stored in
   358  * instances of those classes.  (The size of the class must still be non-zero,
   359  * because distinct array elements of any type must have different addresses.
   360  * However, if the Empty Base Optimization is implemented by the compiler [most
   361  * compilers implement it, and in certain cases C++11 requires it], the size of
   362  * a class inheriting from an empty |Base| class need not be inflated by
   363  * |sizeof(Base)|.)  And intuitively, non-empty classes have data members and/or
   364  * vtable pointers that must be stored in each instance for proper behavior.
   365  *
   366  *   static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty");
   367  *   union U1 { int x; };
   368  *   static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty");
   369  *   struct E1 {};
   370  *   struct E2 { int : 0 };
   371  *   struct E3 : E1 {};
   372  *   struct E4 : E2 {};
   373  *   static_assert(mozilla::IsEmpty<E1>::value &&
   374  *                 mozilla::IsEmpty<E2>::value &&
   375  *                 mozilla::IsEmpty<E3>::value &&
   376  *                 mozilla::IsEmpty<E4>::value,
   377  *                 "all empty");
   378  *   union U2 { E1 e1; };
   379  *   static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty");
   380  *   struct NE1 { int x; };
   381  *   struct NE2 : virtual E1 {};
   382  *   struct NE3 : E2 { virtual ~NE3() {} };
   383  *   struct NE4 { virtual void f() {} };
   384  *   static_assert(!mozilla::IsEmpty<NE1>::value &&
   385  *                 !mozilla::IsEmpty<NE2>::value &&
   386  *                 !mozilla::IsEmpty<NE3>::value &&
   387  *                 !mozilla::IsEmpty<NE4>::value,
   388  *                 "all empty");
   389  */
   390 template<typename T>
   391 struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type>
   392 {};
   395 namespace detail {
   397 template<typename T, bool = IsFloatingPoint<T>::value>
   398 struct IsSignedHelper;
   400 template<typename T>
   401 struct IsSignedHelper<T, true> : TrueType {};
   403 template<typename T>
   404 struct IsSignedHelper<T, false>
   405   : IntegralConstant<bool, IsArithmetic<T>::value && T(-1) < T(1)>
   406 {};
   408 } // namespace detail
   410 /**
   411  * IsSigned determines whether a type is a signed arithmetic type.  |char| is
   412  * considered a signed type if it has the same representation as |signed char|.
   413  *
   414  * Don't use this if the type might be user-defined!  You might or might not get
   415  * a compile error, depending.
   416  *
   417  * mozilla::IsSigned<int>::value is true;
   418  * mozilla::IsSigned<const unsigned int>::value is false;
   419  * mozilla::IsSigned<unsigned char>::value is false;
   420  * mozilla::IsSigned<float>::value is true.
   421  */
   422 template<typename T>
   423 struct IsSigned : detail::IsSignedHelper<T> {};
   425 namespace detail {
   427 template<typename T, bool = IsFloatingPoint<T>::value>
   428 struct IsUnsignedHelper;
   430 template<typename T>
   431 struct IsUnsignedHelper<T, true> : FalseType {};
   433 template<typename T>
   434 struct IsUnsignedHelper<T, false>
   435   : IntegralConstant<bool,
   436                      IsArithmetic<T>::value &&
   437                      (IsSame<typename RemoveCV<T>::Type, bool>::value ||
   438                       T(1) < T(-1))>
   439 {};
   441 } // namespace detail
   443 /**
   444  * IsUnsigned determines whether a type is an unsigned arithmetic type.
   445  *
   446  * Don't use this if the type might be user-defined!  You might or might not get
   447  * a compile error, depending.
   448  *
   449  * mozilla::IsUnsigned<int>::value is false;
   450  * mozilla::IsUnsigned<const unsigned int>::value is true;
   451  * mozilla::IsUnsigned<unsigned char>::value is true;
   452  * mozilla::IsUnsigned<float>::value is false.
   453  */
   454 template<typename T>
   455 struct IsUnsigned : detail::IsUnsignedHelper<T> {};
   457 /* 20.9.5 Type property queries [meta.unary.prop.query] */
   459 /* 20.9.6 Relationships between types [meta.rel] */
   461 /**
   462  * IsSame tests whether two types are the same type.
   463  *
   464  * mozilla::IsSame<int, int>::value is true;
   465  * mozilla::IsSame<int*, int*>::value is true;
   466  * mozilla::IsSame<int, unsigned int>::value is false;
   467  * mozilla::IsSame<void, void>::value is true;
   468  * mozilla::IsSame<const int, int>::value is false;
   469  * mozilla::IsSame<struct S, struct S>::value is true.
   470  */
   471 template<typename T, typename U>
   472 struct IsSame : FalseType {};
   474 template<typename T>
   475 struct IsSame<T, T> : TrueType {};
   477 namespace detail {
   479 #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
   481 template<class Base, class Derived>
   482 struct BaseOfTester : IntegralConstant<bool, __is_base_of(Base, Derived)> {};
   484 #else
   486 // The trickery used to implement IsBaseOf here makes it possible to use it for
   487 // the cases of private and multiple inheritance.  This code was inspired by the
   488 // sample code here:
   489 //
   490 // http://stackoverflow.com/questions/2910979/how-is-base-of-works
   491 template<class Base, class Derived>
   492 struct BaseOfHelper
   493 {
   494   public:
   495     operator Base*() const;
   496     operator Derived*();
   497 };
   499 template<class Base, class Derived>
   500 struct BaseOfTester
   501 {
   502   private:
   503     template<class T>
   504     static char test(Derived*, T);
   505     static int test(Base*, int);
   507   public:
   508     static const bool value =
   509       sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
   510 };
   512 template<class Base, class Derived>
   513 struct BaseOfTester<Base, const Derived>
   514 {
   515   private:
   516     template<class T>
   517     static char test(Derived*, T);
   518     static int test(Base*, int);
   520   public:
   521     static const bool value =
   522       sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
   523 };
   525 template<class Base, class Derived>
   526 struct BaseOfTester<Base&, Derived&> : FalseType {};
   528 template<class Type>
   529 struct BaseOfTester<Type, Type> : TrueType {};
   531 template<class Type>
   532 struct BaseOfTester<Type, const Type> : TrueType {};
   534 #endif
   536 } /* namespace detail */
   538 /*
   539  * IsBaseOf allows to know whether a given class is derived from another.
   540  *
   541  * Consider the following class definitions:
   542  *
   543  *   class A {};
   544  *   class B : public A {};
   545  *   class C {};
   546  *
   547  * mozilla::IsBaseOf<A, B>::value is true;
   548  * mozilla::IsBaseOf<A, C>::value is false;
   549  */
   550 template<class Base, class Derived>
   551 struct IsBaseOf
   552   : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value>
   553 {};
   555 namespace detail {
   557 template<typename From, typename To>
   558 struct ConvertibleTester
   559 {
   560   private:
   561     static From create();
   563     template<typename From1, typename To1>
   564     static char test(To to);
   566     template<typename From1, typename To1>
   567     static int test(...);
   569   public:
   570     static const bool value =
   571       sizeof(test<From, To>(create())) == sizeof(char);
   572 };
   574 } // namespace detail
   576 /**
   577  * IsConvertible determines whether a value of type From will implicitly convert
   578  * to a value of type To.  For example:
   579  *
   580  *   struct A {};
   581  *   struct B : public A {};
   582  *   struct C {};
   583  *
   584  * mozilla::IsConvertible<A, A>::value is true;
   585  * mozilla::IsConvertible<A*, A*>::value is true;
   586  * mozilla::IsConvertible<B, A>::value is true;
   587  * mozilla::IsConvertible<B*, A*>::value is true;
   588  * mozilla::IsConvertible<C, A>::value is false;
   589  * mozilla::IsConvertible<A, C>::value is false;
   590  * mozilla::IsConvertible<A*, C*>::value is false;
   591  * mozilla::IsConvertible<C*, A*>::value is false.
   592  *
   593  * For obscure reasons, you can't use IsConvertible when the types being tested
   594  * are related through private inheritance, and you'll get a compile error if
   595  * you try.  Just don't do it!
   596  */
   597 template<typename From, typename To>
   598 struct IsConvertible
   599   : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value>
   600 {};
   602 /* 20.9.7 Transformations between types [meta.trans] */
   604 /* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
   606 /**
   607  * RemoveConst removes top-level const qualifications on a type.
   608  *
   609  * mozilla::RemoveConst<int>::Type is int;
   610  * mozilla::RemoveConst<const int>::Type is int;
   611  * mozilla::RemoveConst<const int*>::Type is const int*;
   612  * mozilla::RemoveConst<int* const>::Type is int*.
   613  */
   614 template<typename T>
   615 struct RemoveConst
   616 {
   617     typedef T Type;
   618 };
   620 template<typename T>
   621 struct RemoveConst<const T>
   622 {
   623     typedef T Type;
   624 };
   626 /**
   627  * RemoveVolatile removes top-level volatile qualifications on a type.
   628  *
   629  * mozilla::RemoveVolatile<int>::Type is int;
   630  * mozilla::RemoveVolatile<volatile int>::Type is int;
   631  * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*;
   632  * mozilla::RemoveVolatile<int* volatile>::Type is int*.
   633  */
   634 template<typename T>
   635 struct RemoveVolatile
   636 {
   637     typedef T Type;
   638 };
   640 template<typename T>
   641 struct RemoveVolatile<volatile T>
   642 {
   643     typedef T Type;
   644 };
   646 /**
   647  * RemoveCV removes top-level const and volatile qualifications on a type.
   648  *
   649  * mozilla::RemoveCV<int>::Type is int;
   650  * mozilla::RemoveCV<const int>::Type is int;
   651  * mozilla::RemoveCV<volatile int>::Type is int;
   652  * mozilla::RemoveCV<int* const volatile>::Type is int*.
   653  */
   654 template<typename T>
   655 struct RemoveCV
   656 {
   657     typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
   658 };
   660 /* 20.9.7.2 Reference modifications [meta.trans.ref] */
   662 /**
   663  * Converts reference types to the underlying types.
   664  *
   665  * mozilla::RemoveReference<T>::Type is T;
   666  * mozilla::RemoveReference<T&>::Type is T;
   667  * mozilla::RemoveReference<T&&>::Type is T;
   668  */
   670 template<typename T>
   671 struct RemoveReference
   672 {
   673     typedef T Type;
   674 };
   676 template<typename T>
   677 struct RemoveReference<T&>
   678 {
   679     typedef T Type;
   680 };
   682 template<typename T>
   683 struct RemoveReference<T&&>
   684 {
   685     typedef T Type;
   686 };
   688 /* 20.9.7.3 Sign modifications [meta.trans.sign] */
   690 template<bool B, typename T = void>
   691 struct EnableIf;
   693 template<bool Condition, typename A, typename B>
   694 struct Conditional;
   696 namespace detail {
   698 template<bool MakeConst, typename T>
   699 struct WithC : Conditional<MakeConst, const T, T>
   700 {};
   702 template<bool MakeVolatile, typename T>
   703 struct WithV : Conditional<MakeVolatile, volatile T, T>
   704 {};
   707 template<bool MakeConst, bool MakeVolatile, typename T>
   708 struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type>
   709 {};
   711 template<typename T>
   712 struct CorrespondingSigned;
   714 template<>
   715 struct CorrespondingSigned<char> { typedef signed char Type; };
   716 template<>
   717 struct CorrespondingSigned<unsigned char> { typedef signed char Type; };
   718 template<>
   719 struct CorrespondingSigned<unsigned short> { typedef short Type; };
   720 template<>
   721 struct CorrespondingSigned<unsigned int> { typedef int Type; };
   722 template<>
   723 struct CorrespondingSigned<unsigned long> { typedef long Type; };
   724 template<>
   725 struct CorrespondingSigned<unsigned long long> { typedef long long Type; };
   727 template<typename T,
   728          typename CVRemoved = typename RemoveCV<T>::Type,
   729          bool IsSignedIntegerType = IsSigned<CVRemoved>::value &&
   730                                     !IsSame<char, CVRemoved>::value>
   731 struct MakeSigned;
   733 template<typename T, typename CVRemoved>
   734 struct MakeSigned<T, CVRemoved, true>
   735 {
   736     typedef T Type;
   737 };
   739 template<typename T, typename CVRemoved>
   740 struct MakeSigned<T, CVRemoved, false>
   741   : WithCV<IsConst<T>::value, IsVolatile<T>::value,
   742            typename CorrespondingSigned<CVRemoved>::Type>
   743 {};
   745 } // namespace detail
   747 /**
   748  * MakeSigned produces the corresponding signed integer type for a given
   749  * integral type T, with the const/volatile qualifiers of T.  T must be a
   750  * possibly-const/volatile-qualified integral type that isn't bool.
   751  *
   752  * If T is already a signed integer type (not including char!), then T is
   753  * produced.
   754  *
   755  * Otherwise, if T is an unsigned integer type, the signed variety of T, with
   756  * T's const/volatile qualifiers, is produced.
   757  *
   758  * Otherwise, the integral type of the same size as T, with the lowest rank,
   759  * with T's const/volatile qualifiers, is produced.  (This basically only acts
   760  * to produce signed char when T = char.)
   761  *
   762  * mozilla::MakeSigned<unsigned long>::Type is signed long;
   763  * mozilla::MakeSigned<volatile int>::Type is volatile int;
   764  * mozilla::MakeSigned<const unsigned short>::Type is const signed short;
   765  * mozilla::MakeSigned<const char>::Type is const signed char;
   766  * mozilla::MakeSigned<bool> is an error;
   767  * mozilla::MakeSigned<void*> is an error.
   768  */
   769 template<typename T>
   770 struct MakeSigned
   771   : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
   772              typename detail::MakeSigned<T>
   773             >::Type
   774 {};
   776 namespace detail {
   778 template<typename T>
   779 struct CorrespondingUnsigned;
   781 template<>
   782 struct CorrespondingUnsigned<char> { typedef unsigned char Type; };
   783 template<>
   784 struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; };
   785 template<>
   786 struct CorrespondingUnsigned<short> { typedef unsigned short Type; };
   787 template<>
   788 struct CorrespondingUnsigned<int> { typedef unsigned int Type; };
   789 template<>
   790 struct CorrespondingUnsigned<long> { typedef unsigned long Type; };
   791 template<>
   792 struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; };
   795 template<typename T,
   796          typename CVRemoved = typename RemoveCV<T>::Type,
   797          bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value &&
   798                                       !IsSame<char, CVRemoved>::value>
   799 struct MakeUnsigned;
   801 template<typename T, typename CVRemoved>
   802 struct MakeUnsigned<T, CVRemoved, true>
   803 {
   804     typedef T Type;
   805 };
   807 template<typename T, typename CVRemoved>
   808 struct MakeUnsigned<T, CVRemoved, false>
   809   : WithCV<IsConst<T>::value, IsVolatile<T>::value,
   810            typename CorrespondingUnsigned<CVRemoved>::Type>
   811 {};
   813 } // namespace detail
   815 /**
   816  * MakeUnsigned produces the corresponding unsigned integer type for a given
   817  * integral type T, with the const/volatile qualifiers of T.  T must be a
   818  * possibly-const/volatile-qualified integral type that isn't bool.
   819  *
   820  * If T is already an unsigned integer type (not including char!), then T is
   821  * produced.
   822  *
   823  * Otherwise, if T is an signed integer type, the unsigned variety of T, with
   824  * T's const/volatile qualifiers, is produced.
   825  *
   826  * Otherwise, the unsigned integral type of the same size as T, with the lowest
   827  * rank, with T's const/volatile qualifiers, is produced.  (This basically only
   828  * acts to produce unsigned char when T = char.)
   829  *
   830  * mozilla::MakeUnsigned<signed long>::Type is unsigned long;
   831  * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int;
   832  * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short;
   833  * mozilla::MakeUnsigned<const char>::Type is const unsigned char;
   834  * mozilla::MakeUnsigned<bool> is an error;
   835  * mozilla::MakeUnsigned<void*> is an error.
   836  */
   837 template<typename T>
   838 struct MakeUnsigned
   839   : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
   840              typename detail::MakeUnsigned<T>
   841             >::Type
   842 {};
   844 /* 20.9.7.4 Array modifications [meta.trans.arr] */
   846 /* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
   848 /* 20.9.7.6 Other transformations [meta.trans.other] */
   850 /**
   851  * EnableIf is a struct containing a typedef of T if and only if B is true.
   852  *
   853  * mozilla::EnableIf<true, int>::Type is int;
   854  * mozilla::EnableIf<false, int>::Type is a compile-time error.
   855  *
   856  * Use this template to implement SFINAE-style (Substitution Failure Is not An
   857  * Error) requirements.  For example, you might use it to impose a restriction
   858  * on a template parameter:
   859  *
   860  *   template<typename T>
   861  *   class PodVector // vector optimized to store POD (memcpy-able) types
   862  *   {
   863  *      EnableIf<IsPod<T>::value, T>::Type* vector;
   864  *      size_t length;
   865  *      ...
   866  *   };
   867  */
   868 template<bool B, typename T>
   869 struct EnableIf
   870 {};
   872 template<typename T>
   873 struct EnableIf<true, T>
   874 {
   875     typedef T Type;
   876 };
   878 /**
   879  * Conditional selects a class between two, depending on a given boolean value.
   880  *
   881  * mozilla::Conditional<true, A, B>::Type is A;
   882  * mozilla::Conditional<false, A, B>::Type is B;
   883  */
   884 template<bool Condition, typename A, typename B>
   885 struct Conditional
   886 {
   887     typedef A Type;
   888 };
   890 template<class A, class B>
   891 struct Conditional<false, A, B>
   892 {
   893     typedef B Type;
   894 };
   896 } /* namespace mozilla */
   898 #endif /* mozilla_TypeTraits_h */

mercurial