[graphite] Clean up bitwise operators for enum masks

* Rename TFlagsMask<> to Mask<>
* Make Mask<> implicitly convertible to bool
* Rename SKGPU_MAKE_BITFIELD_CLASS_OPS to SKGPU_MAKE_MASK_OPS
* Remove the macro for non-class enums

Change-Id: I86059335d731f34c9c9c20a4cd6d5491543aa3b1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/456816
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/experimental/graphite/include/GraphiteTypes.h b/experimental/graphite/include/GraphiteTypes.h
index d8b1e35..2f7fbad 100644
--- a/experimental/graphite/include/GraphiteTypes.h
+++ b/experimental/graphite/include/GraphiteTypes.h
@@ -13,108 +13,64 @@
 namespace skgpu {
 
 /**
- * Defines overloaded bitwise operators to make it easier to use an enum as a
- * bitfield.
+ * Wraps an enum that is used for flags, and enables masking with type safety. Example:
+ *
+ *   enum class MyFlags {
+ *       kNone = 0,
+ *       kA = 1,
+ *       kB = 2,
+ *       kC = 4,
+ *   };
+ *
+ *   SKGPU_MAKE_MASK_OPS(MyFlags)
+ *
+ *   ...
+ *
+ *       Mask<MyFlags> flags = MyFlags::kA | MyFlags::kB;
+ *
+ *       if (flags & MyFlags::kB) {}
+ *
+ *   ...
  */
-#define SKGPU_MAKE_BITFIELD_OPS(X) \
-    inline X operator |(X a, X b) { \
-        return (X) (+a | +b); \
-    } \
-    inline X& operator |=(X& a, X b) { \
-        return (a = a | b); \
-    } \
-    inline X operator &(X a, X b) { \
-        return (X) (+a & +b); \
-    } \
-    inline X& operator &=(X& a, X b) { \
-        return (a = a & b); \
-    } \
-    template <typename T> \
-    inline X operator &(T a, X b) { \
-        return (X) (+a & +b); \
-    } \
-    template <typename T> \
-    inline X operator &(X a, T b) { \
-        return (X) (+a & +b); \
-    } \
-
-#define SKGPU_DECL_BITFIELD_OPS_FRIENDS(X) \
-    friend X operator |(X a, X b); \
-    friend X& operator |=(X& a, X b); \
-    \
-    friend X operator &(X a, X b); \
-    friend X& operator &=(X& a, X b); \
-    \
-    template <typename T> \
-    friend X operator &(T a, X b); \
-    \
-    template <typename T> \
-    friend X operator &(X a, T b); \
-
-/**
- * Wraps a C++11 enum that we use as a bitfield, and enables a limited amount of
- * masking with type safety. Instantiated with the ~ operator.
- */
-template<typename TFlags> class TFlagsMask {
+template<typename E>
+class Mask {
 public:
-    constexpr explicit TFlagsMask(TFlags value) : TFlagsMask(static_cast<int>(value)) {}
-    constexpr explicit TFlagsMask(int value) : fValue(value) {}
-    constexpr int value() const { return fValue; }
+    SK_ALWAYS_INLINE constexpr Mask(E e) : Mask((int)e) {}
+
+    SK_ALWAYS_INLINE constexpr operator bool() const { return fValue; }
+
+    SK_ALWAYS_INLINE bool operator==(Mask m) const { return fValue == m.fValue; }
+    SK_ALWAYS_INLINE bool operator!=(Mask m) const { return fValue != m.fValue; }
+
+    SK_ALWAYS_INLINE constexpr Mask operator|(Mask m) const { return Mask(fValue | m.fValue); }
+    SK_ALWAYS_INLINE constexpr Mask operator&(Mask m) const { return Mask(fValue & m.fValue); }
+    SK_ALWAYS_INLINE constexpr Mask operator^(Mask m) const { return Mask(fValue ^ m.fValue); }
+    SK_ALWAYS_INLINE constexpr Mask operator~() const { return Mask(~fValue); }
+
+    SK_ALWAYS_INLINE Mask& operator|=(Mask m) { return *this = *this | m; }
+    SK_ALWAYS_INLINE Mask& operator&=(Mask m) { return *this = *this & m; }
+    SK_ALWAYS_INLINE Mask& operator^=(Mask m) { return *this = *this ^ m; }
+
 private:
-    const int fValue;
+    SK_ALWAYS_INLINE constexpr explicit Mask(int value) : fValue(value) {}
+
+    int fValue;
 };
 
 /**
- * Defines bitwise operators that make it possible to use an enum class as a
- * basic bitfield.
+ * Defines functions that make it possible to use bitwise operators on an enum.
  */
-#define SKGPU_MAKE_BITFIELD_CLASS_OPS(X) \
-    SK_MAYBE_UNUSED constexpr TFlagsMask<X> operator~(X a) { \
-        return TFlagsMask<X>(~static_cast<int>(a)); \
-    } \
-    SK_MAYBE_UNUSED constexpr X operator|(X a, X b) { \
-        return static_cast<X>(static_cast<int>(a) | static_cast<int>(b)); \
-    } \
-    SK_MAYBE_UNUSED inline X& operator|=(X& a, X b) { \
-        return (a = a | b); \
-    } \
-    SK_MAYBE_UNUSED constexpr bool operator&(X a, X b) { \
-        return SkToBool(static_cast<int>(a) & static_cast<int>(b)); \
-    } \
-    SK_MAYBE_UNUSED constexpr TFlagsMask<X> operator|(TFlagsMask<X> a, TFlagsMask<X> b) { \
-        return TFlagsMask<X>(a.value() | b.value()); \
-    } \
-    SK_MAYBE_UNUSED constexpr TFlagsMask<X> operator|(TFlagsMask<X> a, X b) { \
-        return TFlagsMask<X>(a.value() | static_cast<int>(b)); \
-    } \
-    SK_MAYBE_UNUSED constexpr TFlagsMask<X> operator|(X a, TFlagsMask<X> b) { \
-        return TFlagsMask<X>(static_cast<int>(a) | b.value()); \
-    } \
-    SK_MAYBE_UNUSED constexpr X operator&(TFlagsMask<X> a, TFlagsMask<X> b) { \
-        return static_cast<X>(a.value() & b.value()); \
-    } \
-    SK_MAYBE_UNUSED constexpr X operator&(TFlagsMask<X> a, X b) { \
-        return static_cast<X>(a.value() & static_cast<int>(b)); \
-    } \
-    SK_MAYBE_UNUSED constexpr X operator&(X a, TFlagsMask<X> b) { \
-        return static_cast<X>(static_cast<int>(a) & b.value()); \
-    } \
-    SK_MAYBE_UNUSED inline X& operator&=(X& a, TFlagsMask<X> b) { \
-        return (a = a & b); \
-    } \
+#define SKGPU_MAKE_MASK_OPS(E) \
+    SK_MAYBE_UNUSED constexpr skgpu::Mask<E> operator|(E a, E b) { return skgpu::Mask<E>(a) | b; } \
+    SK_MAYBE_UNUSED constexpr skgpu::Mask<E> operator&(E a, E b) { return skgpu::Mask<E>(a) & b; } \
+    SK_MAYBE_UNUSED constexpr skgpu::Mask<E> operator^(E a, E b) { return skgpu::Mask<E>(a) ^ b; } \
+    SK_MAYBE_UNUSED constexpr skgpu::Mask<E> operator~(E e) { return ~skgpu::Mask<E>(e); } \
 
-#define SKGPU_DECL_BITFIELD_CLASS_OPS_FRIENDS(X) \
-    friend constexpr TFlagsMask<X> operator ~(X); \
-    friend constexpr X operator |(X, X); \
-    friend X& operator |=(X&, X); \
-    friend constexpr bool operator &(X, X); \
-    friend constexpr TFlagsMask<X> operator|(TFlagsMask<X>, TFlagsMask<X>); \
-    friend constexpr TFlagsMask<X> operator|(TFlagsMask<X>, X); \
-    friend constexpr TFlagsMask<X> operator|(X, TFlagsMask<X>); \
-    friend constexpr X operator&(TFlagsMask<X>, TFlagsMask<X>); \
-    friend constexpr X operator&(TFlagsMask<X>, X); \
-    friend constexpr X operator&(X, TFlagsMask<X>); \
-    friend X& operator &=(X&, TFlagsMask<X>)
+#define SKGPU_DECL_MASK_OPS_FRIENDS(E) \
+    friend constexpr skgpu::Mask<E> operator|(E, E); \
+    friend constexpr skgpu::Mask<E> operator&(E, E); \
+    friend constexpr skgpu::Mask<E> operator^(E, E); \
+    friend constexpr skgpu::Mask<E> operator~(E); \
 
 /**
  * Possible 3D APIs that may be used by Graphite.
diff --git a/gn/tests.gni b/gn/tests.gni
index 42946ae..9a4ef2e 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -389,6 +389,9 @@
   "$_tests/PathOpsTightBoundsTest.cpp",
   "$_tests/PathOpsTypesTest.cpp",
   "$_tests/WangsFormulaTest.cpp",
+
+  # graphite
+  "$_tests/graphite/MaskTest.cpp",
 ]
 
 skgpu_v1_tests_sources = [
diff --git a/tests/graphite/MaskTest.cpp b/tests/graphite/MaskTest.cpp
new file mode 100644
index 0000000..2a2e64a
--- /dev/null
+++ b/tests/graphite/MaskTest.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "experimental/graphite/include/GraphiteTypes.h"
+#include "tests/Test.h"
+
+enum class Flags {
+    kNone = 0,
+    kA = 1,
+    kB = 2,
+    kC = 4
+};
+
+SKGPU_MAKE_MASK_OPS(Flags);
+
+using namespace skgpu;
+
+DEF_TEST(skgpu_Mask, r) {
+    Mask<Flags> flags = Flags::kNone;
+    REPORTER_ASSERT(r, !flags);
+    flags |= Flags::kA;
+    REPORTER_ASSERT(r, flags);
+    REPORTER_ASSERT(r, !(flags & Flags::kB));
+    REPORTER_ASSERT(r, (flags & Flags::kA));
+    flags |= (Flags::kB | Flags::kC);
+    auto mask = Flags::kB | Flags::kC;
+    REPORTER_ASSERT(r, (flags & mask) == mask);
+    REPORTER_ASSERT(r, flags == (Flags::kA | Flags::kB | Flags::kC));
+    flags &= ~Flags::kC;
+    REPORTER_ASSERT(r, flags == (Flags::kA | Flags::kB));
+    REPORTER_ASSERT(r, (flags & mask) != mask);
+    REPORTER_ASSERT(r, (flags & mask) != Flags::kNone);
+    REPORTER_ASSERT(r, (flags & mask));
+    REPORTER_ASSERT(r, flags);
+    flags &= ~Flags::kB;
+    REPORTER_ASSERT(r, (flags & mask) == Flags::kNone);
+    REPORTER_ASSERT(r, !(flags & mask));
+    REPORTER_ASSERT(r, flags);
+    flags = (flags | flags) ^ (flags);
+    REPORTER_ASSERT(r, !flags);
+    flags ^= mask;
+    REPORTER_ASSERT(r, flags == mask);
+    REPORTER_ASSERT(r, !(Flags::kA & Flags::kB));
+    REPORTER_ASSERT(r, (Flags::kA ^ Flags::kB) == (Flags::kA | Flags::kB));
+}