casacore
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: aips2-request@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 //# $Id$
28 
29 #ifndef CASA_CONTAINERS_ALLOCATOR_H_
30 #define CASA_CONTAINERS_ALLOCATOR_H_
31 
32 #include <casacore/casa/config.h>
33 #include <casacore/casa/aips.h>
34 #include <casacore/casa/Utilities/DataType.h>
35 #include <casacore/casa/Arrays/ArrayFwd.h>
36 
37 #include <cstdlib>
38 #include <memory>
39 #include <new>
40 #include <typeinfo>
41 #include <type_traits>
42 
43 namespace casacore { //# NAMESPACE CASACORE - BEGIN
44 
45 #ifndef CASA_DEFAULT_ALIGNMENT
46 # define CASA_DEFAULT_ALIGNMENT (32UL) // AVX/AVX2 alignment
47 #endif
48 
49 // <summary>
50 // A global enum used by some Array/Block constructors.
51 // </summary>
52 // <synopsis>
53 // ArrayInitPolicy is used in functions where an array is allocated/resized.
54 // </synopsis>
56 public:
58  return init == other.init;
59  }
61  return init != other.init;
62  }
63 private:
65  explicit constexpr ArrayInitPolicy(bool v): init(v) {}
66  friend struct ArrayInitPolicies;
67 };
68 
70  // Don't initialize elements in the array. (The array will be explicitly filled with values other than the default value.)
71  static constexpr ArrayInitPolicy NO_INIT = ArrayInitPolicy(false);
72  // Initialize all elements in the array with the default value.
73  static constexpr ArrayInitPolicy INIT = ArrayInitPolicy(true);
74 };
75 
76 template<typename T>
77 using std11_allocator = std::allocator<T>;
78 
79 
80 template<typename T, size_t ALIGNMENT = CASA_DEFAULT_ALIGNMENT>
83  typedef typename Super::size_type size_type;
84  typedef typename Super::difference_type difference_type;
85  typedef typename Super::pointer pointer;
86  typedef typename Super::const_pointer const_pointer;
87  typedef typename Super::reference reference;
88  typedef typename Super::const_reference const_reference;
89  typedef typename Super::value_type value_type;
90 
91  static constexpr size_t alignment = ALIGNMENT;
92 
93  template<typename TOther>
94  struct rebind {
96  };
97  casacore_allocator() throw () {
98  }
99 
101  :Super(other) {
102  }
103 
104  template<typename TOther>
106  }
107 
108  ~casacore_allocator() noexcept {
109  }
110 
111  pointer allocate(size_type elements, const void* = 0) {
112  if (elements > this->max_size()) {
113  throw std::bad_alloc();
114  }
115  void *memptr = 0;
116  int result = posix_memalign(&memptr, ALIGNMENT, sizeof(T) * elements);
117  if (result != 0) {
118  throw std::bad_alloc();
119  }
120  return static_cast<pointer>(memptr);
121  }
122 
124  free(ptr);
125  }
126 };
127 
128 template<typename T, size_t ALIGNMENT>
131  return true;
132 }
133 
134 template<typename T, size_t ALIGNMENT>
137  return false;
138 }
139 
140 template<typename T>
143  typedef typename Super::size_type size_type;
144  typedef typename Super::difference_type difference_type;
145  typedef typename Super::pointer pointer;
146  typedef typename Super::const_pointer const_pointer;
147  typedef typename Super::reference reference;
148  typedef typename Super::const_reference const_reference;
149  typedef typename Super::value_type value_type;
150 
151  template<typename TOther>
152  struct rebind {
154  };
155  new_del_allocator() noexcept {
156  }
157 
158  new_del_allocator(const new_del_allocator&other) noexcept
159  :Super(other) {
160  }
161 
162  template<typename TOther>
164  }
165 
166  ~new_del_allocator() noexcept {
167  }
168 
169  pointer allocate(size_type elements, const void* = 0) {
170  if (elements > this->max_size()) {
171  throw std::bad_alloc();
172  }
173  return new T[elements];
174  }
175 
177  delete[] ptr;
178  }
179  template<typename U, typename... Args>
180  void construct(U *, Args&&... ) {} // do nothing because new T[] does
181  template<typename U>
182  void construct(U *ptr, U &&value) {
183  *ptr = value; // because *ptr was already contructed by new[].
184  }
185  template<typename U>
186  void construct(U *ptr, U &value) {
187  *ptr = value; // because *ptr was already contructed by new[].
188  }
189  template<typename U>
190  void construct(U *ptr, U const &value) {
191  *ptr = value; // because *ptr was already contructed by new[].
192  }
193 
194  template<typename U>
195  void destroy(U *) {} // do nothing because delete[] will do.
196 };
197 
198 template<typename T>
199 inline bool operator==(const new_del_allocator<T>&,
200  const new_del_allocator<T>&) {
201  return true;
202 }
203 
204 template<typename T>
205 inline bool operator!=(const new_del_allocator<T>&,
206  const new_del_allocator<T>&) {
207  return false;
208 }
209 
210 template<typename T> class Block;
211 
213  template<typename T> friend class AbstractAllocator;
214  template<typename T, typename Sub> friend class BaseAllocator;
215  template<typename T> friend class Block;
216 
217  template<typename T2>
218  struct BulkAllocator {
219  typedef typename std::allocator<T2>::size_type size_type;
220  typedef typename std::allocator<T2>::pointer pointer;
221  typedef typename std::allocator<T2>::const_pointer const_pointer;
222  typedef typename std::allocator<T2>::value_type value_type;
223 
224  virtual pointer allocate(size_type elements, const void*ptr = 0) = 0;
225  virtual void deallocate(pointer ptr, size_type size) = 0;
226 
227  virtual void construct(pointer ptr, size_type n, const_pointer src) = 0;
228  virtual void construct(pointer ptr, size_type n, value_type const &initial_value) = 0;
229  virtual void construct(pointer ptr, size_type n) = 0;
230  virtual void destroy(pointer ptr, size_type n) = 0;
231  virtual std::type_info const &allocator_typeid() const = 0;
232  virtual ~BulkAllocator() {}
233  };
234 
235  template<typename Allocator>
236  struct BulkAllocatorImpl: public BulkAllocator<typename Allocator::value_type> {
237  typedef typename Allocator::size_type size_type;
238  typedef typename Allocator::pointer pointer;
239  typedef typename Allocator::const_pointer const_pointer;
240  typedef typename Allocator::value_type value_type;
241  virtual pointer allocate(size_type elements, const void *ptr = 0) override {
242  return allocator.allocate(elements, ptr);
243  }
244  virtual void deallocate(pointer ptr, size_type size) override {
245  allocator.deallocate(ptr, size);
246  }
247 
248  virtual void construct(pointer ptr, size_type n, const_pointer src) override {
249  size_type i = 0;
250  try {
251  for (i = 0; i < n; ++i) {
252  allocator.construct(&ptr[i], src[i]);
253  }
254  } catch (...) {
255  destroy(ptr, i); // rollback constructions
256  throw;
257  }
258  }
259  virtual void construct(pointer ptr, size_type n,
260  value_type const &initial_value) override {
261  size_type i = 0;
262  try {
263  for (i = 0; i < n; ++i) {
264  allocator.construct(&ptr[i], initial_value);
265  }
266  } catch (...) {
267  destroy(ptr, i); // rollback constructions
268  throw;
269  }
270  }
271  virtual void construct(pointer ptr, size_type n) override {
272  size_type i = 0;
273  try {
274  for (i = 0; i < n; ++i) {
275  allocator.construct(&ptr[i]);
276  }
277  } catch (...) {
278  destroy(ptr, i); // rollback constructions
279  throw;
280  }
281  }
282  virtual void destroy(pointer ptr, size_type n) override {
283  for (size_type i = n; i > 0;) {
284  --i;
285  try {
286  allocator.destroy(&ptr[i]);
287  } catch (...) {
288  // Destructor should not raise any exception.
289  }
290  }
291  }
292  virtual std::type_info const &allocator_typeid() const override {
293  return typeid(Allocator);
294  }
295  virtual ~BulkAllocatorImpl() override {}
296 
297  private:
298  static Allocator allocator;
299  };
300 
301  template<typename Allocator>
303  return get_allocator_raw<Allocator>();
304  }
305 
306  template<typename Allocator>
308  // Because this function gets called from destructors of statically allocated objects that get destructed
309  // after the program finishes, the allocator is constructed in a static storage space and is never
310  // destructed.
311  static typename std::aligned_storage<sizeof(BulkAllocatorImpl<Allocator>), alignof(BulkAllocatorImpl<Allocator>)>::type storage;
312  static BulkAllocatorImpl<Allocator>* ptr =
313  new (reinterpret_cast<BulkAllocatorImpl<Allocator>*>(&storage)) BulkAllocatorImpl<Allocator>();
314  return ptr;
315  }
316 
317  // <summary>Allocator specifier</summary>
318  // <synopsis>
319  // This class is just used to avoid ambiguity between overloaded functions.
320  // </synopsis>
321  template<typename T>
322  struct AllocSpec {
324  explicit AllocSpec(BulkAllocator<T> *alloc) : allocator(alloc) {}
325  };
326 };
327 
328 template<typename Allocator>
330 
331 template<typename T>
333 public:
334  typedef T value_type;
335  virtual ~AbstractAllocator(){}
336 protected:
338  friend class Array<T>;
339  friend class Block<T>;
340 
342 };
343 
344 template<typename T, typename Sub>
346 public:
347  typedef T value_type;
348  typedef Sub facade_type;
349  virtual ~BaseAllocator() {}
350 protected:
352 
353  virtual typename Allocator_private::BulkAllocator<T> *getAllocator() const override {
354  return Allocator_private::get_allocator<typename facade_type::type>();
355  }
356 };
357 
358 // An allocator behaves like operator new[]/delete[].
359 // Because it is impossible to decouple construction/destruction from allocation/deallocation with this allocator,
360 // it is discouraged to use this allocator.
361 // Use <src>DefaultAllocator<T></src> or <src>AlignedAllocator<T, ALIGNMENT></src> as possible.
362 // This allocator is provided only for compatibility for calling
363 // <src>Array::takeStorage(), Block::replaceStorage(), Block(size_t, T *&, Bool)</src> etc.
364 // with a storage allocated by operator new[].
365 template<typename T>
366 class NewDelAllocator: public BaseAllocator<T, NewDelAllocator<T> > {
367 public:
369  // an instance of this allocator.
371 protected:
373 };
374 template<typename T>
375 NewDelAllocator<T> NewDelAllocator<T>::value;
376 
377 // An allocator which allocates aligned memory.
378 template<typename T, size_t ALIGNMENT = CASA_DEFAULT_ALIGNMENT>
379 class AlignedAllocator: public BaseAllocator<T, AlignedAllocator<T, ALIGNMENT> > {
380 public:
382  // an instance of this allocator.
384 protected:
386 };
387 template<typename T, size_t ALIGNMENT>
388 AlignedAllocator<T, ALIGNMENT> AlignedAllocator<T, ALIGNMENT>::value;
389 
390 // An aligned allocator with the default alignment.
391 template<typename T>
393 public:
394  typedef typename AlignedAllocator<T>::type type;
395  // an instance of this allocator.
397 protected:
399 };
400 template<typename T>
401 DefaultAllocator<T> DefaultAllocator<T>::value;
402 
403 // <summary>Allocator specifier</summary>
404 // <synopsis>
405 // This class is just used to avoid ambiguity between overloaded functions.
406 // </synopsis>
407 template<typename T>
408 struct AllocSpec {
409  typedef T type;
410  static AllocSpec<T> const value;
411 };
412 template<typename T>
414 
415 
416 } //# NAMESPACE CASACORE - END
417 
418 #endif /* CASA_CONTAINERS_ALLOCATOR_H_ */
virtual Allocator_private::BulkAllocator< T > * getAllocator() const =0
An allocator which allocates aligned memory.
Definition: Allocator.h:379
static AlignedAllocator< T, ALIGNMENT > value
an instance of this allocator.
Definition: Allocator.h:383
casacore_allocator< T, ALIGNMENT > type
Definition: Allocator.h:381
static BulkAllocator< typename Allocator::value_type > * get_allocator()
Definition: Allocator.h:302
static BulkAllocatorImpl< Allocator > * get_allocator_raw()
Definition: Allocator.h:307
Bool operator==(ArrayInitPolicy const &other)
Definition: Allocator.h:57
constexpr ArrayInitPolicy(bool v)
Definition: Allocator.h:65
Bool operator!=(ArrayInitPolicy const &other)
Definition: Allocator.h:60
virtual ~BaseAllocator()
Definition: Allocator.h:349
virtual Allocator_private::BulkAllocator< T > * getAllocator() const override
Definition: Allocator.h:353
simple 1-D array
Definition: Block.h:200
An aligned allocator with the default alignment.
Definition: Allocator.h:392
static DefaultAllocator< T > value
an instance of this allocator.
Definition: Allocator.h:396
AlignedAllocator< T >::type type
Definition: Allocator.h:394
An allocator behaves like operator new[]/delete[].
Definition: Allocator.h:366
static NewDelAllocator< T > value
an instance of this allocator.
Definition: Allocator.h:370
new_del_allocator< T > type
Definition: Allocator.h:368
free(pool)
this file contains all the compiler specific defines
Definition: mainpage.dox:28
bool operator==(const casacore_allocator< T, ALIGNMENT > &, const casacore_allocator< T, ALIGNMENT > &)
Definition: Allocator.h:129
bool operator!=(const casacore_allocator< T, ALIGNMENT > &, const casacore_allocator< T, ALIGNMENT > &)
Definition: Allocator.h:135
std::allocator< T > std11_allocator
Definition: Allocator.h:77
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
LatticeExprNode value(const LatticeExprNode &expr)
This function returns the value of the expression without a mask.
Allocator specifier.
Definition: Allocator.h:408
static AllocSpec< T > const value
Definition: Allocator.h:410
AllocSpec(BulkAllocator< T > *alloc)
Definition: Allocator.h:324
virtual void construct(pointer ptr, size_type n, const_pointer src) override
Definition: Allocator.h:248
virtual std::type_info const & allocator_typeid() const override
Definition: Allocator.h:292
virtual void construct(pointer ptr, size_type n, value_type const &initial_value) override
Definition: Allocator.h:259
virtual void construct(pointer ptr, size_type n) override
Definition: Allocator.h:271
virtual void deallocate(pointer ptr, size_type size) override
Definition: Allocator.h:244
virtual void destroy(pointer ptr, size_type n) override
Definition: Allocator.h:282
virtual pointer allocate(size_type elements, const void *ptr=0) override
Definition: Allocator.h:241
std::allocator< T2 >::size_type size_type
Definition: Allocator.h:219
virtual std::type_info const & allocator_typeid() const =0
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
std::allocator< T2 >::value_type value_type
Definition: Allocator.h:222
std::allocator< T2 >::const_pointer const_pointer
Definition: Allocator.h:221
virtual void construct(pointer ptr, size_type n)=0
virtual void destroy(pointer ptr, size_type n)=0
std::allocator< T2 >::pointer pointer
Definition: Allocator.h:220
static constexpr ArrayInitPolicy NO_INIT
Don't initialize elements in the array.
Definition: Allocator.h:71
static constexpr ArrayInitPolicy INIT
Initialize all elements in the array with the default value.
Definition: Allocator.h:73
casacore_allocator< TOther > other
Definition: Allocator.h:95
void deallocate(pointer ptr, size_type)
Definition: Allocator.h:123
Super::reference reference
Definition: Allocator.h:87
casacore_allocator(const casacore_allocator< TOther > &) noexcept
Definition: Allocator.h:105
Super::difference_type difference_type
Definition: Allocator.h:84
std11_allocator< T > Super
Definition: Allocator.h:82
Super::size_type size_type
Definition: Allocator.h:83
Super::pointer pointer
Definition: Allocator.h:85
Super::const_pointer const_pointer
Definition: Allocator.h:86
Super::const_reference const_reference
Definition: Allocator.h:88
casacore_allocator(const casacore_allocator &other) noexcept
Definition: Allocator.h:100
Super::value_type value_type
Definition: Allocator.h:89
static constexpr size_t alignment
Definition: Allocator.h:91
pointer allocate(size_type elements, const void *=0)
Definition: Allocator.h:111
new_del_allocator< TOther > other
Definition: Allocator.h:153
Super::const_pointer const_pointer
Definition: Allocator.h:146
Super::size_type size_type
Definition: Allocator.h:143
Super::pointer pointer
Definition: Allocator.h:145
void construct(U *ptr, U &value)
Definition: Allocator.h:186
pointer allocate(size_type elements, const void *=0)
Definition: Allocator.h:169
std11_allocator< T > Super
Definition: Allocator.h:142
void construct(U *, Args &&...)
Definition: Allocator.h:180
Super::value_type value_type
Definition: Allocator.h:149
Super::reference reference
Definition: Allocator.h:147
void deallocate(pointer ptr, size_type)
Definition: Allocator.h:176
new_del_allocator(const new_del_allocator &other) noexcept
Definition: Allocator.h:158
void construct(U *ptr, U const &value)
Definition: Allocator.h:190
Super::difference_type difference_type
Definition: Allocator.h:144
void construct(U *ptr, U &&value)
Definition: Allocator.h:182
Super::const_reference const_reference
Definition: Allocator.h:148
new_del_allocator(const new_del_allocator< TOther > &) noexcept
Definition: Allocator.h:163