3 #ifndef __CDS_MEMORY_VYUKOV_QUEUE_ALLOCATOR_H
4 #define __CDS_MEMORY_VYUKOV_QUEUE_ALLOCATOR_H
6 #include <cds/details/allocator.h>
7 #include <cds/intrusive/vyukov_mpmc_cycle_queue.h>
9 namespace cds { namespace memory {
11 /// Free-list based on bounded lock-free queue cds::intrusive::VyukovMPMCCycleQueue
12 /** @ingroup cds_memory_pool
14 - \p T - the type of object maintaining by free-list
15 - \p Options - the options of cds::intrusive::VyukovMPMCCycleQueue class plus
16 cds::opt::allocator option.
20 This free-list is very simple.
21 At construction time, the free-list allocates the array of N items
22 and stores them into queue, where N is the queue capacity.
23 When allocating the free-list tries to pop an object from
24 internal queue i.e. from preallocated pool. If success the popped object is returned.
25 Otherwise a new one is allocated. When deallocating, the free-list checks whether
26 the object is from preallocated pool. If so, the object is pushed into queue, otherwise
27 it is deallocated by using the allocator provided.
28 The pool can manage more than \p N items but only \p N items is contained in the free-list.
32 \p %vyukov_queue_pool should be used together with \ref pool_allocator.
33 You should declare an static object of type \p %vyukov_queue_pool, provide
34 an accessor to that object and use \p pool_allocator as an allocator:
36 #include <cds/memory/vyukov_queue_pool.h>
37 #include <cds/memory/pool_allocator.h>
39 // Pool of Foo object of size 1024.
40 typedef cds::memory::vyukov_queue_pool< Foo, cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > > pool_type;
41 static pool_type thePool;
43 struct pool_accessor {
44 typedef typename pool_type::value_type value_type;
46 pool_type& operator()() const
52 // Declare pool allocator
53 typedef cds::memory::pool_allocator< Foo, pool_accessor > pool_allocator;
57 Foo * p = pool_allocator().allocate( 1 );
68 pool_allocator().deallocate( p , 1 );
71 template <typename T, CDS_DECL_OPTIONS6>
72 class vyukov_queue_pool
75 typedef cds::intrusive::VyukovMPMCCycleQueue< T, CDS_OPTIONS6 > queue_type ; ///< Queue type
79 struct default_options: public queue_type::options
81 typedef CDS_DEFAULT_ALLOCATOR allocator;
83 typedef typename opt::make_options< default_options, CDS_OPTIONS6 >::type options;
87 typedef T value_type ; ///< Value type
88 typedef typename options::allocator::template rebind<value_type>::other allocator_type ; ///< allocator type
93 value_type * m_pFirst;
99 void preallocate_pool()
101 m_pFirst = allocator_type().allocate( m_Queue.capacity() );
102 m_pLast = m_pFirst + m_Queue.capacity();
104 for ( value_type * p = m_pFirst; p < m_pLast; ++p )
105 CDS_VERIFY( m_Queue.push( *p )) ; // must be true
108 bool from_pool( value_type * p ) const
110 return m_pFirst <= p && p < m_pLast;
115 /// Preallocates the pool of object
117 \p nCapacity argument is the queue capacity. It should be passed
118 if the queue is based on dynamically-allocated buffer.
119 See cds::intrusive::VyukovMPMCCycleQueue for explanation.
121 vyukov_queue_pool( size_t nCapacity = 0 )
122 : m_Queue( nCapacity )
127 /// Deallocates the pool.
131 allocator_type().deallocate( m_pFirst, m_Queue.capacity() );
134 /// Allocates an object from pool
136 The pool supports allocation only single object (\p n = 1).
137 If \p n > 1 the behaviour is undefined.
139 If the queue is not empty, the popped value is returned.
140 Otherwise, a new value allocated.
142 value_type * allocate( size_t n )
146 value_type * p = m_Queue.pop();
148 assert( from_pool(p) );
152 return allocator_type().allocate( n );
155 /// Deallocated the object \p p
157 The pool supports allocation only single object (\p n = 1).
158 If \p n > 1 the behaviour is undefined.
160 If \p p is from preallocated pool, it pushes into the queue.
161 Otherwise, \p p is deallocated by allocator provided.
163 void deallocate( value_type * p, size_t n )
168 if ( from_pool( p ) )
171 allocator_type().deallocate( p, n );
176 /// Lazy free-list based on bounded lock-free queue cds::intrusive::VyukovMPMCCycleQueue
177 /** @ingroup cds_memory_pool
179 - \p T - the type of object maintaining by free-list
180 - \p Options - the options of cds::intrusive::VyukovMPMCCycleQueue class plus
181 cds::opt::allocator option.
185 This free-list is very simple.
186 At construction time the pool is empty.
187 When allocating the free-list tries to pop an object from
188 internal queue. If success the popped object is returned.
189 Otherwise a new one is allocated.
190 When deallocating, the free-list tries to push the object into the pool.
191 If internal queue is full, the object is deallocated by using the allocator provided.
192 The pool can manage more than \p N items but only \p N items is placed in the free-list.
196 \p %lazy_vyukov_queue_pool should be used together with \ref pool_allocator.
197 You should declare an static object of type \p %lazy_vyukov_queue_pool, provide
198 an accessor functor to this object and use \p pool_allocator as an allocator:
200 #include <cds/memory/vyukov_queue_pool.h>
201 #include <cds/memory/pool_allocator.h>
203 // Pool of Foo object of size 1024.
204 typedef cds::memory::lazy_vyukov_queue_pool< Foo, cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > > pool_type;
205 static pool_type thePool( 1024 );
207 struct pool_accessor {
208 typedef typename pool_type::value_type value_type;
210 pool_type& operator()() const
216 // Declare pool allocator
217 typedef cds::memory::pool_allocator< Foo, pool_accessor > pool_allocator;
219 // Use pool_allocator
220 // Allocate an object
221 Foo * p = pool_allocator().allocate( 1 );
232 pool_allocator().deallocate( p , 1 );
236 template <typename T, CDS_DECL_OPTIONS6>
237 class lazy_vyukov_queue_pool
240 typedef cds::intrusive::VyukovMPMCCycleQueue< T, CDS_OPTIONS6 > queue_type ; ///< Queue type
244 struct default_options: public queue_type::options
246 typedef CDS_DEFAULT_ALLOCATOR allocator;
248 typedef typename opt::make_options< default_options, CDS_OPTIONS6 >::type options;
252 typedef T value_type ; ///< Value type
253 typedef typename options::allocator::template rebind<value_type>::other allocator_type ; ///< allocator type
261 /// Constructs empty pool
262 lazy_vyukov_queue_pool( size_t nCapacity = 0 )
263 : m_Queue( nCapacity )
266 /// Deallocates all objects from the pool
267 ~lazy_vyukov_queue_pool()
270 while ( !m_Queue.empty() ) {
271 value_type * p = m_Queue.pop();
272 a.deallocate( p, 1 );
276 /// Allocates an object from pool
278 The pool supports allocation only single object (\p n = 1).
279 If \p n > 1 the behaviour is undefined.
281 If the queue is not empty, the popped value is returned.
282 Otherwise, a new value allocated.
284 value_type * allocate( size_t n )
288 value_type * p = m_Queue.pop();
292 return allocator_type().allocate( n );
295 /// Deallocated the object \p p
297 The pool supports allocation only single object (\p n = 1).
298 If \p n > 1 the behaviour is undefined.
300 If the queue is not full, \p p is pushed into the queue.
301 Otherwise, \p p is deallocated by allocator provided.
303 void deallocate( value_type * p, size_t n )
308 if ( !m_Queue.push( *p ))
309 allocator_type().deallocate( p, n );
315 /// Bounded free-list based on bounded lock-free queue cds::intrusive::VyukovMPMCCycleQueue
316 /** @ingroup cds_memory_pool
318 - \p T - the type of object maintaining by free-list
319 - \p Options - the options of cds::intrusive::VyukovMPMCCycleQueue class plus
320 cds::opt::allocator option.
324 At construction time, the free-list allocates the array of N items
325 and stores them into queue, where N is the queue capacity.
326 When allocating the free-list tries to pop an object from
327 internal queue i.e. from preallocated pool. If success the popped object is returned.
328 Otherwise a \p std::bad_alloc exception is raised.
329 So, the pool can contain up to \p N items.
330 When deallocating, the object is pushed into queue.
331 In debug mode the \ref deallocate member function asserts
332 that the pointer is from preallocated pool.
336 \p %bounded_vyukov_queue_pool should be used together with \ref pool_allocator.
337 You should declare an static object of type \p %bounded_vyukov_queue_pool, provide
338 an accessor functor to this object and use \p pool_allocator as an allocator:
340 #include <cds/memory/vyukov_queue_pool.h>
341 #include <cds/memory/pool_allocator.h>
343 // Pool of Foo object of size 1024.
344 typedef cds::memory::bounded_vyukov_queue_pool< Foo, cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > > pool_type;
345 static pool_type thePool;
347 struct pool_accessor {
348 typedef typename pool_type::value_type value_type;
350 pool_type& operator()() const
356 // Declare pool allocator
357 typedef cds::memory::pool_allocator< Foo, pool_accessor > pool_allocator;
359 // Use pool_allocator
360 // Allocate an object
361 Foo * p = pool_allocator().allocate( 1 );
372 pool_allocator().deallocate( p , 1 );
375 template <typename T, CDS_DECL_OPTIONS6>
376 class bounded_vyukov_queue_pool
379 typedef cds::intrusive::VyukovMPMCCycleQueue< T, CDS_OPTIONS6 > queue_type ; ///< Queue type
383 struct default_options: public queue_type::options
385 typedef CDS_DEFAULT_ALLOCATOR allocator;
387 typedef typename opt::make_options< default_options, CDS_OPTIONS6 >::type options;
391 typedef T value_type ; ///< Value type
392 typedef typename options::allocator::template rebind<value_type>::other allocator_type ; ///< allocator type
397 value_type * m_pFirst;
398 value_type * m_pLast;
403 void preallocate_pool()
405 m_pFirst = allocator_type().allocate( m_Queue.capacity() );
406 m_pLast = m_pFirst + m_Queue.capacity();
408 for ( value_type * p = m_pFirst; p < m_pLast; ++p )
409 CDS_VERIFY( m_Queue.push( *p )) ; // must be true
412 bool from_pool( value_type * p ) const
414 return m_pFirst <= p && p < m_pLast;
419 /// Preallocates the pool of object
421 \p nCapacity argument is the queue capacity. It should be passed
422 if the queue is based on dynamically-allocated buffer.
423 See cds::intrusive::VyukovMPMCCycleQueue for explanation.
425 bounded_vyukov_queue_pool( size_t nCapacity = 0 )
426 : m_Queue( nCapacity )
431 /// Deallocates the pool.
432 ~bounded_vyukov_queue_pool()
435 allocator_type().deallocate( m_pFirst, m_Queue.capacity() );
438 /// Allocates an object from pool
440 The pool supports allocation only single object (\p n = 1).
441 If \p n > 1 the behaviour is undefined.
443 If the queue is not empty, the popped value is returned.
444 Otherwise, a \p std::bad_alloc exception is raised.
446 value_type * allocate( size_t n )
450 value_type * p = m_Queue.pop();
452 assert( from_pool(p) );
456 throw std::bad_alloc();
459 /// Deallocated the object \p p
461 The pool supports allocation only single object (\p n = 1).
462 If \p n > 1 the behaviour is undefined.
464 \p should be from preallocated pool.
466 void deallocate( value_type * p, size_t n )
471 assert( from_pool( p ));
478 }} // namespace cds::memory
481 #endif // #ifndef __CDS_MEMORY_VYUKOV_QUEUE_ALLOCATOR_H