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