Files
swift-mirror/include/swift/Basic/FlagSet.h
T
2026-04-24 15:54:30 +01:00

134 lines
5.1 KiB
C++

//===--- FlagSet.h - Helper class for opaque flag types ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the FlagSet template, a class which makes it easier to
// define opaque flag types.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BASIC_FLAGSET_H
#define SWIFT_BASIC_FLAGSET_H
#include <type_traits>
#include <assert.h>
namespace swift {
/// A template designed to simplify the task of defining a wrapper type
/// for a flags bitfield.
template <typename IntType>
class FlagSet {
static_assert(std::is_integral<IntType>::value,
"storage type for FlagSet must be an integral type");
IntType Bits;
protected:
template <unsigned BitWidth>
static constexpr IntType lowMaskFor() {
return IntType((1 << BitWidth) - 1);
}
template <unsigned FirstBit, unsigned BitWidth = 1>
static constexpr IntType maskFor() {
return lowMaskFor<BitWidth>() << FirstBit;
}
constexpr FlagSet(IntType bits = 0) : Bits(bits) {}
/// Read a single-bit flag.
template <unsigned Bit>
constexpr bool getFlag() const {
return Bits & maskFor<Bit>();
}
/// Set a single-bit flag.
template <unsigned Bit>
constexpr void setFlag(bool value) {
if (value) {
Bits |= maskFor<Bit>();
} else {
Bits &= ~maskFor<Bit>();
}
}
/// Read a multi-bit field.
template <unsigned FirstBit, unsigned BitWidth, typename FieldType = IntType>
constexpr FieldType getField() const {
return FieldType((Bits >> FirstBit) & lowMaskFor<BitWidth>());
}
/// Assign to a multi-bit field.
template <unsigned FirstBit, unsigned BitWidth, typename FieldType = IntType>
constexpr void
setField(typename std::enable_if<true, FieldType>::type value) {
// Note that we suppress template argument deduction for FieldType.
assert(IntType(value) <= lowMaskFor<BitWidth>() && "value out of range");
Bits = (Bits & ~maskFor<FirstBit, BitWidth>())
| (IntType(value) << FirstBit);
}
// A convenient macro for defining a getter and setter for a flag.
// Intended to be used in the body of a subclass of FlagSet.
#define FLAGSET_DEFINE_FLAG_ACCESSORS(BIT, GETTER, SETTER) \
bool GETTER() const { \
return this->template getFlag<BIT>(); \
} \
void SETTER(bool value) { \
this->template setFlag<BIT>(value); \
}
// A convenient macro for defining a getter, setter and builder for a flag.
// The builder method returns a copy of the flagset with the relevant bit set
// to the specified value. Builder method chaining provides a clean, safe way
// to construct flag sets within (constant) expression contexts.
#define FLAGSET_DEFINE_FLAG_ACCESSORS_AND_BUILDER(BIT, GETTER, SETTER, \
BUILDER) \
FLAGSET_DEFINE_FLAG_ACCESSORS(BIT, GETTER, SETTER) \
[[nodiscard]] constexpr auto BUILDER(bool value = true) const { \
auto result = *this; \
result.template setFlag<BIT>(value); \
return result; \
}
// A convenient macro for defining a getter and setter for a field.
// Intended to be used in the body of a subclass of FlagSet.
#define FLAGSET_DEFINE_FIELD_ACCESSORS(BIT, WIDTH, TYPE, GETTER, SETTER) \
constexpr TYPE GETTER() const { \
return this->template getField<BIT, WIDTH, TYPE>(); \
} \
void SETTER(TYPE value) { \
this->template setField<BIT, WIDTH, TYPE>(value); \
}
// A convenient macro to expose equality operators.
// These can't be provided directly by FlagSet because that would allow
// different flag sets to be compared if they happen to have the same
// underlying type.
#define FLAGSET_DEFINE_EQUALITY(TYPENAME) \
friend bool operator==(TYPENAME lhs, TYPENAME rhs) { \
return lhs.getOpaqueValue() == rhs.getOpaqueValue(); \
} \
friend bool operator!=(TYPENAME lhs, TYPENAME rhs) { \
return lhs.getOpaqueValue() != rhs.getOpaqueValue(); \
}
public:
/// Get the bits as an opaque integer value.
IntType getOpaqueValue() const {
return Bits;
}
};
} // end namespace swift
#endif