ee7f0302a067adbfa92937b771cdb2709585b55b
[libcds.git] / cds / details / allocator.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_DETAILS_ALLOCATOR_H
32 #define CDSLIB_DETAILS_ALLOCATOR_H
33
34 #include <type_traits>
35 #include <memory>
36 #include <cds/details/defs.h>
37 #include <cds/user_setup/allocator.h>
38
39 namespace cds {
40     namespace details {
41
42         /// Extends \p std::allocator interface to provide semantics like operator \p new and \p delete
43         /**
44             The class is the wrapper around underlying \p Alloc class.
45             \p Alloc provides the \p std::allocator interface.
46         */
47         template <typename T, class Alloc = CDS_DEFAULT_ALLOCATOR >
48         class Allocator
49             : public std::conditional<
50                         std::is_same< T, typename Alloc::value_type>::value
51                         , Alloc
52                         , typename Alloc::template rebind<T>::other
53                      >::type
54         {
55         public:
56             /// Underlying allocator type
57             typedef typename std::conditional<
58                 std::is_same< T, typename Alloc::value_type>::value
59                 , Alloc
60                 , typename Alloc::template rebind<T>::other
61             >::type allocator_type;
62
63             /// \p true if underlined allocator is \p std::allocator, \p false otherwise
64             static CDS_CONSTEXPR bool const c_bStdAllocator = std::is_same< allocator_type, std::allocator<T>>::value;
65
66             /// Element type
67             typedef T   value_type;
68
69             /// Analogue of operator new T(\p src... )
70             template <typename... S>
71             value_type *  New( S const&... src )
72             {
73                 return Construct( allocator_type::allocate(1), src... );
74             }
75
76             /// Analogue of <tt>operator new T( std::forward<Args>(args)... )</tt> (move semantics)
77             template <typename... Args>
78             value_type * MoveNew( Args&&... args )
79             {
80                 return MoveConstruct( allocator_type::allocate(1), std::forward<Args>(args)... );
81             }
82
83             /// Analogue of operator new T[\p nCount ]
84             value_type * NewArray( size_t nCount )
85             {
86                 value_type * p = allocator_type::allocate( nCount );
87                 for ( size_t i = 0; i < nCount; ++i )
88                     Construct( p + i );
89                 return p;
90             }
91
92             /// Analogue of operator new T[\p nCount ].
93             /**
94                 Each item of array of type T is initialized by parameter \p src: T( src )
95             */
96             template <typename S>
97             value_type * NewArray( size_t nCount, S const& src )
98             {
99                 value_type * p = allocator_type::allocate( nCount );
100                 for ( size_t i = 0; i < nCount; ++i )
101                     Construct( p + i, src );
102                 return p;
103             }
104
105 #       if CDS_COMPILER == CDS_COMPILER_INTEL
106             //@cond
107             value_type * NewBlock( size_t nSize )
108             {
109                 return Construct( heap_alloc( nSize ));
110             }
111             //@endcond
112 #       endif
113             /// Allocates block of memory of size at least \p nSize bytes.
114             /**
115                 Internally, the block is allocated as an array of \p void* pointers,
116                 then \p Construct() method is called to initialize \p T.
117
118                 Precondition: <tt> nSize >= sizeof(T) </tt>
119             */
120             template <typename... S>
121             value_type *  NewBlock( size_t nSize, S const&... src )
122             {
123                 return Construct( heap_alloc( nSize ), src... );
124             }
125
126             /// Analogue of operator delete
127             void Delete( value_type * p )
128             {
129                 allocator_type::destroy( p );
130                 allocator_type::deallocate( p, 1 );
131             }
132
133             /// Analogue of operator delete []
134             void Delete( value_type * p, size_t nCount )
135             {
136                  for ( size_t i = 0; i < nCount; ++i )
137                      allocator_type::destroy( p + i );
138                 allocator_type::deallocate( p, nCount );
139             }
140
141 #       if CDS_COMPILER == CDS_COMPILER_INTEL
142             //@cond
143             value_type * Construct( void * p )
144             {
145                 return new( p ) value_type;
146             }
147             //@endcond
148 #       endif
149             /// Analogue of placement operator new( \p p ) T( src... )
150             template <typename... S>
151             value_type * Construct( void * p, S const&... src )
152             {
153                 value_type * pv = new( p ) value_type( src... );
154                 return pv;
155             }
156
157             /// Analogue of placement <tt>operator new( p ) T( std::forward<Args>(args)... )</tt>
158             template <typename... Args>
159             value_type * MoveConstruct( void * p, Args&&... args )
160             {
161                 value_type * pv = new( p ) value_type( std::forward<Args>(args)... );
162                 return pv;
163             }
164
165             /// Rebinds allocator to other type \p Q instead of \p T
166             template <typename Q>
167             struct rebind {
168                 typedef Allocator< Q, typename Alloc::template rebind<Q>::other >    other ; ///< Rebinding result
169             };
170
171         private:
172             //@cond
173             void * heap_alloc( size_t nByteSize )
174             {
175                 assert( nByteSize >= sizeof(value_type));
176
177                 size_t const nPtrSize = ( nByteSize + sizeof(void *) - 1 ) / sizeof(void *);
178                 typedef typename allocator_type::template rebind< void * >::other void_allocator;
179                 return void_allocator().allocate( nPtrSize );
180             }
181             //@endcond
182         };
183
184         /// Deferral removing of the object of type \p T. Helper class
185         template <typename T, typename Alloc = CDS_DEFAULT_ALLOCATOR>
186         struct deferral_deleter {
187             typedef T           type            ; ///< Type
188             typedef Alloc       allocator_type  ; ///< Allocator for removing
189
190             /// Frees the object \p p
191             /**
192                 Caveats: this function uses temporary object of type \ref cds::details::Allocator to free the node \p p.
193                 So, the node allocator should be stateless. It is standard requirement for \p std::allocator class objects.
194
195                 Do not use this function directly.
196             */
197             static void free( T * p )
198             {
199                 Allocator<type, allocator_type> a;
200                 a.Delete( p );
201             }
202         };
203
204     }    // namespace details
205 }    // namespace cds
206
207 #endif    // #ifndef CDSLIB_DETAILS_ALLOCATOR_H