summaryrefslogtreecommitdiffstats
path: root/mfbt/TypedEnumBits.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /mfbt/TypedEnumBits.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'mfbt/TypedEnumBits.h')
-rw-r--r--mfbt/TypedEnumBits.h156
1 files changed, 156 insertions, 0 deletions
diff --git a/mfbt/TypedEnumBits.h b/mfbt/TypedEnumBits.h
new file mode 100644
index 000000000..5ee6315c8
--- /dev/null
+++ b/mfbt/TypedEnumBits.h
@@ -0,0 +1,156 @@
+/* -*- 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)
+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