diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b063cbba76..a6d464e473 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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 diff --git a/src/core/base_bitset_type.hpp b/src/core/base_bitset_type.hpp new file mode 100644 index 0000000000..07fd3b76c4 --- /dev/null +++ b/src/core/base_bitset_type.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 . + */ + +/** + * @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 +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(*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(*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(this->data | other.data)}; + } + + inline constexpr Timpl operator &(const Timpl &other) const + { + return Timpl{static_cast(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 */ diff --git a/src/core/enum_type.hpp b/src/core/enum_type.hpp index 12ce318c69..961b78f415 100644 --- a/src/core/enum_type.hpp +++ b/src/core/enum_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 constexpr std::underlying_type_t to_underlying(enum_type e) { return static_cast>(e); } @@ -117,21 +119,21 @@ debug_inline constexpr void ToggleFlag(T &x, const T y) * @tparam Tend_value Last valid value + 1. */ template ::digits}> -class EnumBitSet { +class EnumBitSet : public BaseBitSet, Tenum, Tstorage> { + using BaseClass = BaseBitSet, 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::max() >> (std::numeric_limits::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 values) : data(0) + constexpr EnumBitSet(std::initializer_list 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(this->data | other.data)}; - } - - inline constexpr EnumBitSet operator &(const EnumBitSet &other) const - { - return EnumBitSet{static_cast(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 */