#pragma once #include #include #include #include #include #include /// Base class for hkArray (a std::vector-like container). template class hkArrayBase { public: HK_DECLARE_CLASS_ALLOCATOR(hkArrayBase) enum : unsigned int { CAPACITY_MASK = 0x3FFFFFFF, FLAG_MASK = 0xC0000000, DONT_DEALLOCATE_FLAG = 0x80000000, }; HK_FORCE_INLINE hkArrayBase(); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) explicit hkArrayBase(hkFinishLoadedObjectFlag f) {} HK_FORCE_INLINE hkArrayBase(T* buffer, int size, int capacity); HK_FORCE_INLINE ~hkArrayBase(); hkArrayBase(const hkArrayBase&) = delete; auto operator=(const hkArrayBase&) = delete; HK_FORCE_INLINE int getSize() const; HK_FORCE_INLINE int getCapacity() const; HK_FORCE_INLINE int getCapacityAndFlags() const; HK_FORCE_INLINE hkBool isEmpty() const; HK_FORCE_INLINE T* data() { return m_data; } HK_FORCE_INLINE const T* data() const { return m_data; } HK_FORCE_INLINE T& operator[](int i); HK_FORCE_INLINE const T& operator[](int i) const; HK_FORCE_INLINE T& back(); HK_FORCE_INLINE const T& back() const; HK_FORCE_INLINE void clear(); HK_FORCE_INLINE void _clearAndDeallocate(hkMemoryAllocator& allocator); HK_FORCE_INLINE void removeAt(int index); HK_FORCE_INLINE void removeAtAndCopy(int index); HK_FORCE_INLINE void removeAtAndCopy(int index, int numToRemove); HK_FORCE_INLINE int indexOf(const T& t, int start = 0, int end = -1) const; HK_FORCE_INLINE int lastIndexOf(const T& t) const; HK_FORCE_INLINE void popBack(int numElemsToRemove = 1); HK_FORCE_INLINE void _pushBack(hkMemoryAllocator& alloc, const T& e); HK_FORCE_INLINE void pushBackUnchecked(const T& e); HK_FORCE_INLINE hkBool tryPushBack(const T& t); HK_FORCE_INLINE hkResult _reserve(hkMemoryAllocator& alloc, int n); HK_FORCE_INLINE hkResult _reserveExactly(hkMemoryAllocator& alloc, int n); HK_FORCE_INLINE void _setSize(hkMemoryAllocator& alloc, int size); HK_FORCE_INLINE void _setSize(hkMemoryAllocator& alloc, int n, const T& fill); HK_FORCE_INLINE hkResult _trySetSize(hkMemoryAllocator& alloc, int size); HK_FORCE_INLINE void setSizeUnchecked(int size); HK_FORCE_INLINE T& _expandOne(hkMemoryAllocator& alloc); HK_FORCE_INLINE T* _expandBy(hkMemoryAllocator& alloc, int n); HK_FORCE_INLINE T* expandByUnchecked(int n); HK_FORCE_INLINE T* _expandAt(hkMemoryAllocator& alloc, int index, int numToInsert); void _insertAt(hkMemoryAllocator& alloc, int i, const T* a, int numElems); void _insertAt(hkMemoryAllocator& alloc, int i, const T& t); void _append(hkMemoryAllocator& alloc, const T* a, int numElems); void _spliceInto(hkMemoryAllocator& alloc, int i, int ndel, const T* p, int numElems); HK_FORCE_INLINE void removeAllAndCopy(const T& t); using iterator = T*; using const_iterator = const T*; HK_FORCE_INLINE iterator begin(); HK_FORCE_INLINE iterator end(); HK_FORCE_INLINE const_iterator begin() const; HK_FORCE_INLINE const_iterator end() const; static HK_FORCE_INLINE void copy(T* dst, const T* src, int n); HK_FORCE_INLINE void setDataAutoFree(T* ptr, int size, int capacity); HK_FORCE_INLINE void setDataUserFree(T* ptr, int size, int capacity); HK_FORCE_INLINE void _setDataUnchecked(T* ptr, int size, int capacityAndFlags); HK_FORCE_INLINE void _optimizeCapacity(hkMemoryAllocator& alloc, int numFreeElemsLeft, hkBool32 shrinkExact = false); protected: HK_FORCE_INLINE hkArrayBase& copyFromArray(hkMemoryAllocator& allocator, const hkArrayBase& src); T* m_data; int m_size; int m_capacityAndFlags; }; /// A dynamically resizable array, similar to std::vector. // FIXME: incomplete template class hkArray : public hkArrayBase { public: using AllocatorType = Allocator; HK_FORCE_INLINE hkArray() = default; HK_FORCE_INLINE hkArray(T* buffer, int size, int capacity) : hkArrayBase(buffer, size, capacity) {} explicit hkArray(hkFinishLoadedObjectFlag f) : hkArrayBase(f) {} HK_FORCE_INLINE ~hkArray() { clearAndDeallocate(); } HK_FORCE_INLINE hkArray& operator=(const hkArrayBase& other); HK_FORCE_INLINE hkArray& operator=(const hkArray& other); HK_FORCE_INLINE void clearAndDeallocate(); HK_FORCE_INLINE void pushBack(const T& e); HK_FORCE_INLINE hkResult reserve(int size); HK_FORCE_INLINE hkResult reserveExactly(int size); HK_FORCE_INLINE void setSize(int size); HK_FORCE_INLINE void setSize(int size, const T& fill); protected: HK_FORCE_INLINE hkArray(const hkArray& other); }; template class hkInplaceArray : public hkArray { public: HK_DECLARE_CLASS_ALLOCATOR(hkInplaceArray) HK_FORCE_INLINE explicit hkInplaceArray(int size = 0); HK_FORCE_INLINE hkInplaceArray(const hkInplaceArray& other); explicit hkInplaceArray(hkFinishLoadedObjectFlag f) : hkArray(f) {} HK_FORCE_INLINE ~hkInplaceArray() = default; using hkArray::operator=; HK_FORCE_INLINE void optimizeCapacity(int numFreeElemsLeft, hkBool32 shrinkExact = false); HK_FORCE_INLINE hkBool wasReallocated() const; HK_FORCE_INLINE int stillInplaceUsingMask() const; T m_storage[N]; }; template inline hkArrayBase::hkArrayBase() : m_data(nullptr), m_size(0), m_capacityAndFlags(DONT_DEALLOCATE_FLAG) {} template inline hkArrayBase::hkArrayBase(T* buffer, int size, int capacity) : m_data(buffer), m_size(size), m_capacityAndFlags(capacity | DONT_DEALLOCATE_FLAG) {} template inline hkArrayBase::~hkArrayBase() = default; template inline int hkArrayBase::getSize() const { return m_size; } template inline int hkArrayBase::getCapacity() const { return m_capacityAndFlags & static_cast(CAPACITY_MASK); } template inline int hkArrayBase::getCapacityAndFlags() const { return m_capacityAndFlags; } template inline hkBool hkArrayBase::isEmpty() const { return m_size == 0; } template inline T& hkArrayBase::operator[](int i) { return m_data[i]; } template inline const T& hkArrayBase::operator[](int i) const { return m_data[i]; } template inline T& hkArrayBase::back() { return m_data[m_size - 1]; } template inline const T& hkArrayBase::back() const { return m_data[m_size - 1]; } template inline void hkArrayBase::clear() { hkArrayUtil::destruct(m_data, m_size); m_size = 0; } template inline void hkArrayBase::_clearAndDeallocate(hkMemoryAllocator& allocator) { clear(); if ((m_capacityAndFlags & DONT_DEALLOCATE_FLAG) == 0) { const int SIZE_ELEM = hkSizeOfTypeOrVoid::val; int numBytes = getCapacity() * SIZE_ELEM; void* storage = const_cast*>(m_data); allocator.bufFree(storage, numBytes); } m_data = nullptr; m_capacityAndFlags = DONT_DEALLOCATE_FLAG; } template inline void hkArrayBase::removeAt(int index) { hkArrayUtil::destruct(&m_data[index], 1); m_size--; if (m_size != index) hkMemUtil::memCpyOneAligned(m_data + index, m_data + m_size); } template inline void hkArrayBase::removeAtAndCopy(int index) { removeAtAndCopy(index, 1); } template inline void hkArrayBase::removeAtAndCopy(int index, int numToRemove) { hkArrayUtil::destruct(m_data + index, numToRemove); m_size -= numToRemove; hkMemUtil::memCpy(m_data + index, m_data + index + numToRemove, (m_size - index) * sizeof(T)); } template inline int hkArrayBase::indexOf(const T& t, int start, int end) const { if (end < 0) end = m_size; for (int i = start; i < end; ++i) { if (m_data[i] == t) return i; } return -1; } template inline void hkArrayBase::popBack(int numElemsToRemove) { hkArrayUtil::destruct(m_data + m_size - numElemsToRemove, numElemsToRemove); m_size -= numElemsToRemove; } template inline void hkArrayBase::_pushBack(hkMemoryAllocator& alloc, const T& e) { if (m_size == getCapacity()) { hkArrayUtil::_reserveMore(alloc, this, sizeof(T)); } pushBackUnchecked(e); } template inline void hkArrayBase::pushBackUnchecked(const T& e) { hkArrayUtil::constructWithCopy(m_data + m_size, 1, e); m_size++; } template inline hkBool hkArrayBase::tryPushBack(const T& t) { if (m_size < getCapacity()) { hkArrayUtil::constructWithCopy(m_data + m_size, 1, t); m_size++; return true; } return false; } template inline hkResult hkArrayBase::_reserve(hkMemoryAllocator& alloc, int n) { const int capacity = getCapacity(); if (capacity < n) { int newCapacity = 2 * capacity; int newSize = n < newCapacity ? newCapacity : n; return hkArrayUtil::_reserve(alloc, this, newSize, sizeof(T)); } return HK_SUCCESS; } template inline hkResult hkArrayBase::_reserveExactly(hkMemoryAllocator& alloc, int n) { if (getCapacity() < n) return hkArrayUtil::_reserve(alloc, this, n, sizeof(T)); return HK_SUCCESS; } template inline void hkArrayBase::_setSize(hkMemoryAllocator& alloc, int n) { _reserve(alloc, n); hkArrayUtil::destruct(m_data + n, m_size - n); hkArrayUtil::construct(m_data + m_size, n - m_size); m_size = n; } template inline void hkArrayBase::_setSize(hkMemoryAllocator& alloc, int n, const T& fill) { _reserve(alloc, n); hkArrayUtil::destruct(m_data + n, m_size - n); hkArrayUtil::constructWithCopy(m_data + m_size, n - m_size, fill); m_size = n; } template inline typename hkArrayBase::iterator hkArrayBase::begin() { return m_data; } template inline typename hkArrayBase::iterator hkArrayBase::end() { return m_data + m_size; } template inline typename hkArrayBase::const_iterator hkArrayBase::begin() const { return m_data; } template inline typename hkArrayBase::const_iterator hkArrayBase::end() const { return m_data + m_size; } template inline void hkArrayBase::copy(T* dst, const T* src, int n) { for (int i = 0; i < n; ++i) { dst[i] = src[i]; } } template inline void hkArrayBase::_setDataUnchecked(T* ptr, int size, int capacityAndFlags) { m_data = ptr; m_size = size; m_capacityAndFlags = capacityAndFlags; } template inline void hkArrayBase::setDataAutoFree(T* ptr, int size, int capacity) { static_assert(std::is_pod_v, "T must be a POD type"); _setDataUnchecked(ptr, size, capacity); } template inline void hkArrayBase::setDataUserFree(T* ptr, int size, int capacity) { static_assert(std::is_pod_v, "T must be a POD type"); _setDataUnchecked(ptr, size, capacity | DONT_DEALLOCATE_FLAG); } template inline hkArrayBase& hkArrayBase::copyFromArray(hkMemoryAllocator& allocator, const hkArrayBase& src) { if constexpr (std::is_pod_v) { if (getCapacity() < src.getSize()) { if ((m_capacityAndFlags & DONT_DEALLOCATE_FLAG) == 0) { allocator._bufFree(m_data, getCapacity()); } int n = src.getSize(); m_data = allocator._bufAlloc(n); m_capacityAndFlags = n; } m_size = src.getSize(); copy(m_data, src.m_data, m_size); } else { const int oldSize = m_size; const int newSize = src.getSize(); const int copiedSize = newSize > oldSize ? oldSize : newSize; _reserve(allocator, newSize); hkArrayUtil::destruct(m_data + newSize, oldSize - newSize); copy(m_data, src.m_data, copiedSize); hkArrayUtil::constructWithArray(m_data + copiedSize, newSize - copiedSize, src.m_data + copiedSize); m_size = newSize; } return *this; } template inline hkArray& hkArray::operator=(const hkArrayBase& a) { this->copyFromArray(Allocator().get(), a); return *this; } template inline hkArray& hkArray::operator=(const hkArray& a) { this->copyFromArray(Allocator().get(), a); return *this; } template inline void hkArray::clearAndDeallocate() { this->_clearAndDeallocate(AllocatorType().get()); } template inline void hkArray::pushBack(const T& e) { this->_pushBack(AllocatorType().get(), e); } template inline void hkArray::setSize(int size) { this->_setSize(AllocatorType().get(), size); } template inline void hkArray::setSize(int size, const T& fill) { this->_setSize(AllocatorType().get(), size, fill); } template inline hkResult hkArray::reserve(int size) { return this->_reserve(AllocatorType().get(), size); } template inline hkResult hkArray::reserveExactly(int size) { return this->_reserveExactly(AllocatorType().get(), size); } template inline hkInplaceArray::hkInplaceArray(int size) : hkArray(m_storage, size, N) {} template inline hkInplaceArray::hkInplaceArray(const hkInplaceArray& other) : hkArray(m_storage, 0, N) { *this = other; } template inline hkBool hkInplaceArray::wasReallocated() const { return this->m_data != m_storage; } template inline int hkInplaceArray::stillInplaceUsingMask() const { return hkArray::m_capacityAndFlags & hkArrayBase::DONT_DEALLOCATE_FLAG; }