#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 /***/> struct TVector { struct TDestructed_deallocate_ { TDestructed_deallocate_(JGadget::TAllocator& 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& 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 > { TVector_pointer_void(const JGadget::TAllocator& allocator); TVector_pointer_void(u32, void* const&, const JGadget::TAllocator& 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 struct TVector_pointer : public TVector_pointer_void { TVector_pointer(const TAllocator& 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 > 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