Files
CDAG/Research/core/Util/ObjectPool.h

131 lines
3.3 KiB
C++

#pragma once
#include <vector>
#include <stack>
#include <algorithm>
#include "../../inc/tbb/parallel_sort.h"
#include "BoolArray.h"
#include "BlockVector.h"
#include "../CollectionHelper.h"
#define USE_BLOCK_VECTOR
// Class for memory efficiency: stores all objects of some type in a vector. Pointers to the object can then be requested.
template<typename T>
class ObjectPool
{
private:
#ifdef USE_BLOCK_VECTOR
BlockVector<T> mData;
#else
std::vector<T> mData;
#endif
BoolArray mMarkedForDeletion;
const size_t mBaseCapacity = 0;
bool AnyMarkedForDeletion() const { return !mMarkedForDeletion.Empty(); }
bool MarkedForDeletion(size_t index) const { return index < mMarkedForDeletion.Size() && mMarkedForDeletion[index]; }
void MarkForDeletion(size_t index)
{
if (index >= mMarkedForDeletion.Size())
mMarkedForDeletion.Resize(index + 1);
mMarkedForDeletion.Set(index, true);
}
public:
ObjectPool(size_t initialCapacity = 1) :
#ifdef USE_BLOCK_VECTOR
mData(BlockVector<T>(initialCapacity)),
#else
mData(std::vector<T>()),
#endif
mMarkedForDeletion(BoolArray()),
mBaseCapacity(initialCapacity)
{
#ifndef USE_BLOCK_VECTOR
mData.reserve(initialCapacity);
#endif
}
// Adds a new item to the pool.
template <class... Args>
T* Create(Args&&... args)
{
//// If any nodes are marked for deletion, reuse their position
//if (!mMarkedForDeletion.empty())
//{
// T* res = &mData[mMarkedForDeletion.top()];
// mMarkedForDeletion.pop();
// return res;
//}
//else // Else, resize the data array to create some space for this new node
//{
mData.emplace_back(std::forward<Args>(args)...);
return &mData[mData.size() - 1];
//}
}
// Moves the node from the given memory position into this pool. Returns the new pointer to this node
T* Add(T* value)
{
mData.emplace_back(std::move(*value));
return &mData[mData.size() - 1];
}
void Delete(size_t i) { MarkForDeletion(i); }
// Removes all nodes that are marked for deletion.
void Clean()
{
// There is only stuff to clean if there are nodes marked for deletion
if (!AnyMarkedForDeletion()) return;
size_t newIdx = 0;
for (size_t oldIdx = 0; oldIdx < mData.size(); oldIdx++)
// If this node should not be deleted, move it to the new position.
if (!MarkedForDeletion(oldIdx))
{
if (oldIdx != newIdx)
mData[newIdx] = std::move(mData[oldIdx]);
//std::swap(mData[newIdx], mData[oldIdx]);
newIdx++;
}
#ifdef USE_BLOCK_VECTOR
mData.shrink(newIdx);
mData.reserve(mBaseCapacity);
#else
mData.erase(mData.begin() + newIdx, mData.end());
mData.shrink_to_fit();
mData.reserve(mBaseCapacity);
#endif
mMarkedForDeletion = BoolArray();
}
void Clear()
{
mData.clear();
mMarkedForDeletion.Clear();
}
template<typename Comparer = std::less<T>>
void Sort(size_t startIdx, size_t endIdx, const Comparer& comparer = Comparer())
{
// Check if any node are deleted in the range that needs to be sorted:
if (AnyMarkedForDeletion() && mMarkedForDeletion.Any(startIdx, endIdx))
Clean();
tbb::parallel_sort(mData.begin() + startIdx, mData.begin() + endIdx, comparer);
}
inline size_t Size() const { return mData.size(); }
inline const T* operator[](size_t i) const
{
if (MarkedForDeletion(i)) return NULL;
return &mData.at(i);
}
inline T* operator[](size_t i)
{
if (MarkedForDeletion(i)) return NULL;
return &mData.at(i);
}
};