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.

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

mercurial