summaryrefslogtreecommitdiff
path: root/mfbt/TypeTraits.h
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/TypeTraits.h')
-rw-r--r--mfbt/TypeTraits.h668
1 files changed, 668 insertions, 0 deletions
diff --git a/mfbt/TypeTraits.h b/mfbt/TypeTraits.h
new file mode 100644
index 0000000..1a1f9cb
--- /dev/null
+++ b/mfbt/TypeTraits.h
@@ -0,0 +1,668 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Template-based metaprogramming and type-testing facilities. */
+
+#ifndef mozilla_TypeTraits_h_
+#define mozilla_TypeTraits_h_
+
+/*
+ * These traits are approximate copies of the traits and semantics from C++11's
+ * <type_traits> header. Don't add traits not in that header! When all
+ * platforms provide that header, we can convert all users and remove this one.
+ */
+
+#include <wchar.h>
+
+namespace mozilla {
+
+/* Forward declarations. */
+
+template<typename> struct RemoveCV;
+
+/* 20.9.3 Helper classes [meta.help] */
+
+/**
+ * Helper class used as a base for various type traits, exposed publicly
+ * because <type_traits> exposes it as well.
+ */
+template<typename T, T Value>
+struct IntegralConstant
+{
+ static const T value = Value;
+ typedef T ValueType;
+ typedef IntegralConstant<T, Value> Type;
+};
+
+/** Convenient aliases. */
+typedef IntegralConstant<bool, true> TrueType;
+typedef IntegralConstant<bool, false> FalseType;
+
+/* 20.9.4 Unary type traits [meta.unary] */
+
+/* 20.9.4.1 Primary type categories [meta.unary.cat] */
+
+namespace detail {
+
+template <typename T>
+struct IsIntegralHelper : FalseType {};
+
+template<> struct IsIntegralHelper<char> : TrueType {};
+template<> struct IsIntegralHelper<signed char> : TrueType {};
+template<> struct IsIntegralHelper<unsigned char> : TrueType {};
+template<> struct IsIntegralHelper<short> : TrueType {};
+template<> struct IsIntegralHelper<unsigned short> : TrueType {};
+template<> struct IsIntegralHelper<int> : TrueType {};
+template<> struct IsIntegralHelper<unsigned int> : TrueType {};
+template<> struct IsIntegralHelper<long> : TrueType {};
+template<> struct IsIntegralHelper<unsigned long> : TrueType {};
+template<> struct IsIntegralHelper<long long> : TrueType {};
+template<> struct IsIntegralHelper<unsigned long long> : TrueType {};
+template<> struct IsIntegralHelper<bool> : TrueType {};
+template<> struct IsIntegralHelper<wchar_t> : TrueType {};
+
+} /* namespace detail */
+
+/**
+ * IsIntegral determines whether a type is an integral type.
+ *
+ * mozilla::IsIntegral<int>::value is true;
+ * mozilla::IsIntegral<unsigned short>::value is true;
+ * mozilla::IsIntegral<const long>::value is true;
+ * mozilla::IsIntegral<int*>::value is false;
+ * mozilla::IsIntegral<double>::value is false;
+ *
+ * Note that the behavior of IsIntegral on char16_t and char32_t is
+ * unspecified.
+ */
+template<typename T>
+struct IsIntegral : detail::IsIntegralHelper<typename RemoveCV<T>::Type>
+{};
+
+template<typename T, typename U>
+struct IsSame;
+
+namespace detail {
+
+template<typename T>
+struct IsFloatingPointHelper
+ : IntegralConstant<bool,
+ IsSame<T, float>::value ||
+ IsSame<T, double>::value ||
+ IsSame<T, long double>::value>
+{};
+
+} // namespace detail
+
+/**
+ * IsFloatingPoint determines whether a type is a floating point type (float,
+ * double, long double).
+ *
+ * mozilla::IsFloatingPoint<int>::value is false;
+ * mozilla::IsFloatingPoint<const float>::value is true;
+ * mozilla::IsFloatingPoint<long double>::value is true;
+ * mozilla::IsFloatingPoint<double*>::value is false.
+ */
+template<typename T>
+struct IsFloatingPoint
+ : detail::IsFloatingPointHelper<typename RemoveCV<T>::Type>
+{};
+
+/**
+ * IsPointer determines whether a type is a pointer type (but not a pointer-to-
+ * member type).
+ *
+ * mozilla::IsPointer<struct S*>::value is true;
+ * mozilla::IsPointer<int**>::value is true;
+ * mozilla::IsPointer<void (*)(void)>::value is true;
+ * mozilla::IsPointer<int>::value is false;
+ * mozilla::IsPointer<struct S>::value is false.
+ */
+template<typename T>
+struct IsPointer : FalseType {};
+
+template<typename T>
+struct IsPointer<T*> : TrueType {};
+
+/* 20.9.4.2 Composite type traits [meta.unary.comp] */
+
+/**
+ * IsArithmetic determines whether a type is arithmetic. A type is arithmetic
+ * iff it is an integral type or a floating point type.
+ *
+ * mozilla::IsArithmetic<int>::value is true;
+ * mozilla::IsArithmetic<double>::value is true;
+ * mozilla::IsArithmetic<long double*>::value is false.
+ */
+template<typename T>
+struct IsArithmetic
+ : IntegralConstant<bool, IsIntegral<T>::value || IsFloatingPoint<T>::value>
+{};
+
+/* 20.9.4.3 Type properties [meta.unary.prop] */
+
+/**
+ * IsConst determines whether a type is const or not.
+ *
+ * mozilla::IsConst<int>::value is false;
+ * mozilla::IsConst<void* const>::value is true;
+ * mozilla::IsConst<const char*>::value is false.
+ */
+template<typename T>
+struct IsConst : FalseType {};
+
+template<typename T>
+struct IsConst<const T> : TrueType {};
+
+/**
+ * IsVolatile determines whether a type is volatile or not.
+ *
+ * mozilla::IsVolatile<int>::value is false;
+ * mozilla::IsVolatile<void* volatile>::value is true;
+ * mozilla::IsVolatile<volatile char*>::value is false.
+ */
+template<typename T>
+struct IsVolatile : FalseType {};
+
+template<typename T>
+struct IsVolatile<volatile T> : TrueType {};
+
+/**
+ * Traits class for identifying POD types. Until C++11 there's no automatic
+ * way to detect PODs, so for the moment this is done manually. Users may
+ * define specializations of this class that inherit from mozilla::TrueType and
+ * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or
+ * false>, or conveniently from mozilla::IsPod for composite types) as needed to
+ * ensure correct IsPod behavior.
+ */
+template<typename T>
+struct IsPod : public FalseType {};
+
+template<> struct IsPod<char> : TrueType {};
+template<> struct IsPod<signed char> : TrueType {};
+template<> struct IsPod<unsigned char> : TrueType {};
+template<> struct IsPod<short> : TrueType {};
+template<> struct IsPod<unsigned short> : TrueType {};
+template<> struct IsPod<int> : TrueType {};
+template<> struct IsPod<unsigned int> : TrueType {};
+template<> struct IsPod<long> : TrueType {};
+template<> struct IsPod<unsigned long> : TrueType {};
+template<> struct IsPod<long long> : TrueType {};
+template<> struct IsPod<unsigned long long> : TrueType {};
+template<> struct IsPod<bool> : TrueType {};
+template<> struct IsPod<float> : TrueType {};
+template<> struct IsPod<double> : TrueType {};
+template<> struct IsPod<wchar_t> : TrueType {};
+template<typename T> struct IsPod<T*> : TrueType {};
+
+namespace detail {
+
+template<typename T, bool = IsFloatingPoint<T>::value>
+struct IsSignedHelper;
+
+template<typename T>
+struct IsSignedHelper<T, true> : TrueType {};
+
+template<typename T>
+struct IsSignedHelper<T, false>
+ : IntegralConstant<bool, IsArithmetic<T>::value && T(-1) < T(1)>
+{};
+
+} // namespace detail
+
+/**
+ * IsSigned determines whether a type is a signed arithmetic type. |char| is
+ * considered a signed type if it has the same representation as |signed char|.
+ *
+ * Don't use this if the type might be user-defined! You might or might not get
+ * a compile error, depending.
+ *
+ * mozilla::IsSigned<int>::value is true;
+ * mozilla::IsSigned<const unsigned int>::value is false;
+ * mozilla::IsSigned<unsigned char>::value is false;
+ * mozilla::IsSigned<float>::value is true.
+ */
+template<typename T>
+struct IsSigned : detail::IsSignedHelper<T> {};
+
+namespace detail {
+
+template<typename T, bool = IsFloatingPoint<T>::value>
+struct IsUnsignedHelper;
+
+template<typename T>
+struct IsUnsignedHelper<T, true> : FalseType {};
+
+template<typename T>
+struct IsUnsignedHelper<T, false>
+ : IntegralConstant<bool,
+ IsArithmetic<T>::value &&
+ (IsSame<typename RemoveCV<T>::Type, bool>::value ||
+ T(1) < T(-1))>
+{};
+
+} // namespace detail
+
+/**
+ * IsUnsigned determines whether a type is an unsigned arithmetic type.
+ *
+ * Don't use this if the type might be user-defined! You might or might not get
+ * a compile error, depending.
+ *
+ * mozilla::IsUnsigned<int>::value is false;
+ * mozilla::IsUnsigned<const unsigned int>::value is true;
+ * mozilla::IsUnsigned<unsigned char>::value is true;
+ * mozilla::IsUnsigned<float>::value is false.
+ */
+template<typename T>
+struct IsUnsigned : detail::IsUnsignedHelper<T> {};
+
+/* 20.9.5 Type property queries [meta.unary.prop.query] */
+
+/* 20.9.6 Relationships between types [meta.rel] */
+
+/**
+ * IsSame tests whether two types are the same type.
+ *
+ * mozilla::IsSame<int, int>::value is true;
+ * mozilla::IsSame<int*, int*>::value is true;
+ * mozilla::IsSame<int, unsigned int>::value is false;
+ * mozilla::IsSame<void, void>::value is true;
+ * mozilla::IsSame<const int, int>::value is false;
+ * mozilla::IsSame<struct S, struct S>::value is true.
+ */
+template<typename T, typename U>
+struct IsSame : FalseType {};
+
+template<typename T>
+struct IsSame<T, T> : TrueType {};
+
+namespace detail {
+
+// The trickery used to implement IsBaseOf here makes it possible to use it for
+// the cases of private and multiple inheritance. This code was inspired by the
+// sample code here:
+//
+// http://stackoverflow.com/questions/2910979/how-is-base-of-works
+template<class Base, class Derived>
+struct BaseOfHelper
+{
+ public:
+ operator Base*() const;
+ operator Derived*();
+};
+
+template<class Base, class Derived>
+struct BaseOfTester
+{
+ private:
+ template<class T>
+ static char test(Derived*, T);
+ static int test(Base*, int);
+
+ public:
+ static const bool value =
+ sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
+};
+
+template<class Base, class Derived>
+struct BaseOfTester<Base, const Derived>
+{
+ private:
+ template<class T>
+ static char test(Derived*, T);
+ static int test(Base*, int);
+
+ public:
+ static const bool value =
+ sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
+};
+
+template<class Base, class Derived>
+struct BaseOfTester<Base&, Derived&> : FalseType {};
+
+template<class Type>
+struct BaseOfTester<Type, Type> : TrueType {};
+
+template<class Type>
+struct BaseOfTester<Type, const Type> : TrueType {};
+
+} /* namespace detail */
+
+/*
+ * IsBaseOf allows to know whether a given class is derived from another.
+ *
+ * Consider the following class definitions:
+ *
+ * class A {};
+ * class B : public A {};
+ * class C {};
+ *
+ * mozilla::IsBaseOf<A, B>::value is true;
+ * mozilla::IsBaseOf<A, C>::value is false;
+ */
+template<class Base, class Derived>
+struct IsBaseOf
+ : IntegralConstant<bool, detail::BaseOfTester<Base, Derived>::value>
+{};
+
+namespace detail {
+
+template<typename From, typename To>
+struct ConvertibleTester
+{
+ private:
+ static From create();
+
+ template<typename From1, typename To1>
+ static char test(To to);
+
+ template<typename From1, typename To1>
+ static int test(...);
+
+ public:
+ static const bool value =
+ sizeof(test<From, To>(create())) == sizeof(char);
+};
+
+} // namespace detail
+
+/**
+ * IsConvertible determines whether a value of type From will implicitly convert
+ * to a value of type To. For example:
+ *
+ * struct A {};
+ * struct B : public A {};
+ * struct C {};
+ *
+ * mozilla::IsConvertible<A, A>::value is true;
+ * mozilla::IsConvertible<A*, A*>::value is true;
+ * mozilla::IsConvertible<B, A>::value is true;
+ * mozilla::IsConvertible<B*, A*>::value is true;
+ * mozilla::IsConvertible<C, A>::value is false;
+ * mozilla::IsConvertible<A, C>::value is false;
+ * mozilla::IsConvertible<A*, C*>::value is false;
+ * mozilla::IsConvertible<C*, A*>::value is false.
+ *
+ * For obscure reasons, you can't use IsConvertible when the types being tested
+ * are related through private inheritance, and you'll get a compile error if
+ * you try. Just don't do it!
+ */
+template<typename From, typename To>
+struct IsConvertible
+ : IntegralConstant<bool, detail::ConvertibleTester<From, To>::value>
+{};
+
+/* 20.9.7 Transformations between types [meta.trans] */
+
+/* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
+
+/**
+ * RemoveConst removes top-level const qualifications on a type.
+ *
+ * mozilla::RemoveConst<int>::Type is int;
+ * mozilla::RemoveConst<const int>::Type is int;
+ * mozilla::RemoveConst<const int*>::Type is const int*;
+ * mozilla::RemoveConst<int* const>::Type is int*.
+ */
+template<typename T>
+struct RemoveConst
+{
+ typedef T Type;
+};
+
+template<typename T>
+struct RemoveConst<const T>
+{
+ typedef T Type;
+};
+
+/**
+ * RemoveVolatile removes top-level volatile qualifications on a type.
+ *
+ * mozilla::RemoveVolatile<int>::Type is int;
+ * mozilla::RemoveVolatile<volatile int>::Type is int;
+ * mozilla::RemoveVolatile<volatile int*>::Type is volatile int*;
+ * mozilla::RemoveVolatile<int* volatile>::Type is int*.
+ */
+template<typename T>
+struct RemoveVolatile
+{
+ typedef T Type;
+};
+
+template<typename T>
+struct RemoveVolatile<volatile T>
+{
+ typedef T Type;
+};
+
+/**
+ * RemoveCV removes top-level const and volatile qualifications on a type.
+ *
+ * mozilla::RemoveCV<int>::Type is int;
+ * mozilla::RemoveCV<const int>::Type is int;
+ * mozilla::RemoveCV<volatile int>::Type is int;
+ * mozilla::RemoveCV<int* const volatile>::Type is int*.
+ */
+template<typename T>
+struct RemoveCV
+{
+ typedef typename RemoveConst<typename RemoveVolatile<T>::Type>::Type Type;
+};
+
+/* 20.9.7.2 Reference modifications [meta.trans.ref] */
+
+/* 20.9.7.3 Sign modifications [meta.trans.sign] */
+
+template<bool B, typename T = void>
+struct EnableIf;
+
+template<bool Condition, typename A, typename B>
+struct Conditional;
+
+namespace detail {
+
+template<bool MakeConst, typename T>
+struct WithC : Conditional<MakeConst, const T, T>
+{};
+
+template<bool MakeVolatile, typename T>
+struct WithV : Conditional<MakeVolatile, volatile T, T>
+{};
+
+
+template<bool MakeConst, bool MakeVolatile, typename T>
+struct WithCV : WithC<MakeConst, typename WithV<MakeVolatile, T>::Type>
+{};
+
+template<typename T>
+struct CorrespondingSigned;
+
+template<>
+struct CorrespondingSigned<char> { typedef signed char Type; };
+template<>
+struct CorrespondingSigned<unsigned char> { typedef signed char Type; };
+template<>
+struct CorrespondingSigned<unsigned short> { typedef short Type; };
+template<>
+struct CorrespondingSigned<unsigned int> { typedef int Type; };
+template<>
+struct CorrespondingSigned<unsigned long> { typedef long Type; };
+template<>
+struct CorrespondingSigned<unsigned long long> { typedef long long Type; };
+
+template<typename T,
+ typename CVRemoved = typename RemoveCV<T>::Type,
+ bool IsSignedIntegerType = IsSigned<CVRemoved>::value &&
+ !IsSame<char, CVRemoved>::value>
+struct MakeSigned;
+
+template<typename T, typename CVRemoved>
+struct MakeSigned<T, CVRemoved, true>
+{
+ typedef T Type;
+};
+
+template<typename T, typename CVRemoved>
+struct MakeSigned<T, CVRemoved, false>
+ : WithCV<IsConst<T>::value, IsVolatile<T>::value,
+ typename CorrespondingSigned<CVRemoved>::Type>
+{};
+
+} // namespace detail
+
+/**
+ * MakeSigned produces the corresponding signed integer type for a given
+ * integral type T, with the const/volatile qualifiers of T. T must be a
+ * possibly-const/volatile-qualified integral type that isn't bool.
+ *
+ * If T is already a signed integer type (not including char!), then T is
+ * produced.
+ *
+ * Otherwise, if T is an unsigned integer type, the signed variety of T, with
+ * T's const/volatile qualifiers, is produced.
+ *
+ * Otherwise, the integral type of the same size as T, with the lowest rank,
+ * with T's const/volatile qualifiers, is produced. (This basically only acts
+ * to produce signed char when T = char.)
+ *
+ * mozilla::MakeSigned<unsigned long>::Type is signed long;
+ * mozilla::MakeSigned<volatile int>::Type is volatile int;
+ * mozilla::MakeSigned<const unsigned short>::Type is const signed short;
+ * mozilla::MakeSigned<const char>::Type is const signed char;
+ * mozilla::MakeSigned<bool> is an error;
+ * mozilla::MakeSigned<void*> is an error.
+ */
+template<typename T>
+struct MakeSigned
+ : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
+ typename detail::MakeSigned<T>
+ >::Type
+{};
+
+namespace detail {
+
+template<typename T>
+struct CorrespondingUnsigned;
+
+template<>
+struct CorrespondingUnsigned<char> { typedef unsigned char Type; };
+template<>
+struct CorrespondingUnsigned<signed char> { typedef unsigned char Type; };
+template<>
+struct CorrespondingUnsigned<short> { typedef unsigned short Type; };
+template<>
+struct CorrespondingUnsigned<int> { typedef unsigned int Type; };
+template<>
+struct CorrespondingUnsigned<long> { typedef unsigned long Type; };
+template<>
+struct CorrespondingUnsigned<long long> { typedef unsigned long long Type; };
+
+
+template<typename T,
+ typename CVRemoved = typename RemoveCV<T>::Type,
+ bool IsUnsignedIntegerType = IsUnsigned<CVRemoved>::value &&
+ !IsSame<char, CVRemoved>::value>
+struct MakeUnsigned;
+
+template<typename T, typename CVRemoved>
+struct MakeUnsigned<T, CVRemoved, true>
+{
+ typedef T Type;
+};
+
+template<typename T, typename CVRemoved>
+struct MakeUnsigned<T, CVRemoved, false>
+ : WithCV<IsConst<T>::value, IsVolatile<T>::value,
+ typename CorrespondingUnsigned<CVRemoved>::Type>
+{};
+
+} // namespace detail
+
+/**
+ * MakeUnsigned produces the corresponding unsigned integer type for a given
+ * integral type T, with the const/volatile qualifiers of T. T must be a
+ * possibly-const/volatile-qualified integral type that isn't bool.
+ *
+ * If T is already an unsigned integer type (not including char!), then T is
+ * produced.
+ *
+ * Otherwise, if T is an signed integer type, the unsigned variety of T, with
+ * T's const/volatile qualifiers, is produced.
+ *
+ * Otherwise, the unsigned integral type of the same size as T, with the lowest
+ * rank, with T's const/volatile qualifiers, is produced. (This basically only
+ * acts to produce unsigned char when T = char.)
+ *
+ * mozilla::MakeUnsigned<signed long>::Type is unsigned long;
+ * mozilla::MakeUnsigned<volatile unsigned int>::Type is volatile unsigned int;
+ * mozilla::MakeUnsigned<const signed short>::Type is const unsigned short;
+ * mozilla::MakeUnsigned<const char>::Type is const unsigned char;
+ * mozilla::MakeUnsigned<bool> is an error;
+ * mozilla::MakeUnsigned<void*> is an error.
+ */
+template<typename T>
+struct MakeUnsigned
+ : EnableIf<IsIntegral<T>::value && !IsSame<bool, typename RemoveCV<T>::Type>::value,
+ typename detail::MakeUnsigned<T>
+ >::Type
+{};
+
+/* 20.9.7.4 Array modifications [meta.trans.arr] */
+
+/* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
+
+/* 20.9.7.6 Other transformations [meta.trans.other] */
+
+/**
+ * EnableIf is a struct containing a typedef of T if and only if B is true.
+ *
+ * mozilla::EnableIf<true, int>::Type is int;
+ * mozilla::EnableIf<false, int>::Type is a compile-time error.
+ *
+ * Use this template to implement SFINAE-style (Substitution Failure Is not An
+ * Error) requirements. For example, you might use it to impose a restriction
+ * on a template parameter:
+ *
+ * template<typename T>
+ * class PodVector // vector optimized to store POD (memcpy-able) types
+ * {
+ * EnableIf<IsPod<T>::value, T>::Type* vector;
+ * size_t length;
+ * ...
+ * };
+ */
+template<bool B, typename T>
+struct EnableIf
+{};
+
+template<typename T>
+struct EnableIf<true, T>
+{
+ typedef T Type;
+};
+
+/**
+ * Conditional selects a class between two, depending on a given boolean value.
+ *
+ * mozilla::Conditional<true, A, B>::Type is A;
+ * mozilla::Conditional<false, A, B>::Type is B;
+ */
+template<bool Condition, typename A, typename B>
+struct Conditional
+{
+ typedef A Type;
+};
+
+template<class A, class B>
+struct Conditional<false, A, B>
+{
+ typedef B Type;
+};
+
+} /* namespace mozilla */
+
+#endif /* mozilla_TypeTraits_h_ */