]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // | |
3 | // (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost | |
4 | // Software License, Version 1.0. (See accompanying file | |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // See http://www.boost.org/libs/container for documentation. | |
8 | // | |
9 | ////////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef BOOST_CONTAINER_ALLOCATOR_HPP | |
12 | #define BOOST_CONTAINER_ALLOCATOR_HPP | |
13 | ||
14 | #ifndef BOOST_CONFIG_HPP | |
15 | # include <boost/config.hpp> | |
16 | #endif | |
17 | ||
18 | #if defined(BOOST_HAS_PRAGMA_ONCE) | |
19 | # pragma once | |
20 | #endif | |
21 | ||
22 | #include <boost/container/detail/config_begin.hpp> | |
23 | #include <boost/container/detail/workaround.hpp> | |
24 | #include <boost/container/container_fwd.hpp> | |
25 | #include <boost/container/detail/version_type.hpp> | |
26 | #include <boost/container/throw_exception.hpp> | |
27 | #include <boost/container/detail/dlmalloc.hpp> | |
28 | #include <boost/container/detail/multiallocation_chain.hpp> | |
29 | #include <boost/static_assert.hpp> | |
30 | #include <cstddef> | |
31 | #include <cassert> | |
32 | ||
33 | //!\file | |
34 | ||
35 | namespace boost { | |
36 | namespace container { | |
37 | ||
38 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
39 | ||
40 | template<unsigned Version, unsigned int AllocationDisableMask> | |
41 | class allocator<void, Version, AllocationDisableMask> | |
42 | { | |
43 | typedef allocator<void, Version, AllocationDisableMask> self_t; | |
44 | public: | |
45 | typedef void value_type; | |
46 | typedef void * pointer; | |
47 | typedef const void* const_pointer; | |
48 | typedef int & reference; | |
49 | typedef const int & const_reference; | |
50 | typedef std::size_t size_type; | |
51 | typedef std::ptrdiff_t difference_type; | |
52 | typedef boost::container::container_detail:: | |
53 | version_type<self_t, Version> version; | |
54 | ||
55 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
56 | typedef boost::container::container_detail:: | |
57 | basic_multiallocation_chain<void*> multiallocation_chain; | |
58 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
59 | ||
60 | //!Obtains an allocator that allocates | |
61 | //!objects of type T2 | |
62 | template<class T2> | |
63 | struct rebind | |
64 | { | |
65 | typedef allocator< T2 | |
66 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
67 | , Version, AllocationDisableMask | |
68 | #endif | |
69 | > other; | |
70 | }; | |
71 | ||
72 | //!Default constructor | |
73 | //!Never throws | |
74 | allocator() | |
75 | {} | |
76 | ||
77 | //!Constructor from other allocator. | |
78 | //!Never throws | |
79 | allocator(const allocator &) | |
80 | {} | |
81 | ||
82 | //!Constructor from related allocator. | |
83 | //!Never throws | |
84 | template<class T2> | |
85 | allocator(const allocator<T2, Version, AllocationDisableMask> &) | |
86 | {} | |
87 | }; | |
88 | ||
89 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
90 | ||
91 | //! This class is an extended STL-compatible that offers advanced allocation mechanism | |
92 | //!(in-place expansion, shrinking, burst-allocation...) | |
93 | //! | |
94 | //! This allocator is a wrapper around a modified DLmalloc. | |
95 | //! If Version is 1, the allocator is a STL conforming allocator. If Version is 2, | |
96 | //! the allocator offers advanced expand in place and burst allocation capabilities. | |
97 | //! | |
98 | //! AllocationDisableMask works only if Version is 2 and it can be an inclusive OR | |
99 | //! of allocation types the user wants to disable. | |
100 | template< class T | |
101 | , unsigned Version BOOST_CONTAINER_DOCONLY(=2) | |
102 | , unsigned int AllocationDisableMask BOOST_CONTAINER_DOCONLY(=0)> | |
103 | class allocator | |
104 | { | |
105 | typedef unsigned int allocation_type; | |
106 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
107 | private: | |
108 | ||
109 | //Self type | |
110 | typedef allocator<T, Version, AllocationDisableMask> self_t; | |
111 | ||
112 | //Not assignable from related allocator | |
113 | template<class T2, unsigned int Version2, unsigned int AllocationDisableMask2> | |
114 | allocator& operator=(const allocator<T2, Version2, AllocationDisableMask2>&); | |
115 | ||
116 | static const unsigned int ForbiddenMask = | |
117 | BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BWD | BOOST_CONTAINER_EXPAND_FWD ; | |
118 | ||
119 | //The mask can't disable all the allocation types | |
120 | BOOST_STATIC_ASSERT(( (AllocationDisableMask & ForbiddenMask) != ForbiddenMask )); | |
121 | ||
122 | //The mask is only valid for version 2 allocators | |
123 | BOOST_STATIC_ASSERT(( Version != 1 || (AllocationDisableMask == 0) )); | |
124 | ||
125 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
126 | ||
127 | public: | |
128 | typedef T value_type; | |
129 | typedef T * pointer; | |
130 | typedef const T * const_pointer; | |
131 | typedef T & reference; | |
132 | typedef const T & const_reference; | |
133 | typedef std::size_t size_type; | |
134 | typedef std::ptrdiff_t difference_type; | |
135 | ||
136 | typedef boost::container::container_detail:: | |
137 | version_type<self_t, Version> version; | |
138 | ||
139 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
140 | typedef boost::container::container_detail:: | |
141 | basic_multiallocation_chain<void*> void_multiallocation_chain; | |
142 | ||
143 | typedef boost::container::container_detail:: | |
144 | transform_multiallocation_chain | |
145 | <void_multiallocation_chain, T> multiallocation_chain; | |
146 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
147 | ||
148 | //!Obtains an allocator that allocates | |
149 | //!objects of type T2 | |
150 | template<class T2> | |
151 | struct rebind | |
152 | { | |
153 | typedef allocator<T2, Version, AllocationDisableMask> other; | |
154 | }; | |
155 | ||
156 | //!Default constructor | |
157 | //!Never throws | |
158 | allocator() BOOST_NOEXCEPT_OR_NOTHROW | |
159 | {} | |
160 | ||
161 | //!Constructor from other allocator. | |
162 | //!Never throws | |
163 | allocator(const allocator &) BOOST_NOEXCEPT_OR_NOTHROW | |
164 | {} | |
165 | ||
166 | //!Constructor from related allocator. | |
167 | //!Never throws | |
168 | template<class T2> | |
169 | allocator(const allocator<T2 | |
170 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
171 | , Version, AllocationDisableMask | |
172 | #endif | |
173 | > &) BOOST_NOEXCEPT_OR_NOTHROW | |
174 | {} | |
175 | ||
176 | //!Allocates memory for an array of count elements. | |
177 | //!Throws std::bad_alloc if there is no enough memory | |
178 | //!If Version is 2, this allocated memory can only be deallocated | |
179 | //!with deallocate() or (for Version == 2) deallocate_many() | |
180 | pointer allocate(size_type count, const void * hint= 0) | |
181 | { | |
182 | (void)hint; | |
183 | if(count > this->max_size()) | |
184 | boost::container::throw_bad_alloc(); | |
185 | void *ret = dlmalloc_malloc(count*sizeof(T)); | |
186 | if(!ret) | |
187 | boost::container::throw_bad_alloc(); | |
188 | return static_cast<pointer>(ret); | |
189 | } | |
190 | ||
191 | //!Deallocates previously allocated memory. | |
192 | //!Never throws | |
193 | void deallocate(pointer ptr, size_type) BOOST_NOEXCEPT_OR_NOTHROW | |
194 | { dlmalloc_free(ptr); } | |
195 | ||
196 | //!Returns the maximum number of elements that could be allocated. | |
197 | //!Never throws | |
198 | size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW | |
199 | { return size_type(-1)/sizeof(T); } | |
200 | ||
201 | //!Swaps two allocators, does nothing | |
202 | //!because this allocator is stateless | |
203 | friend void swap(self_t &, self_t &) BOOST_NOEXCEPT_OR_NOTHROW | |
204 | {} | |
205 | ||
206 | //!An allocator always compares to true, as memory allocated with one | |
207 | //!instance can be deallocated by another instance | |
208 | friend bool operator==(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW | |
209 | { return true; } | |
210 | ||
211 | //!An allocator always compares to false, as memory allocated with one | |
212 | //!instance can be deallocated by another instance | |
213 | friend bool operator!=(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW | |
214 | { return false; } | |
215 | ||
216 | //!An advanced function that offers in-place expansion shrink to fit and new allocation | |
217 | //!capabilities. Memory allocated with this function can only be deallocated with deallocate() | |
218 | //!or deallocate_many(). | |
219 | //!This function is available only with Version == 2 | |
220 | pointer allocation_command(allocation_type command, | |
221 | size_type limit_size, | |
222 | size_type &prefer_in_recvd_out_size, | |
223 | pointer &reuse) | |
224 | { | |
225 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
226 | const allocation_type mask(AllocationDisableMask); | |
227 | command &= ~mask; | |
228 | pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); | |
229 | if(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION)) | |
230 | boost::container::throw_bad_alloc(); | |
231 | return ret; | |
232 | } | |
233 | ||
234 | //!Returns maximum the number of objects the previously allocated memory | |
235 | //!pointed by p can hold. | |
236 | //!Memory must not have been allocated with | |
237 | //!allocate_one or allocate_individual. | |
238 | //!This function is available only with Version == 2 | |
239 | size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW | |
240 | { | |
241 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
242 | return dlmalloc_size(p); | |
243 | } | |
244 | ||
245 | //!Allocates just one object. Memory allocated with this function | |
246 | //!must be deallocated only with deallocate_one(). | |
247 | //!Throws bad_alloc if there is no enough memory | |
248 | //!This function is available only with Version == 2 | |
249 | pointer allocate_one() | |
250 | { | |
251 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
252 | return this->allocate(1); | |
253 | } | |
254 | ||
255 | //!Allocates many elements of size == 1. | |
256 | //!Elements must be individually deallocated with deallocate_one() | |
257 | //!This function is available only with Version == 2 | |
258 | void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) | |
259 | { | |
260 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
261 | this->allocate_many(1, num_elements, chain); | |
262 | } | |
263 | ||
264 | //!Deallocates memory previously allocated with allocate_one(). | |
265 | //!You should never use deallocate_one to deallocate memory allocated | |
266 | //!with other functions different from allocate_one() or allocate_individual. | |
267 | //Never throws | |
268 | void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW | |
269 | { | |
270 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
271 | return this->deallocate(p, 1); | |
272 | } | |
273 | ||
274 | //!Deallocates memory allocated with allocate_one() or allocate_individual(). | |
275 | //!This function is available only with Version == 2 | |
276 | void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW | |
277 | { | |
278 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
279 | return this->deallocate_many(chain); | |
280 | } | |
281 | ||
282 | //!Allocates many elements of size elem_size. | |
283 | //!Elements must be individually deallocated with deallocate() | |
284 | //!This function is available only with Version == 2 | |
285 | void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) | |
286 | { | |
287 | BOOST_STATIC_ASSERT(( Version > 1 ));/* | |
288 | dlmalloc_memchain ch; | |
289 | BOOST_CONTAINER_MEMCHAIN_INIT(&ch); | |
290 | if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ | |
291 | boost::container::throw_bad_alloc(); | |
292 | } | |
293 | chain.incorporate_after(chain.before_begin() | |
294 | ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) | |
295 | ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) | |
296 | ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ | |
297 | if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast<dlmalloc_memchain *>(&chain))){ | |
298 | boost::container::throw_bad_alloc(); | |
299 | } | |
300 | } | |
301 | ||
302 | //!Allocates n_elements elements, each one of size elem_sizes[i] | |
303 | //!Elements must be individually deallocated with deallocate() | |
304 | //!This function is available only with Version == 2 | |
305 | void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) | |
306 | { | |
307 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
308 | dlmalloc_memchain ch; | |
309 | BOOST_CONTAINER_MEMCHAIN_INIT(&ch); | |
310 | if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ | |
311 | boost::container::throw_bad_alloc(); | |
312 | } | |
313 | chain.incorporate_after(chain.before_begin() | |
314 | ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) | |
315 | ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) | |
316 | ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); | |
317 | /* | |
318 | if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast<dlmalloc_memchain *>(&chain))){ | |
319 | boost::container::throw_bad_alloc(); | |
320 | }*/ | |
321 | } | |
322 | ||
323 | //!Deallocates several elements allocated by | |
324 | //!allocate_many(), allocate(), or allocation_command(). | |
325 | //!This function is available only with Version == 2 | |
326 | void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW | |
327 | { | |
328 | BOOST_STATIC_ASSERT(( Version > 1 )); | |
329 | dlmalloc_memchain ch; | |
330 | void *beg(&*chain.begin()), *last(&*chain.last()); | |
331 | size_t size(chain.size()); | |
332 | BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); | |
333 | dlmalloc_multidealloc(&ch); | |
334 | //dlmalloc_multidealloc(reinterpret_cast<dlmalloc_memchain *>(&chain)); | |
335 | } | |
336 | ||
337 | private: | |
338 | ||
339 | pointer priv_allocation_command | |
340 | (allocation_type command, std::size_t limit_size | |
341 | ,size_type &prefer_in_recvd_out_size | |
342 | ,pointer &reuse_ptr) | |
343 | { | |
344 | std::size_t const preferred_size = prefer_in_recvd_out_size; | |
345 | dlmalloc_command_ret_t ret = {0 , 0}; | |
346 | if((limit_size > this->max_size()) | (preferred_size > this->max_size())){ | |
347 | return pointer(); | |
348 | } | |
349 | std::size_t l_size = limit_size*sizeof(T); | |
350 | std::size_t p_size = preferred_size*sizeof(T); | |
351 | std::size_t r_size; | |
352 | { | |
353 | void* reuse_ptr_void = reuse_ptr; | |
354 | ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); | |
355 | reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0; | |
356 | } | |
357 | prefer_in_recvd_out_size = r_size/sizeof(T); | |
358 | return (pointer)ret.first; | |
359 | } | |
360 | }; | |
361 | ||
362 | } //namespace container { | |
363 | } //namespace boost { | |
364 | ||
365 | #include <boost/container/detail/config_end.hpp> | |
366 | ||
367 | #endif //BOOST_CONTAINER_ALLOCATOR_HPP | |
368 |