blob: 67e7a3dbce7b7b216d0ca851ba74ef4843acd8c1 [file] [log] [blame] [edit]
// Copyright 2021 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CORE_FXCRT_MASK_H_
#define CORE_FXCRT_MASK_H_
#include <type_traits>
namespace fxcrt {
// Provides extremely strict type-checking on masks of enum class bitflags,
// for code where flags may not be passed consistently.
template <typename E>
class Mask {
public:
using UnderlyingType = typename std::underlying_type<E>::type;
// Escape hatch for when value comes aross an API, say.
static Mask FromUnderlyingUnchecked(UnderlyingType val) { return Mask(val); }
constexpr Mask() = default;
constexpr Mask(const Mask& that) = default;
// NOLINTNEXTLINE(runtime/explicit)
constexpr Mask(E val) : val_(static_cast<UnderlyingType>(val)) {}
// Unfortunately, std::initializer_list<> can't be used in constexpr
// methods per C++ standards, and we need constexpr for a zero-cost
// abstraction. Hence, expand out constructors of various arity.
constexpr Mask(E v1, E v2)
: val_(static_cast<UnderlyingType>(v1) |
static_cast<UnderlyingType>(v2)) {}
constexpr Mask(E v1, E v2, E v3)
: val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) |
static_cast<UnderlyingType>(v3)) {}
constexpr Mask(E v1, E v2, E v3, E v4)
: val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) |
static_cast<UnderlyingType>(v3) |
static_cast<UnderlyingType>(v4)) {}
constexpr Mask(E v1, E v2, E v3, E v4, E v5)
: val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) |
static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) |
static_cast<UnderlyingType>(v5)) {}
constexpr Mask(E v1, E v2, E v3, E v4, E v5, E v6)
: val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) |
static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) |
static_cast<UnderlyingType>(v5) |
static_cast<UnderlyingType>(v6)) {}
constexpr Mask(E v1, E v2, E v3, E v4, E v5, E v6, E v7)
: val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) |
static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) |
static_cast<UnderlyingType>(v5) | static_cast<UnderlyingType>(v6) |
static_cast<UnderlyingType>(v7)) {}
constexpr Mask(E v1, E v2, E v3, E v4, E v5, E v6, E v7, E v8)
: val_(static_cast<UnderlyingType>(v1) | static_cast<UnderlyingType>(v2) |
static_cast<UnderlyingType>(v3) | static_cast<UnderlyingType>(v4) |
static_cast<UnderlyingType>(v5) | static_cast<UnderlyingType>(v6) |
static_cast<UnderlyingType>(v7) |
static_cast<UnderlyingType>(v8)) {}
explicit operator bool() const { return !!val_; }
Mask operator~() const { return Mask(~val_); }
constexpr Mask operator|(const Mask& that) const {
return Mask(val_ | that.val_);
}
constexpr Mask operator&(const Mask& that) const {
return Mask(val_ & that.val_);
}
constexpr Mask operator^(const Mask& that) const {
return Mask(val_ ^ that.val_);
}
Mask& operator=(const Mask& that) {
val_ = that.val_;
return *this;
}
Mask& operator|=(const Mask& that) {
val_ |= that.val_;
return *this;
}
Mask& operator&=(const Mask& that) {
val_ &= that.val_;
return *this;
}
Mask& operator^=(const Mask& that) {
val_ ^= that.val_;
return *this;
}
bool operator==(const Mask& that) const { return val_ == that.val_; }
bool operator!=(const Mask& that) const { return val_ != that.val_; }
bool TestAll(const Mask& that) const {
return (val_ & that.val_) == that.val_;
}
// Because ~ can't be applied to enum class without casting.
void Clear(const Mask& that) { val_ &= ~that.val_; }
// Escape hatch, usage should be minimized.
UnderlyingType UncheckedValue() const { return val_; }
private:
explicit constexpr Mask(UnderlyingType val) : val_(val) {}
UnderlyingType val_ = 0;
};
} // namespace fxcrt
using fxcrt::Mask;
#endif // CORE_FXCRT_MASK_H_