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 */