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