Chris@16
|
1 // Copyright (C) 2000, 2001 Stephen Cleary
|
Chris@16
|
2 //
|
Chris@16
|
3 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
4 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6 //
|
Chris@16
|
7 // See http://www.boost.org for updates, documentation, and revision history.
|
Chris@16
|
8
|
Chris@16
|
9 #ifndef BOOST_OBJECT_POOL_HPP
|
Chris@16
|
10 #define BOOST_OBJECT_POOL_HPP
|
Chris@16
|
11 /*!
|
Chris@16
|
12 \file
|
Chris@16
|
13 \brief Provides a template type boost::object_pool<T, UserAllocator>
|
Chris@16
|
14 that can be used for fast and efficient memory allocation of objects of type T.
|
Chris@16
|
15 It also provides automatic destruction of non-deallocated objects.
|
Chris@16
|
16 */
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/pool/poolfwd.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 // boost::pool
|
Chris@16
|
21 #include <boost/pool/pool.hpp>
|
Chris@16
|
22
|
Chris@16
|
23 // The following code will be put into Boost.Config in a later revision
|
Chris@16
|
24 #if defined(BOOST_MSVC) || defined(__KCC)
|
Chris@16
|
25 # define BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
|
Chris@16
|
26 #endif
|
Chris@16
|
27
|
Chris@16
|
28 // The following code might be put into some Boost.Config header in a later revision
|
Chris@16
|
29 #ifdef __BORLANDC__
|
Chris@16
|
30 # pragma option push -w-inl
|
Chris@16
|
31 #endif
|
Chris@16
|
32
|
Chris@16
|
33 // There are a few places in this file where the expression "this->m" is used.
|
Chris@16
|
34 // This expression is used to force instantiation-time name lookup, which I am
|
Chris@16
|
35 // informed is required for strict Standard compliance. It's only necessary
|
Chris@16
|
36 // if "m" is a member of a base class that is dependent on a template
|
Chris@16
|
37 // parameter.
|
Chris@16
|
38 // Thanks to Jens Maurer for pointing this out!
|
Chris@16
|
39
|
Chris@16
|
40 namespace boost {
|
Chris@16
|
41
|
Chris@16
|
42 /*! \brief A template class
|
Chris@16
|
43 that can be used for fast and efficient memory allocation of objects.
|
Chris@16
|
44 It also provides automatic destruction of non-deallocated objects.
|
Chris@16
|
45
|
Chris@16
|
46 \details
|
Chris@16
|
47
|
Chris@16
|
48 <b>T</b> The type of object to allocate/deallocate.
|
Chris@16
|
49 T must have a non-throwing destructor.
|
Chris@16
|
50
|
Chris@16
|
51 <b>UserAllocator</b>
|
Chris@16
|
52 Defines the allocator that the underlying Pool will use to allocate memory from the system.
|
Chris@16
|
53 See <a href="boost_pool/pool/pooling.html#boost_pool.pool.pooling.user_allocator">User Allocators</a> for details.
|
Chris@16
|
54
|
Chris@16
|
55 Class object_pool is a template class
|
Chris@16
|
56 that can be used for fast and efficient memory allocation of objects.
|
Chris@16
|
57 It also provides automatic destruction of non-deallocated objects.
|
Chris@16
|
58
|
Chris@16
|
59 When the object pool is destroyed, then the destructor for type T
|
Chris@16
|
60 is called for each allocated T that has not yet been deallocated. O(N).
|
Chris@16
|
61
|
Chris@16
|
62 Whenever an object of type ObjectPool needs memory from the system,
|
Chris@16
|
63 it will request it from its UserAllocator template parameter.
|
Chris@16
|
64 The amount requested is determined using a doubling algorithm;
|
Chris@16
|
65 that is, each time more system memory is allocated,
|
Chris@16
|
66 the amount of system memory requested is doubled.
|
Chris@16
|
67 Users may control the doubling algorithm by the parameters passed
|
Chris@16
|
68 to the object_pool's constructor.
|
Chris@16
|
69 */
|
Chris@16
|
70
|
Chris@16
|
71 template <typename T, typename UserAllocator>
|
Chris@16
|
72 class object_pool: protected pool<UserAllocator>
|
Chris@16
|
73 { //!
|
Chris@16
|
74 public:
|
Chris@16
|
75 typedef T element_type; //!< ElementType
|
Chris@16
|
76 typedef UserAllocator user_allocator; //!<
|
Chris@16
|
77 typedef typename pool<UserAllocator>::size_type size_type; //!< pool<UserAllocator>::size_type
|
Chris@16
|
78 typedef typename pool<UserAllocator>::difference_type difference_type; //!< pool<UserAllocator>::difference_type
|
Chris@16
|
79
|
Chris@16
|
80 protected:
|
Chris@16
|
81 //! \return The underlying boost:: \ref pool storage used by *this.
|
Chris@16
|
82 pool<UserAllocator> & store()
|
Chris@16
|
83 {
|
Chris@16
|
84 return *this;
|
Chris@16
|
85 }
|
Chris@16
|
86 //! \return The underlying boost:: \ref pool storage used by *this.
|
Chris@16
|
87 const pool<UserAllocator> & store() const
|
Chris@16
|
88 {
|
Chris@16
|
89 return *this;
|
Chris@16
|
90 }
|
Chris@16
|
91
|
Chris@16
|
92 // for the sake of code readability :)
|
Chris@16
|
93 static void * & nextof(void * const ptr)
|
Chris@16
|
94 { //! \returns The next memory block after ptr (for the sake of code readability :)
|
Chris@16
|
95 return *(static_cast<void **>(ptr));
|
Chris@16
|
96 }
|
Chris@16
|
97
|
Chris@16
|
98 public:
|
Chris@16
|
99 explicit object_pool(const size_type arg_next_size = 32, const size_type arg_max_size = 0)
|
Chris@16
|
100 :
|
Chris@16
|
101 pool<UserAllocator>(sizeof(T), arg_next_size, arg_max_size)
|
Chris@16
|
102 { //! Constructs a new (empty by default) ObjectPool.
|
Chris@16
|
103 //! \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
|
104 //! \pre next_size != 0.
|
Chris@16
|
105 //! \param max_size Maximum number of chunks to ever request from the system - this puts a cap on the doubling algorithm
|
Chris@16
|
106 //! used by the underlying pool.
|
Chris@16
|
107 }
|
Chris@16
|
108
|
Chris@16
|
109 ~object_pool();
|
Chris@16
|
110
|
Chris@16
|
111 // Returns 0 if out-of-memory.
|
Chris@16
|
112 element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
|
Chris@16
|
113 { //! Allocates memory that can hold one object of type ElementType.
|
Chris@16
|
114 //!
|
Chris@16
|
115 //! If out of memory, returns 0.
|
Chris@16
|
116 //!
|
Chris@16
|
117 //! Amortized O(1).
|
Chris@16
|
118 return static_cast<element_type *>(store().ordered_malloc());
|
Chris@16
|
119 }
|
Chris@16
|
120 void free BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk)
|
Chris@16
|
121 { //! De-Allocates memory that holds a chunk of type ElementType.
|
Chris@16
|
122 //!
|
Chris@16
|
123 //! Note that p may not be 0.\n
|
Chris@16
|
124 //!
|
Chris@16
|
125 //! Note that the destructor for p is not called. O(N).
|
Chris@16
|
126 store().ordered_free(chunk);
|
Chris@16
|
127 }
|
Chris@16
|
128 bool is_from(element_type * const chunk) const
|
Chris@16
|
129 { /*! \returns true if chunk was allocated from *this or
|
Chris@16
|
130 may be returned as the result of a future allocation from *this.
|
Chris@16
|
131
|
Chris@16
|
132 Returns false if chunk was allocated from some other pool or
|
Chris@16
|
133 may be returned as the result of a future allocation from some other pool.
|
Chris@16
|
134
|
Chris@16
|
135 Otherwise, the return value is meaningless.
|
Chris@16
|
136
|
Chris@16
|
137 \note This function may NOT be used to reliably test random pointer values!
|
Chris@16
|
138 */
|
Chris@16
|
139 return store().is_from(chunk);
|
Chris@16
|
140 }
|
Chris@16
|
141
|
Chris@16
|
142 element_type * construct()
|
Chris@16
|
143 { //! \returns A pointer to an object of type T, allocated in memory from the underlying pool
|
Chris@16
|
144 //! and default constructed. The returned objected can be freed by a call to \ref destroy.
|
Chris@16
|
145 //! Otherwise the returned object will be automatically destroyed when *this is destroyed.
|
Chris@16
|
146 element_type * const ret = (malloc)();
|
Chris@16
|
147 if (ret == 0)
|
Chris@16
|
148 return ret;
|
Chris@16
|
149 try { new (ret) element_type(); }
|
Chris@16
|
150 catch (...) { (free)(ret); throw; }
|
Chris@16
|
151 return ret;
|
Chris@16
|
152 }
|
Chris@16
|
153
|
Chris@16
|
154
|
Chris@16
|
155 #if defined(BOOST_DOXYGEN)
|
Chris@16
|
156 template <class Arg1, ... class ArgN>
|
Chris@16
|
157 element_type * construct(Arg1&, ... ArgN&)
|
Chris@16
|
158 {
|
Chris@16
|
159 //! \returns A pointer to an object of type T, allocated in memory from the underlying pool
|
Chris@16
|
160 //! and constructed from arguments Arg1 to ArgN. The returned objected can be freed by a call to \ref destroy.
|
Chris@16
|
161 //! Otherwise the returned object will be automatically destroyed when *this is destroyed.
|
Chris@16
|
162 //!
|
Chris@16
|
163 //! \note Since the number and type of arguments to this function is totally arbitrary, a simple system has been
|
Chris@16
|
164 //! set up to automatically generate template construct functions. This system is based on the macro preprocessor
|
Chris@16
|
165 //! m4, which is standard on UNIX systems and also available for Win32 systems.\n\n
|
Chris@16
|
166 //! detail/pool_construct.m4, when run with m4, will create the file detail/pool_construct.ipp, which only defines
|
Chris@16
|
167 //! the construct functions for the proper number of arguments. The number of arguments may be passed into the
|
Chris@16
|
168 //! file as an m4 macro, NumberOfArguments; if not provided, it will default to 3.\n\n
|
Chris@16
|
169 //! For each different number of arguments (1 to NumberOfArguments), a template function is generated. There
|
Chris@16
|
170 //! are the same number of template parameters as there are arguments, and each argument's type is a reference
|
Chris@16
|
171 //! to that (possibly cv-qualified) template argument. Each possible permutation of the cv-qualifications is also generated.\n\n
|
Chris@16
|
172 //! Because each permutation is generated for each possible number of arguments, the included file size grows
|
Chris@16
|
173 //! exponentially in terms of the number of constructor arguments, not linearly. For the sake of rational
|
Chris@16
|
174 //! compile times, only use as many arguments as you need.\n\n
|
Chris@16
|
175 //! detail/pool_construct.bat and detail/pool_construct.sh are also provided to call m4, defining NumberOfArguments
|
Chris@16
|
176 //! to be their command-line parameter. See these files for more details.
|
Chris@16
|
177 }
|
Chris@16
|
178 #else
|
Chris@16
|
179 // Include automatically-generated file for family of template construct() functions.
|
Chris@16
|
180 // Copy .inc renamed .ipp to conform to Doxygen include filename expectations, PAB 12 Jan 11.
|
Chris@16
|
181 // But still get Doxygen warning:
|
Chris@16
|
182 // I:/boost-sandbox/guild/pool/boost/pool/object_pool.hpp:82:
|
Chris@16
|
183 // Warning: include file boost/pool/detail/pool_construct.ipp
|
Chris@16
|
184 // not found, perhaps you forgot to add its directory to INCLUDE_PATH?
|
Chris@16
|
185 // But the file IS found and referenced OK, but cannot view code.
|
Chris@16
|
186 // This seems because not at the head of the file
|
Chris@16
|
187 // But if moved this up, Doxygen is happy, but of course it won't compile,
|
Chris@16
|
188 // because the many constructors *must* go here.
|
Chris@16
|
189
|
Chris@16
|
190 #ifndef BOOST_NO_TEMPLATE_CV_REF_OVERLOADS
|
Chris@16
|
191 # include <boost/pool/detail/pool_construct.ipp>
|
Chris@16
|
192 #else
|
Chris@16
|
193 # include <boost/pool/detail/pool_construct_simple.ipp>
|
Chris@16
|
194 #endif
|
Chris@16
|
195 #endif
|
Chris@16
|
196 void destroy(element_type * const chunk)
|
Chris@16
|
197 { //! Destroys an object allocated with \ref construct.
|
Chris@16
|
198 //!
|
Chris@16
|
199 //! Equivalent to:
|
Chris@16
|
200 //!
|
Chris@16
|
201 //! p->~ElementType(); this->free(p);
|
Chris@16
|
202 //!
|
Chris@16
|
203 //! \pre p must have been previously allocated from *this via a call to \ref construct.
|
Chris@16
|
204 chunk->~T();
|
Chris@16
|
205 (free)(chunk);
|
Chris@16
|
206 }
|
Chris@16
|
207
|
Chris@16
|
208 size_type get_next_size() const
|
Chris@16
|
209 { //! \returns The number of chunks that will be allocated next time we run out of memory.
|
Chris@16
|
210 return store().get_next_size();
|
Chris@16
|
211 }
|
Chris@16
|
212 void set_next_size(const size_type x)
|
Chris@16
|
213 { //! Set a new number of chunks to allocate the next time we run out of memory.
|
Chris@16
|
214 //! \param x wanted next_size (must not be zero).
|
Chris@16
|
215 store().set_next_size(x);
|
Chris@16
|
216 }
|
Chris@16
|
217 };
|
Chris@16
|
218
|
Chris@16
|
219 template <typename T, typename UserAllocator>
|
Chris@16
|
220 object_pool<T, UserAllocator>::~object_pool()
|
Chris@16
|
221 {
|
Chris@16
|
222 #ifndef BOOST_POOL_VALGRIND
|
Chris@16
|
223 // handle trivial case of invalid list.
|
Chris@16
|
224 if (!this->list.valid())
|
Chris@16
|
225 return;
|
Chris@16
|
226
|
Chris@16
|
227 details::PODptr<size_type> iter = this->list;
|
Chris@16
|
228 details::PODptr<size_type> next = iter;
|
Chris@16
|
229
|
Chris@16
|
230 // Start 'freed_iter' at beginning of free list
|
Chris@16
|
231 void * freed_iter = this->first;
|
Chris@16
|
232
|
Chris@16
|
233 const size_type partition_size = this->alloc_size();
|
Chris@16
|
234
|
Chris@16
|
235 do
|
Chris@16
|
236 {
|
Chris@16
|
237 // increment next
|
Chris@16
|
238 next = next.next();
|
Chris@16
|
239
|
Chris@16
|
240 // delete all contained objects that aren't freed.
|
Chris@16
|
241
|
Chris@16
|
242 // Iterate 'i' through all chunks in the memory block.
|
Chris@16
|
243 for (char * i = iter.begin(); i != iter.end(); i += partition_size)
|
Chris@16
|
244 {
|
Chris@16
|
245 // If this chunk is free,
|
Chris@16
|
246 if (i == freed_iter)
|
Chris@16
|
247 {
|
Chris@16
|
248 // Increment freed_iter to point to next in free list.
|
Chris@16
|
249 freed_iter = nextof(freed_iter);
|
Chris@16
|
250
|
Chris@16
|
251 // Continue searching chunks in the memory block.
|
Chris@16
|
252 continue;
|
Chris@16
|
253 }
|
Chris@16
|
254
|
Chris@16
|
255 // This chunk is not free (allocated), so call its destructor,
|
Chris@16
|
256 static_cast<T *>(static_cast<void *>(i))->~T();
|
Chris@16
|
257 // and continue searching chunks in the memory block.
|
Chris@16
|
258 }
|
Chris@16
|
259
|
Chris@16
|
260 // free storage.
|
Chris@16
|
261 (UserAllocator::free)(iter.begin());
|
Chris@16
|
262
|
Chris@16
|
263 // increment iter.
|
Chris@16
|
264 iter = next;
|
Chris@16
|
265 } while (iter.valid());
|
Chris@16
|
266
|
Chris@16
|
267 // Make the block list empty so that the inherited destructor doesn't try to
|
Chris@16
|
268 // free it again.
|
Chris@16
|
269 this->list.invalidate();
|
Chris@16
|
270 #else
|
Chris@16
|
271 // destruct all used elements:
|
Chris@16
|
272 for(std::set<void*>::iterator pos = this->used_list.begin(); pos != this->used_list.end(); ++pos)
|
Chris@16
|
273 {
|
Chris@16
|
274 static_cast<T*>(*pos)->~T();
|
Chris@16
|
275 }
|
Chris@16
|
276 // base class will actually free the memory...
|
Chris@16
|
277 #endif
|
Chris@16
|
278 }
|
Chris@16
|
279
|
Chris@16
|
280 } // namespace boost
|
Chris@16
|
281
|
Chris@16
|
282 // The following code might be put into some Boost.Config header in a later revision
|
Chris@16
|
283 #ifdef __BORLANDC__
|
Chris@16
|
284 # pragma option pop
|
Chris@16
|
285 #endif
|
Chris@16
|
286
|
Chris@16
|
287 #endif
|