casacore
Loading...
Searching...
No Matches
Allocator.h
Go to the documentation of this file.
1//# Allocator.h:
2//# Copyright (C) 2015
3//# National Astronomical Observatory of Japan
4//# 2-21-1, Osawa, Mitaka, Tokyo, 181-8588, Japan.
5//#
6//# This library is free software; you can redistribute it and/or modify it
7//# under the terms of the GNU Library General Public License as published by
8//# the Free Software Foundation; either version 2 of the License, or (at your
9//# option) any later version.
10//#
11//# This library is distributed in the hope that it will be useful, but WITHOUT
12//# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13//# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14//# License for more details.
15//#
16//# You should have received a copy of the GNU Library General Public License
17//# along with this library; if not, write to the Free Software Foundation,
18//# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
19//#
20//# Correspondence concerning AIPS++ should be addressed as follows:
21//# Internet email: casa-feedback@nrao.edu.
22//# Postal address: AIPS++ Project Office
23//# National Radio Astronomy Observatory
24//# 520 Edgemont Road
25//# Charlottesville, VA 22903-2475 USA
26
27#ifndef CASA_CONTAINERS_ALLOCATOR_H_
28#define CASA_CONTAINERS_ALLOCATOR_H_
29
30#include <casacore/casa/config.h>
31#include <casacore/casa/aips.h>
32#include <casacore/casa/Utilities/DataType.h>
33#include <casacore/casa/Arrays/ArrayFwd.h>
34
35#include <cstddef>
36#include <cstdlib>
37#include <memory>
38#include <new>
39#include <typeinfo>
40#include <type_traits>
41
42namespace casacore { //# NAMESPACE CASACORE - BEGIN
43
44#ifndef CASA_DEFAULT_ALIGNMENT
45# define CASA_DEFAULT_ALIGNMENT (32UL) // AVX/AVX2 alignment
46#endif
47
48// <summary>
49// A global enum used by some Array/Block constructors.
50// </summary>
51// <synopsis>
52// ArrayInitPolicy is used in functions where an array is allocated/resized.
53// </synopsis>
55public:
57 return init == other.init;
58 }
60 return init != other.init;
61 }
62private:
64 explicit constexpr ArrayInitPolicy(bool v): init(v) {}
65 friend struct ArrayInitPolicies;
66};
67
69 // Don't initialize elements in the array. (The array will be explicitly filled with values other than the default value.)
70 static constexpr ArrayInitPolicy NO_INIT = ArrayInitPolicy(false);
71 // Initialize all elements in the array with the default value.
72 static constexpr ArrayInitPolicy INIT = ArrayInitPolicy(true);
73};
74
75template<typename T>
76using std11_allocator = std::allocator<T>;
77
78
79template<typename T, size_t ALIGNMENT = CASA_DEFAULT_ALIGNMENT>
82 using size_type = typename Super::size_type;
83 using difference_type = typename Super::difference_type;
84 using pointer = T*;
85 using const_pointer = const T*;
86 using reference = T&;
87 using const_reference = const T&;
88 using value_type = typename Super::value_type;
89
90 static constexpr size_t alignment = ALIGNMENT;
91
92 template<typename TOther>
96 casacore_allocator() noexcept = default;
97
98 casacore_allocator(const casacore_allocator&other) noexcept = default;
99
100 template<typename TOther>
101 casacore_allocator(const casacore_allocator<TOther>&) noexcept {}
102
103 ~casacore_allocator() noexcept = default;
104
105 pointer allocate(size_type elements, const void* = 0) {
106 if (elements > std::allocator_traits<casacore_allocator>::max_size(*this)) {
107 throw std::bad_alloc();
108 }
109 void *memptr = 0;
110 int result = posix_memalign(&memptr, ALIGNMENT, sizeof(T) * elements);
111 if (result != 0) {
112 throw std::bad_alloc();
113 }
114 return static_cast<pointer>(memptr);
115 }
116
118 free(ptr);
119 }
120};
121
122template<typename T, size_t ALIGNMENT>
125 return true;
126}
127
128template<typename T, size_t ALIGNMENT>
131 return false;
132}
133
134template<typename T>
137 using size_type = typename Super::size_type;
138 using difference_type = typename Super::difference_type;
139 using pointer = T*;
140 using const_pointer = const T*;
141 using reference = T&;
142 using const_reference = const T&;
143 using value_type = typename Super::value_type;
144
145 template<typename TOther>
149 new_del_allocator() noexcept {
150 }
151
153 :Super(other) {
154 }
155
156 template<typename TOther>
159
161 }
162
163 pointer allocate(size_type elements, const void* = 0) {
164 if (elements > std::allocator_traits<new_del_allocator>::max_size(*this)) {
165 throw std::bad_alloc();
166 }
167 return new T[elements];
168 }
169
171 delete[] ptr;
172 }
173 template<typename U, typename... Args>
174 void construct(U *, Args&&... ) {} // do nothing because new T[] does
175 template<typename U>
176 void construct(U *ptr, U &&value) {
177 *ptr = value; // because *ptr was already contructed by new[].
178 }
179 template<typename U>
180 void construct(U *ptr, U &value) {
181 *ptr = value; // because *ptr was already contructed by new[].
182 }
183 template<typename U>
184 void construct(U *ptr, U const &value) {
185 *ptr = value; // because *ptr was already contructed by new[].
186 }
187
188 template<typename U>
189 void destroy(U *) {} // do nothing because delete[] will do.
190};
191
192template<typename T>
194 const new_del_allocator<T>&) {
195 return true;
196}
197
198template<typename T>
200 const new_del_allocator<T>&) {
201 return false;
202}
203
204template<typename T> class Block;
205
207 template<typename T> friend class AbstractAllocator;
208 template<typename T, typename Sub> friend class BaseAllocator;
209 template<typename T> friend class Block;
210
211 template<typename T2>
213 using size_type = typename std::allocator<T2>::size_type;
214 using value_type = typename std::allocator<T2>::value_type;
215 using pointer = T2*;
216 using const_pointer = const T2*;
217
218 virtual pointer allocate(size_type elements, const void*ptr = 0) = 0;
219 virtual void deallocate(pointer ptr, size_type size) = 0;
220
221 virtual void construct(pointer ptr, size_type n, const_pointer src) = 0;
222 virtual void construct(pointer ptr, size_type n, value_type const &initial_value) = 0;
223 virtual void construct(pointer ptr, size_type n) = 0;
224 virtual void destroy(pointer ptr, size_type n) = 0;
225 virtual std::type_info const &allocator_typeid() const = 0;
226 virtual ~BulkAllocator() {}
227 };
228
229 template<typename Allocator>
230 struct BulkAllocatorImpl: public BulkAllocator<typename Allocator::value_type> {
231 typedef typename Allocator::size_type size_type;
232 typedef typename Allocator::pointer pointer;
233 typedef typename Allocator::const_pointer const_pointer;
234 typedef typename Allocator::value_type value_type;
235 virtual pointer allocate(size_type elements, const void *ptr = 0) override {
236 return allocator.allocate(elements, ptr);
237 }
238 virtual void deallocate(pointer ptr, size_type size) override {
239 allocator.deallocate(ptr, size);
240 }
241
242 virtual void construct(pointer ptr, size_type n, const_pointer src) override {
243 size_type i = 0;
244 try {
245 for (i = 0; i < n; ++i) {
246 std::allocator_traits<Allocator>::construct(allocator, &ptr[i], src[i]);
247 }
248 } catch (...) {
249 destroy(ptr, i); // rollback constructions
250 throw;
251 }
252 }
253 virtual void construct(pointer ptr, size_type n,
254 value_type const &initial_value) override {
255 size_type i = 0;
256 try {
257 for (i = 0; i < n; ++i) {
258 std::allocator_traits<Allocator>::construct(allocator, &ptr[i], initial_value);
259 }
260 } catch (...) {
261 destroy(ptr, i); // rollback constructions
262 throw;
263 }
264 }
265 virtual void construct(pointer ptr, size_type n) override {
266 size_type i = 0;
267 try {
268 for (i = 0; i < n; ++i) {
269 std::allocator_traits<Allocator>::construct(allocator, &ptr[i]);
270 }
271 } catch (...) {
272 destroy(ptr, i); // rollback constructions
273 throw;
274 }
275 }
276 virtual void destroy(pointer ptr, size_type n) override {
277 for (size_type i = n; i > 0;) {
278 --i;
279 try {
280 std::allocator_traits<Allocator>::destroy(allocator, &ptr[i]);
281 } catch (...) {
282 // Destructor should not raise any exception.
283 }
284 }
285 }
286 virtual std::type_info const &allocator_typeid() const override {
287 return typeid(Allocator);
288 }
289 virtual ~BulkAllocatorImpl() override {}
290
291 private:
292 static Allocator allocator;
293 };
294
295 template<typename Allocator>
299
300 template<typename Allocator>
302 // Because this function gets called from destructors of statically allocated objects that get destructed
303 // after the program finishes, the allocator is constructed in a static storage space and is never
304 // destructed.
305 alignas(BulkAllocatorImpl<Allocator>) static std::byte storage[sizeof(BulkAllocatorImpl<Allocator>)];
306 static BulkAllocatorImpl<Allocator>* ptr =
308 return ptr;
309 }
310
311 // <summary>Allocator specifier</summary>
312 // <synopsis>
313 // This class is just used to avoid ambiguity between overloaded functions.
314 // </synopsis>
315 template<typename T>
316 struct AllocSpec {
318 explicit AllocSpec(BulkAllocator<T> *alloc) : allocator(alloc) {}
319 };
320};
321
322template<typename Allocator>
324
325template<typename T>
327public:
328 typedef T value_type;
330protected:
332 friend class Array<T>;
333 friend class Block<T>;
334
336};
337
338template<typename T, typename Sub>
340public:
341 typedef T value_type;
342 typedef Sub facade_type;
343 virtual ~BaseAllocator() {}
344protected:
346
350};
351
352// An allocator behaves like operator new[]/delete[].
353// Because it is impossible to decouple construction/destruction from allocation/deallocation with this allocator,
354// it is discouraged to use this allocator.
355// Use <src>DefaultAllocator<T></src> or <src>AlignedAllocator<T, ALIGNMENT></src> as possible.
356// This allocator is provided only for compatibility for calling
357// <src>Array::takeStorage(), Block::replaceStorage(), Block(size_t, T *&, Bool)</src> etc.
358// with a storage allocated by operator new[].
359template<typename T>
360class NewDelAllocator: public BaseAllocator<T, NewDelAllocator<T> > {
361public:
363 // an instance of this allocator.
365protected:
367};
368template<typename T>
370
371// An allocator which allocates aligned memory.
372template<typename T, size_t ALIGNMENT = CASA_DEFAULT_ALIGNMENT>
373class AlignedAllocator: public BaseAllocator<T, AlignedAllocator<T, ALIGNMENT> > {
374public:
376 // an instance of this allocator.
378protected:
380};
381template<typename T, size_t ALIGNMENT>
383
384// An aligned allocator with the default alignment.
385template<typename T>
387public:
389 // an instance of this allocator.
391protected:
393};
394template<typename T>
396
397// <summary>Allocator specifier</summary>
398// <synopsis>
399// This class is just used to avoid ambiguity between overloaded functions.
400// </synopsis>
401template<typename T>
402struct AllocSpec {
403 typedef T type;
404 static AllocSpec<T> const value;
405};
406template<typename T>
408
409
410} //# NAMESPACE CASACORE - END
411
412#endif /* CASA_CONTAINERS_ALLOCATOR_H_ */
virtual Allocator_private::BulkAllocator< T > * getAllocator() const =0
An allocator which allocates aligned memory.
Definition Allocator.h:373
static AlignedAllocator< T, CASA_DEFAULT_ALIGNMENT > value
Definition Allocator.h:377
casacore_allocator< T, ALIGNMENT > type
Definition Allocator.h:375
static BulkAllocator< typename Allocator::value_type > * get_allocator()
Definition Allocator.h:296
static BulkAllocatorImpl< Allocator > * get_allocator_raw()
Definition Allocator.h:301
friend class AbstractAllocator
Definition Allocator.h:207
Bool operator==(ArrayInitPolicy const &other)
Definition Allocator.h:56
friend struct ArrayInitPolicies
Definition Allocator.h:65
constexpr ArrayInitPolicy(bool v)
Definition Allocator.h:64
Bool operator!=(ArrayInitPolicy const &other)
Definition Allocator.h:59
virtual Allocator_private::BulkAllocator< T > * getAllocator() const override
Definition Allocator.h:347
An aligned allocator with the default alignment.
Definition Allocator.h:386
static DefaultAllocator< T > value
an instance of this allocator.
Definition Allocator.h:390
AlignedAllocator< T >::type type
Definition Allocator.h:388
An allocator behaves like operator new[]/delete[].
Definition Allocator.h:360
new_del_allocator< T > type
Definition Allocator.h:362
static NewDelAllocator< T > value
an instance of this allocator.
Definition Allocator.h:364
free(pool)
this file contains all the compiler specific defines
Definition mainpage.dox:28
T * storage()
If you really, really, need a "raw" pointer to the beginning of the storage area this will give it to...
Definition Block.h:550
bool operator==(const casacore_allocator< T, ALIGNMENT > &, const casacore_allocator< T, ALIGNMENT > &)
Definition Allocator.h:123
bool operator!=(const casacore_allocator< T, ALIGNMENT > &, const casacore_allocator< T, ALIGNMENT > &)
Definition Allocator.h:129
bool Bool
Define the standard types used by Casacore.
Definition aipstype.h:40
size_t size() const
Definition Block.h:557
NewDelAllocator< T > NewDelAllocator< T >::value
Definition Allocator.h:369
std::allocator< T > std11_allocator
Definition Allocator.h:76
Allocator specifier.
Definition Allocator.h:402
static AllocSpec< T > const value
Definition Allocator.h:404
AllocSpec(BulkAllocator< T > *alloc)
Definition Allocator.h:318
virtual void construct(pointer ptr, size_type n, const_pointer src) override
Definition Allocator.h:242
virtual void construct(pointer ptr, size_type n, value_type const &initial_value) override
Definition Allocator.h:253
virtual void construct(pointer ptr, size_type n) override
Definition Allocator.h:265
virtual void deallocate(pointer ptr, size_type size) override
Definition Allocator.h:238
virtual void destroy(pointer ptr, size_type n) override
Definition Allocator.h:276
virtual std::type_info const & allocator_typeid() const override
Definition Allocator.h:286
virtual pointer allocate(size_type elements, const void *ptr=0) override
Definition Allocator.h:235
virtual std::type_info const & allocator_typeid() const =0
typename std::allocator< T2 >::size_type size_type
Definition Allocator.h:213
virtual pointer allocate(size_type elements, const void *ptr=0)=0
virtual void deallocate(pointer ptr, size_type size)=0
virtual void construct(pointer ptr, size_type n, value_type const &initial_value)=0
virtual void construct(pointer ptr, size_type n, const_pointer src)=0
virtual void construct(pointer ptr, size_type n)=0
typename std::allocator< T2 >::value_type value_type
Definition Allocator.h:214
virtual void destroy(pointer ptr, size_type n)=0
static constexpr ArrayInitPolicy NO_INIT
Don't initialize elements in the array.
Definition Allocator.h:70
static constexpr ArrayInitPolicy INIT
Initialize all elements in the array with the default value.
Definition Allocator.h:72
casacore_allocator< TOther > other
Definition Allocator.h:94
void deallocate(pointer ptr, size_type)
Definition Allocator.h:117
typename Super::value_type value_type
Definition Allocator.h:88
casacore_allocator() noexcept=default
std11_allocator< T > Super
Definition Allocator.h:81
~casacore_allocator() noexcept=default
typename Super::size_type size_type
Definition Allocator.h:82
static constexpr size_t alignment
Definition Allocator.h:90
pointer allocate(size_type elements, const void *=0)
Definition Allocator.h:105
typename Super::difference_type difference_type
Definition Allocator.h:83
new_del_allocator< TOther > other
Definition Allocator.h:147
typename Super::size_type size_type
Definition Allocator.h:137
void construct(U *ptr, U &value)
Definition Allocator.h:180
pointer allocate(size_type elements, const void *=0)
Definition Allocator.h:163
void construct(U *, Args &&...)
Definition Allocator.h:174
typename Super::difference_type difference_type
Definition Allocator.h:138
typename Super::value_type value_type
Definition Allocator.h:143
void deallocate(pointer ptr, size_type)
Definition Allocator.h:170
new_del_allocator(const new_del_allocator &other) noexcept
Definition Allocator.h:152
std11_allocator< T > Super
Definition Allocator.h:136
void construct(U *ptr, U const &value)
Definition Allocator.h:184
void construct(U *ptr, U &&value)
Definition Allocator.h:176
new_del_allocator(const new_del_allocator< TOther > &) noexcept
Definition Allocator.h:157