288 lines
11 KiB
C++
288 lines
11 KiB
C++
// Copyright (C) 2000, 2001 Stephen Cleary
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
// See http://www.boost.org for updates, documentation, and revision history.
|
|
|
|
#ifndef BOOST_OBJECT_POOL_HPP
|
|
#define BOOST_OBJECT_POOL_HPP
|
|
/*!
|
|
\file
|
|
\brief Provides a template type boost::object_pool<T, UserAllocator>
|
|
that can be used for fast and efficient memory allocation of objects of type T.
|
|
It also provides automatic destruction of non-deallocated objects.
|
|
*/
|
|
|
|
#include <boost/pool/poolfwd.hpp>
|
|
|
|
// boost::pool
|
|
#include <boost/pool/pool.hpp>
|
|
|
|
// The following code will be put into Boost.Config in a later revision
|
|
#if defined(BOOST_MSVC) || defined(__KCC)
|
|
# define BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
|
|
#endif
|
|
|
|
// The following code might be put into some Boost.Config header in a later revision
|
|
#ifdef __BORLANDC__
|
|
# pragma option push -w-inl
|
|
#endif
|
|
|
|
// There are a few places in this file where the expression "this->m" is used.
|
|
// This expression is used to force instantiation-time name lookup, which I am
|
|
// informed is required for strict Standard compliance. It's only necessary
|
|
// if "m" is a member of a base class that is dependent on a template
|
|
// parameter.
|
|
// Thanks to Jens Maurer for pointing this out!
|
|
|
|
namespace boost {
|
|
|
|
/*! \brief A template class
|
|
that can be used for fast and efficient memory allocation of objects.
|
|
It also provides automatic destruction of non-deallocated objects.
|
|
|
|
\details
|
|
|
|
<b>T</b> The type of object to allocate/deallocate.
|
|
T must have a non-throwing destructor.
|
|
|
|
<b>UserAllocator</b>
|
|
Defines the allocator that the underlying Pool will use to allocate memory from the system.
|
|
See <a href="boost_pool/pool/pooling.html#boost_pool.pool.pooling.user_allocator">User Allocators</a> for details.
|
|
|
|
Class object_pool is a template class
|
|
that can be used for fast and efficient memory allocation of objects.
|
|
It also provides automatic destruction of non-deallocated objects.
|
|
|
|
When the object pool is destroyed, then the destructor for type T
|
|
is called for each allocated T that has not yet been deallocated. O(N).
|
|
|
|
Whenever an object of type ObjectPool needs memory from the system,
|
|
it will request it from its UserAllocator template parameter.
|
|
The amount requested is determined using a doubling algorithm;
|
|
that is, each time more system memory is allocated,
|
|
the amount of system memory requested is doubled.
|
|
Users may control the doubling algorithm by the parameters passed
|
|
to the object_pool's constructor.
|
|
*/
|
|
|
|
template <typename T, typename UserAllocator>
|
|
class object_pool: protected pool<UserAllocator>
|
|
{ //!
|
|
public:
|
|
typedef T element_type; //!< ElementType
|
|
typedef UserAllocator user_allocator; //!<
|
|
typedef typename pool<UserAllocator>::size_type size_type; //!< pool<UserAllocator>::size_type
|
|
typedef typename pool<UserAllocator>::difference_type difference_type; //!< pool<UserAllocator>::difference_type
|
|
|
|
protected:
|
|
//! \return The underlying boost:: \ref pool storage used by *this.
|
|
pool<UserAllocator> & store()
|
|
{
|
|
return *this;
|
|
}
|
|
//! \return The underlying boost:: \ref pool storage used by *this.
|
|
const pool<UserAllocator> & store() const
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
// for the sake of code readability :)
|
|
static void * & nextof(void * const ptr)
|
|
{ //! \returns The next memory block after ptr (for the sake of code readability :)
|
|
return *(static_cast<void **>(ptr));
|
|
}
|
|
|
|
public:
|
|
explicit object_pool(const size_type arg_next_size = 32, const size_type arg_max_size = 0)
|
|
:
|
|
pool<UserAllocator>(sizeof(T), arg_next_size, arg_max_size)
|
|
{ //! Constructs a new (empty by default) ObjectPool.
|
|
//! \param next_size Number of chunks to request from the system the next time that object needs to allocate system memory (default 32).
|
|
//! \pre next_size != 0.
|
|
//! \param max_size Maximum number of chunks to ever request from the system - this puts a cap on the doubling algorithm
|
|
//! used by the underlying pool.
|
|
}
|
|
|
|
~object_pool();
|
|
|
|
// Returns 0 if out-of-memory.
|
|
element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
|
|
{ //! Allocates memory that can hold one object of type ElementType.
|
|
//!
|
|
//! If out of memory, returns 0.
|
|
//!
|
|
//! Amortized O(1).
|
|
return static_cast<element_type *>(store().ordered_malloc());
|
|
}
|
|
void free BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk)
|
|
{ //! De-Allocates memory that holds a chunk of type ElementType.
|
|
//!
|
|
//! Note that p may not be 0.\n
|
|
//!
|
|
//! Note that the destructor for p is not called. O(N).
|
|
store().ordered_free(chunk);
|
|
}
|
|
bool is_from(element_type * const chunk) const
|
|
{ /*! \returns true if chunk was allocated from *this or
|
|
may be returned as the result of a future allocation from *this.
|
|
|
|
Returns false if chunk was allocated from some other pool or
|
|
may be returned as the result of a future allocation from some other pool.
|
|
|
|
Otherwise, the return value is meaningless.
|
|
|
|
\note This function may NOT be used to reliably test random pointer values!
|
|
*/
|
|
return store().is_from(chunk);
|
|
}
|
|
|
|
element_type * construct()
|
|
{ //! \returns A pointer to an object of type T, allocated in memory from the underlying pool
|
|
//! and default constructed. The returned objected can be freed by a call to \ref destroy.
|
|
//! Otherwise the returned object will be automatically destroyed when *this is destroyed.
|
|
element_type * const ret = (malloc)();
|
|
if (ret == 0)
|
|
return ret;
|
|
try { new (ret) element_type(); }
|
|
catch (...) { (free)(ret); throw; }
|
|
return ret;
|
|
}
|
|
|
|
|
|
#if defined(BOOST_DOXYGEN)
|
|
template <class Arg1, ... class ArgN>
|
|
element_type * construct(Arg1&, ... ArgN&)
|
|
{
|
|
//! \returns A pointer to an object of type T, allocated in memory from the underlying pool
|
|
//! and constructed from arguments Arg1 to ArgN. The returned objected can be freed by a call to \ref destroy.
|
|
//! Otherwise the returned object will be automatically destroyed when *this is destroyed.
|
|
//!
|
|
//! \note Since the number and type of arguments to this function is totally arbitrary, a simple system has been
|
|
//! set up to automatically generate template construct functions. This system is based on the macro preprocessor
|
|
//! m4, which is standard on UNIX systems and also available for Win32 systems.\n\n
|
|
//! detail/pool_construct.m4, when run with m4, will create the file detail/pool_construct.ipp, which only defines
|
|
//! the construct functions for the proper number of arguments. The number of arguments may be passed into the
|
|
//! file as an m4 macro, NumberOfArguments; if not provided, it will default to 3.\n\n
|
|
//! For each different number of arguments (1 to NumberOfArguments), a template function is generated. There
|
|
//! are the same number of template parameters as there are arguments, and each argument's type is a reference
|
|
//! to that (possibly cv-qualified) template argument. Each possible permutation of the cv-qualifications is also generated.\n\n
|
|
//! Because each permutation is generated for each possible number of arguments, the included file size grows
|
|
//! exponentially in terms of the number of constructor arguments, not linearly. For the sake of rational
|
|
//! compile times, only use as many arguments as you need.\n\n
|
|
//! detail/pool_construct.bat and detail/pool_construct.sh are also provided to call m4, defining NumberOfArguments
|
|
//! to be their command-line parameter. See these files for more details.
|
|
}
|
|
#else
|
|
// Include automatically-generated file for family of template construct() functions.
|
|
// Copy .inc renamed .ipp to conform to Doxygen include filename expectations, PAB 12 Jan 11.
|
|
// But still get Doxygen warning:
|
|
// I:/boost-sandbox/guild/pool/boost/pool/object_pool.hpp:82:
|
|
// Warning: include file boost/pool/detail/pool_construct.ipp
|
|
// not found, perhaps you forgot to add its directory to INCLUDE_PATH?
|
|
// But the file IS found and referenced OK, but cannot view code.
|
|
// This seems because not at the head of the file
|
|
// But if moved this up, Doxygen is happy, but of course it won't compile,
|
|
// because the many constructors *must* go here.
|
|
|
|
#ifndef BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
|
|
# include <boost/pool/detail/pool_construct.ipp>
|
|
#else
|
|
# include <boost/pool/detail/pool_construct_simple.ipp>
|
|
#endif
|
|
#endif
|
|
void destroy(element_type * const chunk)
|
|
{ //! Destroys an object allocated with \ref construct.
|
|
//!
|
|
//! Equivalent to:
|
|
//!
|
|
//! p->~ElementType(); this->free(p);
|
|
//!
|
|
//! \pre p must have been previously allocated from *this via a call to \ref construct.
|
|
chunk->~T();
|
|
(free)(chunk);
|
|
}
|
|
|
|
size_type get_next_size() const
|
|
{ //! \returns The number of chunks that will be allocated next time we run out of memory.
|
|
return store().get_next_size();
|
|
}
|
|
void set_next_size(const size_type x)
|
|
{ //! Set a new number of chunks to allocate the next time we run out of memory.
|
|
//! \param x wanted next_size (must not be zero).
|
|
store().set_next_size(x);
|
|
}
|
|
};
|
|
|
|
template <typename T, typename UserAllocator>
|
|
object_pool<T, UserAllocator>::~object_pool()
|
|
{
|
|
#ifndef BOOST_POOL_VALGRIND
|
|
// handle trivial case of invalid list.
|
|
if (!this->list.valid())
|
|
return;
|
|
|
|
details::PODptr<size_type> iter = this->list;
|
|
details::PODptr<size_type> next = iter;
|
|
|
|
// Start 'freed_iter' at beginning of free list
|
|
void * freed_iter = this->first;
|
|
|
|
const size_type partition_size = this->alloc_size();
|
|
|
|
do
|
|
{
|
|
// increment next
|
|
next = next.next();
|
|
|
|
// delete all contained objects that aren't freed.
|
|
|
|
// Iterate 'i' through all chunks in the memory block.
|
|
for (char * i = iter.begin(); i != iter.end(); i += partition_size)
|
|
{
|
|
// If this chunk is free,
|
|
if (i == freed_iter)
|
|
{
|
|
// Increment freed_iter to point to next in free list.
|
|
freed_iter = nextof(freed_iter);
|
|
|
|
// Continue searching chunks in the memory block.
|
|
continue;
|
|
}
|
|
|
|
// This chunk is not free (allocated), so call its destructor,
|
|
static_cast<T *>(static_cast<void *>(i))->~T();
|
|
// and continue searching chunks in the memory block.
|
|
}
|
|
|
|
// free storage.
|
|
(UserAllocator::free)(iter.begin());
|
|
|
|
// increment iter.
|
|
iter = next;
|
|
} while (iter.valid());
|
|
|
|
// Make the block list empty so that the inherited destructor doesn't try to
|
|
// free it again.
|
|
this->list.invalidate();
|
|
#else
|
|
// destruct all used elements:
|
|
for(std::set<void*>::iterator pos = this->used_list.begin(); pos != this->used_list.end(); ++pos)
|
|
{
|
|
static_cast<T*>(*pos)->~T();
|
|
}
|
|
// base class will actually free the memory...
|
|
#endif
|
|
}
|
|
|
|
} // namespace boost
|
|
|
|
// The following code might be put into some Boost.Config header in a later revision
|
|
#ifdef __BORLANDC__
|
|
# pragma option pop
|
|
#endif
|
|
|
|
#endif
|