mfbt/TypeTraits.h

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

mercurial