Allocator.h

Go to the documentation of this file.
00001 //# Allocator.h:
00002 //# Copyright (C) 2015
00003 //# National Astronomical Observatory of Japan
00004 //# 2-21-1, Osawa, Mitaka, Tokyo, 181-8588, Japan.
00005 //#
00006 //# This library is free software; you can redistribute it and/or modify it
00007 //# under the terms of the GNU Library General Public License as published by
00008 //# the Free Software Foundation; either version 2 of the License, or (at your
00009 //# option) any later version.
00010 //#
00011 //# This library is distributed in the hope that it will be useful, but WITHOUT
00012 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00014 //# License for more details.
00015 //#
00016 //# You should have received a copy of the GNU Library General Public License
00017 //# along with this library; if not, write to the Free Software Foundation,
00018 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00019 //#
00020 //# Correspondence concerning AIPS++ should be addressed as follows:
00021 //#        Internet email: aips2-request@nrao.edu.
00022 //#        Postal address: AIPS++ Project Office
00023 //#                        National Radio Astronomy Observatory
00024 //#                        520 Edgemont Road
00025 //#                        Charlottesville, VA 22903-2475 USA
00026 //#
00027 //# $Id$
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 { //# NAMESPACE CASACORE - BEGIN
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 // <summary>
00052 // A global enum used by some Array/Block constructors.
00053 // </summary>
00054 // <synopsis>
00055 // ArrayInitPolicy is used in functions where an array is allocated/resized.
00056 // </synopsis>
00057 class ArrayInitPolicy {
00058 public:
00059   // Don't initialize elements in the array. (The array will be explicitly filled with values other than the default value.)
00060   static ArrayInitPolicy const NO_INIT;
00061   // Initialize all elements in the array with the default value.
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;   // because *ptr was already contructed by new[].
00220     }
00221     void construct(pointer) {} // do nothing because new T[] does
00222 #else
00223   template<typename U, typename... Args>
00224   void construct(U *, Args&&... ) {} // do nothing because new T[] does
00225   template<typename U>
00226   void construct(U *ptr, U &&value) {
00227       *ptr = value;     // because *ptr was already contructed by new[].
00228   }
00229   template<typename U>
00230   void construct(U *ptr, U &value) {
00231       *ptr = value;     // because *ptr was already contructed by new[].
00232   }
00233   template<typename U>
00234   void construct(U *ptr, U const &value) {
00235       *ptr = value;     // because *ptr was already contructed by new[].
00236   }
00237 #endif
00238 
00239   template<typename U>
00240   void destroy(U *) {} // do nothing because delete[] will do.
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);  // rollback constructions
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);  // rollback constructions
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);  // rollback constructions
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           // Destructor should not raise any exception.
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     // Probably this method is called from BulkAllocatorInitializer<Allocator> first
00367     // while static initialization
00368     // and other threads are not started yet.
00369     if (ptr == 0) {
00370       // Use construct below to avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42032 
00371       ::new (reinterpret_cast<BulkAllocatorImpl<Allocator>*>(u.alloc_obj)) BulkAllocatorImpl<Allocator>(); // this instance will never be destructed.
00372       //      ::new (u.alloc_obj) BulkAllocatorImpl<Allocator>(); // this instance will never be destructed.
00373       ptr = reinterpret_cast<BulkAllocatorImpl<Allocator> *>(u.alloc_obj);
00374     }
00375     return ptr;
00376   }
00377 
00378   // <summary>Allocator specifier</summary>
00379   // <synopsis>
00380   // This class is just used to avoid ambiguity between overloaded functions.
00381   // </synopsis>
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 // An allocator behaves like operator new[]/delete[].
00423 // Because it is impossible to decouple construction/destruction from allocation/deallocation with this allocator,
00424 // it is discouraged to use this allocator.
00425 // Use <src>DefaultAllocator<T></src> or <src>AlignedAllocator<T, ALIGNMENT></src> as possible.
00426 // This allocator is provided only for compatibility for calling
00427 // <src>Array::takeStorage(), Block::replaceStorage(), Block(size_t, T *&, Bool)</src>  etc.
00428 // with a storage allocated by operator new[].
00429 template<typename T>
00430 class NewDelAllocator: public BaseAllocator<T, NewDelAllocator<T> > {
00431 public:
00432   typedef new_del_allocator<T> type;
00433   // an instance of this allocator.
00434   static NewDelAllocator<T> value;
00435 protected:
00436   NewDelAllocator(){}
00437 };
00438 template<typename T>
00439 NewDelAllocator<T> NewDelAllocator<T>::value;
00440 
00441 // An allocator which allocates aligned memory.
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   // an instance of this allocator.
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 // An aligned allocator with the default alignment.
00455 template<typename T>
00456 class DefaultAllocator: public AlignedAllocator<T> {
00457 public:
00458   typedef typename AlignedAllocator<T>::type type;
00459   // an instance of this allocator.
00460   static DefaultAllocator<T> value;
00461 protected:
00462   DefaultAllocator(){}
00463 };
00464 template<typename T>
00465 DefaultAllocator<T> DefaultAllocator<T>::value;
00466 
00467 // <summary>Allocator specifier</summary>
00468 // <synopsis>
00469 // This class is just used to avoid ambiguity between overloaded functions.
00470 // </synopsis>
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 } //# NAMESPACE CASACORE - END
00485 
00486 #endif /* CASA_CONTAINERS_ALLOCATOR_H_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 31 Aug 2016 for casa by  doxygen 1.6.1