Allocators.h revision 533eae20118036f425f27bf0536ef0ccbb090b65
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
17namespace mcld {
18
19/** \class Chunk
20 *  \brief Chunk is the basic unit of the storage of the LinearAllocator
21 *
22 *  @see LinearAllocator
23 */
24template<typename DataType, size_t ChunkSize>
25class Chunk
26{
27public:
28  typedef DataType value_type;
29public:
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
45public:
46  Chunk* next;
47  size_t bound;
48  DataType data[ChunkSize];
49};
50
51template<typename DataType>
52class Chunk<DataType, 0>
53{
54public:
55  typedef DataType value_type;
56
57public:
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
84public:
85  Chunk* next;
86  size_t bound;
87  DataType *data;
88  static size_t m_Size;
89};
90
91template<typename DataType>
92size_t Chunk<DataType, 0>::m_Size = 0;
93
94template<typename ChunkType>
95class LinearAllocatorBase : private Uncopyable
96{
97public:
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
108protected:
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
121public:
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
251protected:
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
266protected:
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 */
288template<typename DataType, size_t ChunkSize>
289class LinearAllocator : public LinearAllocatorBase<Chunk<DataType, ChunkSize> >
290{
291public:
292  template<typename NewDataType>
293  struct rebind {
294    typedef LinearAllocator<NewDataType, ChunkSize> other;
295  };
296
297public:
298  LinearAllocator()
299    : LinearAllocatorBase<Chunk<DataType, ChunkSize> >() {
300  }
301
302  virtual ~LinearAllocator()
303  { }
304};
305
306template<typename DataType>
307class LinearAllocator<DataType, 0> : public LinearAllocatorBase<Chunk<DataType, 0> >
308{
309public:
310  template<typename NewDataType>
311  struct rebind {
312    typedef LinearAllocator<NewDataType, 0> other;
313  };
314
315public:
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
325template<typename DataType>
326class MallocAllocator
327{
328public:
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
343public:
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
379template<>
380class MallocAllocator<void>
381{
382public:
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
397public:
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