Chris@102
|
1 //////////////////////////////////////////////////////////////////////////////
|
Chris@102
|
2 //
|
Chris@102
|
3 // (C) Copyright Ion Gaztanaga 2008-2013. Distributed under the Boost
|
Chris@102
|
4 // Software License, Version 1.0. (See accompanying file
|
Chris@102
|
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
6 //
|
Chris@102
|
7 // See http://www.boost.org/libs/container for documentation.
|
Chris@102
|
8 //
|
Chris@102
|
9 //////////////////////////////////////////////////////////////////////////////
|
Chris@102
|
10
|
Chris@102
|
11 #ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
|
Chris@102
|
12 #define BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
|
Chris@102
|
13
|
Chris@102
|
14 #ifndef BOOST_CONFIG_HPP
|
Chris@102
|
15 # include <boost/config.hpp>
|
Chris@102
|
16 #endif
|
Chris@102
|
17
|
Chris@102
|
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@102
|
19 # pragma once
|
Chris@102
|
20 #endif
|
Chris@102
|
21
|
Chris@102
|
22 #include <boost/container/detail/config_begin.hpp>
|
Chris@102
|
23 #include <boost/container/detail/workaround.hpp>
|
Chris@102
|
24 #include <boost/container/container_fwd.hpp>
|
Chris@102
|
25 #include <boost/container/throw_exception.hpp>
|
Chris@102
|
26 #include <boost/container/detail/node_pool.hpp>
|
Chris@102
|
27 #include <boost/container/detail/mpl.hpp>
|
Chris@102
|
28 #include <boost/container/detail/multiallocation_chain.hpp>
|
Chris@102
|
29 #include <boost/container/detail/alloc_lib_auto_link.hpp>
|
Chris@102
|
30 #include <boost/container/detail/singleton.hpp>
|
Chris@102
|
31
|
Chris@102
|
32 #include <boost/assert.hpp>
|
Chris@102
|
33 #include <boost/static_assert.hpp>
|
Chris@102
|
34 #include <cstddef>
|
Chris@102
|
35
|
Chris@102
|
36 namespace boost {
|
Chris@102
|
37 namespace container {
|
Chris@102
|
38
|
Chris@102
|
39 //!An STL node allocator that uses a modified DlMalloc as memory
|
Chris@102
|
40 //!source.
|
Chris@102
|
41 //!
|
Chris@102
|
42 //!This node allocator shares a segregated storage between all instances
|
Chris@102
|
43 //!of node_allocator with equal sizeof(T).
|
Chris@102
|
44 //!
|
Chris@102
|
45 //!NodesPerBlock is the number of nodes allocated at once when the allocator
|
Chris@102
|
46 //!runs out of nodes
|
Chris@102
|
47 #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
48 template
|
Chris@102
|
49 < class T
|
Chris@102
|
50 , std::size_t NodesPerBlock = NodeAlloc_nodes_per_block>
|
Chris@102
|
51 #else
|
Chris@102
|
52 template
|
Chris@102
|
53 < class T
|
Chris@102
|
54 , std::size_t NodesPerBlock
|
Chris@102
|
55 , std::size_t Version>
|
Chris@102
|
56 #endif
|
Chris@102
|
57 class node_allocator
|
Chris@102
|
58 {
|
Chris@102
|
59 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
60 //! If Version is 1, the allocator is a STL conforming allocator. If Version is 2,
|
Chris@102
|
61 //! the allocator offers advanced expand in place and burst allocation capabilities.
|
Chris@102
|
62 public:
|
Chris@102
|
63 typedef unsigned int allocation_type;
|
Chris@102
|
64 typedef node_allocator<T, NodesPerBlock, Version> self_t;
|
Chris@102
|
65
|
Chris@102
|
66 static const std::size_t nodes_per_block = NodesPerBlock;
|
Chris@102
|
67
|
Chris@102
|
68 BOOST_STATIC_ASSERT((Version <=2));
|
Chris@102
|
69 #endif
|
Chris@102
|
70
|
Chris@102
|
71 public:
|
Chris@102
|
72 //-------
|
Chris@102
|
73 typedef T value_type;
|
Chris@102
|
74 typedef T * pointer;
|
Chris@102
|
75 typedef const T * const_pointer;
|
Chris@102
|
76 typedef typename ::boost::container::
|
Chris@102
|
77 container_detail::unvoid<T>::type & reference;
|
Chris@102
|
78 typedef const typename ::boost::container::
|
Chris@102
|
79 container_detail::unvoid<T>::type & const_reference;
|
Chris@102
|
80 typedef std::size_t size_type;
|
Chris@102
|
81 typedef std::ptrdiff_t difference_type;
|
Chris@102
|
82
|
Chris@102
|
83 typedef boost::container::container_detail::
|
Chris@102
|
84 version_type<self_t, Version> version;
|
Chris@102
|
85
|
Chris@102
|
86 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
87 typedef boost::container::container_detail::
|
Chris@102
|
88 basic_multiallocation_chain<void*> multiallocation_chain_void;
|
Chris@102
|
89 typedef boost::container::container_detail::
|
Chris@102
|
90 transform_multiallocation_chain
|
Chris@102
|
91 <multiallocation_chain_void, T> multiallocation_chain;
|
Chris@102
|
92 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
93
|
Chris@102
|
94 //!Obtains node_allocator from
|
Chris@102
|
95 //!node_allocator
|
Chris@102
|
96 template<class T2>
|
Chris@102
|
97 struct rebind
|
Chris@102
|
98 {
|
Chris@102
|
99 typedef node_allocator< T2, NodesPerBlock
|
Chris@102
|
100 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
101 , Version
|
Chris@102
|
102 #endif
|
Chris@102
|
103 > other;
|
Chris@102
|
104 };
|
Chris@102
|
105
|
Chris@102
|
106 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
107 private:
|
Chris@102
|
108 //!Not assignable from related node_allocator
|
Chris@102
|
109 template<class T2, std::size_t N2>
|
Chris@102
|
110 node_allocator& operator=
|
Chris@102
|
111 (const node_allocator<T2, N2>&);
|
Chris@102
|
112
|
Chris@102
|
113 //!Not assignable from other node_allocator
|
Chris@102
|
114 node_allocator& operator=(const node_allocator&);
|
Chris@102
|
115 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
116
|
Chris@102
|
117 public:
|
Chris@102
|
118
|
Chris@102
|
119 //!Default constructor
|
Chris@102
|
120 node_allocator() BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
121 {}
|
Chris@102
|
122
|
Chris@102
|
123 //!Copy constructor from other node_allocator.
|
Chris@102
|
124 node_allocator(const node_allocator &) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
125 {}
|
Chris@102
|
126
|
Chris@102
|
127 //!Copy constructor from related node_allocator.
|
Chris@102
|
128 template<class T2>
|
Chris@102
|
129 node_allocator
|
Chris@102
|
130 (const node_allocator<T2, NodesPerBlock
|
Chris@102
|
131 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
Chris@102
|
132 , Version
|
Chris@102
|
133 #endif
|
Chris@102
|
134 > &) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
135 {}
|
Chris@102
|
136
|
Chris@102
|
137 //!Destructor
|
Chris@102
|
138 ~node_allocator() BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
139 {}
|
Chris@102
|
140
|
Chris@102
|
141 //!Returns the number of elements that could be allocated.
|
Chris@102
|
142 //!Never throws
|
Chris@102
|
143 size_type max_size() const
|
Chris@102
|
144 { return size_type(-1)/sizeof(T); }
|
Chris@102
|
145
|
Chris@102
|
146 //!Allocate memory for an array of count elements.
|
Chris@102
|
147 //!Throws std::bad_alloc if there is no enough memory
|
Chris@102
|
148 pointer allocate(size_type count, const void * = 0)
|
Chris@102
|
149 {
|
Chris@102
|
150 if(BOOST_UNLIKELY(count > this->max_size()))
|
Chris@102
|
151 boost::container::throw_bad_alloc();
|
Chris@102
|
152
|
Chris@102
|
153 if(Version == 1 && count == 1){
|
Chris@102
|
154 typedef container_detail::shared_node_pool
|
Chris@102
|
155 <sizeof(T), NodesPerBlock> shared_pool_t;
|
Chris@102
|
156 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
|
Chris@102
|
157 return pointer(static_cast<T*>(singleton_t::instance().allocate_node()));
|
Chris@102
|
158 }
|
Chris@102
|
159 else{
|
Chris@102
|
160 void *ret = boost_cont_malloc(count*sizeof(T));
|
Chris@102
|
161 if(BOOST_UNLIKELY(!ret))
|
Chris@102
|
162 boost::container::throw_bad_alloc();
|
Chris@102
|
163 return static_cast<pointer>(ret);
|
Chris@102
|
164 }
|
Chris@102
|
165 }
|
Chris@102
|
166
|
Chris@102
|
167 //!Deallocate allocated memory.
|
Chris@102
|
168 //!Never throws
|
Chris@102
|
169 void deallocate(const pointer &ptr, size_type count) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
170 {
|
Chris@102
|
171 (void)count;
|
Chris@102
|
172 if(Version == 1 && count == 1){
|
Chris@102
|
173 typedef container_detail::shared_node_pool
|
Chris@102
|
174 <sizeof(T), NodesPerBlock> shared_pool_t;
|
Chris@102
|
175 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
|
Chris@102
|
176 singleton_t::instance().deallocate_node(ptr);
|
Chris@102
|
177 }
|
Chris@102
|
178 else{
|
Chris@102
|
179 boost_cont_free(ptr);
|
Chris@102
|
180 }
|
Chris@102
|
181 }
|
Chris@102
|
182
|
Chris@102
|
183 //!Deallocates all free blocks of the pool
|
Chris@102
|
184 static void deallocate_free_blocks() BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
185 {
|
Chris@102
|
186 typedef container_detail::shared_node_pool
|
Chris@102
|
187 <sizeof(T), NodesPerBlock> shared_pool_t;
|
Chris@102
|
188 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
|
Chris@102
|
189 singleton_t::instance().deallocate_free_blocks();
|
Chris@102
|
190 }
|
Chris@102
|
191
|
Chris@102
|
192 pointer allocation_command
|
Chris@102
|
193 (allocation_type command, size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
|
Chris@102
|
194 {
|
Chris@102
|
195 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
196 pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse);
|
Chris@102
|
197 if(BOOST_UNLIKELY(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION)))
|
Chris@102
|
198 boost::container::throw_bad_alloc();
|
Chris@102
|
199 return ret;
|
Chris@102
|
200 }
|
Chris@102
|
201
|
Chris@102
|
202 //!Returns maximum the number of objects the previously allocated memory
|
Chris@102
|
203 //!pointed by p can hold.
|
Chris@102
|
204 size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
205 {
|
Chris@102
|
206 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
207 return boost_cont_size(p);
|
Chris@102
|
208 }
|
Chris@102
|
209
|
Chris@102
|
210 //!Allocates just one object. Memory allocated with this function
|
Chris@102
|
211 //!must be deallocated only with deallocate_one().
|
Chris@102
|
212 //!Throws bad_alloc if there is no enough memory
|
Chris@102
|
213 pointer allocate_one()
|
Chris@102
|
214 {
|
Chris@102
|
215 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
216 typedef container_detail::shared_node_pool
|
Chris@102
|
217 <sizeof(T), NodesPerBlock> shared_pool_t;
|
Chris@102
|
218 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
|
Chris@102
|
219 return (pointer)singleton_t::instance().allocate_node();
|
Chris@102
|
220 }
|
Chris@102
|
221
|
Chris@102
|
222 //!Allocates many elements of size == 1.
|
Chris@102
|
223 //!Elements must be individually deallocated with deallocate_one()
|
Chris@102
|
224 void allocate_individual(std::size_t num_elements, multiallocation_chain &chain)
|
Chris@102
|
225 {
|
Chris@102
|
226 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
227 typedef container_detail::shared_node_pool
|
Chris@102
|
228 <sizeof(T), NodesPerBlock> shared_pool_t;
|
Chris@102
|
229 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
|
Chris@102
|
230 typename shared_pool_t::multiallocation_chain ch;
|
Chris@102
|
231 singleton_t::instance().allocate_nodes(num_elements, ch);
|
Chris@102
|
232 chain.incorporate_after(chain.before_begin(), (T*)&*ch.begin(), (T*)&*ch.last(), ch.size());
|
Chris@102
|
233 }
|
Chris@102
|
234
|
Chris@102
|
235 //!Deallocates memory previously allocated with allocate_one().
|
Chris@102
|
236 //!You should never use deallocate_one to deallocate memory allocated
|
Chris@102
|
237 //!with other functions different from allocate_one(). Never throws
|
Chris@102
|
238 void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
239 {
|
Chris@102
|
240 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
241 typedef container_detail::shared_node_pool
|
Chris@102
|
242 <sizeof(T), NodesPerBlock> shared_pool_t;
|
Chris@102
|
243 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
|
Chris@102
|
244 singleton_t::instance().deallocate_node(p);
|
Chris@102
|
245 }
|
Chris@102
|
246
|
Chris@102
|
247 void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
248 {
|
Chris@102
|
249 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
250 typedef container_detail::shared_node_pool
|
Chris@102
|
251 <sizeof(T), NodesPerBlock> shared_pool_t;
|
Chris@102
|
252 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
|
Chris@102
|
253 typename shared_pool_t::multiallocation_chain ch(&*chain.begin(), &*chain.last(), chain.size());
|
Chris@102
|
254 singleton_t::instance().deallocate_nodes(ch);
|
Chris@102
|
255 }
|
Chris@102
|
256
|
Chris@102
|
257 //!Allocates many elements of size elem_size.
|
Chris@102
|
258 //!Elements must be individually deallocated with deallocate()
|
Chris@102
|
259 void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain)
|
Chris@102
|
260 {
|
Chris@102
|
261 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
262 boost_cont_memchain ch;
|
Chris@102
|
263 BOOST_CONTAINER_MEMCHAIN_INIT(&ch);
|
Chris@102
|
264 if(BOOST_UNLIKELY(!boost_cont_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){
|
Chris@102
|
265 boost::container::throw_bad_alloc();
|
Chris@102
|
266 }
|
Chris@102
|
267 chain.incorporate_after( chain.before_begin()
|
Chris@102
|
268 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
|
Chris@102
|
269 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
|
Chris@102
|
270 , BOOST_CONTAINER_MEMCHAIN_SIZE(&ch));
|
Chris@102
|
271 }
|
Chris@102
|
272
|
Chris@102
|
273 //!Allocates n_elements elements, each one of size elem_sizes[i]
|
Chris@102
|
274 //!Elements must be individually deallocated with deallocate()
|
Chris@102
|
275 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
|
Chris@102
|
276 {
|
Chris@102
|
277 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
278 boost_cont_memchain ch;
|
Chris@102
|
279 boost_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch);
|
Chris@102
|
280 if(BOOST_UNLIKELY(BOOST_CONTAINER_MEMCHAIN_EMPTY(&ch))){
|
Chris@102
|
281 boost::container::throw_bad_alloc();
|
Chris@102
|
282 }
|
Chris@102
|
283 chain.incorporate_after( chain.before_begin()
|
Chris@102
|
284 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
|
Chris@102
|
285 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
|
Chris@102
|
286 , BOOST_CONTAINER_MEMCHAIN_SIZE(&ch));
|
Chris@102
|
287 }
|
Chris@102
|
288
|
Chris@102
|
289 void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
290 {
|
Chris@102
|
291 BOOST_STATIC_ASSERT(( Version > 1 ));
|
Chris@102
|
292 void *first = &*chain.begin();
|
Chris@102
|
293 void *last = &*chain.last();
|
Chris@102
|
294 size_t num = chain.size();
|
Chris@102
|
295 boost_cont_memchain ch;
|
Chris@102
|
296 BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, first, last, num);
|
Chris@102
|
297 boost_cont_multidealloc(&ch);
|
Chris@102
|
298 }
|
Chris@102
|
299
|
Chris@102
|
300 //!Swaps allocators. Does not throw. If each allocator is placed in a
|
Chris@102
|
301 //!different memory segment, the result is undefined.
|
Chris@102
|
302 friend void swap(self_t &, self_t &) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
303 {}
|
Chris@102
|
304
|
Chris@102
|
305 //!An allocator always compares to true, as memory allocated with one
|
Chris@102
|
306 //!instance can be deallocated by another instance
|
Chris@102
|
307 friend bool operator==(const node_allocator &, const node_allocator &) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
308 { return true; }
|
Chris@102
|
309
|
Chris@102
|
310 //!An allocator always compares to false, as memory allocated with one
|
Chris@102
|
311 //!instance can be deallocated by another instance
|
Chris@102
|
312 friend bool operator!=(const node_allocator &, const node_allocator &) BOOST_NOEXCEPT_OR_NOTHROW
|
Chris@102
|
313 { return false; }
|
Chris@102
|
314
|
Chris@102
|
315 private:
|
Chris@102
|
316 pointer priv_allocation_command
|
Chris@102
|
317 (allocation_type command, std::size_t limit_size
|
Chris@102
|
318 ,size_type &prefer_in_recvd_out_size
|
Chris@102
|
319 ,pointer &reuse)
|
Chris@102
|
320 {
|
Chris@102
|
321 std::size_t const preferred_size = prefer_in_recvd_out_size;
|
Chris@102
|
322 boost_cont_command_ret_t ret = {0 , 0};
|
Chris@102
|
323 if((limit_size > this->max_size()) | (preferred_size > this->max_size())){
|
Chris@102
|
324 return pointer();
|
Chris@102
|
325 }
|
Chris@102
|
326 std::size_t l_size = limit_size*sizeof(T);
|
Chris@102
|
327 std::size_t p_size = preferred_size*sizeof(T);
|
Chris@102
|
328 std::size_t r_size;
|
Chris@102
|
329 {
|
Chris@102
|
330 void* reuse_ptr_void = reuse;
|
Chris@102
|
331 ret = boost_cont_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void);
|
Chris@102
|
332 reuse = static_cast<T*>(reuse_ptr_void);
|
Chris@102
|
333 }
|
Chris@102
|
334 prefer_in_recvd_out_size = r_size/sizeof(T);
|
Chris@102
|
335 return (pointer)ret.first;
|
Chris@102
|
336 }
|
Chris@102
|
337 };
|
Chris@102
|
338
|
Chris@102
|
339 } //namespace container {
|
Chris@102
|
340 } //namespace boost {
|
Chris@102
|
341
|
Chris@102
|
342 #include <boost/container/detail/config_end.hpp>
|
Chris@102
|
343
|
Chris@102
|
344 #endif //#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
|