Use tagged pointers in the vehicle pool on supported (64 bit) platforms
Use to avoid needing to dereference each pointer to get the vehicle type when doing per-vehicle type iteration
This commit is contained in:
@@ -27,4 +27,12 @@
|
||||
# error "TTD_ENDIAN is not defined; please set it to either TTD_LITTLE_ENDIAN or TTD_BIG_ENDIAN"
|
||||
#endif /* !TTD_ENDIAN */
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64)
|
||||
/** Tagged pointers (upper bits) may be used on this architecture */
|
||||
# define OTTD_UPPER_TAGGED_PTR 1
|
||||
#else
|
||||
/** Tagged pointers (upper bits) may not be used on this architecture */
|
||||
# define OTTD_UPPER_TAGGED_PTR 0
|
||||
#endif
|
||||
|
||||
#endif /* ENDIAN_TYPE_HPP */
|
||||
|
@@ -21,8 +21,8 @@
|
||||
* @param type The return type of the method.
|
||||
*/
|
||||
#define DEFINE_POOL_METHOD(type) \
|
||||
template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero> \
|
||||
type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero>
|
||||
template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero, typename Tops> \
|
||||
type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero, Tops>
|
||||
|
||||
/**
|
||||
* Create a clean pool.
|
||||
@@ -107,9 +107,9 @@ DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
|
||||
* @pre index < this->size
|
||||
* @pre this->Get(index) == nullptr
|
||||
*/
|
||||
DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
|
||||
DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index, Pool::ParamType param)
|
||||
{
|
||||
dbg_assert(this->data[index] == nullptr);
|
||||
dbg_assert(this->data[index] == Tops::NullValue());
|
||||
|
||||
this->first_unused = std::max(this->first_unused, index + 1);
|
||||
this->items++;
|
||||
@@ -129,7 +129,7 @@ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
|
||||
} else {
|
||||
item = (Titem *)MallocT<byte>(size);
|
||||
}
|
||||
this->data[index] = item;
|
||||
this->data[index] = Tops::PutPtr(item, param);
|
||||
SetBit(this->free_bitmap[index / 64], index % 64);
|
||||
item->index = (Tindex)(uint)index;
|
||||
return item;
|
||||
@@ -141,7 +141,7 @@ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
|
||||
* @return pointer to allocated item
|
||||
* @note error() on failure! (no free item)
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size, Pool::ParamType param)
|
||||
{
|
||||
size_t index = this->FindFirstFree();
|
||||
|
||||
@@ -154,7 +154,7 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
}
|
||||
|
||||
this->first_free = index + 1;
|
||||
return this->AllocateItem(size, index);
|
||||
return this->AllocateItem(size, index, param);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +164,7 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
* @return pointer to allocated item
|
||||
* @note SlErrorCorruptFmt() on failure! (index out of range or already used)
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index, Pool::ParamType param)
|
||||
{
|
||||
[[noreturn]] extern void SlErrorCorruptFmt(const char *format, ...);
|
||||
|
||||
@@ -174,11 +174,11 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
|
||||
|
||||
if (index >= this->size) this->ResizeFor(index);
|
||||
|
||||
if (this->data[index] != nullptr) {
|
||||
if (this->data[index] != Tops::NullValue()) {
|
||||
SlErrorCorruptFmt("%s index " PRINTF_SIZE " already in use", this->name, index);
|
||||
}
|
||||
|
||||
return this->AllocateItem(size, index);
|
||||
return this->AllocateItem(size, index, param);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,15 +190,15 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
|
||||
DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
|
||||
{
|
||||
dbg_assert(index < this->size);
|
||||
dbg_assert(this->data[index] != nullptr);
|
||||
dbg_assert(this->data[index] != Tops::NullValue());
|
||||
if (Tcache) {
|
||||
AllocCache *ac = (AllocCache *)this->data[index];
|
||||
ac->next = this->alloc_cache;
|
||||
this->alloc_cache = ac;
|
||||
} else {
|
||||
free(this->data[index]);
|
||||
free(Tops::GetPtr(this->data[index]));
|
||||
}
|
||||
this->data[index] = nullptr;
|
||||
this->data[index] = Tops::NullValue();
|
||||
ClrBit(this->free_bitmap[index / 64], index % 64);
|
||||
this->first_free = std::min(this->first_free, index);
|
||||
this->items--;
|
||||
@@ -238,8 +238,8 @@ DEFINE_POOL_METHOD(void)::CleanPool()
|
||||
* forcefully instantiated.
|
||||
*/
|
||||
#define INSTANTIATE_POOL_METHODS(name) \
|
||||
template void * name ## Pool::GetNew(size_t size); \
|
||||
template void * name ## Pool::GetNew(size_t size, size_t index); \
|
||||
template void * name ## Pool::GetNew(size_t size, name ## Pool::ParamType param); \
|
||||
template void * name ## Pool::GetNew(size_t size, size_t index, name ## Pool::ParamType param); \
|
||||
template void name ## Pool::FreeItem(size_t index); \
|
||||
template void name ## Pool::CleanPool();
|
||||
|
||||
|
@@ -66,6 +66,19 @@ private:
|
||||
PoolBase(const PoolBase &other);
|
||||
};
|
||||
|
||||
struct DefaultPoolItemParam{};
|
||||
|
||||
template <class Titem>
|
||||
struct DefaultPoolOps {
|
||||
using Tptr = Titem *;
|
||||
using Tparam_type = DefaultPoolItemParam;
|
||||
|
||||
static constexpr Titem *GetPtr(Titem *ptr) { return ptr; }
|
||||
static constexpr Titem *PutPtr(Titem *ptr, DefaultPoolItemParam param) { return ptr; }
|
||||
static constexpr Titem *NullValue() { return nullptr; }
|
||||
static constexpr DefaultPoolItemParam DefaultItemParam() { return {}; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for all pools.
|
||||
* @tparam Titem Type of the class/struct that is going to be pooled
|
||||
@@ -77,8 +90,11 @@ private:
|
||||
* @tparam Tzero Whether to zero the memory
|
||||
* @warning when Tcache is enabled *all* instances of this pool's item must be of the same size.
|
||||
*/
|
||||
template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type = PT_NORMAL, bool Tcache = false, bool Tzero = true>
|
||||
template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type = PT_NORMAL, bool Tcache = false, bool Tzero = true, typename Tops = DefaultPoolOps<Titem> >
|
||||
struct Pool : PoolBase {
|
||||
using ParamType = typename Tops::Tparam_type;
|
||||
using PtrType = typename Tops::Tptr;
|
||||
|
||||
/* Ensure Tmax_size is within the bounds of Tindex. */
|
||||
static_assert((uint64_t)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0);
|
||||
|
||||
@@ -95,12 +111,18 @@ struct Pool : PoolBase {
|
||||
#endif /* WITH_ASSERT */
|
||||
bool cleaning; ///< True if cleaning pool (deleting all items)
|
||||
|
||||
Titem **data; ///< Pointer to array of pointers to Titem
|
||||
PtrType *data; ///< Pointer to array of Tops::Tptr (by default: pointers to Titem)
|
||||
uint64_t *free_bitmap; ///< Pointer to free bitmap
|
||||
|
||||
Pool(const char *name);
|
||||
void CleanPool() override;
|
||||
|
||||
inline PtrType GetRaw(size_t index)
|
||||
{
|
||||
dbg_assert_msg(index < this->first_unused, "index: " PRINTF_SIZE ", first_unused: " PRINTF_SIZE ", name: %s", index, this->first_unused, this->name);
|
||||
return this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Titem with given index
|
||||
* @param index of item to get
|
||||
@@ -109,8 +131,7 @@ struct Pool : PoolBase {
|
||||
*/
|
||||
inline Titem *Get(size_t index)
|
||||
{
|
||||
dbg_assert_msg(index < this->first_unused, "index: " PRINTF_SIZE ", first_unused: " PRINTF_SIZE ", name: %s", index, this->first_unused, this->name);
|
||||
return this->data[index];
|
||||
return Tops::GetPtr(this->GetRaw(index));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +141,7 @@ struct Pool : PoolBase {
|
||||
*/
|
||||
inline bool IsValidID(size_t index)
|
||||
{
|
||||
return index < this->first_unused && this->Get(index) != nullptr;
|
||||
return index < this->first_unused && this->GetRaw(index) != Tops::NullValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,13 +252,25 @@ struct Pool : PoolBase {
|
||||
* Base class for all PoolItems
|
||||
* @tparam Tpool The pool this item is going to be part of
|
||||
*/
|
||||
template <struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero> *Tpool>
|
||||
template <struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero, Tops> *Tpool>
|
||||
struct PoolItem {
|
||||
Tindex index; ///< Index of this pool item
|
||||
|
||||
/** Type of the pool this item is going to be part of */
|
||||
typedef struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero> Pool;
|
||||
typedef struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero, Tops> Pool;
|
||||
|
||||
protected:
|
||||
static inline void *NewWithParam(size_t size, ParamType param)
|
||||
{
|
||||
return Tpool->GetNew(size, param);
|
||||
}
|
||||
|
||||
static inline void *NewWithParam(size_t size, size_t index, ParamType param)
|
||||
{
|
||||
return Tpool->GetNew(size, index, param);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Allocates space for new Titem
|
||||
* @param size size of Titem
|
||||
@@ -246,7 +279,7 @@ struct Pool : PoolBase {
|
||||
*/
|
||||
inline void *operator new(size_t size)
|
||||
{
|
||||
return Tpool->GetNew(size);
|
||||
return NewWithParam(size, Tops::DefaultItemParam());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,7 +305,7 @@ struct Pool : PoolBase {
|
||||
*/
|
||||
inline void *operator new(size_t size, size_t index)
|
||||
{
|
||||
return Tpool->GetNew(size, index);
|
||||
return NewWithParam(size, index, Tops::DefaultItemParam());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,12 +441,12 @@ private:
|
||||
/** Cache of freed pointers */
|
||||
AllocCache *alloc_cache;
|
||||
|
||||
void *AllocateItem(size_t size, size_t index);
|
||||
void *AllocateItem(size_t size, size_t index, ParamType param);
|
||||
void ResizeFor(size_t index);
|
||||
size_t FindFirstFree();
|
||||
|
||||
void *GetNew(size_t size);
|
||||
void *GetNew(size_t size, size_t index);
|
||||
void *GetNew(size_t size, ParamType param);
|
||||
void *GetNew(size_t size, size_t index, ParamType param);
|
||||
|
||||
void FreeItem(size_t index);
|
||||
};
|
||||
|
Reference in New Issue
Block a user