123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- // 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 BOOST_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 BOOST_BORLANDC
- # pragma option pop
- #endif
- #endif
|