1
0
Fork 0

Codechange: introduce BaseBitSet as base for EnumBitSet

pull/13512/head
Rubidium 2025-02-08 11:55:07 +01:00 committed by rubidium42
parent b9777269ce
commit e972033e11
3 changed files with 152 additions and 95 deletions

View File

@ -3,6 +3,7 @@ add_files(
alloc_func.hpp
alloc_type.hpp
backup_type.hpp
base_bitset_type.hpp
bitmath_func.hpp
convertible_through_base.hpp
endian_func.hpp

View File

@ -0,0 +1,140 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file base_bitset_type.hpp Base for bitset types that accept strong types,
* i.e. types that need some casting like StrongType and enum class.
*/
#ifndef BASE_BITSET_TYPE_HPP
#define BASE_BITSET_TYPE_HPP
/**
* Base for bit set wrapper.
* Allows wrapping strong type values as a bit set. Methods are loosely modelled on std::bitset.
* @tparam Tvalue_type Type of values to wrap.
* @tparam Tstorage Storage type required to hold values.
*/
template <typename Timpl, typename Tvalue_type, typename Tstorage>
class BaseBitSet {
public:
using ValueType = Tvalue_type; ///< Value type of this BaseBitSet.
using BaseType = Tstorage; ///< Storage type of this BaseBitSet, be ConvertibleThroughBase
constexpr BaseBitSet() : data(0) {}
explicit constexpr BaseBitSet(Tstorage data) : data(data) {}
constexpr auto operator <=>(const BaseBitSet &) const noexcept = default;
/**
* Set the value-th bit.
* @param value Bit to set.
* @returns The bit set
*/
inline constexpr Timpl &Set(Tvalue_type value)
{
this->data |= (1ULL << Timpl::DecayValueType(value));
return static_cast<Timpl&>(*this);
}
/**
* Reset the value-th bit.
* @param value Bit to reset.
* @returns The bit set
*/
inline constexpr Timpl &Reset(Tvalue_type value)
{
this->data &= ~(1ULL << Timpl::DecayValueType(value));
return static_cast<Timpl&>(*this);
}
/**
* Flip the value-th bit.
* @param value Bit to flip.
* @returns The bit set
*/
inline constexpr Timpl &Flip(Tvalue_type value)
{
if (this->Test(value)) {
return this->Reset(value);
} else {
return this->Set(value);
}
}
/**
* Test if the value-th bit is set.
* @param value Bit to check.
* @returns true iff the requested bit is set.
*/
inline constexpr bool Test(Tvalue_type value) const
{
return (this->data & (1ULL << Timpl::DecayValueType(value))) != 0;
}
/**
* Test if all of the values are set.
* @param other BitSet of values to test.
* @returns true iff all of the values are set.
*/
inline constexpr bool All(const Timpl &other) const
{
return (this->data & other.data) == other.data;
}
/**
* Test if any of the given values are set.
* @param other BitSet of values to test.
* @returns true iff any of the given values are set.
*/
inline constexpr bool Any(const Timpl &other) const
{
return (this->data & other.data) != 0;
}
/**
* Test if any of the values are set.
* @returns true iff any of the values are set.
*/
inline constexpr bool Any() const
{
return this->data != 0;
}
/**
* Test if none of the values are set.
* @returns true iff none of the values are set.
*/
inline constexpr bool None() const
{
return this->data == 0;
}
inline constexpr Timpl operator |(const Timpl &other) const
{
return Timpl{static_cast<Tstorage>(this->data | other.data)};
}
inline constexpr Timpl operator &(const Timpl &other) const
{
return Timpl{static_cast<Tstorage>(this->data & other.data)};
}
/**
* Retrieve the raw value behind this bit set.
* @returns the raw value.
*/
inline constexpr Tstorage base() const noexcept
{
return this->data;
}
private:
Tstorage data; ///< Bitmask of values.
};
#endif /* BASE_BITSET_TYPE_HPP */

View File

@ -10,6 +10,8 @@
#ifndef ENUM_TYPE_HPP
#define ENUM_TYPE_HPP
#include "base_bitset_type.hpp"
/** Implementation of std::to_underlying (from C++23) */
template <typename enum_type>
constexpr std::underlying_type_t<enum_type> to_underlying(enum_type e) { return static_cast<std::underlying_type_t<enum_type>>(e); }
@ -117,21 +119,21 @@ debug_inline constexpr void ToggleFlag(T &x, const T y)
* @tparam Tend_value Last valid value + 1.
*/
template <typename Tenum, typename Tstorage, Tenum Tend_value = Tenum{std::numeric_limits<Tstorage>::digits}>
class EnumBitSet {
class EnumBitSet : public BaseBitSet<EnumBitSet<Tenum, Tstorage, Tend_value>, Tenum, Tstorage> {
using BaseClass = BaseBitSet<EnumBitSet<Tenum, Tstorage, Tend_value>, Tenum, Tstorage>;
public:
using EnumType = Tenum; ///< Enum type of this EnumBitSet.
using BaseType = Tstorage; ///< Storage type of this EnumBitSet, be ConvertibleThroughBase
using EnumType = BaseClass::ValueType;
static constexpr Tstorage MASK = std::numeric_limits<Tstorage>::max() >> (std::numeric_limits<Tstorage>::digits - to_underlying(Tend_value)); ///< Mask of valid values.
constexpr EnumBitSet() : data(0) {}
constexpr EnumBitSet(Tenum value) : data(0) { this->Set(value); }
explicit constexpr EnumBitSet(Tstorage data) : data(data & MASK) {}
constexpr EnumBitSet() : BaseClass() {}
constexpr EnumBitSet(Tenum value) : BaseClass() { this->Set(value); }
explicit constexpr EnumBitSet(Tstorage data) : BaseClass(data & MASK) {}
/**
* Construct an EnumBitSet from a list of enum values.
* @param values List of enum values.
*/
constexpr EnumBitSet(std::initializer_list<const Tenum> values) : data(0)
constexpr EnumBitSet(std::initializer_list<const Tenum> values) : BaseClass()
{
for (const Tenum &value : values) {
this->Set(value);
@ -140,102 +142,16 @@ public:
constexpr auto operator <=>(const EnumBitSet &) const noexcept = default;
/**
* Set the enum value.
* @param value Enum value to set.
* @returns The EnumBitset
*/
inline constexpr EnumBitSet &Set(Tenum value)
{
this->data |= (1ULL << to_underlying(value));
return *this;
}
/**
* Reset the enum value to not set.
* @param value Enum value to reset.
* @returns The EnumBitset
*/
inline constexpr EnumBitSet &Reset(Tenum value)
{
this->data &= ~(1ULL << to_underlying(value));
return *this;
}
/**
* Flip the enum value.
* @param value Enum value to flip.
* @returns The EnumBitset
*/
inline constexpr EnumBitSet &Flip(Tenum value)
{
if (this->Test(value)) {
return this->Reset(value);
} else {
return this->Set(value);
}
}
/**
* Test if the enum value is set.
* @param value Enum value to check.
* @returns true iff the requested value is set.
*/
inline constexpr bool Test(Tenum value) const
{
return (this->data & (1ULL << to_underlying(value))) != 0;
}
/**
* Test if all of the enum values are set.
* @param other BitSet of enum values to test.
* @returns true iff all of the enum values are set.
*/
inline constexpr bool All(const EnumBitSet &other) const
{
return (this->data & other.data) == other.data;
}
/**
* Test if any of the enum values are set.
* @param other BitSet of enum values to test.
* @returns true iff any of the enum values are set.
*/
inline constexpr bool Any(const EnumBitSet &other) const
{
return (this->data & other.data) != 0;
}
inline constexpr EnumBitSet operator |(const EnumBitSet &other) const
{
return EnumBitSet{static_cast<Tstorage>(this->data | other.data)};
}
inline constexpr EnumBitSet operator &(const EnumBitSet &other) const
{
return EnumBitSet{static_cast<Tstorage>(this->data & other.data)};
}
/**
* Test that the raw value of this EnumBitSet is valid.
* @returns true iff the no bits outside the masked value are set.
*/
inline constexpr bool IsValid() const
{
return (this->data & MASK) == this->data;
return (this->base() & MASK) == this->base();
}
/**
* Retrieve the raw value behind this EnumBitSet.
* @returns the raw value.
*/
inline constexpr Tstorage base() const noexcept
{
return this->data;
}
private:
Tstorage data; ///< Bitmask of enum values.
static constexpr size_t DecayValueType(const BaseClass::ValueType &value) { return to_underlying(value); }
};
#endif /* ENUM_TYPE_HPP */