223 lines
5.5 KiB
C++
223 lines
5.5 KiB
C++
#pragma once
|
|
#include <vector>
|
|
#include <array>
|
|
#include "IndexIterator.h"
|
|
//#include "../BitHelper.h"
|
|
|
|
template <typename T, unsigned8 BLOCK_POINTER_BITS = 14>
|
|
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<T> block;
|
|
std::vector<block*> 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 BlockVector<T>, const T> const_iterator;
|
|
typedef IndexIterator<BlockVector<T>, T> iterator;
|
|
|
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
|
|
BlockVector() : mData(std::vector<std::array<T, BLOCK_SIZE>*>()), mSize(0) {}
|
|
BlockVector(size_t capacity) :
|
|
mData(std::vector<block*>()),
|
|
mSize(0)
|
|
{
|
|
reserve(capacity);
|
|
}
|
|
BlockVector(const BlockVector& r)
|
|
{
|
|
mData = std::vector<block*>(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 <class... Args>
|
|
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>(args)...);
|
|
else b->at(itemIndex) = T(std::forward<Args>(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());
|
|
}
|
|
|
|
}; |