Fixed make_comparator metafunction
[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             /// \p true if underlined allocator is \p std::allocator, \p false otherwise
36             static CDS_CONSTEXPR bool const c_bStdAllocator = std::is_same< allocator_type, std::allocator<T>>::value;
37
38             /// Element type
39             typedef T   value_type;
40
41             /// Analogue of operator new T(\p src... )
42             template <typename... S>
43             value_type *  New( S const&... src )
44             {
45                 return Construct( allocator_type::allocate(1), src... );
46             }
47
48             /// Analogue of <tt>operator new T( std::forward<Args>(args)... )</tt> (move semantics)
49             template <typename... Args>
50             value_type * MoveNew( Args&&... args )
51             {
52                 return MoveConstruct( allocator_type::allocate(1), std::forward<Args>(args)... );
53             }
54
55             /// Analogue of operator new T[\p nCount ]
56             value_type * NewArray( size_t nCount )
57             {
58                 value_type * p = allocator_type::allocate( nCount );
59                 for ( size_t i = 0; i < nCount; ++i )
60                     Construct( p + i );
61                 return p;
62             }
63
64             /// Analogue of operator new T[\p nCount ].
65             /**
66                 Each item of array of type T is initialized by parameter \p src: T( src )
67             */
68             template <typename S>
69             value_type * NewArray( size_t nCount, S const& src )
70             {
71                 value_type * p = allocator_type::allocate( nCount );
72                 for ( size_t i = 0; i < nCount; ++i )
73                     Construct( p + i, src );
74                 return p;
75             }
76
77 #       if CDS_COMPILER == CDS_COMPILER_INTEL
78             //@cond
79             value_type * NewBlock( size_t nSize )
80             {
81                 return Construct( heap_alloc( nSize ));
82             }
83             //@endcond
84 #       endif
85             /// Allocates block of memory of size at least \p nSize bytes.
86             /**
87                 Internally, the block is allocated as an array of \p void* pointers,
88                 then \p Construct() method is called to initialize \p T.
89
90                 Precondition: <tt> nSize >= sizeof(T) </tt>
91             */
92             template <typename... S>
93             value_type *  NewBlock( size_t nSize, S const&... src )
94             {
95                 return Construct( heap_alloc( nSize ), src... );
96             }
97
98             /// Analogue of operator delete
99             void Delete( value_type * p )
100             {
101                 allocator_type::destroy( p );
102                 allocator_type::deallocate( p, 1 );
103             }
104
105             /// Analogue of operator delete []
106             void Delete( value_type * p, size_t nCount )
107             {
108                  for ( size_t i = 0; i < nCount; ++i )
109                      allocator_type::destroy( p + i );
110                 allocator_type::deallocate( p, nCount );
111             }
112
113 #       if CDS_COMPILER == CDS_COMPILER_INTEL
114             //@cond
115             value_type * Construct( void * p )
116             {
117                 return new( p ) value_type;
118             }
119             //@endcond
120 #       endif
121             /// Analogue of placement operator new( \p p ) T( src... )
122             template <typename... S>
123             value_type * Construct( void * p, S const&... src )
124             {
125                 value_type * pv = new( p ) value_type( src... );
126                 return pv;
127             }
128
129             /// Analogue of placement <tt>operator new( p ) T( std::forward<Args>(args)... )</tt>
130             template <typename... Args>
131             value_type * MoveConstruct( void * p, Args&&... args )
132             {
133                 value_type * pv = new( p ) value_type( std::forward<Args>(args)... );
134                 return pv;
135             }
136
137             /// Rebinds allocator to other type \p Q instead of \p T
138             template <typename Q>
139             struct rebind {
140                 typedef Allocator< Q, typename Alloc::template rebind<Q>::other >    other ; ///< Rebinding result
141             };
142
143         private:
144             //@cond
145             void * heap_alloc( size_t nByteSize )
146             {
147                 assert( nByteSize >= sizeof(value_type));
148
149                 size_t const nPtrSize = ( nByteSize + sizeof(void *) - 1 ) / sizeof(void *);
150                 typedef typename allocator_type::template rebind< void * >::other void_allocator;
151                 return void_allocator().allocate( nPtrSize );
152             }
153             //@endcond
154         };
155
156         /// Deferral removing of the object of type \p T. Helper class
157         template <typename T, typename Alloc = CDS_DEFAULT_ALLOCATOR>
158         struct deferral_deleter {
159             typedef T           type            ; ///< Type
160             typedef Alloc       allocator_type  ; ///< Allocator for removing
161
162             /// Frees the object \p p
163             /**
164                 Caveats: this function uses temporary object of type \ref cds::details::Allocator to free the node \p p.
165                 So, the node allocator should be stateless. It is standard requirement for \p std::allocator class objects.
166
167                 Do not use this function directly.
168             */
169             static void free( T * p )
170             {
171                 Allocator<type, allocator_type> a;
172                 a.Delete( p );
173             }
174         };
175
176     }    // namespace details
177 }    // namespace cds
178
179 #endif    // #ifndef CDSLIB_DETAILS_ALLOCATOR_H