00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef CASA_CONTAINERS_ALLOCATOR_H_
00030 #define CASA_CONTAINERS_ALLOCATOR_H_
00031
00032 #include <casacore/casa/config.h>
00033 #include <casacore/casa/aips.h>
00034 #include <casacore/casa/Utilities/DataType.h>
00035
00036 #include <memory>
00037 #include <typeinfo>
00038
00039 #include <cstdlib>
00040 namespace casacore {
00041
00042 #if __cplusplus < 201103L && ! defined(noexcept)
00043 # define noexcept throw()
00044 # define CASA_UNDEF_noexcept
00045 #endif
00046
00047 #ifndef CASA_DEFAULT_ALIGNMENT
00048 # define CASA_DEFAULT_ALIGNMENT (32UL) // AVX/AVX2 alignment
00049 #endif
00050
00051
00052
00053
00054
00055
00056
00057 class ArrayInitPolicy {
00058 public:
00059
00060 static ArrayInitPolicy const NO_INIT;
00061
00062 static ArrayInitPolicy const INIT;
00063 Bool operator ==(ArrayInitPolicy const &other) {
00064 return init == other.init;
00065 }
00066 Bool operator !=(ArrayInitPolicy const &other) {
00067 return init != other.init;
00068 }
00069 private:
00070 Bool init;
00071 explicit ArrayInitPolicy(bool v): init(v) {}
00072 };
00073
00074 #if __cplusplus < 201103L
00075 template<typename T>
00076 struct std11_allocator: public std::allocator<T> {
00077 typedef std::allocator<T> Super;
00078 typedef typename Super::size_type size_type;
00079 typedef typename Super::difference_type difference_type;
00080 typedef typename Super::pointer pointer;
00081 typedef typename Super::const_pointer const_pointer;
00082 typedef typename Super::reference reference;
00083 typedef typename Super::const_reference const_reference;
00084 typedef typename Super::value_type value_type;
00085
00086 template<typename TOther>
00087 struct rebind {
00088 typedef std11_allocator<TOther> other;
00089 };
00090 void construct(pointer ptr) {
00091 ::new(static_cast<void *>(ptr)) T();
00092 }
00093 void construct(pointer ptr, const_reference val) {
00094 Super::construct(ptr, val);
00095 }
00096 };
00097
00098 template<typename T>
00099 inline bool operator==(const std11_allocator<T>&,
00100 const std11_allocator<T>&) {
00101 return true;
00102 }
00103
00104 template<typename T>
00105 inline bool operator!=(const std11_allocator<T>&,
00106 const std11_allocator<T>&) {
00107 return false;
00108 }
00109
00110 #else
00111 template<typename T>
00112 using std11_allocator = std::allocator<T>;
00113 #endif
00114
00115 template<typename T, size_t ALIGNMENT = CASA_DEFAULT_ALIGNMENT>
00116 struct casacore_allocator: public std11_allocator<T> {
00117 typedef std11_allocator<T> Super;
00118 typedef typename Super::size_type size_type;
00119 typedef typename Super::difference_type difference_type;
00120 typedef typename Super::pointer pointer;
00121 typedef typename Super::const_pointer const_pointer;
00122 typedef typename Super::reference reference;
00123 typedef typename Super::const_reference const_reference;
00124 typedef typename Super::value_type value_type;
00125 #if __cplusplus < 201103L
00126 enum {alignment = ALIGNMENT};
00127 #else
00128 static constexpr size_t alignment = ALIGNMENT;
00129 #endif
00130
00131 template<typename TOther>
00132 struct rebind {
00133 typedef casacore_allocator<TOther> other;
00134 };
00135 casacore_allocator() throw () {
00136 }
00137
00138 casacore_allocator(const casacore_allocator&other) noexcept
00139 :Super(other) {
00140 }
00141
00142 template<typename TOther>
00143 casacore_allocator(const casacore_allocator<TOther>&) noexcept {
00144 }
00145
00146 ~casacore_allocator() noexcept {
00147 }
00148
00149 pointer allocate(size_type elements, const void* = 0) {
00150 if (elements > this->max_size()) {
00151 throw std::bad_alloc();
00152 }
00153 void *memptr = 0;
00154 int result = posix_memalign(&memptr, ALIGNMENT, sizeof(T) * elements);
00155 if (result != 0) {
00156 throw std::bad_alloc();
00157 }
00158 return static_cast<pointer>(memptr);
00159 }
00160
00161 void deallocate(pointer ptr, size_type) {
00162 free(ptr);
00163 }
00164 };
00165
00166 template<typename T, size_t ALIGNMENT>
00167 inline bool operator==(const casacore_allocator<T, ALIGNMENT>&,
00168 const casacore_allocator<T, ALIGNMENT>&) {
00169 return true;
00170 }
00171
00172 template<typename T, size_t ALIGNMENT>
00173 inline bool operator!=(const casacore_allocator<T, ALIGNMENT>&,
00174 const casacore_allocator<T, ALIGNMENT>&) {
00175 return false;
00176 }
00177
00178 template<typename T>
00179 struct new_del_allocator: public std11_allocator<T> {
00180 typedef std11_allocator<T> Super;
00181 typedef typename Super::size_type size_type;
00182 typedef typename Super::difference_type difference_type;
00183 typedef typename Super::pointer pointer;
00184 typedef typename Super::const_pointer const_pointer;
00185 typedef typename Super::reference reference;
00186 typedef typename Super::const_reference const_reference;
00187 typedef typename Super::value_type value_type;
00188
00189 template<typename TOther>
00190 struct rebind {
00191 typedef new_del_allocator<TOther> other;
00192 };
00193 new_del_allocator() noexcept {
00194 }
00195
00196 new_del_allocator(const new_del_allocator&other) noexcept
00197 :Super(other) {
00198 }
00199
00200 template<typename TOther>
00201 new_del_allocator(const new_del_allocator<TOther>&) noexcept {
00202 }
00203
00204 ~new_del_allocator() noexcept {
00205 }
00206
00207 pointer allocate(size_type elements, const void* = 0) {
00208 if (elements > this->max_size()) {
00209 throw std::bad_alloc();
00210 }
00211 return new T[elements];
00212 }
00213
00214 void deallocate(pointer ptr, size_type) {
00215 delete[] ptr;
00216 }
00217 #if __cplusplus < 201103L
00218 void construct(pointer ptr, const_reference value) {
00219 *ptr = value;
00220 }
00221 void construct(pointer) {}
00222 #else
00223 template<typename U, typename... Args>
00224 void construct(U *, Args&&... ) {}
00225 template<typename U>
00226 void construct(U *ptr, U &&value) {
00227 *ptr = value;
00228 }
00229 template<typename U>
00230 void construct(U *ptr, U &value) {
00231 *ptr = value;
00232 }
00233 template<typename U>
00234 void construct(U *ptr, U const &value) {
00235 *ptr = value;
00236 }
00237 #endif
00238
00239 template<typename U>
00240 void destroy(U *) {}
00241 };
00242
00243 template<typename T>
00244 inline bool operator==(const new_del_allocator<T>&,
00245 const new_del_allocator<T>&) {
00246 return true;
00247 }
00248
00249 template<typename T>
00250 inline bool operator!=(const new_del_allocator<T>&,
00251 const new_del_allocator<T>&) {
00252 return false;
00253 }
00254
00255 template<typename T> class Array;
00256 template<typename T> class Block;
00257
00258 class Allocator_private {
00259 template<typename T> friend class AbstractAllocator;
00260 template<typename T, typename Sub> friend class BaseAllocator;
00261 template<typename T> friend class Array;
00262 template<typename T> friend class Block;
00263
00264 template<typename T2>
00265 struct BulkAllocator {
00266 typedef typename std::allocator<T2>::size_type size_type;
00267 typedef typename std::allocator<T2>::pointer pointer;
00268 typedef typename std::allocator<T2>::const_pointer const_pointer;
00269 typedef typename std::allocator<T2>::value_type value_type;
00270
00271 virtual pointer allocate(size_type elements, const void*ptr = 0) = 0;
00272 virtual void deallocate(pointer ptr, size_type size) = 0;
00273
00274 virtual void construct(pointer ptr, size_type n, const_pointer src) = 0;
00275 virtual void construct(pointer ptr, size_type n, value_type const &initial_value) = 0;
00276 virtual void construct(pointer ptr, size_type n) = 0;
00277 virtual void destroy(pointer ptr, size_type n) = 0;
00278 virtual std::type_info const &allocator_typeid() const = 0;
00279 virtual ~BulkAllocator() {}
00280 };
00281
00282 template<typename Allocator>
00283 struct BulkAllocatorImpl: public BulkAllocator<typename Allocator::value_type> {
00284 typedef typename Allocator::size_type size_type;
00285 typedef typename Allocator::pointer pointer;
00286 typedef typename Allocator::const_pointer const_pointer;
00287 typedef typename Allocator::value_type value_type;
00288 virtual pointer allocate(size_type elements, const void *ptr = 0) {
00289 return allocator.allocate(elements, ptr);
00290 }
00291 virtual void deallocate(pointer ptr, size_type size) {
00292 allocator.deallocate(ptr, size);
00293 }
00294
00295 virtual void construct(pointer ptr, size_type n, const_pointer src) {
00296 size_type i = 0;
00297 try {
00298 for (i = 0; i < n; ++i) {
00299 allocator.construct(&ptr[i], src[i]);
00300 }
00301 } catch (...) {
00302 destroy(ptr, i);
00303 throw;
00304 }
00305 }
00306 virtual void construct(pointer ptr, size_type n,
00307 value_type const &initial_value) {
00308 size_type i = 0;
00309 try {
00310 for (i = 0; i < n; ++i) {
00311 allocator.construct(&ptr[i], initial_value);
00312 }
00313 } catch (...) {
00314 destroy(ptr, i);
00315 throw;
00316 }
00317 }
00318 virtual void construct(pointer ptr, size_type n) {
00319 size_type i = 0;
00320 try {
00321 for (i = 0; i < n; ++i) {
00322 allocator.construct(&ptr[i]);
00323 }
00324 } catch (...) {
00325 destroy(ptr, i);
00326 throw;
00327 }
00328 }
00329 virtual void destroy(pointer ptr, size_type n) {
00330 for (size_type i = n; i > 0;) {
00331 --i;
00332 try {
00333 allocator.destroy(&ptr[i]);
00334 } catch (...) {
00335
00336 }
00337 }
00338 }
00339 virtual std::type_info const &allocator_typeid() const {
00340 return typeid(Allocator);
00341 }
00342 virtual ~BulkAllocatorImpl() {}
00343
00344 private:
00345 static Allocator allocator;
00346 };
00347
00348 template<typename Allocator>
00349 static BulkAllocator<typename Allocator::value_type> *get_allocator() {
00350 return get_allocator_raw<Allocator>();
00351 }
00352 template<typename Allocator>
00353 class BulkAllocatorInitializer {
00354 BulkAllocatorInitializer() {
00355 get_allocator_raw<Allocator>();
00356 }
00357 static BulkAllocatorInitializer<Allocator> instance;
00358 };
00359 template<typename Allocator>
00360 static BulkAllocatorImpl<Allocator> *get_allocator_raw() {
00361 static union {
00362 void *dummy;
00363 char alloc_obj[sizeof(BulkAllocatorImpl<Allocator> )];
00364 } u;
00365 static BulkAllocatorImpl<Allocator> *ptr = 0;
00366
00367
00368
00369 if (ptr == 0) {
00370
00371 ::new (reinterpret_cast<BulkAllocatorImpl<Allocator>*>(u.alloc_obj)) BulkAllocatorImpl<Allocator>();
00372
00373 ptr = reinterpret_cast<BulkAllocatorImpl<Allocator> *>(u.alloc_obj);
00374 }
00375 return ptr;
00376 }
00377
00378
00379
00380
00381
00382 template<typename T>
00383 struct AllocSpec {
00384 BulkAllocator<T> *allocator;
00385 explicit AllocSpec(BulkAllocator<T> *alloc) : allocator(alloc) {}
00386 };
00387 };
00388
00389 template<typename Allocator>
00390 Allocator Allocator_private::BulkAllocatorImpl<Allocator>::allocator;
00391
00392 template<typename Allocator>
00393 Allocator_private::BulkAllocatorInitializer<Allocator> Allocator_private::BulkAllocatorInitializer<Allocator>::instance;
00394
00395 template<typename T>
00396 class AbstractAllocator {
00397 public:
00398 typedef T value_type;
00399 virtual ~AbstractAllocator(){}
00400 protected:
00401 AbstractAllocator(){}
00402 friend class Array<T>;
00403 friend class Block<T>;
00404
00405 virtual Allocator_private::BulkAllocator<T> *getAllocator() const = 0;
00406 };
00407
00408 template<typename T, typename Sub>
00409 class BaseAllocator: public AbstractAllocator<T> {
00410 public:
00411 typedef T value_type;
00412 typedef Sub facade_type;
00413 virtual ~BaseAllocator() {}
00414 protected:
00415 BaseAllocator() {}
00416
00417 virtual typename Allocator_private::BulkAllocator<T> *getAllocator() const {
00418 return Allocator_private::get_allocator<typename facade_type::type>();
00419 }
00420 };
00421
00422
00423
00424
00425
00426
00427
00428
00429 template<typename T>
00430 class NewDelAllocator: public BaseAllocator<T, NewDelAllocator<T> > {
00431 public:
00432 typedef new_del_allocator<T> type;
00433
00434 static NewDelAllocator<T> value;
00435 protected:
00436 NewDelAllocator(){}
00437 };
00438 template<typename T>
00439 NewDelAllocator<T> NewDelAllocator<T>::value;
00440
00441
00442 template<typename T, size_t ALIGNMENT = CASA_DEFAULT_ALIGNMENT>
00443 class AlignedAllocator: public BaseAllocator<T, AlignedAllocator<T, ALIGNMENT> > {
00444 public:
00445 typedef casacore_allocator<T, ALIGNMENT> type;
00446
00447 static AlignedAllocator<T, ALIGNMENT> value;
00448 protected:
00449 AlignedAllocator(){}
00450 };
00451 template<typename T, size_t ALIGNMENT>
00452 AlignedAllocator<T, ALIGNMENT> AlignedAllocator<T, ALIGNMENT>::value;
00453
00454
00455 template<typename T>
00456 class DefaultAllocator: public AlignedAllocator<T> {
00457 public:
00458 typedef typename AlignedAllocator<T>::type type;
00459
00460 static DefaultAllocator<T> value;
00461 protected:
00462 DefaultAllocator(){}
00463 };
00464 template<typename T>
00465 DefaultAllocator<T> DefaultAllocator<T>::value;
00466
00467
00468
00469
00470
00471 template<typename T>
00472 struct AllocSpec {
00473 typedef T type;
00474 static AllocSpec<T> const value;
00475 };
00476 template<typename T>
00477 AllocSpec<T> const AllocSpec<T>::value = AllocSpec<T>();
00478
00479 #if defined(CASA_UNDEF_noexcept)
00480 # undef noexcept
00481 # undef CASA_UNDEF_noexcept
00482 #endif
00483
00484 }
00485
00486 #endif