123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- /* -*- Mode: C++; tab-width: 8; 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/. */
- /*
- * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags.
- */
- #ifndef mozilla_TypedEnumBits_h
- #define mozilla_TypedEnumBits_h
- #include "mozilla/Attributes.h"
- #include "mozilla/IntegerTypeTraits.h"
- 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 constexpr CastableTypedEnumResult(E aValue)
- : mValue(aValue)
- {}
- constexpr operator E() const { return mValue; }
- template<typename DestinationType>
- explicit constexpr
- operator DestinationType() const { return DestinationType(mValue); }
- constexpr bool operator !() const { return !bool(mValue); }
- };
- #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \
- template<typename E> \
- constexpr ReturnType \
- operator Op(const OtherType& aE, const CastableTypedEnumResult<E>& aR) \
- { \
- return ReturnType(aE Op OtherType(aR)); \
- } \
- template<typename E> \
- constexpr ReturnType \
- operator Op(const CastableTypedEnumResult<E>& aR, const OtherType& aE) \
- { \
- return ReturnType(OtherType(aR) Op aE); \
- } \
- template<typename E> \
- constexpr ReturnType \
- operator Op(const CastableTypedEnumResult<E>& aR1, \
- const CastableTypedEnumResult<E>& aR2) \
- { \
- return ReturnType(OtherType(aR1) Op OtherType(aR2)); \
- }
- 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>
- constexpr CastableTypedEnumResult<E>
- operator ~(const CastableTypedEnumResult<E>& aR)
- {
- return CastableTypedEnumResult<E>(~(E(aR)));
- }
- #define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \
- template<typename E> \
- E& \
- operator Op(E& aR1, \
- const CastableTypedEnumResult<E>& aR2) \
- { \
- return aR1 Op E(aR2); \
- }
- 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
- namespace detail {
- template<typename E>
- struct UnsignedIntegerTypeForEnum
- : UnsignedStdintTypeForSize<sizeof(E)>
- {};
- } // namespace detail
- } // namespace mozilla
- #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \
- inline 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; \
- }
- /**
- * 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.
- */
- #define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
- MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \
- MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \
- MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \
- inline constexpr mozilla::CastableTypedEnumResult<Name> \
- operator~(Name a) \
- { \
- typedef mozilla::CastableTypedEnumResult<Name> Result; \
- typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
- return Result(Name(~(U(a)))); \
- }
- #endif // mozilla_TypedEnumBits_h
|