1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2008-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)
7 // See http://www.boost.org/libs/container for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
12 #define BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/container/detail/config_begin.hpp>
19 #include <boost/container/detail/workaround.hpp>
20 #include <boost/container/container_fwd.hpp>
21 #include <boost/container/throw_exception.hpp>
22 #include <boost/container/detail/node_pool.hpp>
23 #include <boost/container/detail/mpl.hpp>
24 #include <boost/container/detail/multiallocation_chain.hpp>
25 #include <boost/container/detail/alloc_lib_auto_link.hpp>
26 #include <boost/container/detail/singleton.hpp>
28 #include <boost/assert.hpp>
29 #include <boost/utility/addressof.hpp>
30 #include <boost/static_assert.hpp>
38 //!An STL node allocator that uses a modified DlMalloc as memory
41 //!This node allocator shares a segregated storage between all instances
42 //!of node_allocator with equal sizeof(T).
44 //!NodesPerBlock is the number of nodes allocated at once when the allocator
46 #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
49 , std::size_t NodesPerBlock = NodeAlloc_nodes_per_block>
53 , std::size_t NodesPerBlock
54 , std::size_t Version>
58 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
59 //! If Version is 1, the allocator is a STL conforming allocator. If Version is 2,
60 //! the allocator offers advanced expand in place and burst allocation capabilities.
62 typedef unsigned int allocation_type;
63 typedef node_allocator<T, NodesPerBlock, Version> self_t;
65 static const std::size_t nodes_per_block = NodesPerBlock;
67 BOOST_STATIC_ASSERT((Version <=2));
74 typedef const T * const_pointer;
75 typedef typename ::boost::container::
76 container_detail::unvoid<T>::type & reference;
77 typedef const typename ::boost::container::
78 container_detail::unvoid<T>::type & const_reference;
79 typedef std::size_t size_type;
80 typedef std::ptrdiff_t difference_type;
82 typedef boost::container::container_detail::
83 version_type<self_t, Version> version;
85 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
86 typedef boost::container::container_detail::
87 basic_multiallocation_chain<void*> multiallocation_chain_void;
88 typedef boost::container::container_detail::
89 transform_multiallocation_chain
90 <multiallocation_chain_void, T> multiallocation_chain;
91 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
93 //!Obtains node_allocator from
98 typedef node_allocator< T2, NodesPerBlock
99 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
105 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
107 //!Not assignable from related node_allocator
108 template<class T2, std::size_t N2>
109 node_allocator& operator=
110 (const node_allocator<T2, N2>&);
112 //!Not assignable from other node_allocator
113 node_allocator& operator=(const node_allocator&);
114 #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
118 //!Default constructor
119 node_allocator() BOOST_CONTAINER_NOEXCEPT
122 //!Copy constructor from other node_allocator.
123 node_allocator(const node_allocator &) BOOST_CONTAINER_NOEXCEPT
126 //!Copy constructor from related node_allocator.
129 (const node_allocator<T2, NodesPerBlock
130 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
133 > &) BOOST_CONTAINER_NOEXCEPT
137 ~node_allocator() BOOST_CONTAINER_NOEXCEPT
140 //!Returns the number of elements that could be allocated.
142 size_type max_size() const
143 { return size_type(-1)/sizeof(T); }
145 //!Allocate memory for an array of count elements.
146 //!Throws std::bad_alloc if there is no enough memory
147 pointer allocate(size_type count, const void * = 0)
149 if(count > this->max_size())
150 boost::container::throw_bad_alloc();
152 if(Version == 1 && count == 1){
153 typedef container_detail::shared_node_pool
154 <sizeof(T), NodesPerBlock> shared_pool_t;
155 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
156 return pointer(static_cast<T*>(singleton_t::instance().allocate_node()));
159 void *ret = boost_cont_malloc(count*sizeof(T));
161 boost::container::throw_bad_alloc();
162 return static_cast<pointer>(ret);
166 //!Deallocate allocated memory.
168 void deallocate(const pointer &ptr, size_type count) BOOST_CONTAINER_NOEXCEPT
171 if(Version == 1 && count == 1){
172 typedef container_detail::shared_node_pool
173 <sizeof(T), NodesPerBlock> shared_pool_t;
174 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
175 singleton_t::instance().deallocate_node(ptr);
178 boost_cont_free(ptr);
182 //!Deallocates all free blocks of the pool
183 static void deallocate_free_blocks() BOOST_CONTAINER_NOEXCEPT
185 typedef container_detail::shared_node_pool
186 <sizeof(T), NodesPerBlock> shared_pool_t;
187 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
188 singleton_t::instance().deallocate_free_blocks();
191 std::pair<pointer, bool>
192 allocation_command(allocation_type command,
193 size_type limit_size,
194 size_type preferred_size,
195 size_type &received_size, pointer reuse = pointer())
197 BOOST_STATIC_ASSERT(( Version > 1 ));
198 std::pair<pointer, bool> ret =
199 priv_allocation_command(command, limit_size, preferred_size, received_size, reuse);
200 if(!ret.first && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION))
201 boost::container::throw_bad_alloc();
205 //!Returns maximum the number of objects the previously allocated memory
206 //!pointed by p can hold.
207 size_type size(pointer p) const BOOST_CONTAINER_NOEXCEPT
209 BOOST_STATIC_ASSERT(( Version > 1 ));
210 return boost_cont_size(p);
213 //!Allocates just one object. Memory allocated with this function
214 //!must be deallocated only with deallocate_one().
215 //!Throws bad_alloc if there is no enough memory
216 pointer allocate_one()
218 BOOST_STATIC_ASSERT(( Version > 1 ));
219 typedef container_detail::shared_node_pool
220 <sizeof(T), NodesPerBlock> shared_pool_t;
221 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
222 return (pointer)singleton_t::instance().allocate_node();
225 //!Allocates many elements of size == 1.
226 //!Elements must be individually deallocated with deallocate_one()
227 void allocate_individual(std::size_t num_elements, multiallocation_chain &chain)
229 BOOST_STATIC_ASSERT(( Version > 1 ));
230 typedef container_detail::shared_node_pool
231 <sizeof(T), NodesPerBlock> shared_pool_t;
232 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
233 typename shared_pool_t::multiallocation_chain ch;
234 singleton_t::instance().allocate_nodes(num_elements, ch);
235 chain.incorporate_after(chain.before_begin(), (T*)&*ch.begin(), (T*)&*ch.last(), ch.size());
238 //!Deallocates memory previously allocated with allocate_one().
239 //!You should never use deallocate_one to deallocate memory allocated
240 //!with other functions different from allocate_one(). Never throws
241 void deallocate_one(pointer p) BOOST_CONTAINER_NOEXCEPT
243 BOOST_STATIC_ASSERT(( Version > 1 ));
244 typedef container_detail::shared_node_pool
245 <sizeof(T), NodesPerBlock> shared_pool_t;
246 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
247 singleton_t::instance().deallocate_node(p);
250 void deallocate_individual(multiallocation_chain &chain) BOOST_CONTAINER_NOEXCEPT
252 BOOST_STATIC_ASSERT(( Version > 1 ));
253 typedef container_detail::shared_node_pool
254 <sizeof(T), NodesPerBlock> shared_pool_t;
255 typedef container_detail::singleton_default<shared_pool_t> singleton_t;
256 typename shared_pool_t::multiallocation_chain ch(&*chain.begin(), &*chain.last(), chain.size());
257 singleton_t::instance().deallocate_nodes(ch);
260 //!Allocates many elements of size elem_size.
261 //!Elements must be individually deallocated with deallocate()
262 void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain)
264 BOOST_STATIC_ASSERT(( Version > 1 ));
265 boost_cont_memchain ch;
266 BOOST_CONTAINER_MEMCHAIN_INIT(&ch);
267 if(!boost_cont_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){
268 boost::container::throw_bad_alloc();
270 chain.incorporate_after( chain.before_begin()
271 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
272 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
273 , BOOST_CONTAINER_MEMCHAIN_SIZE(&ch));
276 //!Allocates n_elements elements, each one of size elem_sizes[i]
277 //!Elements must be individually deallocated with deallocate()
278 void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
280 BOOST_STATIC_ASSERT(( Version > 1 ));
281 boost_cont_memchain ch;
282 boost_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch);
283 if(BOOST_CONTAINER_MEMCHAIN_EMPTY(&ch)){
284 boost::container::throw_bad_alloc();
286 chain.incorporate_after( chain.before_begin()
287 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
288 , (T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch)
289 , BOOST_CONTAINER_MEMCHAIN_SIZE(&ch));
292 void deallocate_many(multiallocation_chain &chain) BOOST_CONTAINER_NOEXCEPT
294 BOOST_STATIC_ASSERT(( Version > 1 ));
295 void *first = &*chain.begin();
296 void *last = &*chain.last();
297 size_t num = chain.size();
298 boost_cont_memchain ch;
299 BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, first, last, num);
300 boost_cont_multidealloc(&ch);
303 //!Swaps allocators. Does not throw. If each allocator is placed in a
304 //!different memory segment, the result is undefined.
305 friend void swap(self_t &, self_t &) BOOST_CONTAINER_NOEXCEPT
308 //!An allocator always compares to true, as memory allocated with one
309 //!instance can be deallocated by another instance
310 friend bool operator==(const node_allocator &, const node_allocator &) BOOST_CONTAINER_NOEXCEPT
313 //!An allocator always compares to false, as memory allocated with one
314 //!instance can be deallocated by another instance
315 friend bool operator!=(const node_allocator &, const node_allocator &) BOOST_CONTAINER_NOEXCEPT
319 std::pair<pointer, bool> priv_allocation_command
320 (allocation_type command, std::size_t limit_size
321 ,std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr)
323 boost_cont_command_ret_t ret = {0 , 0};
324 if(limit_size > this->max_size() || preferred_size > this->max_size()){
326 return std::pair<pointer, bool>(pointer(), false);
328 std::size_t l_size = limit_size*sizeof(T);
329 std::size_t p_size = preferred_size*sizeof(T);
332 ret = boost_cont_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr);
334 received_size = r_size/sizeof(T);
335 return std::pair<pointer, bool>(static_cast<pointer>(ret.first), !!ret.second);
339 } //namespace container {
340 } //namespace boost {
342 #include <boost/container/detail/config_end.hpp>
344 #endif //#ifndef BOOST_CONTAINER_POOLED_NODE_ALLOCATOR_HPP