139 lines
4.7 KiB
C++
139 lines
4.7 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#pragma once
|
|
|
|
#ifdef __cpp_concepts
|
|
#define TIL_ENUMSET_VARARG template<std::same_as<T>... Args>
|
|
#else
|
|
#define TIL_ENUMSET_VARARG template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<T, Args>...>>>
|
|
#endif
|
|
|
|
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|
{
|
|
// til::enumset stores a fixed size array of boolean elements, the positions
|
|
// in the array being identified by values from a given enumerated type.
|
|
// Position N corresponds to bit 1<<N in the UnderlyingType integer.
|
|
//
|
|
// If you only need 32 positions for your T, UnderlyingType can be set uint32_t.
|
|
// It defaults to uintptr_t allowing you to set as many positions as a pointer has bits.
|
|
// This class doesn't statically assert that your given position fits into UnderlyingType.
|
|
template<typename T, typename UnderlyingType = uintptr_t>
|
|
class enumset
|
|
{
|
|
static_assert(std::is_unsigned_v<UnderlyingType>);
|
|
|
|
public:
|
|
// Method Description:
|
|
// - Constructs a new bitset with the given list of positions set to true.
|
|
TIL_ENUMSET_VARARG
|
|
constexpr enumset(Args... positions) noexcept :
|
|
_data{ to_underlying(positions...) }
|
|
{
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns the underlying bit positions as a copy.
|
|
constexpr UnderlyingType bits() const noexcept
|
|
{
|
|
return _data;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns the value of the bit at the given position.
|
|
// Throws std::out_of_range if it is not a valid position
|
|
// in the bitset.
|
|
constexpr bool test(const T pos) const noexcept
|
|
{
|
|
const auto mask = to_underlying(pos);
|
|
return (_data & mask) != 0;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns true if any of the bits are set to true.
|
|
constexpr bool any() const noexcept
|
|
{
|
|
return _data != 0;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns true if any of the bits in the given positions are true.
|
|
TIL_ENUMSET_VARARG
|
|
constexpr bool any(Args... positions) const noexcept
|
|
{
|
|
const auto mask = to_underlying(positions...);
|
|
return (_data & mask) != 0;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns true if all of the bits are set to true.
|
|
constexpr bool all() const noexcept
|
|
{
|
|
return _data == ~UnderlyingType{ 0 };
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns true if all of the bits in the given positions are true.
|
|
TIL_ENUMSET_VARARG
|
|
constexpr bool all(Args... positions) const noexcept
|
|
{
|
|
const auto mask = to_underlying(positions...);
|
|
return (_data & mask) == mask;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Sets all of the bits in the given positions to true.
|
|
TIL_ENUMSET_VARARG
|
|
constexpr enumset& set(Args... positions) noexcept
|
|
{
|
|
_data |= to_underlying(positions...);
|
|
return *this;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Sets the bit in the given position to the specified value.
|
|
constexpr enumset& set(const T pos, const bool val) noexcept
|
|
{
|
|
const auto mask = to_underlying(pos);
|
|
// false == 0 --> UnderlyingType(-0) == 0b0000...
|
|
// true == 1 --> UnderlyingType(-1) == 0b1111...
|
|
#pragma warning(suppress : 4804) // '-': unsafe use of type 'bool' in operation
|
|
_data = (_data & ~mask) | (-val & mask);
|
|
return *this;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Resets all of the bits in the given positions to false.
|
|
TIL_ENUMSET_VARARG
|
|
constexpr enumset& reset(Args... positions) noexcept
|
|
{
|
|
_data &= ~to_underlying(positions...);
|
|
return *this;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Flips the bit at the given position.
|
|
TIL_ENUMSET_VARARG
|
|
constexpr enumset& flip(Args... positions) noexcept
|
|
{
|
|
_data ^= to_underlying(positions...);
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
template<typename... Args>
|
|
static constexpr UnderlyingType to_underlying(Args... positions) noexcept
|
|
{
|
|
return ((UnderlyingType{ 1 } << static_cast<UnderlyingType>(positions)) | ...);
|
|
}
|
|
|
|
template<>
|
|
static constexpr UnderlyingType to_underlying() noexcept
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
UnderlyingType _data{};
|
|
};
|
|
}
|