Move libcds 1.6.0 from SVN
[libcds.git] / cds / details / allocator.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_DETAILS_ALLOCATOR_H
4 #define __CDS_DETAILS_ALLOCATOR_H
5
6 /*
7     Allocator class for the library. Supports allocating and constructing of objects
8
9     Editions:
10         2008.03.08    Maxim.Khiszinsky    Created
11 */
12
13 #include <cds/details/defs.h>
14 #include <cds/user_setup/allocator.h>
15 #include <cds/details/std/type_traits.h>
16 #include <memory>
17 #include <boost/type_traits/has_trivial_destructor.hpp>
18
19 namespace cds {
20     namespace details {
21
22         /// Extends \p std::allocator interface to provide semantics like operator \p new and \p delete
23         /**
24             The class is the wrapper around underlying \p Alloc class.
25             \p Alloc provides the \p std::allocator interface.
26         */
27         template <typename T, class Alloc = CDS_DEFAULT_ALLOCATOR >
28         class Allocator
29             : public std::conditional<
30                         std::is_same< T, typename Alloc::value_type>::value
31                         , Alloc
32                         , typename Alloc::template rebind<T>::other
33                      >::type
34         {
35         public:
36             /// Underlying allocator type
37             typedef typename std::conditional<
38                 std::is_same< T, typename Alloc::value_type>::value
39                 , Alloc
40                 , typename Alloc::template rebind<T>::other
41             >::type allocator_type;
42
43             /// Element type
44             typedef T   value_type;
45
46 #       ifdef CDS_CXX11_VARIADIC_TEMPLATE_SUPPORT
47             /// Analogue of operator new T(\p src... )
48             template <typename... S>
49             value_type *  New( S const&... src )
50             {
51                 return Construct( allocator_type::allocate(1), src... );
52             }
53 #       else
54             //@cond
55             /// Analogue of operator new T
56             value_type *  New()
57             {
58                 return Construct( allocator_type::allocate(1) );
59             }
60
61             /// Analogue of operator new T(\p src )
62             template <typename S>
63             value_type *  New( S const& src )
64             {
65                 return Construct( allocator_type::allocate(1), src );
66             }
67
68             /// Analogue of operator new T( \p s1, \p s2 )
69             template <typename S1, typename S2>
70             value_type *  New( S1 const& s1, S2 const& s2 )
71             {
72                 return Construct( allocator_type::allocate(1), s1, s2 );
73             }
74
75             /// Analogue of operator new T( \p s1, \p s2, \p s3 )
76             template <typename S1, typename S2, typename S3>
77             value_type *  New( S1 const& s1, S2 const& s2, S3 const& s3 )
78             {
79                 return Construct( allocator_type::allocate(1), s1, s2, s3 );
80             }
81             //@endcond
82 #       endif
83
84 #       ifdef CDS_EMPLACE_SUPPORT
85             /// Analogue of <tt>operator new T( std::forward<Args>(args)... )</tt> (move semantics)
86             /**
87                 This function is available only for compiler that supports
88                 variadic template and move semantics
89             */
90             template <typename... Args>
91             value_type * MoveNew( Args&&... args )
92             {
93                 return MoveConstruct( allocator_type::allocate(1), std::forward<Args>(args)... );
94             }
95 #       endif
96
97
98             /// Analogue of operator new T[\p nCount ]
99             value_type * NewArray( size_t nCount )
100             {
101                 value_type * p = allocator_type::allocate( nCount );
102                 for ( size_t i = 0; i < nCount; ++i )
103                     Construct( p + i );
104                 return p;
105             }
106
107             /// Analogue of operator new T[\p nCount ].
108             /**
109                 Each item of array of type T is initialized by parameter \p src: T( src )
110             */
111             template <typename S>
112             value_type * NewArray( size_t nCount, S const& src )
113             {
114                 value_type * p = allocator_type::allocate( nCount );
115                 for ( size_t i = 0; i < nCount; ++i )
116                     Construct( p + i, src );
117                 return p;
118             }
119
120 #       ifdef CDS_CXX11_VARIADIC_TEMPLATE_SUPPORT
121 #       if CDS_COMPILER == CDS_COMPILER_INTEL
122             //@cond
123             value_type * NewBlock( size_t nSize )
124             {
125                 return Construct( heap_alloc( nSize ));
126             }
127             //@endcond
128 #       endif
129             /// Allocates block of memory of size at least \p nSize bytes.
130             /**
131                 Internally, the block is allocated as an array of \p void* pointers,
132                 then \p Construct() method is called to initialize \p T.
133
134                 Precondition: <tt> nSize >= sizeof(T) </tt>
135             */
136             template <typename... S>
137             value_type *  NewBlock( size_t nSize, S const&... src )
138             {
139                 return Construct( heap_alloc( nSize ), src... );
140             }
141 #       else
142             //@cond
143             value_type * NewBlock( size_t nSize )
144             {
145                 return Construct( heap_alloc( nSize ));
146             }
147             template <typename S>
148             value_type * NewBlock( size_t nSize, S const& arg )
149             {
150                 return Construct( heap_alloc( nSize ), arg );
151             }
152             template <typename S1, typename S2>
153             value_type * NewBlock( size_t nSize, S1 const& arg1, S2 const& arg2 )
154             {
155                 return Construct( heap_alloc( nSize ), arg1, arg2 );
156             }
157             template <typename S1, typename S2, typename S3>
158             value_type * NewBlock( size_t nSize, S1 const& arg1, S2 const& arg2, S3 const& arg3 )
159             {
160                 return Construct( heap_alloc( nSize ), arg1, arg2, arg3 );
161             }
162             //@endcond
163 #       endif
164
165             /// Analogue of operator delete
166             void Delete( value_type * p )
167             {
168                 allocator_type::destroy( p );
169                 allocator_type::deallocate( p, 1 );
170             }
171
172             /// Analogue of operator delete []
173             void Delete( value_type * p, size_t nCount )
174             {
175                  for ( size_t i = 0; i < nCount; ++i )
176                      allocator_type::destroy( p + i );
177                 allocator_type::deallocate( p, nCount );
178             }
179
180 #       ifdef CDS_CXX11_VARIADIC_TEMPLATE_SUPPORT
181 #       if CDS_COMPILER == CDS_COMPILER_INTEL
182             //@cond
183             value_type * Construct( void * p )
184             {
185                 return new( p ) value_type;
186             }
187             //@endcond
188 #       endif
189             /// Analogue of placement operator new( \p p ) T( src... )
190             template <typename... S>
191             value_type * Construct( void * p, S const&... src )
192             {
193                 return new( p ) value_type( src... );
194             }
195 #       else
196             //@cond
197             /// Analogue of placement operator new( \p p ) T
198             value_type * Construct( void * p )
199             {
200                 return new( p ) value_type;
201             }
202
203
204             /// Analogue of placement operator new( \p p ) T( \p src )
205             template <typename S>
206             value_type * Construct( void * p, S const& src )
207             {
208                 return new( p ) value_type( src );
209             }
210
211             /// Analogue of placement operator new( \p p ) T( \p s1, \p s2 )
212             template <typename S1, typename S2>
213             value_type *  Construct( void * p, S1 const& s1, S2 const& s2 )
214             {
215                 return new( p ) value_type( s1, s2 );
216             }
217
218             /// Analogue of placement operator new( \p p ) T( \p s1, \p s2, \p s3 )
219             template <typename S1, typename S2, typename S3>
220             value_type *  Construct( void * p, S1 const& s1, S2 const& s2, S3 const& s3 )
221             {
222                 return new( p ) value_type( s1, s2, s3 );
223             }
224             //@endcond
225 #       endif
226
227 #       ifdef CDS_EMPLACE_SUPPORT
228             /// Analogue of placement <tt>operator new( p ) T( std::forward<Args>(args)... )</tt>
229             /**
230                 This function is available only for compiler that supports
231                 variadic template and move semantics
232             */
233             template <typename... Args>
234             value_type * MoveConstruct( void * p, Args&&... args )
235             {
236                 return new( p ) value_type( std::forward<Args>(args)... );
237             }
238 #       endif
239
240             /// Rebinds allocator to other type \p Q instead of \p T
241             template <typename Q>
242             struct rebind {
243                 typedef Allocator< Q, typename Alloc::template rebind<Q>::other >    other ; ///< Rebinding result
244             };
245
246         private:
247             //@cond
248             void * heap_alloc( size_t nByteSize )
249             {
250                 assert( nByteSize >= sizeof(value_type));
251
252                 size_t const nPtrSize = ( nByteSize + sizeof(void *) - 1 ) / sizeof(void *);
253                 typedef typename allocator_type::template rebind< void * >::other void_allocator;
254                 return void_allocator().allocate( nPtrSize );
255             }
256             //@endcond
257         };
258
259         //@cond
260         namespace {
261             template <class T>
262             static inline void impl_call_dtor(T* p, boost::false_type const&)
263             {
264                 p->T::~T();
265             }
266
267             template <class T>
268             static inline void impl_call_dtor(T* p, boost::true_type const&)
269             {}
270         }
271         //@endcond
272
273         /// Helper function to call destructor of type T
274         /**
275             This function is empty for the type T that has trivial destructor.
276         */
277         template <class T>
278         static inline void call_dtor( T* p )
279         {
280             impl_call_dtor( p, ::boost::has_trivial_destructor<T>() );
281         }
282
283
284         /// Deferral removing of the object of type \p T. Helper class
285         template <typename T, typename Alloc = CDS_DEFAULT_ALLOCATOR>
286         struct deferral_deleter {
287             typedef T           type            ; ///< Type
288             typedef Alloc       allocator_type  ; ///< Allocator for removing
289
290             /// Frees the object \p p
291             /**
292                 Caveats: this function uses temporary object of type \ref cds::details::Allocator to free the node \p p.
293                 So, the node allocator should be stateless. It is standard requirement for \p std::allocator class objects.
294
295                 Do not use this function directly.
296             */
297             static void free( T * p )
298             {
299                 Allocator<T, Alloc> a;
300                 a.Delete( p );
301             }
302         };
303
304     }    // namespace details
305 }    // namespace cds
306
307 #endif    // #ifndef __CDS_DETAILS_ALLOCATOR_H