From 30127dfe909ca787c92fc32683bb00b1585b0808 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Tue, 28 Jan 2025 22:24:42 +0100 Subject: [PATCH] Codechange: prepare the pool for strongly typed pool element IDs --- src/base_station_base.h | 6 ++-- src/core/pool_func.hpp | 7 +++- src/core/pool_type.hpp | 71 ++++++++++++++++++++++++++++++++++++----- src/vehicle_base.h | 6 ++-- 4 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/base_station_base.h b/src/base_station_base.h index e4e6965f6a..585dfc6fd0 100644 --- a/src/base_station_base.h +++ b/src/base_station_base.h @@ -241,7 +241,7 @@ struct SpecializedStation : public BaseStation { * @param index tested index * @return is this index valid index of T? */ - static inline bool IsValidID(size_t index) + static inline bool IsValidID(auto index) { return BaseStation::IsValidID(index) && IsExpected(BaseStation::Get(index)); } @@ -250,7 +250,7 @@ struct SpecializedStation : public BaseStation { * Gets station with given index * @return pointer to station with given index casted to T * */ - static inline T *Get(size_t index) + static inline T *Get(auto index) { return (T *)BaseStation::Get(index); } @@ -259,7 +259,7 @@ struct SpecializedStation : public BaseStation { * Returns station if the index is a valid index for this station type * @return pointer to station with given index if it's a station of this type */ - static inline T *GetIfValid(size_t index) + static inline T *GetIfValid(auto index) { return IsValidID(index) ? Get(index) : nullptr; } diff --git a/src/core/pool_func.hpp b/src/core/pool_func.hpp index 178f387cd7..e11473dc66 100644 --- a/src/core/pool_func.hpp +++ b/src/core/pool_func.hpp @@ -124,7 +124,12 @@ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index) } this->data[index] = item; SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE); - item->index = (Tindex)(uint)index; + if constexpr (std::is_base_of_v) { + /* MSVC complains about casting to narrower type, so first cast to the base type... then to the strong type. */ + item->index = static_cast(static_cast(index)); + } else { + item->index = static_cast(index); + } return item; } diff --git a/src/core/pool_type.hpp b/src/core/pool_type.hpp index 5cb69fa3c4..6d4bd9fce9 100644 --- a/src/core/pool_type.hpp +++ b/src/core/pool_type.hpp @@ -24,6 +24,54 @@ static constexpr PoolTypes PT_ALL = {PoolType::Normal, PoolType::NetworkClient, typedef std::vector PoolVector; ///< Vector of pointers to PoolBase +/** Non-templated base for #PoolID for use with type trait queries. */ +struct PoolIDBase {}; + +/** + * Templated helper to make a PoolID a single POD value. + * + * Example usage: + * + * using MyType = PoolID; + * + * @tparam TBaseType Type of the derived class (i.e. the concrete usage of this class). + * @tparam TTag An unique struct to keep types of the same TBaseType distinct. + * @tparam TEnd The PoolID at the end of the pool (equivalent to size). + * @tparam TInvalid The PoolID denoting an invalid value. + */ +template +struct EMPTY_BASES PoolID : PoolIDBase { + using BaseType = TBaseType; + + constexpr PoolID() = default; + constexpr PoolID(const PoolID &) = default; + constexpr PoolID(PoolID &&) = default; + + explicit constexpr PoolID(const TBaseType &value) : value(value) {} + + constexpr PoolID &operator =(const PoolID &rhs) { this->value = rhs.value; return *this; } + constexpr PoolID &operator =(PoolID &&rhs) { this->value = std::move(rhs.value); return *this; } + + /* Only allow conversion to BaseType via method. */ + constexpr TBaseType base() const noexcept { return this->value; } + + static constexpr PoolID Begin() { return PoolID{}; } + static constexpr PoolID End() { return PoolID{static_cast(TEnd)}; } + static constexpr PoolID Invalid() { return PoolID{static_cast(TInvalid)}; } + + constexpr auto operator++() { ++this->value; return this; } + constexpr auto operator+(const std::integral auto &val) const { return this->value + val; } + + constexpr bool operator==(const PoolID &rhs) const { return this->value == rhs.value; } + constexpr auto operator<=>(const PoolID &rhs) const { return this->value <=> rhs.value; } + + constexpr bool operator==(const size_t &rhs) const { return this->value == rhs; } + constexpr auto operator<=>(const size_t &rhs) const { return this->value <=> rhs; } +private: + /* Do not explicitly initialize. */ + TBaseType value; +}; + /** Base class for base of all pools. */ struct PoolBase { const PoolType type; ///< Type of this pool. @@ -83,6 +131,8 @@ private: static constexpr size_t GetMaxIndexValue(T) { return std::numeric_limits::max(); } template requires std::is_enum_v static constexpr size_t GetMaxIndexValue(T) { return std::numeric_limits>::max(); } + template requires std::is_base_of_v + static constexpr size_t GetMaxIndexValue(T) { return std::numeric_limits::max(); } public: /* Ensure the highest possible index, i.e. Tmax_size -1, is within the bounds of Tindex. */ static_assert(Tmax_size - 1 <= GetMaxIndexValue(Tindex{})); @@ -263,8 +313,8 @@ public: { if (p == nullptr) return; Titem *pn = static_cast(p); - assert(pn == Tpool->Get(pn->index)); - Tpool->FreeItem(pn->index); + assert(pn == Tpool->Get(Pool::GetRawIndex(pn->index))); + Tpool->FreeItem(Pool::GetRawIndex(pn->index)); } /** @@ -328,9 +378,9 @@ public: * @param index index to examine * @return true if PoolItem::Get(index) will return non-nullptr pointer */ - static inline bool IsValidID(size_t index) + static inline bool IsValidID(auto index) { - return Tpool->IsValidID(index); + return Tpool->IsValidID(GetRawIndex(index)); } /** @@ -339,9 +389,9 @@ public: * @return pointer to Titem * @pre index < this->first_unused */ - static inline Titem *Get(size_t index) + static inline Titem *Get(auto index) { - return Tpool->Get(index); + return Tpool->Get(GetRawIndex(index)); } /** @@ -350,9 +400,9 @@ public: * @return pointer to Titem * @note returns nullptr for invalid index */ - static inline Titem *GetIfValid(size_t index) + static inline Titem *GetIfValid(auto index) { - return index < Tpool->first_unused ? Tpool->Get(index) : nullptr; + return GetRawIndex(index) < Tpool->first_unused ? Tpool->Get(GetRawIndex(index)) : nullptr; } /** @@ -414,6 +464,11 @@ private: void *GetNew(size_t size, size_t index); void FreeItem(size_t index); + + /* Temporary helper functions to get the raw index from either strongly and non-strongly typed pool items. */ + static constexpr size_t GetRawIndex(size_t index) { return index; } + template requires std::is_base_of_v + static constexpr size_t GetRawIndex(const T &index) { return index.base(); } }; #endif /* POOL_TYPE_HPP */ diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 52a82cb594..8d042aabae 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -1177,7 +1177,7 @@ struct SpecializedVehicle : public Vehicle { * @param index tested index * @return is this index valid index of T? */ - static inline bool IsValidID(size_t index) + static inline bool IsValidID(auto index) { return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type; } @@ -1186,7 +1186,7 @@ struct SpecializedVehicle : public Vehicle { * Gets vehicle with given index * @return pointer to vehicle with given index casted to T * */ - static inline T *Get(size_t index) + static inline T *Get(auto index) { return (T *)Vehicle::Get(index); } @@ -1195,7 +1195,7 @@ struct SpecializedVehicle : public Vehicle { * Returns vehicle if the index is a valid index for this vehicle type * @return pointer to vehicle with given index if it's a vehicle of this type */ - static inline T *GetIfValid(size_t index) + static inline T *GetIfValid(auto index) { return IsValidID(index) ? Get(index) : nullptr; }