Home | History | Annotate | Download | only in Support
      1 //===- Allocators.h ---------------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #ifndef MCLD_SUPPORT_ALLOCATORS_H
     10 #define MCLD_SUPPORT_ALLOCATORS_H
     11 #include <mcld/ADT/Uncopyable.h>
     12 #include <mcld/ADT/TypeTraits.h>
     13 
     14 #include <cstddef>
     15 #include <cstdlib>
     16 
     17 namespace mcld {
     18 
     19 /** \class Chunk
     20  *  \brief Chunk is the basic unit of the storage of the LinearAllocator
     21  *
     22  *  @see LinearAllocator
     23  */
     24 template<typename DataType, size_t ChunkSize>
     25 class Chunk
     26 {
     27 public:
     28   typedef DataType value_type;
     29 public:
     30   Chunk()
     31   : next(0), bound(0)
     32   { }
     33 
     34   static size_t size() { return ChunkSize; }
     35 
     36   static void construct(value_type* pPtr)
     37   { new (pPtr) value_type(); }
     38 
     39   static void construct(value_type* pPtr, const value_type& pValue)
     40   { new (pPtr) value_type(pValue); }
     41 
     42   static void destroy(value_type* pPtr)
     43   { }
     44 
     45 public:
     46   Chunk* next;
     47   size_t bound;
     48   DataType data[ChunkSize];
     49 };
     50 
     51 template<typename DataType>
     52 class Chunk<DataType, 0>
     53 {
     54 public:
     55   typedef DataType value_type;
     56 
     57 public:
     58   Chunk()
     59   : next(0), bound(0) {
     60     if (0 != m_Size)
     61       data = (DataType*)malloc(sizeof(DataType)*m_Size);
     62     else
     63       data = 0;
     64   }
     65 
     66   ~Chunk() {
     67     if (data)
     68       free(data);
     69   }
     70 
     71   static size_t size() { return m_Size; }
     72 
     73   static void setSize(size_t pSize) { m_Size = pSize; }
     74 
     75   static void construct(value_type* pPtr)
     76   { new (pPtr) value_type(); }
     77 
     78   static void construct(value_type* pPtr, const value_type& pValue)
     79   { new (pPtr) value_type(pValue); }
     80 
     81   static void destroy(value_type* pPtr)
     82   { pPtr->~value_type(); }
     83 
     84 public:
     85   Chunk* next;
     86   size_t bound;
     87   DataType *data;
     88   static size_t m_Size;
     89 };
     90 
     91 template<typename DataType>
     92 size_t Chunk<DataType, 0>::m_Size = 0;
     93 
     94 template<typename ChunkType>
     95 class LinearAllocatorBase : private Uncopyable
     96 {
     97 public:
     98   typedef ChunkType                             chunk_type;
     99   typedef typename ChunkType::value_type        value_type;
    100   typedef typename ChunkType::value_type*       pointer;
    101   typedef typename ChunkType::value_type&       reference;
    102   typedef const typename ChunkType::value_type* const_pointer;
    103   typedef const typename ChunkType::value_type& const_reference;
    104   typedef size_t                                size_type;
    105   typedef ptrdiff_t                             difference_type;
    106   typedef unsigned char                         byte_type;
    107 
    108 protected:
    109   LinearAllocatorBase()
    110     : m_pRoot(0),
    111       m_pCurrent(0),
    112       m_AllocatedNum(0) {
    113   }
    114 
    115   // LinearAllocatorBase does NOT mean to destroy the allocated memory.
    116   // If you want a memory allocator to release memory at destruction, please
    117   // use GCFactory series.
    118   virtual ~LinearAllocatorBase()
    119   { }
    120 
    121 public:
    122   pointer address(reference X) const
    123   { return &X; }
    124 
    125   const_pointer address(const_reference X) const
    126   { return &X; }
    127 
    128   /// standard construct - constructing an object on the location pointed by
    129   //  pPtr, and using its copy constructor to initialized its value to pValue.
    130   //
    131   //  @param pPtr the address where the object to be constructed
    132   //  @param pValue the value to be constructed
    133   void construct(pointer pPtr, const_reference pValue)
    134   { chunk_type::construct(pPtr, pValue); }
    135 
    136   /// default construct - constructing an object on the location pointed by
    137   //  pPtr, and using its default constructor to initialized its value to
    138   //  pValue.
    139   //
    140   //  @param pPtr the address where the object to be constructed
    141   void construct(pointer pPtr)
    142   { chunk_type::construct(pPtr); }
    143 
    144   /// standard destroy - destroy data on arbitrary address
    145   //  @para pPtr the address where the data to be destruected.
    146   void destroy(pointer pPtr)
    147   { chunk_type::destroy(pPtr); }
    148 
    149   /// allocate - allocate N data in order.
    150   //  - Disallow to allocate a chunk whose size is bigger than a chunk.
    151   //
    152   //  @param N the number of allocated data.
    153   //  @return the start address of the allocated memory
    154   pointer allocate(size_type N) {
    155     if (0 == N || N > chunk_type::size())
    156       return 0;
    157 
    158     if (empty())
    159       initialize();
    160 
    161     size_type rest_num_elem = chunk_type::size() - m_pCurrent->bound;
    162     pointer result = 0;
    163     if (N > rest_num_elem)
    164       getNewChunk();
    165     result = m_pCurrent->data + m_pCurrent->bound;
    166     m_pCurrent->bound += N;
    167     return result;
    168   }
    169 
    170   /// allocate - clone function of allocating one datum.
    171   pointer allocate() {
    172     if (empty())
    173       initialize();
    174 
    175     pointer result = 0;
    176     if (chunk_type::size() == m_pCurrent->bound)
    177       getNewChunk();
    178     result = m_pCurrent->data + m_pCurrent->bound;
    179     ++m_pCurrent->bound;
    180     return result;
    181   }
    182 
    183   /// deallocate - deallocate N data from the pPtr
    184   //  - if we can simply release some memory, then do it. Otherwise, do
    185   //    nothing.
    186   void deallocate(pointer &pPtr, size_type N) {
    187     if (0 == N ||
    188         N > chunk_type::size() ||
    189         0 == m_pCurrent->bound ||
    190         N >= m_pCurrent->bound)
    191       return;
    192     if (!isAvailable(pPtr))
    193       return;
    194     m_pCurrent->bound -= N;
    195     pPtr = 0;
    196   }
    197 
    198   /// deallocate - clone function of deallocating one datum
    199   void deallocate(pointer &pPtr) {
    200     if (0 == m_pCurrent->bound)
    201       return;
    202     if (!isAvailable(pPtr))
    203       return;
    204     m_pCurrent->bound -= 1;
    205     pPtr = 0;
    206   }
    207 
    208   /// isIn - whether the pPtr is in the current chunk?
    209   bool isIn(pointer pPtr) const {
    210     if (pPtr >= &(m_pCurrent->data[0]) &&
    211         pPtr <= &(m_pCurrent->data[chunk_type::size()-1]))
    212       return true;
    213     return false;
    214   }
    215 
    216   /// isIn - whether the pPtr is allocated, and can be constructed.
    217   bool isAvailable(pointer pPtr) const {
    218     if (pPtr >= &(m_pCurrent->data[m_pCurrent->bound]) &&
    219         pPtr <= &(m_pCurrent->data[chunk_type::size()-1]))
    220       return true;
    221     return false;
    222   }
    223 
    224   void reset() {
    225     m_pRoot = 0;
    226     m_pCurrent = 0;
    227     m_AllocatedNum = 0;
    228   }
    229 
    230   /// clear - clear all chunks
    231   void clear() {
    232     chunk_type *cur = m_pRoot, *prev;
    233     while (0 != cur) {
    234       prev = cur;
    235       cur = cur->next;
    236       for (unsigned int idx = 0; idx != prev->bound; ++idx)
    237         destroy(prev->data + idx);
    238       delete prev;
    239     }
    240     reset();
    241   }
    242 
    243   // -----  observers  ----- //
    244   bool empty() const {
    245     return (0 == m_pRoot);
    246   }
    247 
    248   size_type max_size() const
    249   { return m_AllocatedNum; }
    250 
    251 protected:
    252   inline void initialize() {
    253     m_pRoot = new chunk_type();
    254     m_pCurrent = m_pRoot;
    255     m_AllocatedNum += chunk_type::size();
    256   }
    257 
    258   inline chunk_type *getNewChunk() {
    259     chunk_type *result = new chunk_type();
    260     m_pCurrent->next = result;
    261     m_pCurrent = result;
    262     m_AllocatedNum += chunk_type::size();
    263     return result;
    264   }
    265 
    266 protected:
    267   chunk_type *m_pRoot;
    268   chunk_type *m_pCurrent;
    269   size_type   m_AllocatedNum;
    270 };
    271 
    272 /** \class LinearAllocator
    273  *  \brief LinearAllocator is another bump pointer allocator which should be
    274  *  limited in use of two-phase memory allocation.
    275  *
    276  *  Two-phase memory allocation clear separates the use of memory into 'claim'
    277  *  and 'release' phases. There are no interleaving allocation and
    278  *  deallocation. Interleaving 'allocate' and 'deallocate' increases the size
    279  *  of allocated memory, and causes bad locality.
    280  *
    281  *  The underlying concept of LinearAllocator is a memory pool. LinearAllocator
    282  *  is a simple implementation of boost::pool's ordered_malloc() and
    283  *  ordered_free().
    284  *
    285  *  template argument DataType is the DataType to be allocated
    286  *  template argument ChunkSize is the number of bytes of a chunk
    287  */
    288 template<typename DataType, size_t ChunkSize>
    289 class LinearAllocator : public LinearAllocatorBase<Chunk<DataType, ChunkSize> >
    290 {
    291 public:
    292   template<typename NewDataType>
    293   struct rebind {
    294     typedef LinearAllocator<NewDataType, ChunkSize> other;
    295   };
    296 
    297 public:
    298   LinearAllocator()
    299     : LinearAllocatorBase<Chunk<DataType, ChunkSize> >() {
    300   }
    301 
    302   virtual ~LinearAllocator()
    303   { }
    304 };
    305 
    306 template<typename DataType>
    307 class LinearAllocator<DataType, 0> : public LinearAllocatorBase<Chunk<DataType, 0> >
    308 {
    309 public:
    310   template<typename NewDataType>
    311   struct rebind {
    312     typedef LinearAllocator<NewDataType, 0> other;
    313   };
    314 
    315 public:
    316   explicit LinearAllocator(size_t pNum)
    317     : LinearAllocatorBase<Chunk<DataType, 0> >() {
    318     Chunk<DataType, 0>::setSize(pNum);
    319   }
    320 
    321   virtual ~LinearAllocator()
    322   { }
    323 };
    324 
    325 template<typename DataType>
    326 class MallocAllocator
    327 {
    328 public:
    329   typedef size_t          size_type;
    330   typedef ptrdiff_t       difference_type;
    331   typedef DataType*       pointer;
    332   typedef const DataType* const_pointer;
    333   typedef DataType&       reference;
    334   typedef const DataType& const_reference;
    335   typedef DataType        value_type;
    336 
    337   template<typename OtherDataType>
    338   struct rebind
    339   {
    340     typedef MallocAllocator<OtherDataType> other;
    341   };
    342 
    343 public:
    344   MallocAllocator() throw()
    345   { }
    346 
    347   MallocAllocator(const MallocAllocator&) throw()
    348   { }
    349 
    350   ~MallocAllocator() throw()
    351   { }
    352 
    353   pointer address(reference X) const
    354   { return &X; }
    355 
    356   const_pointer address(const_reference X) const
    357   { return &X; }
    358 
    359   pointer allocate(size_type pNumOfElements, const void* = 0)
    360   {
    361     return static_cast<DataType*>(
    362                        std::malloc(pNumOfElements*sizeof(DataType)));
    363   }
    364 
    365   void deallocate(pointer pObject, size_type)
    366   { std::free(static_cast<void*>(pObject)); }
    367 
    368   size_type max_size() const throw()
    369   { return size_t(-1) / sizeof(DataType); }
    370 
    371   void construct(pointer pObject, const DataType& pValue)
    372   { ::new((void *)pObject) value_type(pValue); }
    373 
    374   void destroy(pointer pObject)
    375   { pObject->~DataType(); }
    376 
    377 };
    378 
    379 template<>
    380 class MallocAllocator<void>
    381 {
    382 public:
    383   typedef size_t      size_type;
    384   typedef ptrdiff_t   difference_type;
    385   typedef void*       pointer;
    386   typedef const void* const_pointer;
    387   typedef void*       reference;
    388   typedef const void* const_reference;
    389   typedef void*       value_type;
    390 
    391   template<typename OtherDataType>
    392   struct rebind
    393   {
    394     typedef MallocAllocator<OtherDataType> other;
    395   };
    396 
    397 public:
    398   MallocAllocator() throw()
    399   { }
    400 
    401   MallocAllocator(const MallocAllocator&) throw()
    402   { }
    403 
    404   ~MallocAllocator() throw()
    405   { }
    406 
    407   size_type max_size() const throw()
    408   { return size_t(-1) / sizeof(void*); }
    409 
    410   pointer address(reference X) const
    411   { return X; }
    412 
    413   const_pointer address(const_reference X) const
    414   { return X; }
    415 
    416   template<typename DataType>
    417   DataType* allocate(size_type pNumOfElements, const void* = 0) {
    418     return static_cast<DataType*>(
    419                        std::malloc(pNumOfElements*sizeof(DataType)));
    420   }
    421 
    422   pointer allocate(size_type pNumOfElements, const void* = 0) {
    423     return std::malloc(pNumOfElements);
    424   }
    425 
    426   template<typename DataType>
    427   void deallocate(DataType* pObject, size_type)
    428   { std::free(static_cast<void*>(pObject)); }
    429 
    430   void deallocate(pointer pObject, size_type)
    431   { std::free(pObject); }
    432 
    433   template<typename DataType>
    434   void construct(DataType* pObject, const DataType& pValue)
    435   { /* do nothing */ }
    436 
    437   void construct(pointer pObject, const_reference pValue)
    438   { /* do nothing */ }
    439 
    440   template<typename DataType>
    441   void destroy(DataType* pObject)
    442   { /* do nothing */ }
    443 
    444   void destroy(pointer pObject)
    445   { /* do nothing */ }
    446 };
    447 
    448 } // namespace mcld
    449 
    450 #endif
    451 
    452