issue#11: cds: changed __CDS_ guard prefix to CDSLIB_ for all .h files
[libcds.git] / cds / details / allocator.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_DETAILS_ALLOCATOR_H
4 #define CDSLIB_DETAILS_ALLOCATOR_H
5
6 #include <type_traits>
7 #include <memory>
8 #include <cds/details/defs.h>
9 #include <cds/user_setup/allocator.h>
10
11 namespace cds {
12     namespace details {
13
14         /// Extends \p std::allocator interface to provide semantics like operator \p new and \p delete
15         /**
16             The class is the wrapper around underlying \p Alloc class.
17             \p Alloc provides the \p std::allocator interface.
18         */
19         template <typename T, class Alloc = CDS_DEFAULT_ALLOCATOR >
20         class Allocator
21             : public std::conditional<
22                         std::is_same< T, typename Alloc::value_type>::value
23                         , Alloc
24                         , typename Alloc::template rebind<T>::other
25                      >::type
26         {
27         public:
28             /// Underlying allocator type
29             typedef typename std::conditional<
30                 std::is_same< T, typename Alloc::value_type>::value
31                 , Alloc
32                 , typename Alloc::template rebind<T>::other
33             >::type allocator_type;
34
35             /// Element type
36             typedef T   value_type;
37
38             /// Analogue of operator new T(\p src... )
39             template <typename... S>
40             value_type *  New( S const&... src )
41             {
42                 return Construct( allocator_type::allocate(1), src... );
43             }
44
45             /// Analogue of <tt>operator new T( std::forward<Args>(args)... )</tt> (move semantics)
46             template <typename... Args>
47             value_type * MoveNew( Args&&... args )
48             {
49                 return MoveConstruct( allocator_type::allocate(1), std::forward<Args>(args)... );
50             }
51
52             /// Analogue of operator new T[\p nCount ]
53             value_type * NewArray( size_t nCount )
54             {
55                 value_type * p = allocator_type::allocate( nCount );
56                 for ( size_t i = 0; i < nCount; ++i )
57                     Construct( p + i );
58                 return p;
59             }
60
61             /// Analogue of operator new T[\p nCount ].
62             /**
63                 Each item of array of type T is initialized by parameter \p src: T( src )
64             */
65             template <typename S>
66             value_type * NewArray( size_t nCount, S const& src )
67             {
68                 value_type * p = allocator_type::allocate( nCount );
69                 for ( size_t i = 0; i < nCount; ++i )
70                     Construct( p + i, src );
71                 return p;
72             }
73
74 #       if CDS_COMPILER == CDS_COMPILER_INTEL
75             //@cond
76             value_type * NewBlock( size_t nSize )
77             {
78                 return Construct( heap_alloc( nSize ));
79             }
80             //@endcond
81 #       endif
82             /// Allocates block of memory of size at least \p nSize bytes.
83             /**
84                 Internally, the block is allocated as an array of \p void* pointers,
85                 then \p Construct() method is called to initialize \p T.
86
87                 Precondition: <tt> nSize >= sizeof(T) </tt>
88             */
89             template <typename... S>
90             value_type *  NewBlock( size_t nSize, S const&... src )
91             {
92                 return Construct( heap_alloc( nSize ), src... );
93             }
94
95             /// Analogue of operator delete
96             void Delete( value_type * p )
97             {
98                 allocator_type::destroy( p );
99                 allocator_type::deallocate( p, 1 );
100             }
101
102             /// Analogue of operator delete []
103             void Delete( value_type * p, size_t nCount )
104             {
105                  for ( size_t i = 0; i < nCount; ++i )
106                      allocator_type::destroy( p + i );
107                 allocator_type::deallocate( p, nCount );
108             }
109
110 #       if CDS_COMPILER == CDS_COMPILER_INTEL
111             //@cond
112             value_type * Construct( void * p )
113             {
114                 return new( p ) value_type;
115             }
116             //@endcond
117 #       endif
118             /// Analogue of placement operator new( \p p ) T( src... )
119             template <typename... S>
120             value_type * Construct( void * p, S const&... src )
121             {
122                 return new( p ) value_type( src... );
123             }
124
125             /// Analogue of placement <tt>operator new( p ) T( std::forward<Args>(args)... )</tt>
126             template <typename... Args>
127             value_type * MoveConstruct( void * p, Args&&... args )
128             {
129                 return new( p ) value_type( std::forward<Args>(args)... );
130             }
131
132             /// Rebinds allocator to other type \p Q instead of \p T
133             template <typename Q>
134             struct rebind {
135                 typedef Allocator< Q, typename Alloc::template rebind<Q>::other >    other ; ///< Rebinding result
136             };
137
138         private:
139             //@cond
140             void * heap_alloc( size_t nByteSize )
141             {
142                 assert( nByteSize >= sizeof(value_type));
143
144                 size_t const nPtrSize = ( nByteSize + sizeof(void *) - 1 ) / sizeof(void *);
145                 typedef typename allocator_type::template rebind< void * >::other void_allocator;
146                 return void_allocator().allocate( nPtrSize );
147             }
148             //@endcond
149         };
150
151         /// Deferral removing of the object of type \p T. Helper class
152         template <typename T, typename Alloc = CDS_DEFAULT_ALLOCATOR>
153         struct deferral_deleter {
154             typedef T           type            ; ///< Type
155             typedef Alloc       allocator_type  ; ///< Allocator for removing
156
157             /// Frees the object \p p
158             /**
159                 Caveats: this function uses temporary object of type \ref cds::details::Allocator to free the node \p p.
160                 So, the node allocator should be stateless. It is standard requirement for \p std::allocator class objects.
161
162                 Do not use this function directly.
163             */
164             static void free( T * p )
165             {
166                 Allocator<T, Alloc> a;
167                 a.Delete( p );
168             }
169         };
170
171     }    // namespace details
172 }    // namespace cds
173
174 #endif    // #ifndef CDSLIB_DETAILS_ALLOCATOR_H