mirror of https://github.com/OpenTTD/OpenTTD
Codechange: introduce BaseBitSet as base for EnumBitSet
parent
b9777269ce
commit
e972033e11
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue