Initial commit: Final state of the master project
This commit is contained in:
223
Research/core/Util/BlockVector.h
Normal file
223
Research/core/Util/BlockVector.h
Normal file
@@ -0,0 +1,223 @@
|
||||
#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());
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user