terminal/src/inc/til/enumset.h
James Holderness 09d0ac768a
Add an enum-compatible bitset class. (#10492)
## Summary of the Pull Request

This introduces a new TIL class that is equivalent in functionality to a `std::bitset`, but where the positions in the bitset are enum values. It also has a few additional methods allowing for setting and testing multiple positions at the same time. The idea is that this class could be used in place of the `WI_SetFlag` and `WI_IsFlagSet` macros when working with sets of flags.

## PR Checklist
* [x] Closes #10432
* [x] CLA signed.
* [x] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. Issue number where discussion took place: #10432

## Validation Steps Performed

I've added a few unit tests that verify the behaviour of all the new methods that aren't part of `std::bitset`. I've also tried it out as a replacement for the `GridLines` enum used in the renderer, and confirmed that it has all the functionality needed to replace that cleanly.
2021-09-27 13:27:29 +00:00

133 lines
4.5 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include <bitset>
namespace til // Terminal Implementation Library. Also: "Today I Learned"
{
// By design, this class hides several methods in the std::bitset class
// so they can be called with an enum parameter instead of a size_t, so
// we need to disable the "hides a non-virtual function" warning.
#pragma warning(push)
#pragma warning(disable : 26434)
// til::enumset is a subclass of std::bitset, storing a fixed size array of
// boolean elements, the positions in the array being identified by values
// from a given enumerated type. By default it holds the same number of
// bits as a size_t value.
template<typename Type, size_t Bits = std::numeric_limits<size_t>::digits>
class enumset : public std::bitset<Bits>
{
using _base = std::bitset<Bits>;
public:
using reference = typename _base::reference;
enumset() = default;
// Method Description:
// - Constructs a new bitset with the given list of positions set to true.
template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<Type, Args>...>>>
constexpr enumset(const Args... positions) noexcept :
_base((... | (1ULL << static_cast<size_t>(positions))))
{
}
// Method Description:
// - Returns the value of the bit at the given position.
constexpr bool operator[](const Type pos) const
{
return _base::operator[](static_cast<size_t>(pos));
}
// Method Description:
// - Returns a reference to the bit at the given position.
reference operator[](const Type pos)
{
return _base::operator[](static_cast<size_t>(pos));
}
// 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.
bool test(const Type pos) const
{
return _base::test(static_cast<size_t>(pos));
}
// Method Description:
// - Returns true if any of the bits are set to true.
bool any() const noexcept
{
return _base::any();
}
// Method Description:
// - Returns true if any of the bits in the given positions are true.
template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<Type, Args>...>>>
bool any(const Args... positions) const noexcept
{
return (enumset{ positions... } & *this) != 0;
}
// Method Description:
// - Returns true if all of the bits are set to true.
bool all() const noexcept
{
return _base::all();
}
// Method Description:
// - Returns true if all of the bits in the given positions are true.
template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<Type, Args>...>>>
bool all(const Args... positions) const noexcept
{
return (enumset{ positions... } & *this) == enumset{ positions... };
}
// Method Description:
// - Sets the bit in the given position to the specified value.
enumset& set(const Type pos, const bool val = true)
{
_base::set(static_cast<size_t>(pos), val);
return *this;
}
// Method Description:
// - Resets the bit in the given position to false.
enumset& reset(const Type pos)
{
_base::reset(static_cast<size_t>(pos));
return *this;
}
// Method Description:
// - Flips the bit at the given position.
enumset& flip(const Type pos)
{
_base::flip(static_cast<size_t>(pos));
return *this;
}
// Method Description:
// - Sets all of the bits in the given positions to true.
template<typename... Args>
enumset& set_all(const Args... positions)
{
return (..., set(positions));
}
// Method Description:
// - Resets all of the bits in the given positions to false.
template<typename... Args>
enumset& reset_all(const Args... positions)
{
return (..., reset(positions));
}
};
#pragma warning(pop)
}