From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- mfbt/TypeTraits.h | 1262 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1262 insertions(+) create mode 100644 mfbt/TypeTraits.h (limited to 'mfbt/TypeTraits.h') diff --git a/mfbt/TypeTraits.h b/mfbt/TypeTraits.h new file mode 100644 index 000000000..084f608ca --- /dev/null +++ b/mfbt/TypeTraits.h @@ -0,0 +1,1262 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 + +#include "mozilla/Types.h" + +/* + * These traits are approximate copies of the traits and semantics from C++11's + * 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 + +namespace mozilla { + +/* Forward declarations. */ + +template struct RemoveCV; +template struct AddRvalueReference; + +/* 20.2.4 Function template declval [declval] */ + +/** + * DeclVal simplifies the definition of expressions which occur as unevaluated + * operands. It converts T to a reference type, making it possible to use in + * decltype expressions even if T does not have a default constructor, e.g.: + * decltype(DeclVal().foo()) + */ +template +typename AddRvalueReference::Type DeclVal(); + +/* 20.9.3 Helper classes [meta.help] */ + +/** + * Helper class used as a base for various type traits, exposed publicly + * because exposes it as well. + */ +template +struct IntegralConstant +{ + static const T value = Value; + typedef T ValueType; + typedef IntegralConstant Type; +}; + +/** Convenient aliases. */ +typedef IntegralConstant TrueType; +typedef IntegralConstant FalseType; + +/* 20.9.4 Unary type traits [meta.unary] */ + +/* 20.9.4.1 Primary type categories [meta.unary.cat] */ + +namespace detail { + +template +struct IsVoidHelper : FalseType {}; + +template<> +struct IsVoidHelper : TrueType {}; + +} // namespace detail + +/** + * IsVoid determines whether a type is void. + * + * mozilla::IsVoid::value is false; + * mozilla::IsVoid::value is true; + * mozilla::IsVoid::value is false; + * mozilla::IsVoid::value is true. + */ +template +struct IsVoid : detail::IsVoidHelper::Type> {}; + +namespace detail { + +template +struct IsIntegralHelper : FalseType {}; + +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; +template<> struct IsIntegralHelper : TrueType {}; + +} /* namespace detail */ + +/** + * IsIntegral determines whether a type is an integral type. + * + * mozilla::IsIntegral::value is true; + * mozilla::IsIntegral::value is true; + * mozilla::IsIntegral::value is true; + * mozilla::IsIntegral::value is false; + * mozilla::IsIntegral::value is false; + */ +template +struct IsIntegral : detail::IsIntegralHelper::Type> +{}; + +template +struct IsSame; + +namespace detail { + +template +struct IsFloatingPointHelper + : IntegralConstant::value || + IsSame::value || + IsSame::value> +{}; + +} // namespace detail + +/** + * IsFloatingPoint determines whether a type is a floating point type (float, + * double, long double). + * + * mozilla::IsFloatingPoint::value is false; + * mozilla::IsFloatingPoint::value is true; + * mozilla::IsFloatingPoint::value is true; + * mozilla::IsFloatingPoint::value is false. + */ +template +struct IsFloatingPoint + : detail::IsFloatingPointHelper::Type> +{}; + +namespace detail { + +template +struct IsArrayHelper : FalseType {}; + +template +struct IsArrayHelper : TrueType {}; + +template +struct IsArrayHelper : TrueType {}; + +} // namespace detail + +/** + * IsArray determines whether a type is an array type, of known or unknown + * length. + * + * mozilla::IsArray::value is false; + * mozilla::IsArray::value is true; + * mozilla::IsArray::value is true. + */ +template +struct IsArray : detail::IsArrayHelper::Type> +{}; + +namespace detail { + +template +struct IsFunPtr; + +template +struct IsFunPtr + : public FalseType +{}; + +template +struct IsFunPtr + : public TrueType +{}; + +}; // namespace detail + +/** + * IsFunction determines whether a type is a function type. Function pointers + * don't qualify here--only the type of an actual function symbol. We do not + * correctly handle varags function types because of a bug in MSVC. + * + * Given the function: + * void f(int) {} + * + * mozilla::IsFunction is true; + * mozilla::IsFunction is false; + * mozilla::IsFunction is true. + */ +template +struct IsFunction + : public detail::IsFunPtr::Type *> +{}; + +namespace detail { + +template +struct IsPointerHelper : FalseType {}; + +template +struct IsPointerHelper : TrueType {}; + +} // namespace detail + +/** + * IsPointer determines whether a type is a possibly-CV-qualified pointer type + * (but not a pointer-to-member type). + * + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is true; + * mozilla::IsPointer::value is false; + * mozilla::IsPointer::value is false. + * mozilla::IsPointer::value is false + */ +template +struct IsPointer : detail::IsPointerHelper::Type> +{}; + +/** + * IsLvalueReference determines whether a type is an lvalue reference. + * + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is false; + * mozilla::IsLvalueReference::value is true; + * mozilla::IsLvalueReference::value is false. + */ +template +struct IsLvalueReference : FalseType {}; + +template +struct IsLvalueReference : TrueType {}; + +/** + * IsRvalueReference determines whether a type is an rvalue reference. + * + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is false; + * mozilla::IsRvalueReference::value is true. + */ +template +struct IsRvalueReference : FalseType {}; + +template +struct IsRvalueReference : TrueType {}; + +namespace detail { + +// __is_enum is a supported extension across all of our supported compilers. +template +struct IsEnumHelper + : IntegralConstant +{}; + +} // namespace detail + +/** + * IsEnum determines whether a type is an enum type. + * + * mozilla::IsEnum::value is true; + * mozilla::IsEnum::value is false; + * mozilla::IsEnum::value is false; + */ +template +struct IsEnum + : detail::IsEnumHelper::Type> +{}; + +namespace detail { + +// __is_class is a supported extension across all of our supported compilers: +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx +template +struct IsClassHelper + : IntegralConstant +{}; + +} // namespace detail + +/** + * IsClass determines whether a type is a class type (but not a union). + * + * struct S {}; + * union U {}; + * mozilla::IsClass::value is false; + * mozilla::IsClass::value is true; + * mozilla::IsClass::value is false; + */ +template +struct IsClass + : detail::IsClassHelper::Type> +{}; + +/* 20.9.4.2 Composite type traits [meta.unary.comp] */ + +/** + * IsReference determines whether a type is an lvalue or rvalue reference. + * + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is false; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is true; + * mozilla::IsReference::value is true. + */ +template +struct IsReference + : IntegralConstant::value || IsRvalueReference::value> +{}; + +/** + * IsArithmetic determines whether a type is arithmetic. A type is arithmetic + * iff it is an integral type or a floating point type. + * + * mozilla::IsArithmetic::value is true; + * mozilla::IsArithmetic::value is true; + * mozilla::IsArithmetic::value is false. + */ +template +struct IsArithmetic + : IntegralConstant::value || IsFloatingPoint::value> +{}; + +namespace detail { + +template +struct IsMemberPointerHelper : FalseType {}; + +template +struct IsMemberPointerHelper : TrueType {}; + +} // namespace detail + +/** + * IsMemberPointer determines whether a type is pointer to non-static member + * object or a pointer to non-static member function. + * + * mozilla::IsMemberPointer::value is true + * mozilla::IsMemberPointer::value is false + */ +template +struct IsMemberPointer + : detail::IsMemberPointerHelper::Type> +{}; + +/** + * IsScalar determines whether a type is a scalar type. + * + * mozilla::IsScalar::value is true + * mozilla::IsScalar::value is true + * mozilla::IsScalar::value is false + */ +template +struct IsScalar + : IntegralConstant::value || IsEnum::value || + IsPointer::value || IsMemberPointer::value> +{}; + +/* 20.9.4.3 Type properties [meta.unary.prop] */ + +/** + * IsConst determines whether a type is const or not. + * + * mozilla::IsConst::value is false; + * mozilla::IsConst::value is true; + * mozilla::IsConst::value is false. + */ +template +struct IsConst : FalseType {}; + +template +struct IsConst : TrueType {}; + +/** + * IsVolatile determines whether a type is volatile or not. + * + * mozilla::IsVolatile::value is false; + * mozilla::IsVolatile::value is true; + * mozilla::IsVolatile::value is false. + */ +template +struct IsVolatile : FalseType {}; + +template +struct IsVolatile : 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, or conveniently from mozilla::IsPod for composite types) as needed to + * ensure correct IsPod behavior. + */ +template +struct IsPod : public FalseType {}; + +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template<> struct IsPod : TrueType {}; +template struct IsPod : TrueType {}; + +namespace detail { + +// __is_empty is a supported extension across all of our supported compilers: +// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html +// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits +// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx +template +struct IsEmptyHelper + : IntegralConstant::value && __is_empty(T)> +{}; + +} // namespace detail + +/** + * IsEmpty determines whether a type is a class (but not a union) that is empty. + * + * A class is empty iff it and all its base classes have no non-static data + * members (except bit-fields of length 0) and no virtual member functions, and + * no base class is empty or a virtual base class. + * + * Intuitively, empty classes don't have any data that has to be stored in + * instances of those classes. (The size of the class must still be non-zero, + * because distinct array elements of any type must have different addresses. + * However, if the Empty Base Optimization is implemented by the compiler [most + * compilers implement it, and in certain cases C++11 requires it], the size of + * a class inheriting from an empty |Base| class need not be inflated by + * |sizeof(Base)|.) And intuitively, non-empty classes have data members and/or + * vtable pointers that must be stored in each instance for proper behavior. + * + * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); + * union U1 { int x; }; + * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); + * struct E1 {}; + * struct E2 { int : 0 }; + * struct E3 : E1 {}; + * struct E4 : E2 {}; + * static_assert(mozilla::IsEmpty::value && + * mozilla::IsEmpty::value && + * mozilla::IsEmpty::value && + * mozilla::IsEmpty::value, + * "all empty"); + * union U2 { E1 e1; }; + * static_assert(!mozilla::IsEmpty::value, "not a class => not empty"); + * struct NE1 { int x; }; + * struct NE2 : virtual E1 {}; + * struct NE3 : E2 { virtual ~NE3() {} }; + * struct NE4 { virtual void f() {} }; + * static_assert(!mozilla::IsEmpty::value && + * !mozilla::IsEmpty::value && + * !mozilla::IsEmpty::value && + * !mozilla::IsEmpty::value, + * "all empty"); + */ +template +struct IsEmpty : detail::IsEmptyHelper::Type> +{}; + + +namespace detail { + +template::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> +struct IsSignedHelper; + +// Floating point is signed. +template +struct IsSignedHelper : TrueType {}; + +// Integral is conditionally signed. +template +struct IsSignedHelper + : IntegralConstant +{}; + +// Non-floating point, non-integral is not signed. +template +struct IsSignedHelper : FalseType {}; + +} // 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|. + * + * mozilla::IsSigned::value is true; + * mozilla::IsSigned::value is false; + * mozilla::IsSigned::value is false; + * mozilla::IsSigned::value is true. + */ +template +struct IsSigned : detail::IsSignedHelper {}; + +namespace detail { + +template::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> +struct IsUnsignedHelper; + +// Floating point is not unsigned. +template +struct IsUnsignedHelper : FalseType {}; + +// Integral is conditionally unsigned. +template +struct IsUnsignedHelper + : IntegralConstant::value || bool(NoCV(1) < NoCV(-1)))> +{}; + +// Non-floating point, non-integral is not unsigned. +template +struct IsUnsignedHelper : FalseType {}; + +} // namespace detail + +/** + * IsUnsigned determines whether a type is an unsigned arithmetic type. + * + * mozilla::IsUnsigned::value is false; + * mozilla::IsUnsigned::value is true; + * mozilla::IsUnsigned::value is true; + * mozilla::IsUnsigned::value is false. + */ +template +struct IsUnsigned : detail::IsUnsignedHelper {}; + +namespace detail { + +struct DoIsDestructibleImpl +{ + template().~T())> + static TrueType test(int); + template + static FalseType test(...); +}; + +template +struct IsDestructibleImpl : public DoIsDestructibleImpl +{ + typedef decltype(test(0)) Type; +}; + +} // namespace detail + +template +struct IsDestructible : public detail::IsDestructibleImpl::Type {}; + +/* 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::value is true; + * mozilla::IsSame::value is true; + * mozilla::IsSame::value is false; + * mozilla::IsSame::value is true; + * mozilla::IsSame::value is false; + * mozilla::IsSame::value is true. + */ +template +struct IsSame : FalseType {}; + +template +struct IsSame : TrueType {}; + +namespace detail { + +#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) + +template +struct BaseOfTester : IntegralConstant {}; + +#else + +// 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 +struct BaseOfHelper +{ +public: + operator Base*() const; + operator Derived*(); +}; + +template +struct BaseOfTester +{ +private: + template + static char test(Derived*, T); + static int test(Base*, int); + +public: + static const bool value = + sizeof(test(BaseOfHelper(), int())) == sizeof(char); +}; + +template +struct BaseOfTester +{ +private: + template + static char test(Derived*, T); + static int test(Base*, int); + +public: + static const bool value = + sizeof(test(BaseOfHelper(), int())) == sizeof(char); +}; + +template +struct BaseOfTester : FalseType {}; + +template +struct BaseOfTester : TrueType {}; + +template +struct BaseOfTester : TrueType {}; + +#endif + +} /* 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::value is true; + * mozilla::IsBaseOf::value is false; + */ +template +struct IsBaseOf + : IntegralConstant::value> +{}; + +namespace detail { + +template +struct ConvertibleTester +{ +private: + template + static char test_helper(To1); + + template + static decltype(test_helper(DeclVal())) test(int); + + template + static int test(...); + +public: + static const bool value = + sizeof(test(0)) == 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::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is true; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::value is false; + * mozilla::IsConvertible::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! + * + * Note - we need special handling for void, which ConvertibleTester doesn't + * handle. The void handling here doesn't handle const/volatile void correctly, + * which could be easily fixed if the need arises. + */ +template +struct IsConvertible + : IntegralConstant::value> +{}; + +template +struct IsConvertible + : IntegralConstant::value> +{}; + +template +struct IsConvertible + : IntegralConstant::value> +{}; + +template<> +struct IsConvertible + : TrueType +{}; + +/* 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::Type is int; + * mozilla::RemoveConst::Type is int; + * mozilla::RemoveConst::Type is const int*; + * mozilla::RemoveConst::Type is int*. + */ +template +struct RemoveConst +{ + typedef T Type; +}; + +template +struct RemoveConst +{ + typedef T Type; +}; + +/** + * RemoveVolatile removes top-level volatile qualifications on a type. + * + * mozilla::RemoveVolatile::Type is int; + * mozilla::RemoveVolatile::Type is int; + * mozilla::RemoveVolatile::Type is volatile int*; + * mozilla::RemoveVolatile::Type is int*. + */ +template +struct RemoveVolatile +{ + typedef T Type; +}; + +template +struct RemoveVolatile +{ + typedef T Type; +}; + +/** + * RemoveCV removes top-level const and volatile qualifications on a type. + * + * mozilla::RemoveCV::Type is int; + * mozilla::RemoveCV::Type is int; + * mozilla::RemoveCV::Type is int; + * mozilla::RemoveCV::Type is int*. + */ +template +struct RemoveCV +{ + typedef typename RemoveConst::Type>::Type Type; +}; + +/* 20.9.7.2 Reference modifications [meta.trans.ref] */ + +/** + * Converts reference types to the underlying types. + * + * mozilla::RemoveReference::Type is T; + * mozilla::RemoveReference::Type is T; + * mozilla::RemoveReference::Type is T; + */ + +template +struct RemoveReference +{ + typedef T Type; +}; + +template +struct RemoveReference +{ + typedef T Type; +}; + +template +struct RemoveReference +{ + typedef T Type; +}; + +template +struct Conditional; + +namespace detail { + +enum Voidness { TIsVoid, TIsNotVoid }; + +template::value ? TIsVoid : TIsNotVoid> +struct AddLvalueReferenceHelper; + +template +struct AddLvalueReferenceHelper +{ + typedef void Type; +}; + +template +struct AddLvalueReferenceHelper +{ + typedef T& Type; +}; + +} // namespace detail + +/** + * AddLvalueReference adds an lvalue & reference to T if one isn't already + * present. (Note: adding an lvalue reference to an rvalue && reference in + * essence replaces the && with a &&, per C+11 reference collapsing rules. For + * example, int&& would become int&.) + * + * The final computed type will only *not* be an lvalue reference if T is void. + * + * mozilla::AddLvalueReference::Type is int&; + * mozilla::AddLvalueRference::Type is volatile int&; + * mozilla::AddLvalueReference::Type is void*&; + * mozilla::AddLvalueReference::Type is void; + * mozilla::AddLvalueReference::Type is struct S&. + */ +template +struct AddLvalueReference + : detail::AddLvalueReferenceHelper +{}; + +namespace detail { + +template::value ? TIsVoid : TIsNotVoid> +struct AddRvalueReferenceHelper; + +template +struct AddRvalueReferenceHelper +{ + typedef void Type; +}; + +template +struct AddRvalueReferenceHelper +{ + typedef T&& Type; +}; + +} // namespace detail + +/** + * AddRvalueReference adds an rvalue && reference to T if one isn't already + * present. (Note: adding an rvalue reference to an lvalue & reference in + * essence keeps the &, per C+11 reference collapsing rules. For example, + * int& would remain int&.) + * + * The final computed type will only *not* be a reference if T is void. + * + * mozilla::AddRvalueReference::Type is int&&; + * mozilla::AddRvalueRference::Type is volatile int&; + * mozilla::AddRvalueRference::Type is const int&&; + * mozilla::AddRvalueReference::Type is void*&&; + * mozilla::AddRvalueReference::Type is void; + * mozilla::AddRvalueReference::Type is struct S&. + */ +template +struct AddRvalueReference + : detail::AddRvalueReferenceHelper +{}; + +/* 20.9.7.3 Sign modifications [meta.trans.sign] */ + +template +struct EnableIf; + +namespace detail { + +template +struct WithC : Conditional +{}; + +template +struct WithV : Conditional +{}; + + +template +struct WithCV : WithC::Type> +{}; + +template +struct CorrespondingSigned; + +template<> +struct CorrespondingSigned { typedef signed char Type; }; +template<> +struct CorrespondingSigned { typedef signed char Type; }; +template<> +struct CorrespondingSigned { typedef short Type; }; +template<> +struct CorrespondingSigned { typedef int Type; }; +template<> +struct CorrespondingSigned { typedef long Type; }; +template<> +struct CorrespondingSigned { typedef long long Type; }; + +template::Type, + bool IsSignedIntegerType = IsSigned::value && + !IsSame::value> +struct MakeSigned; + +template +struct MakeSigned +{ + typedef T Type; +}; + +template +struct MakeSigned + : WithCV::value, IsVolatile::value, + typename CorrespondingSigned::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::Type is signed long; + * mozilla::MakeSigned::Type is volatile int; + * mozilla::MakeSigned::Type is const signed short; + * mozilla::MakeSigned::Type is const signed char; + * mozilla::MakeSigned is an error; + * mozilla::MakeSigned is an error. + */ +template +struct MakeSigned + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeSigned + >::Type +{}; + +namespace detail { + +template +struct CorrespondingUnsigned; + +template<> +struct CorrespondingUnsigned { typedef unsigned char Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned char Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned short Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned int Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned long Type; }; +template<> +struct CorrespondingUnsigned { typedef unsigned long long Type; }; + + +template::Type, + bool IsUnsignedIntegerType = IsUnsigned::value && + !IsSame::value> +struct MakeUnsigned; + +template +struct MakeUnsigned +{ + typedef T Type; +}; + +template +struct MakeUnsigned + : WithCV::value, IsVolatile::value, + typename CorrespondingUnsigned::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::Type is unsigned long; + * mozilla::MakeUnsigned::Type is volatile unsigned int; + * mozilla::MakeUnsigned::Type is const unsigned short; + * mozilla::MakeUnsigned::Type is const unsigned char; + * mozilla::MakeUnsigned is an error; + * mozilla::MakeUnsigned is an error. + */ +template +struct MakeUnsigned + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeUnsigned + >::Type +{}; + +/* 20.9.7.4 Array modifications [meta.trans.arr] */ + +/** + * RemoveExtent produces either the type of the elements of the array T, or T + * itself. + * + * mozilla::RemoveExtent::Type is int; + * mozilla::RemoveExtent::Type is const int; + * mozilla::RemoveExtent::Type is volatile int; + * mozilla::RemoveExtent::Type is long[17]. + */ +template +struct RemoveExtent +{ + typedef T Type; +}; + +template +struct RemoveExtent +{ + typedef T Type; +}; + +template +struct RemoveExtent +{ + typedef T Type; +}; + +/* 20.9.7.5 Pointer modifications [meta.trans.ptr] */ + +namespace detail { + +template +struct RemovePointerHelper +{ + typedef T Type; +}; + +template +struct RemovePointerHelper +{ + typedef Pointee Type; +}; + +} // namespace detail + +/** + * Produces the pointed-to type if a pointer is provided, else returns the input + * type. Note that this does not dereference pointer-to-member pointers. + * + * struct S { bool m; void f(); }; + * mozilla::RemovePointer::Type is int; + * mozilla::RemovePointer::Type is int; + * mozilla::RemovePointer::Type is int; + * mozilla::RemovePointer::Type is int; + * mozilla::RemovePointer::Type is const long; + * mozilla::RemovePointer::Type is void; + * mozilla::RemovePointer::Type is void (S::*)(); + * mozilla::RemovePointer::Type is void(); + * mozilla::RemovePointer::Type is bool S::*. + */ +template +struct RemovePointer + : detail::RemovePointerHelper::Type> +{}; + +/** + * Converts T& to T*. Otherwise returns T* given T. Note that C++17 wants + * std::add_pointer to work differently for function types. We don't implement + * that behavior here. + * + * mozilla::AddPointer is int*; + * mozilla::AddPointer is int**; + * mozilla::AddPointer is int*; + * mozilla::AddPointer is int** const. + */ +template +struct AddPointer +{ + typedef typename RemoveReference::Type* Type; +}; + +/* 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::Type is int; + * mozilla::EnableIf::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 + * class PodVector // vector optimized to store POD (memcpy-able) types + * { + * EnableIf::value, T>::Type* vector; + * size_t length; + * ... + * }; + */ +template +struct EnableIf +{}; + +template +struct EnableIf +{ + typedef T Type; +}; + +/** + * Conditional selects a class between two, depending on a given boolean value. + * + * mozilla::Conditional::Type is A; + * mozilla::Conditional::Type is B; + */ +template +struct Conditional +{ + typedef A Type; +}; + +template +struct Conditional +{ + typedef B Type; +}; + +namespace detail { + +template::value, + bool IsFunction = IsFunction::value> +struct DecaySelector; + +template +struct DecaySelector +{ + typedef typename RemoveCV::Type Type; +}; + +template +struct DecaySelector +{ + typedef typename RemoveExtent::Type* Type; +}; + +template +struct DecaySelector +{ + typedef typename AddPointer::Type Type; +}; + +}; // namespace detail + +/** + * Strips const/volatile off a type and decays it from an lvalue to an + * rvalue. So function types are converted to function pointers, arrays to + * pointers, and references are removed. + * + * mozilla::Decay::Type is int + * mozilla::Decay::Type is int + * mozilla::Decay::Type is int + * mozilla::Decay::Type is int + * mozilla::Decay::Type is int* + * mozilla::Decay::Type is int(*)(int) + */ +template +class Decay + : public detail::DecaySelector::Type> +{ +}; + +} /* namespace mozilla */ + +#endif /* mozilla_TypeTraits_h */ -- cgit v1.2.3