1 // Copyright 2021 The PDFium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CORE_FXCRT_MASK_H_ 6 #define CORE_FXCRT_MASK_H_ 7 8 #include <type_traits> 9 10 namespace fxcrt { 11 12 // Provides extremely strict type-checking on masks of enum class bitflags, 13 // for code where flags may not be passed consistently. 14 template <typename E> 15 class Mask { 16 public: 17 using UnderlyingType = typename std::underlying_type<E>::type; 18 19 // Escape hatch for when value comes aross an API, say. FromUnderlyingUnchecked(UnderlyingType val)20 static Mask FromUnderlyingUnchecked(UnderlyingType val) { return Mask(val); } 21 22 constexpr Mask() = default; 23 constexpr Mask(const Mask& that) = default; 24 25 // NOLINTNEXTLINE(runtime/explicit) Mask(E val)26 constexpr Mask(E val) : val_(static_cast<UnderlyingType>(val)) {} 27 28 // Unfortunately, std::initializer_list<> can't be used in constexpr 29 // methods per C++ standards, and we need constexpr for a zero-cost 30 // abstraction. Hence, expand out constructors of various arity. Mask(E v1,E v2)31 constexpr Mask(E v1, E v2) 32 : val_(static_cast<UnderlyingType>(v1) | 33 static_cast<UnderlyingType>(v2)) {} 34 Mask(E v1,E v2,E v3)35 constexpr Mask(E v1, E v2, E v3) 36 : val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) | 37 static_cast<UnderlyingType>(v3)) {} 38 Mask(E v1,E v2,E v3,E v4)39 constexpr Mask(E v1, E v2, E v3, E v4) 40 : val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) | 41 static_cast<UnderlyingType>(v3) | 42 static_cast<UnderlyingType>(v4)) {} 43 Mask(E v1,E v2,E v3,E v4,E v5)44 constexpr Mask(E v1, E v2, E v3, E v4, E v5) 45 : val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) | 46 static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) | 47 static_cast<UnderlyingType>(v5)) {} 48 Mask(E v1,E v2,E v3,E v4,E v5,E v6)49 constexpr Mask(E v1, E v2, E v3, E v4, E v5, E v6) 50 : val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) | 51 static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) | 52 static_cast<UnderlyingType>(v5) | 53 static_cast<UnderlyingType>(v6)) {} 54 Mask(E v1,E v2,E v3,E v4,E v5,E v6,E v7)55 constexpr Mask(E v1, E v2, E v3, E v4, E v5, E v6, E v7) 56 : val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) | 57 static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) | 58 static_cast<UnderlyingType>(v5) | static_cast<UnderlyingType>(v6) | 59 static_cast<UnderlyingType>(v7)) {} 60 Mask(E v1,E v2,E v3,E v4,E v5,E v6,E v7,E v8)61 constexpr Mask(E v1, E v2, E v3, E v4, E v5, E v6, E v7, E v8) 62 : val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) | 63 static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) | 64 static_cast<UnderlyingType>(v5) | static_cast<UnderlyingType>(v6) | 65 static_cast<UnderlyingType>(v7) | 66 static_cast<UnderlyingType>(v8)) {} 67 68 explicit operator bool() const { return !!val_; } 69 Mask operator~() const { return Mask(~val_); } 70 constexpr Mask operator|(const Mask& that) const { 71 return Mask(val_ | that.val_); 72 } 73 constexpr Mask operator&(const Mask& that) const { 74 return Mask(val_ & that.val_); 75 } 76 constexpr Mask operator^(const Mask& that) const { 77 return Mask(val_ ^ that.val_); 78 } 79 Mask& operator=(const Mask& that) { 80 val_ = that.val_; 81 return *this; 82 } 83 Mask& operator|=(const Mask& that) { 84 val_ |= that.val_; 85 return *this; 86 } 87 Mask& operator&=(const Mask& that) { 88 val_ &= that.val_; 89 return *this; 90 } 91 Mask& operator^=(const Mask& that) { 92 val_ ^= that.val_; 93 return *this; 94 } 95 bool operator==(const Mask& that) const { return val_ == that.val_; } 96 bool operator!=(const Mask& that) const { return val_ != that.val_; } 97 TestAll(const Mask & that)98 bool TestAll(const Mask& that) const { 99 return (val_ & that.val_) == that.val_; 100 } 101 102 // Because ~ can't be applied to enum class without casting. Clear(const Mask & that)103 void Clear(const Mask& that) { val_ &= ~that.val_; } 104 105 // Escape hatch, usage should be minimized. UncheckedValue()106 UnderlyingType UncheckedValue() const { return val_; } 107 108 private: Mask(UnderlyingType val)109 explicit constexpr Mask(UnderlyingType val) : val_(val) {} 110 111 UnderlyingType val_ = 0; 112 }; 113 114 } // namespace fxcrt 115 116 using fxcrt::Mask; 117 118 #endif // CORE_FXCRT_MASK_H_ 119