1 // Copyright (C) 2000, 2001 Stephen Cleary
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org for updates, documentation, and revision history.
8 
9 #ifndef BOOST_OBJECT_POOL_HPP
10 #define BOOST_OBJECT_POOL_HPP
11 
12 #include <boost/pool/poolfwd.hpp>
13 
14 // boost::pool
15 #include <boost/pool/pool.hpp>
16 
17 // The following code will be put into Boost.Config in a later revision
18 #if defined(BOOST_MSVC) || defined(__KCC)
19 # define BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
20 #endif
21 
22 // The following code might be put into some Boost.Config header in a later revision
23 #ifdef __BORLANDC__
24 # pragma option push -w-inl
25 #endif
26 
27 // There are a few places in this file where the expression "this->m" is used.
28 // This expression is used to force instantiation-time name lookup, which I am
29 //   informed is required for strict Standard compliance.  It's only necessary
30 //   if "m" is a member of a base class that is dependent on a template
31 //   parameter.
32 // Thanks to Jens Maurer for pointing this out!
33 
34 namespace boost {
35 
36 // T must have a non-throwing destructor
37 template <typename T, typename UserAllocator>
38 class object_pool: protected pool<UserAllocator>
39 {
40   public:
41     typedef T element_type;
42     typedef UserAllocator user_allocator;
43     typedef typename pool<UserAllocator>::size_type size_type;
44     typedef typename pool<UserAllocator>::difference_type difference_type;
45 
46   protected:
store()47     pool<UserAllocator> & store() { return *this; }
store() const48     const pool<UserAllocator> & store() const { return *this; }
49 
50     // for the sake of code readability :)
nextof(void * const ptr)51     static void * & nextof(void * const ptr)
52     { return *(static_cast<void **>(ptr)); }
53 
54   public:
55     // This constructor parameter is an extension!
object_pool(const size_type next_size=32,const size_type max_size=0)56     explicit object_pool(const size_type next_size = 32, const size_type max_size = 0)
57     :pool<UserAllocator>(sizeof(T), next_size, max_size) { }
58 
59     ~object_pool();
60 
61     // Returns 0 if out-of-memory
BOOST_PREVENT_MACRO_SUBSTITUTION()62     element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
63     { return static_cast<element_type *>(store().ordered_malloc()); }
BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk)64     void free BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk)
65     { store().ordered_free(chunk); }
is_from(element_type * const chunk) const66     bool is_from(element_type * const chunk) const
67     { return store().is_from(chunk); }
68 
construct()69     element_type * construct()
70     {
71       element_type * const ret = (malloc)();
72       if (ret == 0)
73         return ret;
74       try { new (ret) element_type(); }
75       catch (...) { (free)(ret); throw; }
76       return ret;
77     }
78 
79     // Include automatically-generated file for family of template construct()
80     //  functions
81 #ifndef BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
82 #   include <boost/pool/detail/pool_construct.inc>
83 #else
84 #   include <boost/pool/detail/pool_construct_simple.inc>
85 #endif
86 
destroy(element_type * const chunk)87     void destroy(element_type * const chunk)
88     {
89       chunk->~T();
90       (free)(chunk);
91     }
92 
93     // These functions are extensions!
get_next_size() const94     size_type get_next_size() const { return store().get_next_size(); }
set_next_size(const size_type x)95     void set_next_size(const size_type x) { store().set_next_size(x); }
96 };
97 
98 template <typename T, typename UserAllocator>
~object_pool()99 object_pool<T, UserAllocator>::~object_pool()
100 {
101   // handle trivial case
102   if (!this->list.valid())
103     return;
104 
105   details::PODptr<size_type> iter = this->list;
106   details::PODptr<size_type> next = iter;
107 
108   // Start 'freed_iter' at beginning of free list
109   void * freed_iter = this->first;
110 
111   const size_type partition_size = this->alloc_size();
112 
113   do
114   {
115     // increment next
116     next = next.next();
117 
118     // delete all contained objects that aren't freed
119 
120     // Iterate 'i' through all chunks in the memory block
121     for (char * i = iter.begin(); i != iter.end(); i += partition_size)
122     {
123       // If this chunk is free
124       if (i == freed_iter)
125       {
126         // Increment freed_iter to point to next in free list
127         freed_iter = nextof(freed_iter);
128 
129         // Continue searching chunks in the memory block
130         continue;
131       }
132 
133       // This chunk is not free (allocated), so call its destructor
134       static_cast<T *>(static_cast<void *>(i))->~T();
135       // and continue searching chunks in the memory block
136     }
137 
138     // free storage
139     (UserAllocator::free)(iter.begin());
140 
141     // increment iter
142     iter = next;
143   } while (iter.valid());
144 
145   // Make the block list empty so that the inherited destructor doesn't try to
146   //  free it again.
147   this->list.invalidate();
148 }
149 
150 } // namespace boost
151 
152 // The following code might be put into some Boost.Config header in a later revision
153 #ifdef __BORLANDC__
154 # pragma option pop
155 #endif
156 
157 #endif
158