#ifndef PKE_DYNAMIC_ARRAY_HPP #define PKE_DYNAMIC_ARRAY_HPP #include "pk.h" #include #include #include #include #include #define BAKE_DYN_ARRAY(T) template struct DynArray; struct DynArrayBase { mutable struct pk_membucket *bkt = nullptr; mutable char *ptr = nullptr; int64_t elementSize = 0; int64_t elementCount = 0; int64_t reservedCount = 0; }; template struct DynArray: DynArrayBase { explicit DynArray(struct pk_membucket *bucket = nullptr); explicit DynArray(int64_t reserveCount, struct pk_membucket *bucket = nullptr); DynArray(const DynArray &other); DynArray(DynArray &&other); DynArray &operator=(const DynArray &other); DynArray &operator=(DynArray &&other); ~DynArray(); T &operator[](int64_t index); T *GetPtr(); int64_t Count() const; bool Has(const T &val); template int64_t FindFirstIndex(bool fn(const T&, const T2&), const T2 &val); T& Push(); void Push(const T &val); T Pop(); void Remove(int64_t index, int64_t count = 1); void Reserve(int64_t count); void Resize(int64_t count); protected: using DynArrayBase::bkt; using DynArrayBase::ptr; using DynArrayBase::elementSize; using DynArrayBase::elementCount; using DynArrayBase::reservedCount; }; void DynArrayReserve(DynArrayBase *arr, int64_t count); void DynArrayDestroy(DynArrayBase *arr); template inline DynArray::DynArray(int64_t count, struct pk_membucket *bucket) { this->bkt = bucket; this->elementSize = sizeof(T); if (count > 0) DynArrayReserve(this, count); if IS_CONSTRUCTIBLE(T) { for (long i = 0; i < count; ++i) { new (this->ptr + (i * sizeof(T))) T{}; } } } template inline DynArray::DynArray(struct pk_membucket *bucket) { this->bkt = bucket; this->elementSize = sizeof(T); } template inline DynArray::DynArray(const DynArray &rh) { this->bkt = rh.bkt; this->ptr = rh.ptr; this->elementSize = rh.elementSize; this->elementCount = rh.elementCount; this->reservedCount = rh.reservedCount; rh.ptr = nullptr; } template inline DynArray::DynArray(DynArray &&rh) { this->bkt = rh.bkt; this->ptr = rh.ptr; this->elementSize = rh.elementSize; this->elementCount = rh.elementCount; this->reservedCount = rh.reservedCount; rh.ptr = nullptr; } template inline DynArray &DynArray::operator=(const DynArray &rh) { this->bkt = rh.bkt; this->ptr = rh.ptr; this->elementSize = rh.elementSize; this->elementCount = rh.elementCount; this->reservedCount = rh.reservedCount; rh.ptr = nullptr; return *this; } template inline DynArray &DynArray::operator=(DynArray &&rh) { this->bkt = rh.bkt; this->ptr = rh.ptr; this->elementSize = rh.elementSize; this->elementCount = rh.elementCount; this->reservedCount = rh.reservedCount; rh.ptr = nullptr; return *this; } template inline DynArray::~DynArray() { if (this->ptr == nullptr || this->ptr == CAFE_BABE(char)) return; if IS_DESTRUCTIBLE(T) { for (long i = 0; i < this->elementCount; ++i) { reinterpret_cast(this->ptr + (i * sizeof(T)))->~T(); } } DynArrayDestroy(this); } template inline T &DynArray::operator[](int64_t index) { assert(index < this->elementCount && "Invalid DynArray[] index - out of bounds"); assert(index < this->reservedCount && "Invalid DynArray[] index - out of reserved bounds"); assert(index >= 0 && "Invalid DynArray[] index - unlikely value"); return *reinterpret_cast((this->ptr + (sizeof(T) * index))); } template inline T *DynArray::GetPtr() { return reinterpret_cast(reinterpret_cast(this->ptr)); } template inline int64_t DynArray::Count() const { return this->elementCount; } template inline bool DynArray::Has(const T &val) { for (long i = 0; i < this->elementCount; ++i) { if ((*this)[i] == val) return true; } return false; } template template inline int64_t DynArray::FindFirstIndex(bool Fn(const T&, const T2&), const T2 &val) { for (long i = 0; i < this->elementCount; ++i) { if (Fn((*this)[i], val)) return i; } return -1; } template inline T &DynArray::Push() { if (this->elementCount + 1 > this->reservedCount) { auto safeReserveCount = this->reservedCount < 2 ? 2 : this->reservedCount; DynArrayReserve(this, int64_t(safeReserveCount * 1.5)); } auto itemPtr = this->ptr + (sizeof(T) * this->elementCount); if IS_CONSTRUCTIBLE(T) { new (itemPtr) T{}; } this->elementCount += 1; return *reinterpret_cast(itemPtr); } template inline void DynArray::Push(const T &val) { if (this->elementCount + 1 > this->reservedCount) { auto safeReserveCount = this->reservedCount < 2 ? 2 : this->reservedCount; DynArrayReserve(this, int64_t(safeReserveCount * 1.5)); } auto itemPtr = this->ptr + (sizeof(T) * this->elementCount); auto &targetItem = *reinterpret_cast(itemPtr); if constexpr (std::is_assignable::value) { targetItem = val; } else { memcpy(targetItem, val, sizeof(T)); } this->elementCount += 1; } template inline T DynArray::Pop() { assert(this->elementCount > 0 && "Invalid DynArray::Pop() - Contains no elements"); this->elementCount -= 1; return *reinterpret_cast((this->ptr + (sizeof(T) * this->elementCount))); } template inline void DynArray::Remove(int64_t index, int64_t count) { assert(index <= this->elementCount && "Invalid DynArray::Remove() - Out of bounds"); int64_t moveCount = (this->elementCount - index - count); assert(moveCount >= 0 && "Invalid DynArray::Remove() - Removing too many elements"); assert(moveCount <= this->elementCount - index && "Invalid DynArray::Remove() - Removing too many elements"); if IS_DESTRUCTIBLE(T) { for (long i = 0; i < count; ++i) { reinterpret_cast(this->ptr + ((index + i) * sizeof(T)))->~T(); } } if (moveCount == 0) { this->elementCount = index; return; } T *tmp = pk_new_arr(moveCount, this->bkt); memcpy(tmp, this->ptr + (sizeof(T) * (index + count)), sizeof(T) * moveCount); memcpy(this->ptr + (sizeof(T) * index), tmp, sizeof(T) * moveCount); pk_delete_arr(tmp, moveCount, this->bkt); this->elementCount -= count; } template inline void DynArray::Reserve(int64_t count) { if (count > 0) { return DynArrayReserve(this, count); } } template inline void DynArray::Resize(int64_t count) { int64_t beforeCount = this->elementCount; if IS_DESTRUCTIBLE(T) { if (beforeCount > count) { for (int64_t i = beforeCount - 1; i >= count; --i) { T *ptr = reinterpret_cast(this->ptr + (i * sizeof(T))); ptr->~T(); } } } if (count > 0) { DynArrayReserve(this, count); if IS_CONSTRUCTIBLE(T) { for (long i = beforeCount; i < count; ++i) { new (this->ptr + (i * sizeof(T))) T{}; } } } this->elementCount = count; } #endif /* PKE_DYNAMIC_ARRAY_HPP */