Tue, 06 Jan 2015 21:39:09 +0100
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 */ |