mirror of
https://github.com/zeldaret/tww.git
synced 2026-05-23 23:05:11 -04:00
291 lines
8.6 KiB
C++
291 lines
8.6 KiB
C++
#ifndef _JSYSTEM_JGADGET_VECTOR_H
|
|
#define _JSYSTEM_JGADGET_VECTOR_H
|
|
|
|
#include "JSystem/JGadget/allocator.h"
|
|
#include "algorithm.h"
|
|
#include "msl_memory.h"
|
|
|
|
namespace JGadget {
|
|
namespace vector {
|
|
u32 extend_default(u32, u32, u32);
|
|
|
|
typedef u32 (*ExtendFunc)(u32, u32, u32);
|
|
|
|
} // namespace vector
|
|
|
|
template <typename T, class Allocator = JGadget::TAllocator<T> /***/>
|
|
struct TVector {
|
|
struct TDestructed_deallocate_ {
|
|
TDestructed_deallocate_(JGadget::TAllocator<T>& alloc, T* pointer)
|
|
{
|
|
mAllocator = &alloc;
|
|
mPointer = pointer;
|
|
}
|
|
|
|
~TDestructed_deallocate_() { mAllocator->deallocate(mPointer, 0); }
|
|
|
|
void set(T* p) { mPointer = p; }
|
|
|
|
Allocator* mAllocator;
|
|
T* mPointer;
|
|
};
|
|
|
|
~TVector() {
|
|
Confirm();
|
|
clear();
|
|
delete mBegin;
|
|
}
|
|
|
|
void insert(T* position, u32 count, T const& value)
|
|
{
|
|
if (!count) {
|
|
return;
|
|
}
|
|
|
|
void** v = Insert_raw(position, count); // insert `count` values before element at `position`
|
|
|
|
if (v != this->mEnd) {
|
|
for (int i = 0; i != count; i++) {
|
|
if (v) {
|
|
*v = value;
|
|
}
|
|
v++;
|
|
}
|
|
}
|
|
}
|
|
|
|
T* Insert_raw(T* position, u32 count)
|
|
{
|
|
// purpose: to make space for `count` many elements at the supplied location
|
|
// returns: pointer to location for new items
|
|
|
|
T* const pFirst = position;
|
|
|
|
// JUT_DEBUG_ASSERT((mBegin<=pItFirst_)&&(pItFirst_<=mEnd), 0x1be);
|
|
|
|
// it's assumed the pointer is to something already in the vector, or pointing to the end
|
|
|
|
if (count == 0) {
|
|
return position;
|
|
}
|
|
|
|
// can we fit in the space already allocated?
|
|
if (count + size() <= mCapacity) {
|
|
|
|
// get the theoretical new end
|
|
void** newEnd = pFirst + count;
|
|
|
|
// if there exists items in the current vector past where we will insert these items
|
|
// then we need to move them to be at the end of the vector
|
|
if (newEnd < mEnd) {
|
|
|
|
// get a pointer to the `count` many values that need to be pushed to the end
|
|
void** pOverwrittenValues = mEnd - count;
|
|
|
|
// copy `count` many values to the end of the vector
|
|
std::uninitialized_copy(pOverwrittenValues, mEnd, mEnd);
|
|
|
|
// copy the remaining values that need to be shifted
|
|
// copying backwards so we don't move a value into the range we're copying from, erasing data
|
|
std::copy_backward(pFirst, pOverwrittenValues, mEnd);
|
|
|
|
// destroy everything from pFirst -> newEnd, this treats the inserted items as "uninitialized"
|
|
DestroyElement_(pFirst, newEnd);
|
|
|
|
// increment count
|
|
mEnd += count;
|
|
|
|
// return pointer to new items
|
|
return position;
|
|
} else {
|
|
// position + count >= mEnd
|
|
// else our values that we want to add will write beyond the current mEnd
|
|
|
|
// copy the values that exist at our pointer to the newEnd, which is position + count, making room for our `count` many
|
|
// items
|
|
std::uninitialized_copy(pFirst, mEnd, newEnd);
|
|
|
|
// uninitialize the values that used to be there
|
|
DestroyElement_(pFirst, mEnd);
|
|
|
|
// increment count
|
|
mEnd += count;
|
|
|
|
// return pointer to new items
|
|
return position;
|
|
}
|
|
}
|
|
|
|
// count + size() > mCapacity
|
|
// we need more space
|
|
|
|
// figure out how much space we'll need
|
|
u32 newSize = GetSize_extend_(count);
|
|
|
|
// allocate that space
|
|
void** newDataPointer = mAllocator.allocate(newSize, 0);
|
|
|
|
// make sure that data was actually allocated
|
|
if (!newDataPointer) {
|
|
// return end pointer so we know not to actually assign any values
|
|
return end();
|
|
}
|
|
|
|
// this struct will deallocate the specified data pointer when destroyed
|
|
// If we end up throwing an exception, it'll deallocate our new data pointer, no leaks!
|
|
TDestructed_deallocate_ destructionDeallocator(mAllocator, newDataPointer);
|
|
|
|
// copy all the beginning of our data up to our pointer to the new data
|
|
void** const endOfCopy = std::uninitialized_copy(mBegin, pFirst, newDataPointer);
|
|
|
|
// copy the rest of the data to fit at the end of our new data
|
|
// this leaves a gap of `count` many items in our new data
|
|
std::uninitialized_copy(pFirst, mEnd, endOfCopy + count);
|
|
|
|
// destroy all our current elements, the other elements should be living in the new data
|
|
// and we're about to deallocate our
|
|
DestroyElement_all_();
|
|
|
|
// everything should be set, so now we can deallocate our old data pointer
|
|
// when this func exits
|
|
destructionDeallocator.set(mBegin);
|
|
|
|
// set our new vector member variables
|
|
mEnd = newDataPointer + (mEnd - mBegin + count);
|
|
mBegin = newDataPointer;
|
|
mCapacity = newSize;
|
|
|
|
// return where the gap of `count` many items lives
|
|
return endOfCopy;
|
|
}
|
|
|
|
void** insert(T* position, const T& value)
|
|
{
|
|
u32 posOffset = position - mBegin;
|
|
// insert one value of `value` at `position`
|
|
insert(position, 1, value);
|
|
return mBegin + posOffset; // return pointer to new value at position
|
|
}
|
|
|
|
void assign(u32, const T&);
|
|
void resize(u32, const T&);
|
|
void Resize_raw(u32);
|
|
void operator=(const TVector<T>& rhs);
|
|
|
|
size_t GetSize_extend_(size_t count) const
|
|
{
|
|
u32 oldSize = size();
|
|
u32 neededNewSpace = oldSize + count;
|
|
u32 extendedSize = mExtend(capacity(), oldSize, count);
|
|
|
|
return neededNewSpace > extendedSize ? neededNewSpace : extendedSize;
|
|
}
|
|
|
|
T* begin() { return mBegin; }
|
|
T* const begin() const { return mBegin; }
|
|
T* end() { return mEnd; }
|
|
T* const end() const { return mEnd; }
|
|
|
|
size_t capacity() const { return mCapacity; }
|
|
|
|
inline size_t size() const
|
|
{
|
|
if (begin() == NULL) {
|
|
return 0;
|
|
}
|
|
return ((int)mEnd - (int)mBegin) / 4;
|
|
}
|
|
|
|
void DestroyElement_(T* pFirst, T* pLast)
|
|
{
|
|
void** iter = pFirst;
|
|
while (iter != pLast) {
|
|
mAllocator.destroy(iter);
|
|
++iter;
|
|
}
|
|
}
|
|
void DestroyElement_all_() { DestroyElement_(mBegin, mEnd); }
|
|
|
|
void Confirm() const {}
|
|
|
|
void clear() {
|
|
erase(begin(), end());
|
|
}
|
|
T* erase(T* start, T* end) {
|
|
T* ppvVar3 = std::copy(end, TVector::end(), start);
|
|
DestroyElement_(ppvVar3, mEnd);
|
|
mEnd = ppvVar3;
|
|
return start;
|
|
}
|
|
|
|
/* 0x00 */ Allocator mAllocator;
|
|
/* 0x04 */ T* mBegin;
|
|
/* 0x08 */ T* mEnd;
|
|
/* 0x0C */ size_t mCapacity;
|
|
/* 0x10 */ vector::ExtendFunc mExtend;
|
|
};
|
|
|
|
// clang-format off
|
|
struct TVector_pointer_void : public TVector<void*, TAllocator<void*> > {
|
|
TVector_pointer_void(const JGadget::TAllocator<void*>& allocator);
|
|
TVector_pointer_void(u32, void* const&, const JGadget::TAllocator<void*>& allocator); // unused/inlined
|
|
|
|
~TVector_pointer_void();
|
|
|
|
void** erase(void**, void**);
|
|
void** insert(void**, void* const&);
|
|
|
|
void clear() { erase(begin(), end()); }
|
|
void push_back(const void*& value) { insert(end(), (void* const&)value); }
|
|
|
|
/* 0x00 */ /* TVector */
|
|
};
|
|
// clang-format on
|
|
|
|
template <typename T>
|
|
struct TVector_pointer : public TVector_pointer_void {
|
|
TVector_pointer(const TAllocator<void*>& allocator)
|
|
: TVector_pointer_void(allocator)
|
|
{
|
|
}
|
|
|
|
~TVector_pointer() { }
|
|
|
|
const T* begin() const { return (const T*)TVector_pointer_void::begin(); }
|
|
T* begin() { return (T*)TVector_pointer_void::begin(); }
|
|
|
|
const T* end() const { return (const T*)TVector_pointer_void::end(); }
|
|
T* end() { return (T*)TVector_pointer_void::end(); }
|
|
|
|
void push_back(const T& value) { TVector_pointer_void::push_back((const void*&)value); }
|
|
|
|
/* 0x00 */ /* TVector_pointer_void */
|
|
};
|
|
|
|
// clang-format off
|
|
typedef JGadget::TVector<void*, JGadget::TAllocator<void*> > TVPVBase;
|
|
// clang-format on
|
|
|
|
// template <>
|
|
// void TVPVBase::insert(void** values, u32 count, void* const& defaultValue)
|
|
// {
|
|
// if (!count) {
|
|
// return;
|
|
// }
|
|
|
|
// void** v = Insert_raw(values, count);
|
|
|
|
// if (v != this->mEnd) {
|
|
// for (int i = 0; i != count; i++) {
|
|
// if (v) {
|
|
// *v = defaultValue;
|
|
// }
|
|
// v++;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
} // namespace JGadget
|
|
|
|
#endif
|