1
0
Fork 0

Codechange: prepare the pool for strongly typed pool element IDs

pull/13511/head
Rubidium 2025-01-28 22:24:42 +01:00 committed by rubidium42
parent 82c5e37b46
commit 30127dfe90
4 changed files with 75 additions and 15 deletions

View File

@ -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;
}

View File

@ -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<PoolIDBase, Tindex>) {
/* MSVC complains about casting to narrower type, so first cast to the base type... then to the strong type. */
item->index = static_cast<Tindex>(static_cast<Tindex::BaseType>(index));
} else {
item->index = static_cast<Tindex>(index);
}
return item;
}

View File

@ -24,6 +24,54 @@ static constexpr PoolTypes PT_ALL = {PoolType::Normal, PoolType::NetworkClient,
typedef std::vector<struct PoolBase *> 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<int, struct MyTypeTag, 16, 0xFF>;
*
* @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 <typename TBaseType, typename TTag, TBaseType TEnd, TBaseType TInvalid>
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<TBaseType>(TEnd)}; }
static constexpr PoolID Invalid() { return PoolID{static_cast<TBaseType>(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<TBaseType, TTag, TEnd, TInvalid> &rhs) const { return this->value == rhs.value; }
constexpr auto operator<=>(const PoolID<TBaseType, TTag, TEnd, TInvalid> &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<T>::max(); }
template <typename T> requires std::is_enum_v<T>
static constexpr size_t GetMaxIndexValue(T) { return std::numeric_limits<std::underlying_type_t<T>>::max(); }
template <typename T> requires std::is_base_of_v<PoolIDBase, T>
static constexpr size_t GetMaxIndexValue(T) { return std::numeric_limits<typename T::BaseType>::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<Titem *>(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 <typename T> requires std::is_base_of_v<PoolIDBase, T>
static constexpr size_t GetRawIndex(const T &index) { return index.base(); }
};
#endif /* POOL_TYPE_HPP */

View File

@ -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;
}