gecko-dev/mfbt/TypedEnumBits.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

136 lines
5.7 KiB
C
Raw Normal View History

/* -*- 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