mfbt/TypeTraits.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/TypeTraits.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,898 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Template-based metaprogramming and type-testing facilities. */
    1.11 +
    1.12 +#ifndef mozilla_TypeTraits_h
    1.13 +#define mozilla_TypeTraits_h
    1.14 +
    1.15 +#include "mozilla/Types.h"
    1.16 +
    1.17 +/*
    1.18 + * These traits are approximate copies of the traits and semantics from C++11's
    1.19 + * <type_traits> header.  Don't add traits not in that header!  When all
    1.20 + * platforms provide that header, we can convert all users and remove this one.
    1.21 + */
    1.22 +
    1.23 +#include <wchar.h>
    1.24 +
    1.25 +namespace mozilla {
    1.26 +
    1.27 +/* Forward declarations. */
    1.28 +
    1.29 +template<typename> struct RemoveCV;
    1.30 +
    1.31 +/* 20.9.3 Helper classes [meta.help] */
    1.32 +
    1.33 +/**
    1.34 + * Helper class used as a base for various type traits, exposed publicly
    1.35 + * because <type_traits> exposes it as well.
    1.36 + */
    1.37 +template<typename T, T Value>
    1.38 +struct IntegralConstant
    1.39 +{
    1.40 +    static const T value = Value;
    1.41 +    typedef T ValueType;
    1.42 +    typedef IntegralConstant<T, Value> Type;
    1.43 +};
    1.44 +
    1.45 +/** Convenient aliases. */
    1.46 +typedef IntegralConstant<bool, true> TrueType;
    1.47 +typedef IntegralConstant<bool, false> FalseType;
    1.48 +
    1.49 +/* 20.9.4 Unary type traits [meta.unary] */
    1.50 +
    1.51 +/* 20.9.4.1 Primary type categories [meta.unary.cat] */
    1.52 +
    1.53 +namespace detail {
    1.54 +
    1.55 +template <typename T>
    1.56 +struct IsIntegralHelper : FalseType {};
    1.57 +
    1.58 +template<> struct IsIntegralHelper<char>               : TrueType {};
    1.59 +template<> struct IsIntegralHelper<signed char>        : TrueType {};
    1.60 +template<> struct IsIntegralHelper<unsigned char>      : TrueType {};
    1.61 +template<> struct IsIntegralHelper<short>              : TrueType {};
    1.62 +template<> struct IsIntegralHelper<unsigned short>     : TrueType {};
    1.63 +template<> struct IsIntegralHelper<int>                : TrueType {};
    1.64 +template<> struct IsIntegralHelper<unsigned int>       : TrueType {};
    1.65 +template<> struct IsIntegralHelper<long>               : TrueType {};
    1.66 +template<> struct IsIntegralHelper<unsigned long>      : TrueType {};
    1.67 +template<> struct IsIntegralHelper<long long>          : TrueType {};
    1.68 +template<> struct IsIntegralHelper<unsigned long long> : TrueType {};
    1.69 +template<> struct IsIntegralHelper<bool>               : TrueType {};
    1.70 +template<> struct IsIntegralHelper<wchar_t>            : TrueType {};
    1.71 +#ifdef MOZ_CHAR16_IS_NOT_WCHAR
    1.72 +template<> struct IsIntegralHelper<char16_t>           : TrueType {};
    1.73 +#endif
    1.74 +
    1.75 +} /* namespace detail */
    1.76 +
    1.77 +/**
    1.78 + * IsIntegral determines whether a type is an integral type.
    1.79 + *
    1.80 + * mozilla::IsIntegral<int>::value is true;
    1.81 + * mozilla::IsIntegral<unsigned short>::value is true;
    1.82 + * mozilla::IsIntegral<const long>::value is true;
    1.83 + * mozilla::IsIntegral<int*>::value is false;
    1.84 + * mozilla::IsIntegral<double>::value is false;
    1.85 + *
    1.86 + * Note that the behavior of IsIntegral on char16_t and char32_t is
    1.87 + * unspecified.
    1.88 + */
    1.89 +template<typename T>
    1.90 +struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type>
    1.91 +{};
    1.92 +
    1.93 +template<typename T, typename U>
    1.94 +struct IsSame;
    1.95 +
    1.96 +namespace detail {
    1.97 +
    1.98 +template<typename T>
    1.99 +struct IsFloatingPointHelper
   1.100 +  : IntegralConstant<bool,
   1.101 +                     IsSame<T, float>::value ||
   1.102 +                     IsSame<T, double>::value ||
   1.103 +                     IsSame<T, long double>::value>
   1.104 +{};
   1.105 +
   1.106 +} // namespace detail
   1.107 +
   1.108 +/**
   1.109 + * IsFloatingPoint determines whether a type is a floating point type (float,
   1.110 + * double, long double).
   1.111 + *
   1.112 + * mozilla::IsFloatingPoint<int>::value is false;
   1.113 + * mozilla::IsFloatingPoint<const float>::value is true;
   1.114 + * mozilla::IsFloatingPoint<long double>::value is true;
   1.115 + * mozilla::IsFloatingPoint<double*>::value is false.
   1.116 + */
   1.117 +template<typename T>
   1.118 +struct IsFloatingPoint
   1.119 +  : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type>
   1.120 +{};
   1.121 +
   1.122 +namespace detail {
   1.123 +
   1.124 +template<typename T>
   1.125 +struct IsArrayHelper : FalseType {};
   1.126 +
   1.127 +template<typename T, decltype(sizeof(1)) N>
   1.128 +struct IsArrayHelper<T[N]> : TrueType {};
   1.129 +
   1.130 +template<typename T>
   1.131 +struct IsArrayHelper<T[]> : TrueType {};
   1.132 +
   1.133 +} // namespace detail
   1.134 +
   1.135 +/**
   1.136 + * IsArray determines whether a type is an array type, of known or unknown
   1.137 + * length.
   1.138 + *
   1.139 + * mozilla::IsArray<int>::value is false;
   1.140 + * mozilla::IsArray<int[]>::value is true;
   1.141 + * mozilla::IsArray<int[5]>::value is true.
   1.142 + */
   1.143 +template<typename T>
   1.144 +struct IsArray : detail::IsArrayHelper<typename RemoveCV<T>::Type>
   1.145 +{};
   1.146 +
   1.147 +/**
   1.148 + * IsPointer determines whether a type is a pointer type (but not a pointer-to-
   1.149 + * member type).
   1.150 + *
   1.151 + * mozilla::IsPointer<struct S*>::value is true;
   1.152 + * mozilla::IsPointer<int**>::value is true;
   1.153 + * mozilla::IsPointer<void (*)(void)>::value is true;
   1.154 + * mozilla::IsPointer<int>::value is false;
   1.155 + * mozilla::IsPointer<struct S>::value is false.
   1.156 + */
   1.157 +template<typename T>
   1.158 +struct IsPointer : FalseType {};
   1.159 +
   1.160 +template<typename T>
   1.161 +struct IsPointer<T*> : TrueType {};
   1.162 +
   1.163 +/**
   1.164 + * IsLvalueReference determines whether a type is an lvalue reference.
   1.165 + *
   1.166 + * mozilla::IsLvalueReference<struct S*>::value is false;
   1.167 + * mozilla::IsLvalueReference<int**>::value is false;
   1.168 + * mozilla::IsLvalueReference<void (*)(void)>::value is false;
   1.169 + * mozilla::IsLvalueReference<int>::value is false;
   1.170 + * mozilla::IsLvalueReference<struct S>::value is false;
   1.171 + * mozilla::IsLvalueReference<struct S*&>::value is true;
   1.172 + * mozilla::IsLvalueReference<struct S&&>::value is false.
   1.173 + */
   1.174 +template<typename T>
   1.175 +struct IsLvalueReference : FalseType {};
   1.176 +
   1.177 +template<typename T>
   1.178 +struct IsLvalueReference<T&> : TrueType {};
   1.179 +
   1.180 +/**
   1.181 + * IsRvalueReference determines whether a type is an rvalue reference.
   1.182 + *
   1.183 + * mozilla::IsRvalueReference<struct S*>::value is false;
   1.184 + * mozilla::IsRvalueReference<int**>::value is false;
   1.185 + * mozilla::IsRvalueReference<void (*)(void)>::value is false;
   1.186 + * mozilla::IsRvalueReference<int>::value is false;
   1.187 + * mozilla::IsRvalueReference<struct S>::value is false;
   1.188 + * mozilla::IsRvalueReference<struct S*&>::value is false;
   1.189 + * mozilla::IsRvalueReference<struct S&&>::value is true.
   1.190 + */
   1.191 +template<typename T>
   1.192 +struct IsRvalueReference : FalseType {};
   1.193 +
   1.194 +template<typename T>
   1.195 +struct IsRvalueReference<T&&> : TrueType {};
   1.196 +
   1.197 +namespace detail {
   1.198 +
   1.199 +// __is_enum is a supported extension across all of our supported compilers.
   1.200 +template<typename T>
   1.201 +struct IsEnumHelper
   1.202 +  : IntegralConstant<bool, __is_enum(T)>
   1.203 +{};
   1.204 +
   1.205 +} // namespace detail
   1.206 +
   1.207 +/**
   1.208 + * IsEnum determines whether a type is an enum type.
   1.209 + *
   1.210 + * mozilla::IsEnum<enum S>::value is true;
   1.211 + * mozilla::IsEnum<enum S*>::value is false;
   1.212 + * mozilla::IsEnum<int>::value is false;
   1.213 + */
   1.214 +template<typename T>
   1.215 +struct IsEnum
   1.216 +  : detail::IsEnumHelper<typename RemoveCV<T>::Type>
   1.217 +{};
   1.218 +
   1.219 +namespace detail {
   1.220 +
   1.221 +// __is_class is a supported extension across all of our supported compilers:
   1.222 +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
   1.223 +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
   1.224 +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
   1.225 +template<typename T>
   1.226 +struct IsClassHelper
   1.227 +  : IntegralConstant<bool, __is_class(T)>
   1.228 +{};
   1.229 +
   1.230 +} // namespace detail
   1.231 +
   1.232 +/**
   1.233 + * IsClass determines whether a type is a class type (but not a union).
   1.234 + *
   1.235 + * struct S {};
   1.236 + * union U {};
   1.237 + * mozilla::IsClass<int>::value is false;
   1.238 + * mozilla::IsClass<const S>::value is true;
   1.239 + * mozilla::IsClass<U>::value is false;
   1.240 + */
   1.241 +template<typename T>
   1.242 +struct IsClass
   1.243 +  : detail::IsClassHelper<typename RemoveCV<T>::Type>
   1.244 +{};
   1.245 +
   1.246 +/* 20.9.4.2 Composite type traits [meta.unary.comp] */
   1.247 +
   1.248 +/**
   1.249 + * IsReference determines whether a type is an lvalue or rvalue reference.
   1.250 + *
   1.251 + * mozilla::IsReference<struct S*>::value is false;
   1.252 + * mozilla::IsReference<int**>::value is false;
   1.253 + * mozilla::IsReference<int&>::value is true;
   1.254 + * mozilla::IsReference<void (*)(void)>::value is false;
   1.255 + * mozilla::IsReference<const int&>::value is true;
   1.256 + * mozilla::IsReference<int>::value is false;
   1.257 + * mozilla::IsReference<struct S>::value is false;
   1.258 + * mozilla::IsReference<struct S&>::value is true;
   1.259 + * mozilla::IsReference<struct S*&>::value is true;
   1.260 + * mozilla::IsReference<struct S&&>::value is true.
   1.261 + */
   1.262 +template<typename T>
   1.263 +struct IsReference
   1.264 +  : IntegralConstant<bool,
   1.265 +                     IsLvalueReference<T>::value || IsRvalueReference<T>::value>
   1.266 +{};
   1.267 +
   1.268 +/**
   1.269 + * IsArithmetic determines whether a type is arithmetic.  A type is arithmetic
   1.270 + * iff it is an integral type or a floating point type.
   1.271 + *
   1.272 + * mozilla::IsArithmetic<int>::value is true;
   1.273 + * mozilla::IsArithmetic<double>::value is true;
   1.274 + * mozilla::IsArithmetic<long double*>::value is false.
   1.275 + */
   1.276 +template<typename T>
   1.277 +struct IsArithmetic
   1.278 +  : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value>
   1.279 +{};
   1.280 +
   1.281 +/* 20.9.4.3 Type properties [meta.unary.prop] */
   1.282 +
   1.283 +/**
   1.284 + * IsConst determines whether a type is const or not.
   1.285 + *
   1.286 + * mozilla::IsConst<int>::value is false;
   1.287 + * mozilla::IsConst<void* const>::value is true;
   1.288 + * mozilla::IsConst<const char*>::value is false.
   1.289 + */
   1.290 +template<typename T>
   1.291 +struct IsConst : FalseType {};
   1.292 +
   1.293 +template<typename T>
   1.294 +struct IsConst<const T> : TrueType {};
   1.295 +
   1.296 +/**
   1.297 + * IsVolatile determines whether a type is volatile or not.
   1.298 + *
   1.299 + * mozilla::IsVolatile<int>::value is false;
   1.300 + * mozilla::IsVolatile<void* volatile>::value is true;
   1.301 + * mozilla::IsVolatile<volatile char*>::value is false.
   1.302 + */
   1.303 +template<typename T>
   1.304 +struct IsVolatile : FalseType {};
   1.305 +
   1.306 +template<typename T>
   1.307 +struct IsVolatile<volatile T> : TrueType {};
   1.308 +
   1.309 +/**
   1.310 + * Traits class for identifying POD types.  Until C++11 there's no automatic
   1.311 + * way to detect PODs, so for the moment this is done manually.  Users may
   1.312 + * define specializations of this class that inherit from mozilla::TrueType and
   1.313 + * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or
   1.314 + * false>, or conveniently from mozilla::IsPod for composite types) as needed to
   1.315 + * ensure correct IsPod behavior.
   1.316 + */
   1.317 +template<typename T>
   1.318 +struct IsPod : public FalseType {};
   1.319 +
   1.320 +template<> struct IsPod<char>               : TrueType {};
   1.321 +template<> struct IsPod<signed char>        : TrueType {};
   1.322 +template<> struct IsPod<unsigned char>      : TrueType {};
   1.323 +template<> struct IsPod<short>              : TrueType {};
   1.324 +template<> struct IsPod<unsigned short>     : TrueType {};
   1.325 +template<> struct IsPod<int>                : TrueType {};
   1.326 +template<> struct IsPod<unsigned int>       : TrueType {};
   1.327 +template<> struct IsPod<long>               : TrueType {};
   1.328 +template<> struct IsPod<unsigned long>      : TrueType {};
   1.329 +template<> struct IsPod<long long>          : TrueType {};
   1.330 +template<> struct IsPod<unsigned long long> : TrueType {};
   1.331 +template<> struct IsPod<bool>               : TrueType {};
   1.332 +template<> struct IsPod<float>              : TrueType {};
   1.333 +template<> struct IsPod<double>             : TrueType {};
   1.334 +template<> struct IsPod<wchar_t>            : TrueType {};
   1.335 +#ifdef MOZ_CHAR16_IS_NOT_WCHAR
   1.336 +template<> struct IsPod<char16_t>           : TrueType {};
   1.337 +#endif
   1.338 +template<typename T> struct IsPod<T*>       : TrueType {};
   1.339 +
   1.340 +namespace detail {
   1.341 +
   1.342 +// __is_empty is a supported extension across all of our supported compilers:
   1.343 +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
   1.344 +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
   1.345 +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
   1.346 +template<typename T>
   1.347 +struct IsEmptyHelper
   1.348 +  : IntegralConstant<bool, IsClass<T>::value && __is_empty(T)>
   1.349 +{};
   1.350 +
   1.351 +} // namespace detail
   1.352 +
   1.353 +/**
   1.354 + * IsEmpty determines whether a type is a class (but not a union) that is empty.
   1.355 + *
   1.356 + * A class is empty iff it and all its base classes have no non-static data
   1.357 + * members (except bit-fields of length 0) and no virtual member functions, and
   1.358 + * no base class is empty or a virtual base class.
   1.359 + *
   1.360 + * Intuitively, empty classes don't have any data that has to be stored in
   1.361 + * instances of those classes.  (The size of the class must still be non-zero,
   1.362 + * because distinct array elements of any type must have different addresses.
   1.363 + * However, if the Empty Base Optimization is implemented by the compiler [most
   1.364 + * compilers implement it, and in certain cases C++11 requires it], the size of
   1.365 + * a class inheriting from an empty |Base| class need not be inflated by
   1.366 + * |sizeof(Base)|.)  And intuitively, non-empty classes have data members and/or
   1.367 + * vtable pointers that must be stored in each instance for proper behavior.
   1.368 + *
   1.369 + *   static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty");
   1.370 + *   union U1 { int x; };
   1.371 + *   static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty");
   1.372 + *   struct E1 {};
   1.373 + *   struct E2 { int : 0 };
   1.374 + *   struct E3 : E1 {};
   1.375 + *   struct E4 : E2 {};
   1.376 + *   static_assert(mozilla::IsEmpty<E1>::value &&
   1.377 + *                 mozilla::IsEmpty<E2>::value &&
   1.378 + *                 mozilla::IsEmpty<E3>::value &&
   1.379 + *                 mozilla::IsEmpty<E4>::value,
   1.380 + *                 "all empty");
   1.381 + *   union U2 { E1 e1; };
   1.382 + *   static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty");
   1.383 + *   struct NE1 { int x; };
   1.384 + *   struct NE2 : virtual E1 {};
   1.385 + *   struct NE3 : E2 { virtual ~NE3() {} };
   1.386 + *   struct NE4 { virtual void f() {} };
   1.387 + *   static_assert(!mozilla::IsEmpty<NE1>::value &&
   1.388 + *                 !mozilla::IsEmpty<NE2>::value &&
   1.389 + *                 !mozilla::IsEmpty<NE3>::value &&
   1.390 + *                 !mozilla::IsEmpty<NE4>::value,
   1.391 + *                 "all empty");
   1.392 + */
   1.393 +template<typename T>
   1.394 +struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type>
   1.395 +{};
   1.396 +
   1.397 +
   1.398 +namespace detail {
   1.399 +
   1.400 +template<typename T, bool = IsFloatingPoint<T>::value>
   1.401 +struct IsSignedHelper;
   1.402 +
   1.403 +template<typename T>
   1.404 +struct IsSignedHelper<T, true> : TrueType {};
   1.405 +
   1.406 +template<typename T>
   1.407 +struct IsSignedHelper<T, false>
   1.408 +  : IntegralConstant<bool, IsArithmetic<T>::value && T(-1) < T(1)>
   1.409 +{};
   1.410 +
   1.411 +} // namespace detail
   1.412 +
   1.413 +/**
   1.414 + * IsSigned determines whether a type is a signed arithmetic type.  |char| is
   1.415 + * considered a signed type if it has the same representation as |signed char|.
   1.416 + *
   1.417 + * Don't use this if the type might be user-defined!  You might or might not get
   1.418 + * a compile error, depending.
   1.419 + *
   1.420 + * mozilla::IsSigned<int>::value is true;
   1.421 + * mozilla::IsSigned<const unsigned int>::value is false;
   1.422 + * mozilla::IsSigned<unsigned char>::value is false;
   1.423 + * mozilla::IsSigned<float>::value is true.
   1.424 + */
   1.425 +template<typename T>
   1.426 +struct IsSigned : detail::IsSignedHelper<T> {};
   1.427 +
   1.428 +namespace detail {
   1.429 +
   1.430 +template<typename T, bool = IsFloatingPoint<T>::value>
   1.431 +struct IsUnsignedHelper;
   1.432 +
   1.433 +template<typename T>
   1.434 +struct IsUnsignedHelper<T, true> : FalseType {};
   1.435 +
   1.436 +template<typename T>
   1.437 +struct IsUnsignedHelper<T, false>
   1.438 +  : IntegralConstant<bool,
   1.439 +                     IsArithmetic<T>::value &&
   1.440 +                     (IsSame<typename RemoveCV<T>::Type, bool>::value ||
   1.441 +                      T(1) < T(-1))>
   1.442 +{};
   1.443 +
   1.444 +} // namespace detail
   1.445 +
   1.446 +/**
   1.447 + * IsUnsigned determines whether a type is an unsigned arithmetic type.
   1.448 + *
   1.449 + * Don't use this if the type might be user-defined!  You might or might not get
   1.450 + * a compile error, depending.
   1.451 + *
   1.452 + * mozilla::IsUnsigned<int>::value is false;
   1.453 + * mozilla::IsUnsigned<const unsigned int>::value is true;
   1.454 + * mozilla::IsUnsigned<unsigned char>::value is true;
   1.455 + * mozilla::IsUnsigned<float>::value is false.
   1.456 + */
   1.457 +template<typename T>
   1.458 +struct IsUnsigned : detail::IsUnsignedHelper<T> {};
   1.459 +
   1.460 +/* 20.9.5 Type property queries [meta.unary.prop.query] */
   1.461 +
   1.462 +/* 20.9.6 Relationships between types [meta.rel] */
   1.463 +
   1.464 +/**
   1.465 + * IsSame tests whether two types are the same type.
   1.466 + *
   1.467 + * mozilla::IsSame<int, int>::value is true;
   1.468 + * mozilla::IsSame<int*, int*>::value is true;
   1.469 + * mozilla::IsSame<int, unsigned int>::value is false;
   1.470 + * mozilla::IsSame<void, void>::value is true;
   1.471 + * mozilla::IsSame<const int, int>::value is false;
   1.472 + * mozilla::IsSame<struct S, struct S>::value is true.
   1.473 + */
   1.474 +template<typename T, typename U>
   1.475 +struct IsSame : FalseType {};
   1.476 +
   1.477 +template<typename T>
   1.478 +struct IsSame<T, T> : TrueType {};
   1.479 +
   1.480 +namespace detail {
   1.481 +
   1.482 +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
   1.483 +
   1.484 +template<class Base, class Derived>
   1.485 +struct BaseOfTester : IntegralConstant<bool, __is_base_of(Base, Derived)> {};
   1.486 +
   1.487 +#else
   1.488 +
   1.489 +// The trickery used to implement IsBaseOf here makes it possible to use it for
   1.490 +// the cases of private and multiple inheritance.  This code was inspired by the
   1.491 +// sample code here:
   1.492 +//
   1.493 +// http://stackoverflow.com/questions/2910979/how-is-base-of-works
   1.494 +template<class Base, class Derived>
   1.495 +struct BaseOfHelper
   1.496 +{
   1.497 +  public:
   1.498 +    operator Base*() const;
   1.499 +    operator Derived*();
   1.500 +};
   1.501 +
   1.502 +template<class Base, class Derived>
   1.503 +struct BaseOfTester
   1.504 +{
   1.505 +  private:
   1.506 +    template<class T>
   1.507 +    static char test(Derived*, T);
   1.508 +    static int test(Base*, int);
   1.509 +
   1.510 +  public:
   1.511 +    static const bool value =
   1.512 +      sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
   1.513 +};
   1.514 +
   1.515 +template<class Base, class Derived>
   1.516 +struct BaseOfTester<Base, const Derived>
   1.517 +{
   1.518 +  private:
   1.519 +    template<class T>
   1.520 +    static char test(Derived*, T);
   1.521 +    static int test(Base*, int);
   1.522 +
   1.523 +  public:
   1.524 +    static const bool value =
   1.525 +      sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
   1.526 +};
   1.527 +
   1.528 +template<class Base, class Derived>
   1.529 +struct BaseOfTester<Base&, Derived&> : FalseType {};
   1.530 +
   1.531 +template<class Type>
   1.532 +struct BaseOfTester<Type, Type> : TrueType {};
   1.533 +
   1.534 +template<class Type>
   1.535 +struct BaseOfTester<Type, const Type> : TrueType {};
   1.536 +
   1.537 +#endif
   1.538 +
   1.539 +} /* namespace detail */
   1.540 +
   1.541 +/*
   1.542 + * IsBaseOf allows to know whether a given class is derived from another.
   1.543 + *
   1.544 + * Consider the following class definitions:
   1.545 + *
   1.546 + *   class A {};
   1.547 + *   class B : public A {};
   1.548 + *   class C {};
   1.549 + *
   1.550 + * mozilla::IsBaseOf<A, B>::value is true;
   1.551 + * mozilla::IsBaseOf<A, C>::value is false;
   1.552 + */
   1.553 +template<class Base, class Derived>
   1.554 +struct IsBaseOf
   1.555 +  : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value>
   1.556 +{};
   1.557 +
   1.558 +namespace detail {
   1.559 +
   1.560 +template<typename From, typename To>
   1.561 +struct ConvertibleTester
   1.562 +{
   1.563 +  private:
   1.564 +    static From create();
   1.565 +
   1.566 +    template<typename From1, typename To1>
   1.567 +    static char test(To to);
   1.568 +
   1.569 +    template<typename From1, typename To1>
   1.570 +    static int test(...);
   1.571 +
   1.572 +  public:
   1.573 +    static const bool value =
   1.574 +      sizeof(test<From, To>(create())) == sizeof(char);
   1.575 +};
   1.576 +
   1.577 +} // namespace detail
   1.578 +
   1.579 +/**
   1.580 + * IsConvertible determines whether a value of type From will implicitly convert
   1.581 + * to a value of type To.  For example:
   1.582 + *
   1.583 + *   struct A {};
   1.584 + *   struct B : public A {};
   1.585 + *   struct C {};
   1.586 + *
   1.587 + * mozilla::IsConvertible<A, A>::value is true;
   1.588 + * mozilla::IsConvertible<A*, A*>::value is true;
   1.589 + * mozilla::IsConvertible<B, A>::value is true;
   1.590 + * mozilla::IsConvertible<B*, A*>::value is true;
   1.591 + * mozilla::IsConvertible<C, A>::value is false;
   1.592 + * mozilla::IsConvertible<A, C>::value is false;
   1.593 + * mozilla::IsConvertible<A*, C*>::value is false;
   1.594 + * mozilla::IsConvertible<C*, A*>::value is false.
   1.595 + *
   1.596 + * For obscure reasons, you can't use IsConvertible when the types being tested
   1.597 + * are related through private inheritance, and you'll get a compile error if
   1.598 + * you try.  Just don't do it!
   1.599 + */
   1.600 +template<typename From, typename To>
   1.601 +struct IsConvertible
   1.602 +  : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value>
   1.603 +{};
   1.604 +
   1.605 +/* 20.9.7 Transformations between types [meta.trans] */
   1.606 +
   1.607 +/* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
   1.608 +
   1.609 +/**
   1.610 + * RemoveConst removes top-level const qualifications on a type.
   1.611 + *
   1.612 + * mozilla::RemoveConst<int>::Type is int;
   1.613 + * mozilla::RemoveConst<const int>::Type is int;
   1.614 + * mozilla::RemoveConst<const int*>::Type is const int*;
   1.615 + * mozilla::RemoveConst<int* const>::Type is int*.
   1.616 + */
   1.617 +template<typename T>
   1.618 +struct RemoveConst
   1.619 +{
   1.620 +    typedef T Type;
   1.621 +};
   1.622 +
   1.623 +template<typename T>
   1.624 +struct RemoveConst<const T>
   1.625 +{
   1.626 +    typedef T Type;
   1.627 +};
   1.628 +
   1.629 +/**
   1.630 + * RemoveVolatile removes top-level volatile qualifications on a type.
   1.631 + *
   1.632 + * mozilla::RemoveVolatile<int>::Type is int;
   1.633 + * mozilla::RemoveVolatile<volatile int>::Type is int;
   1.634 + * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*;
   1.635 + * mozilla::RemoveVolatile<int* volatile>::Type is int*.
   1.636 + */
   1.637 +template<typename T>
   1.638 +struct RemoveVolatile
   1.639 +{
   1.640 +    typedef T Type;
   1.641 +};
   1.642 +
   1.643 +template<typename T>
   1.644 +struct RemoveVolatile<volatile T>
   1.645 +{
   1.646 +    typedef T Type;
   1.647 +};
   1.648 +
   1.649 +/**
   1.650 + * RemoveCV removes top-level const and volatile qualifications on a type.
   1.651 + *
   1.652 + * mozilla::RemoveCV<int>::Type is int;
   1.653 + * mozilla::RemoveCV<const int>::Type is int;
   1.654 + * mozilla::RemoveCV<volatile int>::Type is int;
   1.655 + * mozilla::RemoveCV<int* const volatile>::Type is int*.
   1.656 + */
   1.657 +template<typename T>
   1.658 +struct RemoveCV
   1.659 +{
   1.660 +    typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
   1.661 +};
   1.662 +
   1.663 +/* 20.9.7.2 Reference modifications [meta.trans.ref] */
   1.664 +
   1.665 +/**
   1.666 + * Converts reference types to the underlying types.
   1.667 + *
   1.668 + * mozilla::RemoveReference<T>::Type is T;
   1.669 + * mozilla::RemoveReference<T&>::Type is T;
   1.670 + * mozilla::RemoveReference<T&&>::Type is T;
   1.671 + */
   1.672 +
   1.673 +template<typename T>
   1.674 +struct RemoveReference
   1.675 +{
   1.676 +    typedef T Type;
   1.677 +};
   1.678 +
   1.679 +template<typename T>
   1.680 +struct RemoveReference<T&>
   1.681 +{
   1.682 +    typedef T Type;
   1.683 +};
   1.684 +
   1.685 +template<typename T>
   1.686 +struct RemoveReference<T&&>
   1.687 +{
   1.688 +    typedef T Type;
   1.689 +};
   1.690 +
   1.691 +/* 20.9.7.3 Sign modifications [meta.trans.sign] */
   1.692 +
   1.693 +template<bool B, typename T = void>
   1.694 +struct EnableIf;
   1.695 +
   1.696 +template<bool Condition, typename A, typename B>
   1.697 +struct Conditional;
   1.698 +
   1.699 +namespace detail {
   1.700 +
   1.701 +template<bool MakeConst, typename T>
   1.702 +struct WithC : Conditional<MakeConst, const T, T>
   1.703 +{};
   1.704 +
   1.705 +template<bool MakeVolatile, typename T>
   1.706 +struct WithV : Conditional<MakeVolatile, volatile T, T>
   1.707 +{};
   1.708 +
   1.709 +
   1.710 +template<bool MakeConst, bool MakeVolatile, typename T>
   1.711 +struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type>
   1.712 +{};
   1.713 +
   1.714 +template<typename T>
   1.715 +struct CorrespondingSigned;
   1.716 +
   1.717 +template<>
   1.718 +struct CorrespondingSigned<char> { typedef signed char Type; };
   1.719 +template<>
   1.720 +struct CorrespondingSigned<unsigned char> { typedef signed char Type; };
   1.721 +template<>
   1.722 +struct CorrespondingSigned<unsigned short> { typedef short Type; };
   1.723 +template<>
   1.724 +struct CorrespondingSigned<unsigned int> { typedef int Type; };
   1.725 +template<>
   1.726 +struct CorrespondingSigned<unsigned long> { typedef long Type; };
   1.727 +template<>
   1.728 +struct CorrespondingSigned<unsigned long long> { typedef long long Type; };
   1.729 +
   1.730 +template<typename T,
   1.731 +         typename CVRemoved = typename RemoveCV<T>::Type,
   1.732 +         bool IsSignedIntegerType = IsSigned<CVRemoved>::value &&
   1.733 +                                    !IsSame<char, CVRemoved>::value>
   1.734 +struct MakeSigned;
   1.735 +
   1.736 +template<typename T, typename CVRemoved>
   1.737 +struct MakeSigned<T, CVRemoved, true>
   1.738 +{
   1.739 +    typedef T Type;
   1.740 +};
   1.741 +
   1.742 +template<typename T, typename CVRemoved>
   1.743 +struct MakeSigned<T, CVRemoved, false>
   1.744 +  : WithCV<IsConst<T>::value, IsVolatile<T>::value,
   1.745 +           typename CorrespondingSigned<CVRemoved>::Type>
   1.746 +{};
   1.747 +
   1.748 +} // namespace detail
   1.749 +
   1.750 +/**
   1.751 + * MakeSigned produces the corresponding signed integer type for a given
   1.752 + * integral type T, with the const/volatile qualifiers of T.  T must be a
   1.753 + * possibly-const/volatile-qualified integral type that isn't bool.
   1.754 + *
   1.755 + * If T is already a signed integer type (not including char!), then T is
   1.756 + * produced.
   1.757 + *
   1.758 + * Otherwise, if T is an unsigned integer type, the signed variety of T, with
   1.759 + * T's const/volatile qualifiers, is produced.
   1.760 + *
   1.761 + * Otherwise, the integral type of the same size as T, with the lowest rank,
   1.762 + * with T's const/volatile qualifiers, is produced.  (This basically only acts
   1.763 + * to produce signed char when T = char.)
   1.764 + *
   1.765 + * mozilla::MakeSigned<unsigned long>::Type is signed long;
   1.766 + * mozilla::MakeSigned<volatile int>::Type is volatile int;
   1.767 + * mozilla::MakeSigned<const unsigned short>::Type is const signed short;
   1.768 + * mozilla::MakeSigned<const char>::Type is const signed char;
   1.769 + * mozilla::MakeSigned<bool> is an error;
   1.770 + * mozilla::MakeSigned<void*> is an error.
   1.771 + */
   1.772 +template<typename T>
   1.773 +struct MakeSigned
   1.774 +  : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
   1.775 +             typename detail::MakeSigned<T>
   1.776 +            >::Type
   1.777 +{};
   1.778 +
   1.779 +namespace detail {
   1.780 +
   1.781 +template<typename T>
   1.782 +struct CorrespondingUnsigned;
   1.783 +
   1.784 +template<>
   1.785 +struct CorrespondingUnsigned<char> { typedef unsigned char Type; };
   1.786 +template<>
   1.787 +struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; };
   1.788 +template<>
   1.789 +struct CorrespondingUnsigned<short> { typedef unsigned short Type; };
   1.790 +template<>
   1.791 +struct CorrespondingUnsigned<int> { typedef unsigned int Type; };
   1.792 +template<>
   1.793 +struct CorrespondingUnsigned<long> { typedef unsigned long Type; };
   1.794 +template<>
   1.795 +struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; };
   1.796 +
   1.797 +
   1.798 +template<typename T,
   1.799 +         typename CVRemoved = typename RemoveCV<T>::Type,
   1.800 +         bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value &&
   1.801 +                                      !IsSame<char, CVRemoved>::value>
   1.802 +struct MakeUnsigned;
   1.803 +
   1.804 +template<typename T, typename CVRemoved>
   1.805 +struct MakeUnsigned<T, CVRemoved, true>
   1.806 +{
   1.807 +    typedef T Type;
   1.808 +};
   1.809 +
   1.810 +template<typename T, typename CVRemoved>
   1.811 +struct MakeUnsigned<T, CVRemoved, false>
   1.812 +  : WithCV<IsConst<T>::value, IsVolatile<T>::value,
   1.813 +           typename CorrespondingUnsigned<CVRemoved>::Type>
   1.814 +{};
   1.815 +
   1.816 +} // namespace detail
   1.817 +
   1.818 +/**
   1.819 + * MakeUnsigned produces the corresponding unsigned integer type for a given
   1.820 + * integral type T, with the const/volatile qualifiers of T.  T must be a
   1.821 + * possibly-const/volatile-qualified integral type that isn't bool.
   1.822 + *
   1.823 + * If T is already an unsigned integer type (not including char!), then T is
   1.824 + * produced.
   1.825 + *
   1.826 + * Otherwise, if T is an signed integer type, the unsigned variety of T, with
   1.827 + * T's const/volatile qualifiers, is produced.
   1.828 + *
   1.829 + * Otherwise, the unsigned integral type of the same size as T, with the lowest
   1.830 + * rank, with T's const/volatile qualifiers, is produced.  (This basically only
   1.831 + * acts to produce unsigned char when T = char.)
   1.832 + *
   1.833 + * mozilla::MakeUnsigned<signed long>::Type is unsigned long;
   1.834 + * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int;
   1.835 + * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short;
   1.836 + * mozilla::MakeUnsigned<const char>::Type is const unsigned char;
   1.837 + * mozilla::MakeUnsigned<bool> is an error;
   1.838 + * mozilla::MakeUnsigned<void*> is an error.
   1.839 + */
   1.840 +template<typename T>
   1.841 +struct MakeUnsigned
   1.842 +  : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
   1.843 +             typename detail::MakeUnsigned<T>
   1.844 +            >::Type
   1.845 +{};
   1.846 +
   1.847 +/* 20.9.7.4 Array modifications [meta.trans.arr] */
   1.848 +
   1.849 +/* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
   1.850 +
   1.851 +/* 20.9.7.6 Other transformations [meta.trans.other] */
   1.852 +
   1.853 +/**
   1.854 + * EnableIf is a struct containing a typedef of T if and only if B is true.
   1.855 + *
   1.856 + * mozilla::EnableIf<true, int>::Type is int;
   1.857 + * mozilla::EnableIf<false, int>::Type is a compile-time error.
   1.858 + *
   1.859 + * Use this template to implement SFINAE-style (Substitution Failure Is not An
   1.860 + * Error) requirements.  For example, you might use it to impose a restriction
   1.861 + * on a template parameter:
   1.862 + *
   1.863 + *   template<typename T>
   1.864 + *   class PodVector // vector optimized to store POD (memcpy-able) types
   1.865 + *   {
   1.866 + *      EnableIf<IsPod<T>::value, T>::Type* vector;
   1.867 + *      size_t length;
   1.868 + *      ...
   1.869 + *   };
   1.870 + */
   1.871 +template<bool B, typename T>
   1.872 +struct EnableIf
   1.873 +{};
   1.874 +
   1.875 +template<typename T>
   1.876 +struct EnableIf<true, T>
   1.877 +{
   1.878 +    typedef T Type;
   1.879 +};
   1.880 +
   1.881 +/**
   1.882 + * Conditional selects a class between two, depending on a given boolean value.
   1.883 + *
   1.884 + * mozilla::Conditional<true, A, B>::Type is A;
   1.885 + * mozilla::Conditional<false, A, B>::Type is B;
   1.886 + */
   1.887 +template<bool Condition, typename A, typename B>
   1.888 +struct Conditional
   1.889 +{
   1.890 +    typedef A Type;
   1.891 +};
   1.892 +
   1.893 +template<class A, class B>
   1.894 +struct Conditional<false, A, B>
   1.895 +{
   1.896 +    typedef B Type;
   1.897 +};
   1.898 +
   1.899 +} /* namespace mozilla */
   1.900 +
   1.901 +#endif /* mozilla_TypeTraits_h */

mercurial