forked from mirrors/gecko-dev
		
	 265e672179
			
		
	
	
		265e672179
		
	
	
	
	
		
			
			# ignore-this-changeset --HG-- extra : amend_source : 4d301d3b0b8711c4692392aa76088ba7fd7d1022
		
			
				
	
	
		
			135 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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/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)
 | |
| 
 | |
| 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
 |