зеркало из https://github.com/mozilla/gecko-dev.git
Bug 987290 - Allow using MFBT Typed Enums as bitwise flags - r=Waldo
This commit is contained in:
Родитель
29cd3a729e
Коммит
888ca078bf
|
@ -9,40 +9,11 @@
|
|||
#ifndef mozilla_TypedEnum_h
|
||||
#define mozilla_TypedEnum_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/TypedEnumInternal.h"
|
||||
#include "mozilla/MacroArgs.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#if defined(__clang__)
|
||||
/*
|
||||
* Per Clang documentation, "Note that marketing version numbers should not
|
||||
* be used to check for language features, as different vendors use different
|
||||
* numbering schemes. Instead, use the feature checking macros."
|
||||
*/
|
||||
# ifndef __has_extension
|
||||
# define __has_extension __has_feature /* compatibility, for older versions of clang */
|
||||
# endif
|
||||
# if __has_extension(cxx_strong_enums)
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 3)
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# if _MSC_VER >= 1400
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# endif
|
||||
# if _MSC_VER >= 1700
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MOZ_ENUM_TYPE specifies the underlying numeric type for an enum. It's
|
||||
* specified by placing MOZ_ENUM_TYPE(type) immediately after the enum name in
|
||||
|
@ -190,9 +161,13 @@
|
|||
# define MOZ_END_NESTED_ENUM_CLASS(Name) \
|
||||
}; \
|
||||
Name() {} \
|
||||
Name(Enum aEnum) : mEnum(aEnum) {} \
|
||||
explicit Name(int num) : mEnum((Enum)num) {} \
|
||||
operator Enum() const { return mEnum; } \
|
||||
MOZ_CONSTEXPR Name(Enum aEnum) : mEnum(aEnum) {} \
|
||||
template<typename Other> \
|
||||
explicit MOZ_CONSTEXPR Name(Other num) : mEnum((Enum)num) {} \
|
||||
MOZ_CONSTEXPR operator Enum() const { return mEnum; } \
|
||||
explicit MOZ_CONSTEXPR Name(const mozilla::CastableTypedEnumResult<Name>& aOther) \
|
||||
: mEnum(aOther.get()) \
|
||||
{} \
|
||||
private: \
|
||||
Enum mEnum; \
|
||||
};
|
||||
|
@ -230,7 +205,6 @@
|
|||
inline bool operator&&(const Name::Enum&, const bool&) MOZ_DELETE; \
|
||||
inline bool operator||(const bool&, const Name::Enum&) MOZ_DELETE; \
|
||||
inline bool operator||(const Name::Enum&, const bool&) MOZ_DELETE; \
|
||||
inline int operator~(const Name::Enum&) MOZ_DELETE; \
|
||||
inline int operator&(const int&, const Name::Enum&) MOZ_DELETE; \
|
||||
inline int operator&(const Name::Enum&, const int&) MOZ_DELETE; \
|
||||
inline int operator|(const int&, const Name::Enum&) MOZ_DELETE; \
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags. */
|
||||
|
||||
#ifndef mozilla_TypedEnumBits_h
|
||||
#define mozilla_TypedEnumBits_h
|
||||
|
||||
#include "mozilla/IntegerTypeTraits.h"
|
||||
#include "mozilla/TypedEnumInternal.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \
|
||||
template<typename E> \
|
||||
MOZ_CONSTEXPR ReturnType \
|
||||
operator Op(const OtherType& e, const CastableTypedEnumResult<E>& r) \
|
||||
{ \
|
||||
return ReturnType(e Op OtherType(r)); \
|
||||
} \
|
||||
template<typename E> \
|
||||
MOZ_CONSTEXPR ReturnType \
|
||||
operator Op(const CastableTypedEnumResult<E>& r, const OtherType& e) \
|
||||
{ \
|
||||
return ReturnType(OtherType(r) Op e); \
|
||||
} \
|
||||
template<typename E> \
|
||||
MOZ_CONSTEXPR ReturnType \
|
||||
operator Op(const CastableTypedEnumResult<E>& r1, \
|
||||
const CastableTypedEnumResult<E>& r2) \
|
||||
{ \
|
||||
return ReturnType(OtherType(r1) Op OtherType(r2)); \
|
||||
}
|
||||
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult<E>)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult<E>)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult<E>)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP(||, bool, bool)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool)
|
||||
|
||||
template <typename E>
|
||||
MOZ_CONSTEXPR CastableTypedEnumResult<E>
|
||||
operator ~(const CastableTypedEnumResult<E>& r)
|
||||
{
|
||||
return CastableTypedEnumResult<E>(~(E(r)));
|
||||
}
|
||||
|
||||
#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \
|
||||
template<typename E> \
|
||||
E& \
|
||||
operator Op(E& r1, \
|
||||
const CastableTypedEnumResult<E>& r2) \
|
||||
{ \
|
||||
return r1 Op E(r2); \
|
||||
}
|
||||
|
||||
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=)
|
||||
|
||||
#undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP
|
||||
|
||||
#undef MOZ_CASTABLETYPEDENUMRESULT_BINOP
|
||||
|
||||
#ifndef MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
|
||||
#define MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(Op, ReturnType) \
|
||||
template<typename E> \
|
||||
MOZ_CONSTEXPR ReturnType \
|
||||
operator Op(typename E::Enum e, const CastableTypedEnumResult<E>& r) \
|
||||
{ \
|
||||
return ReturnType(e Op E(r)); \
|
||||
} \
|
||||
template<typename E> \
|
||||
MOZ_CONSTEXPR ReturnType \
|
||||
operator Op(const CastableTypedEnumResult<E>& r, typename E::Enum e) \
|
||||
{ \
|
||||
return ReturnType(E(r) Op e); \
|
||||
}
|
||||
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(|, CastableTypedEnumResult<E>)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(&, CastableTypedEnumResult<E>)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(^, CastableTypedEnumResult<E>)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(==, bool)
|
||||
MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11(!=, bool)
|
||||
|
||||
#undef MOZ_CASTABLETYPEDENUMRESULT_BINOP_EXTRA_NON_CXX11
|
||||
|
||||
#endif // not MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
|
||||
namespace detail {
|
||||
template<typename E>
|
||||
struct UnsignedIntegerTypeForEnum
|
||||
: UnsignedStdintTypeForSize<sizeof(E)>
|
||||
{};
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \
|
||||
inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult<Name> \
|
||||
operator Op(Name a, Name b) \
|
||||
{ \
|
||||
typedef mozilla::CastableTypedEnumResult<Name> Result; \
|
||||
typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
|
||||
return Result(Name(U(a) Op U(b))); \
|
||||
} \
|
||||
\
|
||||
inline Name& \
|
||||
operator Op##=(Name& a, Name b) \
|
||||
{ \
|
||||
return a = a Op b; \
|
||||
}
|
||||
|
||||
#define MOZ_MAKE_ENUM_CLASS_OPS_IMPL(Name) \
|
||||
MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \
|
||||
MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \
|
||||
MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \
|
||||
inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult<Name> \
|
||||
operator~(Name a) \
|
||||
{ \
|
||||
typedef mozilla::CastableTypedEnumResult<Name> Result; \
|
||||
typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
|
||||
return Result(Name(~(U(a)))); \
|
||||
}
|
||||
|
||||
#ifndef MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# define MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, Op) \
|
||||
inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult<Name> \
|
||||
operator Op(Name a, Name::Enum b) \
|
||||
{ \
|
||||
return a Op Name(b); \
|
||||
} \
|
||||
\
|
||||
inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult<Name> \
|
||||
operator Op(Name::Enum a, Name b) \
|
||||
{ \
|
||||
return Name(a) Op b; \
|
||||
} \
|
||||
\
|
||||
inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult<Name> \
|
||||
operator Op(Name::Enum a, Name::Enum b) \
|
||||
{ \
|
||||
return Name(a) Op Name(b); \
|
||||
} \
|
||||
\
|
||||
inline Name& \
|
||||
operator Op##=(Name& a, Name::Enum b) \
|
||||
{ \
|
||||
return a = a Op Name(b); \
|
||||
}
|
||||
|
||||
# define MOZ_MAKE_ENUM_CLASS_OPS_EXTRA_NON_CXX11(Name) \
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, |) \
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, &) \
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_BINOP_EXTRA_NON_CXX11(Name, ^) \
|
||||
inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult<Name> \
|
||||
operator~(Name::Enum a) \
|
||||
{ \
|
||||
return ~(Name(a)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators
|
||||
* for the given enum type. Use this to enable using an enum type as bit-field.
|
||||
*/
|
||||
#ifdef MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
|
||||
MOZ_MAKE_ENUM_CLASS_OPS_IMPL(Name)
|
||||
#else
|
||||
# define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
|
||||
MOZ_MAKE_ENUM_CLASS_OPS_IMPL(Name) \
|
||||
MOZ_MAKE_ENUM_CLASS_OPS_EXTRA_NON_CXX11(Name)
|
||||
#endif
|
||||
|
||||
#endif // mozilla_TypedEnumBits_h
|
|
@ -0,0 +1,112 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* Internal stuff needed by TypedEnum.h and TypedEnumBits.h. */
|
||||
|
||||
// NOTE: When we can assume C++11 enum class support and TypedEnum.h goes away,
|
||||
// we should then consider folding TypedEnumInternal.h into TypedEnumBits.h.
|
||||
|
||||
#ifndef mozilla_TypedEnumInternal_h
|
||||
#define mozilla_TypedEnumInternal_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#if defined(__clang__)
|
||||
/*
|
||||
* Per Clang documentation, "Note that marketing version numbers should not
|
||||
* be used to check for language features, as different vendors use different
|
||||
* numbering schemes. Instead, use the feature checking macros."
|
||||
*/
|
||||
# ifndef __has_extension
|
||||
# define __has_extension __has_feature /* compatibility, for older versions of clang */
|
||||
# endif
|
||||
# if __has_extension(cxx_strong_enums)
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 3)
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# if _MSC_VER >= 1400
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# endif
|
||||
# if _MSC_VER >= 1700
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* The problem that CastableTypedEnumResult aims to solve is that
|
||||
* typed enums are not convertible to bool, and there is no way to make them
|
||||
* be, yet user code wants to be able to write
|
||||
*
|
||||
* if (myFlags & Flags::SOME_PARTICULAR_FLAG) (1)
|
||||
*
|
||||
* There are different approaches to solving this. Most of them require
|
||||
* adapting user code. For example, we could implement operator! and have
|
||||
* the user write
|
||||
*
|
||||
* if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG)) (2)
|
||||
*
|
||||
* Or we could supply a IsNonZero() or Any() function returning whether
|
||||
* an enum value is nonzero, and have the user write
|
||||
*
|
||||
* if (Any(Flags & Flags::SOME_PARTICULAR_FLAG)) (3)
|
||||
*
|
||||
* But instead, we choose to preserve the original user syntax (1) as it
|
||||
* is inherently more readable, and to ease porting existing code to typed
|
||||
* enums. We achieve this by having operator& and other binary bitwise
|
||||
* operators have as return type a class, CastableTypedEnumResult,
|
||||
* that wraps a typed enum but adds bool convertibility.
|
||||
*/
|
||||
template<typename E>
|
||||
class CastableTypedEnumResult
|
||||
{
|
||||
private:
|
||||
const E mValue;
|
||||
|
||||
public:
|
||||
explicit MOZ_CONSTEXPR CastableTypedEnumResult(E value)
|
||||
: mValue(value)
|
||||
{}
|
||||
|
||||
MOZ_CONSTEXPR operator E() const { return mValue; }
|
||||
|
||||
template<typename DestinationType>
|
||||
MOZ_EXPLICIT_CONVERSION MOZ_CONSTEXPR
|
||||
operator DestinationType() const {
|
||||
return DestinationType(mValue);
|
||||
}
|
||||
|
||||
MOZ_CONSTEXPR bool operator !() const { return !bool(mValue); }
|
||||
|
||||
#ifndef MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
// This get() method is used to implement a constructor in the
|
||||
// non-c++11 fallback path for MOZ_BEGIN_ENUM_CLASS, taking a
|
||||
// CastableTypedEnumResult. If we try to implement it using the
|
||||
// above conversion operator E(), then at least clang 3.3
|
||||
// (when forced to take the non-c++11 fallback path) compiles
|
||||
// this constructor to an infinite recursion. So we introduce this
|
||||
// get() method, that does exactly the same as the conversion operator,
|
||||
// to work around this.
|
||||
MOZ_CONSTEXPR E get() const { return mValue; }
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // mozilla_TypedEnumInternal_h
|
|
@ -61,6 +61,8 @@ EXPORTS.mozilla = [
|
|||
'TemplateLib.h',
|
||||
'ThreadLocal.h',
|
||||
'TypedEnum.h',
|
||||
'TypedEnumBits.h',
|
||||
'TypedEnumInternal.h',
|
||||
'Types.h',
|
||||
'TypeTraits.h',
|
||||
'Vector.h',
|
||||
|
|
|
@ -4,37 +4,565 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/TypedEnum.h"
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// A rough feature check for is_literal_type. Not very carefully checked.
|
||||
// Feel free to amend as needed.
|
||||
// We leave ANDROID out because it's using stlport which doesn't have std::is_literal_type.
|
||||
#if __cplusplus >= 201103L && !defined(ANDROID)
|
||||
# if defined(__clang__)
|
||||
/*
|
||||
* Per Clang documentation, "Note that marketing version numbers should not
|
||||
* be used to check for language features, as different vendors use different
|
||||
* numbering schemes. Instead, use the feature checking macros."
|
||||
*/
|
||||
# ifndef __has_extension
|
||||
# define __has_extension __has_feature /* compatibility, for older versions of clang */
|
||||
# endif
|
||||
# if __has_extension(is_literal) && __has_include(<type_traits>)
|
||||
# define MOZ_HAVE_IS_LITERAL
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0)
|
||||
# define MOZ_HAVE_IS_LITERAL
|
||||
# endif
|
||||
# endif
|
||||
# elif defined(_MSC_VER)
|
||||
# if _MSC_VER >= 1700
|
||||
# define MOZ_HAVE_IS_LITERAL
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_HAVE_IS_LITERAL
|
||||
#include <type_traits>
|
||||
template<typename T>
|
||||
void
|
||||
RequireLiteralType()
|
||||
{
|
||||
static_assert(std::is_literal_type<T>::value, "Expected a literal type");
|
||||
}
|
||||
#else // not MOZ_HAVE_IS_LITERAL
|
||||
template<typename T>
|
||||
void
|
||||
RequireLiteralType()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
RequireLiteralType(const T&)
|
||||
{
|
||||
RequireLiteralType<T>();
|
||||
}
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(AutoEnum)
|
||||
A,
|
||||
B
|
||||
B = -3,
|
||||
C
|
||||
MOZ_END_ENUM_CLASS(AutoEnum)
|
||||
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(CharEnum, char)
|
||||
A,
|
||||
B
|
||||
B = 3,
|
||||
C
|
||||
MOZ_END_ENUM_CLASS(CharEnum)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(AutoEnumBitField)
|
||||
A = 0x10,
|
||||
B = 0x20,
|
||||
C
|
||||
MOZ_END_ENUM_CLASS(AutoEnumBitField)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(CharEnumBitField, char)
|
||||
A = 0x10,
|
||||
B,
|
||||
C = 0x40
|
||||
MOZ_END_ENUM_CLASS(CharEnumBitField)
|
||||
|
||||
struct Nested
|
||||
{
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS(AutoEnum)
|
||||
C
|
||||
A,
|
||||
B,
|
||||
C = -1
|
||||
MOZ_END_NESTED_ENUM_CLASS(AutoEnum)
|
||||
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS(CharEnum, char)
|
||||
D = 4,
|
||||
E
|
||||
A = 4,
|
||||
B,
|
||||
C = 1
|
||||
MOZ_END_NESTED_ENUM_CLASS(CharEnum)
|
||||
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS(AutoEnumBitField)
|
||||
A,
|
||||
B = 0x20,
|
||||
C
|
||||
MOZ_END_NESTED_ENUM_CLASS(AutoEnumBitField)
|
||||
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS(CharEnumBitField, char)
|
||||
A = 1,
|
||||
B = 1,
|
||||
C = 1
|
||||
MOZ_END_NESTED_ENUM_CLASS(CharEnumBitField)
|
||||
};
|
||||
|
||||
// Simply check that this compiles.
|
||||
const AutoEnum autoEnum = AutoEnum::A;
|
||||
const CharEnum charEnum = CharEnum::B;
|
||||
const Nested::AutoEnum nestedAutoEnum = Nested::AutoEnum::C;
|
||||
const Nested::CharEnum nestedCharEnum = Nested::CharEnum::D;
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AutoEnumBitField)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CharEnumBitField)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::AutoEnumBitField)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Nested::CharEnumBitField)
|
||||
|
||||
#define MAKE_STANDARD_BITFIELD_FOR_TYPE(IntType) \
|
||||
MOZ_BEGIN_ENUM_CLASS(BitFieldFor_##IntType, IntType) \
|
||||
A = 1, \
|
||||
B = 2, \
|
||||
C = 4, \
|
||||
MOZ_END_ENUM_CLASS(BitFieldFor_##IntType) \
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(BitFieldFor_##IntType)
|
||||
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(int8_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint8_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(int16_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint16_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(int32_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint32_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(int64_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(uint64_t)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(char)
|
||||
typedef signed char signed_char;
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(signed_char)
|
||||
typedef unsigned char unsigned_char;
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_char)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(short)
|
||||
typedef unsigned short unsigned_short;
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_short)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(int)
|
||||
typedef unsigned int unsigned_int;
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_int)
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(long)
|
||||
typedef unsigned long unsigned_long;
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long)
|
||||
typedef long long long_long;
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(long_long)
|
||||
typedef unsigned long long unsigned_long_long;
|
||||
MAKE_STANDARD_BITFIELD_FOR_TYPE(unsigned_long_long)
|
||||
|
||||
#undef MAKE_STANDARD_BITFIELD_FOR_TYPE
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
TestNonConvertibilityForOneType()
|
||||
{
|
||||
using mozilla::IsConvertible;
|
||||
#ifdef MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
static_assert(!IsConvertible<T, bool>::value, "should not be convertible");
|
||||
static_assert(!IsConvertible<T, int>::value, "should not be convertible");
|
||||
static_assert(!IsConvertible<T, uint64_t>::value, "should not be convertible");
|
||||
#endif
|
||||
|
||||
static_assert(!IsConvertible<bool, T>::value, "should not be convertible");
|
||||
static_assert(!IsConvertible<int, T>::value, "should not be convertible");
|
||||
static_assert(!IsConvertible<uint64_t, T>::value, "should not be convertible");
|
||||
}
|
||||
|
||||
template<typename TypedEnum>
|
||||
void
|
||||
TestTypedEnumBasics()
|
||||
{
|
||||
const TypedEnum a = TypedEnum::A;
|
||||
int unused = int(a);
|
||||
(void) unused;
|
||||
RequireLiteralType(TypedEnum::A);
|
||||
RequireLiteralType(a);
|
||||
TestNonConvertibilityForOneType<TypedEnum>();
|
||||
}
|
||||
|
||||
// Op wraps a bitwise binary operator, passed as a char template parameter,
|
||||
// and applies it to its arguments (t1, t2). For example,
|
||||
//
|
||||
// Op<'|'>(t1, t2)
|
||||
//
|
||||
// is the same as
|
||||
//
|
||||
// t1 | t2.
|
||||
//
|
||||
template<char o, typename T1, typename T2>
|
||||
auto Op(const T1& t1, const T2& t2)
|
||||
-> decltype(t1 | t2) // See the static_assert's below --- the return type
|
||||
// depends solely on the operands type, not on the
|
||||
// choice of operation.
|
||||
{
|
||||
using mozilla::IsSame;
|
||||
static_assert(IsSame<decltype(t1 | t2), decltype(t1 & t2)>::value,
|
||||
"binary ops should have the same result type");
|
||||
static_assert(IsSame<decltype(t1 | t2), decltype(t1 ^ t2)>::value,
|
||||
"binary ops should have the same result type");
|
||||
|
||||
static_assert(o == '|' ||
|
||||
o == '&' ||
|
||||
o == '^', "unexpected operator character");
|
||||
|
||||
return o == '|' ? t1 | t2
|
||||
: o == '&' ? t1 & t2
|
||||
: t1 ^ t2;
|
||||
}
|
||||
|
||||
// OpAssign wraps a bitwise binary operator, passed as a char template
|
||||
// parameter, and applies the corresponding compound-assignment operator to its
|
||||
// arguments (t1, t2). For example,
|
||||
//
|
||||
// OpAssign<'|'>(t1, t2)
|
||||
//
|
||||
// is the same as
|
||||
//
|
||||
// t1 |= t2.
|
||||
//
|
||||
template<char o, typename T1, typename T2>
|
||||
T1& OpAssign(T1& t1, const T2& t2)
|
||||
{
|
||||
static_assert(o == '|' ||
|
||||
o == '&' ||
|
||||
o == '^', "unexpected operator character");
|
||||
|
||||
switch (o) {
|
||||
case '|': return t1 |= t2;
|
||||
case '&': return t1 &= t2;
|
||||
case '^': return t1 ^= t2;
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
// Tests a single binary bitwise operator, using a single set of three operands.
|
||||
// The operations tested are:
|
||||
//
|
||||
// result = t1 Op t2;
|
||||
// result Op= t3;
|
||||
//
|
||||
// Where Op is the operator specified by the char template parameter 'o' and can
|
||||
// be any of '|', '&', '^'.
|
||||
//
|
||||
// Note that the operands t1, t2, t3 are intentionally passed with free types
|
||||
// (separate template parameters for each) because their type may actually be
|
||||
// different from TypedEnum:
|
||||
// 1) Their type could be CastableTypedEnumResult<TypedEnum> if they are
|
||||
// the result of a bitwise operation themselves;
|
||||
// 2) In the non-c++11 legacy path, the type of enum values is also
|
||||
// different from TypedEnum.
|
||||
//
|
||||
template<typename TypedEnum, char o, typename T1, typename T2, typename T3>
|
||||
void TestBinOp(const T1& t1, const T2& t2, const T3& t3)
|
||||
{
|
||||
typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
|
||||
UnsignedIntegerType;
|
||||
|
||||
// Part 1:
|
||||
// Test the bitwise binary operator i.e.
|
||||
// result = t1 Op t2;
|
||||
auto result = Op<o>(t1, t2);
|
||||
|
||||
typedef decltype(result) ResultType;
|
||||
|
||||
RequireLiteralType<ResultType>();
|
||||
TestNonConvertibilityForOneType<ResultType>();
|
||||
|
||||
UnsignedIntegerType unsignedIntegerResult
|
||||
= Op<o>(UnsignedIntegerType(t1), UnsignedIntegerType(t2));
|
||||
|
||||
MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
|
||||
MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(TypedEnum(result)));
|
||||
MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
|
||||
MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
|
||||
MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
|
||||
|
||||
// Part 2:
|
||||
// Test the compound-assignment operator, i.e.
|
||||
// result Op= t3;
|
||||
TypedEnum newResult = result;
|
||||
OpAssign<o>(newResult, t3);
|
||||
UnsignedIntegerType unsignedIntegerNewResult = unsignedIntegerResult;
|
||||
OpAssign<o>(unsignedIntegerNewResult, UnsignedIntegerType(t3));
|
||||
MOZ_RELEASE_ASSERT(unsignedIntegerNewResult == UnsignedIntegerType(newResult));
|
||||
|
||||
// Part 3:
|
||||
// Test additional boolean operators that we unfortunately had to add to
|
||||
// CastableTypedEnumResult at some point to please some compiler,
|
||||
// even though bool convertibility should have been enough.
|
||||
MOZ_RELEASE_ASSERT(result == TypedEnum(result));
|
||||
MOZ_RELEASE_ASSERT(!(result != TypedEnum(result)));
|
||||
MOZ_RELEASE_ASSERT((result && true) == bool(result));
|
||||
MOZ_RELEASE_ASSERT((result && false) == false);
|
||||
MOZ_RELEASE_ASSERT((true && result) == bool(result));
|
||||
MOZ_RELEASE_ASSERT((false && result && false) == false);
|
||||
MOZ_RELEASE_ASSERT((result || false) == bool(result));
|
||||
MOZ_RELEASE_ASSERT((result || true) == true);
|
||||
MOZ_RELEASE_ASSERT((false || result) == bool(result));
|
||||
MOZ_RELEASE_ASSERT((true || result) == true);
|
||||
}
|
||||
|
||||
// Similar to TestBinOp but testing the unary ~ operator.
|
||||
template<typename TypedEnum, typename T>
|
||||
void TestTilde(const T& t)
|
||||
{
|
||||
typedef typename mozilla::detail::UnsignedIntegerTypeForEnum<TypedEnum>::Type
|
||||
UnsignedIntegerType;
|
||||
|
||||
auto result = ~t;
|
||||
|
||||
typedef decltype(result) ResultType;
|
||||
|
||||
RequireLiteralType<ResultType>();
|
||||
TestNonConvertibilityForOneType<ResultType>();
|
||||
|
||||
UnsignedIntegerType unsignedIntegerResult = ~(UnsignedIntegerType(t));
|
||||
|
||||
MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(result));
|
||||
MOZ_RELEASE_ASSERT(unsignedIntegerResult == UnsignedIntegerType(TypedEnum(result)));
|
||||
MOZ_RELEASE_ASSERT((!unsignedIntegerResult) == (!result));
|
||||
MOZ_RELEASE_ASSERT((!!unsignedIntegerResult) == (!!result));
|
||||
MOZ_RELEASE_ASSERT(bool(unsignedIntegerResult) == bool(result));
|
||||
}
|
||||
|
||||
// Helper dispatching a given triple of operands to all operator-specific
|
||||
// testing functions.
|
||||
template<typename TypedEnum, typename T1, typename T2, typename T3>
|
||||
void TestAllOpsForGivenOperands(const T1& t1, const T2& t2, const T3& t3)
|
||||
{
|
||||
TestBinOp<TypedEnum, '|'>(t1, t2, t3);
|
||||
TestBinOp<TypedEnum, '&'>(t1, t2, t3);
|
||||
TestBinOp<TypedEnum, '^'>(t1, t2, t3);
|
||||
TestTilde<TypedEnum>(t1);
|
||||
}
|
||||
|
||||
// Helper building various triples of operands using a given operator,
|
||||
// and testing all operators with them.
|
||||
template<typename TypedEnum, char o>
|
||||
void TestAllOpsForOperandsBuiltUsingGivenOp()
|
||||
{
|
||||
// The type of enum values like TypedEnum::A may be different from
|
||||
// TypedEnum. That is the case in the legacy non-C++11 path. We want to
|
||||
// ensure good test coverage even when these two types are distinct.
|
||||
// To that effect, we have both 'auto' typed variables, preserving the
|
||||
// original type of enum values, and 'plain' typed variables, that
|
||||
// are plain TypedEnum's.
|
||||
|
||||
const TypedEnum a_plain = TypedEnum::A;
|
||||
const TypedEnum b_plain = TypedEnum::B;
|
||||
const TypedEnum c_plain = TypedEnum::C;
|
||||
|
||||
auto a_auto = TypedEnum::A;
|
||||
auto b_auto = TypedEnum::B;
|
||||
auto c_auto = TypedEnum::C;
|
||||
|
||||
auto ab_plain = Op<o>(a_plain, b_plain);
|
||||
auto bc_plain = Op<o>(b_plain, c_plain);
|
||||
auto ab_auto = Op<o>(a_auto, b_auto);
|
||||
auto bc_auto = Op<o>(b_auto, c_auto);
|
||||
|
||||
// On each row below, we pass a triple of operands. Keep in mind that this
|
||||
// is going to be received as (t1, t2, t3) and the actual tests performed
|
||||
// will be of the form
|
||||
//
|
||||
// result = t1 Op t2;
|
||||
// result Op= t3;
|
||||
//
|
||||
// For this reason, we carefully ensure that the values of (t1, t2)
|
||||
// systematically cover all types of such pairs; to limit complexity,
|
||||
// we are not so careful with t3, and we just try to pass t3's
|
||||
// that may lead to nontrivial bitwise operations.
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_plain, c_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_plain, b_auto);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_plain, a_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_plain, a_auto);
|
||||
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_plain, b_auto, c_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_plain, bc_auto, b_auto);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, c_auto, a_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_plain, bc_auto, a_auto);
|
||||
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_plain, c_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_plain, b_auto);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_plain, a_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_plain, a_auto);
|
||||
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_auto, b_auto, c_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(a_auto, bc_auto, b_auto);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, c_auto, a_plain);
|
||||
TestAllOpsForGivenOperands<TypedEnum>(ab_auto, bc_auto, a_auto);
|
||||
}
|
||||
|
||||
// Tests all bitwise operations on a given TypedEnum bitfield.
|
||||
template<typename TypedEnum>
|
||||
void
|
||||
TestTypedEnumBitField()
|
||||
{
|
||||
TestTypedEnumBasics<TypedEnum>();
|
||||
|
||||
TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '|'>();
|
||||
TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '&'>();
|
||||
TestAllOpsForOperandsBuiltUsingGivenOp<TypedEnum, '^'>();
|
||||
}
|
||||
|
||||
// Checks that enum bitwise expressions have the same non-convertibility properties as
|
||||
// c++11 enum classes do, i.e. not implicitly convertible to anything
|
||||
// (though *explicitly* convertible).
|
||||
void TestNoConversionsBetweenUnrelatedTypes()
|
||||
{
|
||||
using mozilla::IsConvertible;
|
||||
|
||||
// Two typed enum classes having the same underlying integer type, to ensure that
|
||||
// we would catch bugs accidentally allowing conversions in that case.
|
||||
typedef CharEnumBitField T1;
|
||||
typedef Nested::CharEnumBitField T2;
|
||||
|
||||
static_assert(!IsConvertible<T1, T2>::value,
|
||||
"should not be convertible");
|
||||
static_assert(!IsConvertible<T1, decltype(T2::A)>::value,
|
||||
"should not be convertible");
|
||||
static_assert(!IsConvertible<T1, decltype(T2::A | T2::B)>::value,
|
||||
"should not be convertible");
|
||||
|
||||
static_assert(!IsConvertible<decltype(T1::A), T2>::value,
|
||||
"should not be convertible");
|
||||
static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A)>::value,
|
||||
"should not be convertible");
|
||||
static_assert(!IsConvertible<decltype(T1::A), decltype(T2::A | T2::B)>::value,
|
||||
"should not be convertible");
|
||||
|
||||
// The following are #ifdef MOZ_HAVE_EXPLICIT_CONVERSION because
|
||||
// without support for explicit conversion operators, we can't easily have these
|
||||
// bad conversions completely removed. They still do fail to compile in practice,
|
||||
// but not in a way that we can static_assert on.
|
||||
#ifdef MOZ_HAVE_EXPLICIT_CONVERSION
|
||||
static_assert(!IsConvertible<decltype(T1::A | T1::B), T2>::value,
|
||||
"should not be convertible");
|
||||
static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A)>::value,
|
||||
"should not be convertible");
|
||||
static_assert(!IsConvertible<decltype(T1::A | T1::B), decltype(T2::A | T2::B)>::value,
|
||||
"should not be convertible");
|
||||
#endif
|
||||
}
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Int8EnumWithHighBits, int8_t)
|
||||
A = 0x20,
|
||||
B = 0x40
|
||||
MOZ_END_ENUM_CLASS(Int8EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int8EnumWithHighBits)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Uint8EnumWithHighBits, uint8_t)
|
||||
A = 0x40,
|
||||
B = 0x80
|
||||
MOZ_END_ENUM_CLASS(Uint8EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint8EnumWithHighBits)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Int16EnumWithHighBits, int16_t)
|
||||
A = 0x2000,
|
||||
B = 0x4000
|
||||
MOZ_END_ENUM_CLASS(Int16EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int16EnumWithHighBits)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Uint16EnumWithHighBits, uint16_t)
|
||||
A = 0x4000,
|
||||
B = 0x8000
|
||||
MOZ_END_ENUM_CLASS(Uint16EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint16EnumWithHighBits)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Int32EnumWithHighBits, int32_t)
|
||||
A = 0x20000000,
|
||||
B = 0x40000000
|
||||
MOZ_END_ENUM_CLASS(Int32EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int32EnumWithHighBits)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Uint32EnumWithHighBits, uint32_t)
|
||||
A = 0x40000000u,
|
||||
B = 0x80000000u
|
||||
MOZ_END_ENUM_CLASS(Uint32EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint32EnumWithHighBits)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Int64EnumWithHighBits, int64_t)
|
||||
A = 0x2000000000000000ll,
|
||||
B = 0x4000000000000000ll
|
||||
MOZ_END_ENUM_CLASS(Int64EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Int64EnumWithHighBits)
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(Uint64EnumWithHighBits, uint64_t)
|
||||
A = 0x4000000000000000ull,
|
||||
B = 0x8000000000000000ull
|
||||
MOZ_END_ENUM_CLASS(Uint64EnumWithHighBits)
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Uint64EnumWithHighBits)
|
||||
|
||||
// Checks that we don't accidentally truncate high bits by coercing to the wrong
|
||||
// integer type internally when implementing bitwise ops.
|
||||
template<typename EnumType, typename IntType>
|
||||
void TestIsNotTruncated()
|
||||
{
|
||||
EnumType a = EnumType::A;
|
||||
EnumType b = EnumType::B;
|
||||
MOZ_RELEASE_ASSERT(IntType(a));
|
||||
MOZ_RELEASE_ASSERT(IntType(b));
|
||||
MOZ_RELEASE_ASSERT(a | EnumType::B);
|
||||
MOZ_RELEASE_ASSERT(a | b);
|
||||
MOZ_RELEASE_ASSERT(EnumType::A | EnumType::B);
|
||||
EnumType c = EnumType::A | EnumType::B;
|
||||
MOZ_RELEASE_ASSERT(IntType(c));
|
||||
MOZ_RELEASE_ASSERT(c & c);
|
||||
MOZ_RELEASE_ASSERT(c | c);
|
||||
MOZ_RELEASE_ASSERT(c == (EnumType::A | EnumType::B));
|
||||
MOZ_RELEASE_ASSERT(a != (EnumType::A | EnumType::B));
|
||||
MOZ_RELEASE_ASSERT(b != (EnumType::A | EnumType::B));
|
||||
MOZ_RELEASE_ASSERT(c & EnumType::A);
|
||||
MOZ_RELEASE_ASSERT(c & EnumType::B);
|
||||
EnumType d = EnumType::A;
|
||||
d |= EnumType::B;
|
||||
MOZ_RELEASE_ASSERT(d == c);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
TestTypedEnumBasics<AutoEnum>();
|
||||
TestTypedEnumBasics<CharEnum>();
|
||||
TestTypedEnumBasics<Nested::AutoEnum>();
|
||||
TestTypedEnumBasics<Nested::CharEnum>();
|
||||
|
||||
TestTypedEnumBitField<AutoEnumBitField>();
|
||||
TestTypedEnumBitField<CharEnumBitField>();
|
||||
TestTypedEnumBitField<Nested::AutoEnumBitField>();
|
||||
TestTypedEnumBitField<Nested::CharEnumBitField>();
|
||||
|
||||
TestTypedEnumBitField<BitFieldFor_uint8_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_int8_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_uint16_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_int16_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_uint32_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_int32_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_uint64_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_int64_t>();
|
||||
TestTypedEnumBitField<BitFieldFor_char>();
|
||||
TestTypedEnumBitField<BitFieldFor_signed_char>();
|
||||
TestTypedEnumBitField<BitFieldFor_unsigned_char>();
|
||||
TestTypedEnumBitField<BitFieldFor_short>();
|
||||
TestTypedEnumBitField<BitFieldFor_unsigned_short>();
|
||||
TestTypedEnumBitField<BitFieldFor_int>();
|
||||
TestTypedEnumBitField<BitFieldFor_unsigned_int>();
|
||||
TestTypedEnumBitField<BitFieldFor_long>();
|
||||
TestTypedEnumBitField<BitFieldFor_unsigned_long>();
|
||||
TestTypedEnumBitField<BitFieldFor_long_long>();
|
||||
TestTypedEnumBitField<BitFieldFor_unsigned_long_long>();
|
||||
|
||||
TestNoConversionsBetweenUnrelatedTypes();
|
||||
|
||||
TestIsNotTruncated<Int8EnumWithHighBits, int8_t>();
|
||||
TestIsNotTruncated<Int16EnumWithHighBits, int16_t>();
|
||||
TestIsNotTruncated<Int32EnumWithHighBits, int32_t>();
|
||||
TestIsNotTruncated<Int64EnumWithHighBits, int64_t>();
|
||||
TestIsNotTruncated<Uint8EnumWithHighBits, uint8_t>();
|
||||
TestIsNotTruncated<Uint16EnumWithHighBits, uint16_t>();
|
||||
TestIsNotTruncated<Uint32EnumWithHighBits, uint32_t>();
|
||||
TestIsNotTruncated<Uint64EnumWithHighBits, uint64_t>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче