Remove CDS_RVALUE_SUPPORT, CDS_MOVE_SEMANTICS_SUPPORT macros and emulating code
[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 <type_traits>
14 #include <memory>
15 #include <cds/details/defs.h>
16 #include <cds/user_setup/allocator.h>
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             /// Analogue of operator new T(\p src... )
47             template <typename... S>
48             value_type *  New( S const&... src )
49             {
50                 return Construct( allocator_type::allocate(1), src... );
51             }
52
53 #       ifdef CDS_EMPLACE_SUPPORT
54             /// Analogue of <tt>operator new T( std::forward<Args>(args)... )</tt> (move semantics)
55             /**
56                 This function is available only for compiler that supports
57                 variadic template and move semantics
58             */
59             template <typename... Args>
60             value_type * MoveNew( Args&&... args )
61             {
62                 return MoveConstruct( allocator_type::allocate(1), std::forward<Args>(args)... );
63             }
64 #       endif
65
66
67             /// Analogue of operator new T[\p nCount ]
68             value_type * NewArray( size_t nCount )
69             {
70                 value_type * p = allocator_type::allocate( nCount );
71                 for ( size_t i = 0; i < nCount; ++i )
72                     Construct( p + i );
73                 return p;
74             }
75
76             /// Analogue of operator new T[\p nCount ].
77             /**
78                 Each item of array of type T is initialized by parameter \p src: T( src )
79             */
80             template <typename S>
81             value_type * NewArray( size_t nCount, S const& src )
82             {
83                 value_type * p = allocator_type::allocate( nCount );
84                 for ( size_t i = 0; i < nCount; ++i )
85                     Construct( p + i, src );
86                 return p;
87             }
88
89 #       if CDS_COMPILER == CDS_COMPILER_INTEL
90             //@cond
91             value_type * NewBlock( size_t nSize )
92             {
93                 return Construct( heap_alloc( nSize ));
94             }
95             //@endcond
96 #       endif
97             /// Allocates block of memory of size at least \p nSize bytes.
98             /**
99                 Internally, the block is allocated as an array of \p void* pointers,
100                 then \p Construct() method is called to initialize \p T.
101
102                 Precondition: <tt> nSize >= sizeof(T) </tt>
103             */
104             template <typename... S>
105             value_type *  NewBlock( size_t nSize, S const&... src )
106             {
107                 return Construct( heap_alloc( nSize ), src... );
108             }
109
110             /// Analogue of operator delete
111             void Delete( value_type * p )
112             {
113                 allocator_type::destroy( p );
114                 allocator_type::deallocate( p, 1 );
115             }
116
117             /// Analogue of operator delete []
118             void Delete( value_type * p, size_t nCount )
119             {
120                  for ( size_t i = 0; i < nCount; ++i )
121                      allocator_type::destroy( p + i );
122                 allocator_type::deallocate( p, nCount );
123             }
124
125 #       if CDS_COMPILER == CDS_COMPILER_INTEL
126             //@cond
127             value_type * Construct( void * p )
128             {
129                 return new( p ) value_type;
130             }
131             //@endcond
132 #       endif
133             /// Analogue of placement operator new( \p p ) T( src... )
134             template <typename... S>
135             value_type * Construct( void * p, S const&... src )
136             {
137                 return new( p ) value_type( src... );
138             }
139
140 #       ifdef CDS_EMPLACE_SUPPORT
141             /// Analogue of placement <tt>operator new( p ) T( std::forward<Args>(args)... )</tt>
142             /**
143                 This function is available only for compiler that supports
144                 variadic template and move semantics
145             */
146             template <typename... Args>
147             value_type * MoveConstruct( void * p, Args&&... args )
148             {
149                 return new( p ) value_type( std::forward<Args>(args)... );
150             }
151 #       endif
152
153             /// Rebinds allocator to other type \p Q instead of \p T
154             template <typename Q>
155             struct rebind {
156                 typedef Allocator< Q, typename Alloc::template rebind<Q>::other >    other ; ///< Rebinding result
157             };
158
159         private:
160             //@cond
161             void * heap_alloc( size_t nByteSize )
162             {
163                 assert( nByteSize >= sizeof(value_type));
164
165                 size_t const nPtrSize = ( nByteSize + sizeof(void *) - 1 ) / sizeof(void *);
166                 typedef typename allocator_type::template rebind< void * >::other void_allocator;
167                 return void_allocator().allocate( nPtrSize );
168             }
169             //@endcond
170         };
171
172         //@cond
173         namespace {
174             template <class T>
175             static inline void impl_call_dtor(T* p, boost::false_type const&)
176             {
177                 p->T::~T();
178             }
179
180             template <class T>
181             static inline void impl_call_dtor(T* p, boost::true_type const&)
182             {}
183         }
184         //@endcond
185
186         /// Helper function to call destructor of type T
187         /**
188             This function is empty for the type T that has trivial destructor.
189         */
190         template <class T>
191         static inline void call_dtor( T* p )
192         {
193             impl_call_dtor( p, ::boost::has_trivial_destructor<T>() );
194         }
195
196
197         /// Deferral removing of the object of type \p T. Helper class
198         template <typename T, typename Alloc = CDS_DEFAULT_ALLOCATOR>
199         struct deferral_deleter {
200             typedef T           type            ; ///< Type
201             typedef Alloc       allocator_type  ; ///< Allocator for removing
202
203             /// Frees the object \p p
204             /**
205                 Caveats: this function uses temporary object of type \ref cds::details::Allocator to free the node \p p.
206                 So, the node allocator should be stateless. It is standard requirement for \p std::allocator class objects.
207
208                 Do not use this function directly.
209             */
210             static void free( T * p )
211             {
212                 Allocator<T, Alloc> a;
213                 a.Delete( p );
214             }
215         };
216
217     }    // namespace details
218 }    // namespace cds
219
220 #endif    // #ifndef __CDS_DETAILS_ALLOCATOR_H