#pragma once #include #include #include "IndexIterator.h" //#include "../BitHelper.h" template class BlockVector { public: const static unsigned64 BLOCK_SIZE = 1 << BLOCK_POINTER_BITS; const static size_t BLOCK_SIZE_MASK = BLOCK_SIZE - 1; protected: typedef std::vector block; std::vector mData; size_t mSize; inline size_t block_count(size_t n) const { return (n >> BLOCK_POINTER_BITS) + ((n % BLOCK_SIZE == 0) ? 0 : 1); } inline size_t block_index(size_t i) const { return i >> BLOCK_POINTER_BITS; } inline size_t item_index(size_t i) const { return i & BLOCK_SIZE_MASK; } void shrink_blocks(size_t newBlockCount) { // If the size is smaller, delete blocks that are no longer needed. for (size_t i = newBlockCount; i < mData.size(); i++) delete mData[i]; } void init_blocks(size_t oldSize = 0) { for (size_t i = oldSize; i < mData.size(); i++) mData[i] = new block(BLOCK_SIZE); } void init_blocks(const T& value, size_t oldSize) { for (size_t i = oldSize; i < mData.size(); i++) mData[i] = new block(BLOCK_SIZE, value); } public: typedef IndexIterator, const T> const_iterator; typedef IndexIterator, T> iterator; typedef std::reverse_iterator const_reverse_iterator; typedef std::reverse_iterator reverse_iterator; BlockVector() : mData(std::vector*>()), mSize(0) {} BlockVector(size_t capacity) : mData(std::vector()), mSize(0) { reserve(capacity); } BlockVector(const BlockVector& r) { mData = std::vector(r.mData.size()); init(0); for (size_t block = 0; block < r.mData.size(); block++) std::copy(r.mData[block]->begin(), r.mData[block]->end(), mData[block]->begin()); mSize = r.mSize; } BlockVector(BlockVector&& r) { mData = std::move(r.mData); r.mData.clear(); mSize = std::move(r.mSize); r.mSize = 0; } virtual ~BlockVector() { for (block* arr : mData) { arr->clear(); delete arr; } mData.clear(); } // Capacity size_t size() const { return mSize; } size_t max_size() const { return mData.max_size() * mSize; } void reserve(size_t n) { size_t newBlockCount = block_count(n); if (mData.size() >= newBlockCount) return; // big enough size_t oldSize = mData.size(); mData.resize(newBlockCount); for (size_t i = oldSize; i < mData.size(); i++) { mData[i] = new block(); mData[i]->reserve(BLOCK_SIZE); } } // Shrinks the vector so it contains n entries. void shrink(size_t n) { size_t newBlockCount = block_count(n); shrink_blocks(newBlockCount); mData.resize(newBlockCount); mSize = n; } void resize(size_t n) { size_t oldBlockCount = mData.size(); size_t newBlockCount = block_count(n); shrink_blocks(newBlockCount); mData.resize(newBlockCount, NULL); init_blocks(oldBlockCount); mSize = n; } void resize(size_t n, const T& val) { size_t oldBlockCount = mData.size(); size_t newBlockCount = block_count(n); shrink_blocks(newBlockCount); mData.resize(newBlockCount, NULL); init_blocks(val, oldBlockCount); mSize = n; } inline size_t capacity() const { return mData.size() * BLOCK_SIZE; } inline bool empty() const { return mData.empty(); } void shrink_to_fit() { resize(mSize); } // Element access const T& at(size_t i) const { assert(i < mSize); return mData[block_index(i)]->at(item_index(i)); } T& at(size_t i) { assert(i < mSize); return mData[block_index(i)]->at(item_index(i)); } const T& operator[](size_t i) const { return at(i); } T& operator[](size_t i) { return at(i); } const T& front() const { return at(0); } T& front() { return at(0); } const T& back() const { return at(mSize - 1); } T& back() { return at(mSize - 1); } // Modifiers void push_back(const T& val) { // Increase the size if it doesn't fit if (block_index(mSize) >= mData.size()) reserve(mSize + 1); // Put the item in the last position block* b = mData[block_index(mSize)]; size_t itemIndex = item_index(mSize); if (b->size() == itemIndex) b->push_back(val); else mData->at(itemIndex) = val; mSize++; } void push_back(T&& val) { // Increase the size if it doesn't fit if (block_index(mSize) >= mData.size()) reserve(mSize + 1); // Put the item in the last position block* b = mData[block_index(mSize)]; size_t itemIndex = item_index(mSize); if (b->size() == itemIndex) b->push_back(val); else b->at(itemIndex) = val; mSize++; } template void emplace_back(Args&&... args) { size_t blockIndex = block_index(mSize); if (blockIndex >= mData.size()) reserve(mSize + 1); block* b = mData[blockIndex]; size_t itemIndex = item_index(mSize); if (b->size() == itemIndex) b->emplace_back(std::forward(args)...); else b->at(itemIndex) = T(std::forward(args)...); mSize++; } void pop_back() { mSize--; } void clear() { for (block* block : mData) delete block; mData.clear(); mSize = 0; } // Iterators const_iterator begin() const { return const_iterator(this, 0); } const_iterator end() const { return const_iterator(this, mSize); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } iterator begin() { return iterator(this, 0); } iterator end() { return iterator(this, mSize); } reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } };