2016-05-17 03:04:11 +12:00
|
|
|
#pragma once
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#ifndef TCG_POOL_H
|
|
|
|
#define TCG_POOL_H
|
|
|
|
|
|
|
|
// STD includes
|
|
|
|
#include "assert.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// Discriminate rvalues support - either use Boost's config.hpp for automatic
|
|
|
|
// lookup,
|
2016-03-19 06:57:51 +13:00
|
|
|
// or deal with it manually
|
|
|
|
|
|
|
|
#ifndef TCG_RVALUES_SUPPORT
|
|
|
|
#include <boost/config.hpp>
|
|
|
|
|
|
|
|
#ifdef BOOST_NO_RVALUE_REFERENCES
|
|
|
|
#define TCG_RVALUES_SUPPORT 0
|
|
|
|
#else
|
|
|
|
#define TCG_RVALUES_SUPPORT 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\file pool.h
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
\brief This file contains an implementation of the \a pool container
|
|
|
|
concept.
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
\details A pool is a container that supports two fundamental operations,
|
|
|
|
acquire() and
|
|
|
|
release(), whose purpose is that of marking access operations to a
|
|
|
|
resource
|
2016-03-19 06:57:51 +13:00
|
|
|
that <I>should not be destroyed</I> when the access operation ends.
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
Creation and destruction of resources can be a time-consuming task
|
|
|
|
that could
|
|
|
|
be avoided when it is known that resources could be reused - which
|
|
|
|
is the very
|
2016-03-19 06:57:51 +13:00
|
|
|
reason why caching can be a useful approach to some problems.
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
The classical cache concept is nothing more than that of a standard
|
|
|
|
associative
|
2021-07-08 13:39:28 +12:00
|
|
|
map, tweaked to accommodate specific commodities - such as managing
|
2016-06-15 18:43:10 +12:00
|
|
|
the cache
|
2016-03-19 06:57:51 +13:00
|
|
|
size.
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
However, sometimes resources could be considered to be effectively
|
2021-07-08 13:39:28 +12:00
|
|
|
identical,
|
2016-06-15 18:43:10 +12:00
|
|
|
to the point that assigning a key is merely a way to keep the
|
|
|
|
objects
|
|
|
|
distinct in the cache. Users are in the condition to require only
|
|
|
|
two functions,
|
2016-03-19 06:57:51 +13:00
|
|
|
one to acquire() a resource, the other to release() it.
|
|
|
|
|
|
|
|
The Pool concept we are introducing satisfies the following ruleset:
|
|
|
|
|
|
|
|
<UL>
|
2016-06-15 18:43:10 +12:00
|
|
|
<LI> The pool is a dynamical container which allocates resources by
|
|
|
|
invoking the
|
2016-03-19 06:57:51 +13:00
|
|
|
objects' default constructor. </LI>
|
2016-06-15 18:43:10 +12:00
|
|
|
<LI> Objects in the pool are \b not destructed, except when the pool
|
|
|
|
is explicitly
|
2016-03-19 06:57:51 +13:00
|
|
|
\a squeezed by the user.</LI>
|
2016-06-15 18:43:10 +12:00
|
|
|
<LI> Keys are indices, returned by the pool with an incremental
|
|
|
|
ordering. </LI>
|
|
|
|
<LI> An object which has been acquired cannot be acquired again
|
|
|
|
until it has been
|
2016-03-19 06:57:51 +13:00
|
|
|
released </LI>
|
|
|
|
</UL>
|
|
|
|
*/
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
namespace tcg {
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//****************************************************************************
|
|
|
|
// TCG Indices Pool class
|
|
|
|
//****************************************************************************
|
|
|
|
|
|
|
|
template <typename T = size_t, typename Cont = std::vector<T>>
|
2016-06-15 18:43:10 +12:00
|
|
|
class indices_pool {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
typedef T value_type;
|
|
|
|
typedef Cont container_type;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
T m_start; //!< First index to be acquired
|
|
|
|
T m_size; //!< Current indices count
|
|
|
|
Cont m_releasedIndices; //!< Priority queue of released indices
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
indices_pool(value_type start = 0) : m_start(start), m_size(0) {}
|
|
|
|
~indices_pool() {}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
template <typename iter>
|
|
|
|
indices_pool(value_type size, iter releasedBegin, iter releasedEnd,
|
|
|
|
value_type start = 0)
|
|
|
|
: m_start(start)
|
|
|
|
, m_size(size)
|
|
|
|
, m_releasedIndices(releasedBegin, releasedEnd) {
|
|
|
|
std::make_heap(m_releasedIndices.begin(), m_releasedIndices.end(),
|
|
|
|
std::greater<T>());
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
template <typename iter>
|
|
|
|
indices_pool(iter acquiredBegin, iter acquiredEnd, value_type start = 0)
|
|
|
|
: m_start(start) {
|
|
|
|
if (acquiredBegin == acquiredEnd)
|
|
|
|
m_size = 0;
|
|
|
|
else {
|
|
|
|
// Sort the acquired indices
|
|
|
|
std::vector<T> acquired(acquiredBegin, acquiredEnd);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
std::sort(acquired.begin(), acquired.end());
|
|
|
|
assert(acquired.front() >= m_start);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// Scan them, adding holes in the acquired sequence to released indices
|
|
|
|
m_size = acquired.back() - m_start + 1;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(m_size >= (T)acquired.size());
|
|
|
|
m_releasedIndices.reserve(m_size - acquired.size());
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
T curIdx = m_start;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
typename std::vector<T>::iterator at, aEnd(acquired.end());
|
|
|
|
for (at = acquired.begin(); at != aEnd; ++at, ++curIdx)
|
|
|
|
for (; curIdx != *at; ++curIdx) m_releasedIndices.push_back(curIdx);
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
std::make_heap(m_releasedIndices.begin(), m_releasedIndices.end(),
|
|
|
|
std::greater<T>());
|
|
|
|
}
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
value_type size() const { return m_size; }
|
|
|
|
value_type releasedSize() const { return m_releasedIndices.size(); }
|
|
|
|
value_type acquiredSize() const { return size() - releasedSize(); }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
const container_type &releasedIndices() const { return m_releasedIndices; }
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
value_type acquire() {
|
|
|
|
if (!m_releasedIndices.empty()) {
|
|
|
|
value_type idx = m_releasedIndices.front();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
pop_heap(m_releasedIndices.begin(), m_releasedIndices.end(),
|
|
|
|
std::greater<T>());
|
|
|
|
m_releasedIndices.pop_back();
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return idx;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
return m_start + m_size++;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void release(value_type idx) {
|
|
|
|
m_releasedIndices.push_back(idx);
|
|
|
|
push_heap(m_releasedIndices.begin(), m_releasedIndices.end(),
|
|
|
|
std::greater<T>());
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void clear() {
|
|
|
|
m_size = 0;
|
|
|
|
m_releasedIndices.clear();
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
//! Removes pool entries whose index is beyond that of the last acquired one.
|
|
|
|
void squeeze() {
|
|
|
|
if (m_releasedIndices.empty()) return;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
std::sort_heap(m_releasedIndices.begin(), m_releasedIndices.end(),
|
|
|
|
std::greater<T>()); // O(n logn)
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
// Decrease the pool size as long as the back items are unused
|
|
|
|
T lastIndex = m_start + m_size - 1;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
typename Cont::iterator ut, uEnd(m_releasedIndices.end());
|
|
|
|
for (ut = m_releasedIndices.begin(); ut != uEnd && *ut == lastIndex; ++ut)
|
|
|
|
--lastIndex, --m_size;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
if (ut != m_releasedIndices.begin()) m_releasedIndices.swap(Cont(ut, uEnd));
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
std::make_heap(m_releasedIndices.begin(), m_releasedIndices.end(),
|
|
|
|
std::greater<T>()); // O(n)
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#if (TCG_RVALUES_SUPPORT > 0)
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
indices_pool(const indices_pool &other)
|
|
|
|
: m_start(other.m_start)
|
|
|
|
, m_size(other.m_size)
|
|
|
|
, m_releasedIndices(other.m_releasedIndices) {}
|
|
|
|
|
|
|
|
indices_pool &operator=(const indices_pool &other) {
|
|
|
|
m_start = other.m_start, m_size = other.m_size,
|
|
|
|
m_releasedIndices = other.m_releasedIndices;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
indices_pool(indices_pool &&other)
|
|
|
|
: m_start(other.m_start)
|
|
|
|
, m_size(other.m_size)
|
|
|
|
, m_releasedIndices(
|
|
|
|
std::forward<container_type &&>(other.m_releasedIndices)) {}
|
|
|
|
|
|
|
|
indices_pool &operator=(indices_pool &&other) {
|
|
|
|
m_start = other.m_start, m_size = other.m_size;
|
|
|
|
m_releasedIndices =
|
|
|
|
std::forward<container_type &&>(other.m_releasedIndices);
|
|
|
|
return *this;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
|
|
|
|
|
|
template <typename T, typename Cont = std::vector<T>>
|
2016-06-15 18:43:10 +12:00
|
|
|
class pool {
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
typedef T value_type;
|
|
|
|
typedef Cont container_type;
|
|
|
|
typedef size_t size_type;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
Cont m_objects; //!< Objects in the pool
|
|
|
|
tcg::indices_pool<size_t> m_indices; //!< Indices Pool representing m_objects
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
pool() {}
|
|
|
|
~pool() {}
|
|
|
|
|
|
|
|
const tcg::indices_pool<size_t> &indices() const { return m_indices; }
|
|
|
|
|
|
|
|
size_type size() const {
|
|
|
|
assert(m_indices.size() <= m_objects.size());
|
|
|
|
return m_objects.size();
|
|
|
|
}
|
|
|
|
size_type releasedSize() const {
|
|
|
|
return m_objects.size() - m_indices.acquiredSize();
|
|
|
|
}
|
|
|
|
size_type acquiredSize() const { return m_indices.acquiredSize(); }
|
|
|
|
|
|
|
|
const value_type &operator[](size_type idx) const { return m_objects[idx]; }
|
|
|
|
value_type &operator[](size_type idx) { return m_objects[idx]; }
|
|
|
|
|
|
|
|
size_type acquire() {
|
|
|
|
size_t result = m_indices.acquire();
|
|
|
|
if (result >= m_objects.size()) {
|
|
|
|
assert(result == m_objects.size());
|
|
|
|
m_objects.push_back(T());
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void release(size_type idx) { m_indices.release(idx); }
|
|
|
|
|
|
|
|
void releaseAll() { m_indices.clear(); }
|
|
|
|
void clear() {
|
|
|
|
releaseAll();
|
|
|
|
m_objects.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Removes pool entries whose index is beyond that of the last acquired one.
|
|
|
|
void squeeze() {
|
|
|
|
m_indices.squeeze();
|
|
|
|
m_objects.resize(m_indices.size());
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
} // namespace tcg
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
#endif // TCG_POOL_H
|