blob: c66b77e428051db539273af481975f9b11df9b46 [file] [log] [blame]
//===- Allocators.h -------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_SUPPORT_ALLOCATORS_H_
#define MCLD_SUPPORT_ALLOCATORS_H_
#include "mcld/ADT/TypeTraits.h"
#include "mcld/Support/Compiler.h"
#include <cstddef>
#include <cstdlib>
namespace mcld {
/** \class Chunk
* \brief Chunk is the basic unit of the storage of the LinearAllocator
*
* @see LinearAllocator
*/
template <typename DataType, size_t ChunkSize>
class Chunk {
public:
typedef DataType value_type;
public:
Chunk() : next(NULL), bound(0) {}
static size_t size() { return ChunkSize; }
static void construct(value_type* pPtr) { new (pPtr) value_type(); }
static void construct(value_type* pPtr, const value_type& pValue) {
new (pPtr) value_type(pValue);
}
static void destroy(value_type* pPtr) {}
public:
Chunk* next;
size_t bound;
DataType data[ChunkSize];
};
template <typename DataType>
class Chunk<DataType, 0> {
public:
typedef DataType value_type;
public:
Chunk() : next(NULL), bound(0) {
if (m_Size != 0)
data = reinterpret_cast<DataType*>(malloc(sizeof(DataType) * m_Size));
else
data = 0;
}
~Chunk() {
if (data)
free(data);
}
static size_t size() { return m_Size; }
static void setSize(size_t pSize) { m_Size = pSize; }
static void construct(value_type* pPtr) { new (pPtr) value_type(); }
static void construct(value_type* pPtr, const value_type& pValue) {
new (pPtr) value_type(pValue);
}
static void destroy(value_type* pPtr) { pPtr->~value_type(); }
public:
Chunk* next;
size_t bound;
DataType* data;
static size_t m_Size;
};
template <typename DataType>
size_t Chunk<DataType, 0>::m_Size = 0;
template <typename ChunkType>
class LinearAllocatorBase {
public:
typedef ChunkType chunk_type;
typedef typename ChunkType::value_type value_type;
typedef typename ChunkType::value_type* pointer;
typedef typename ChunkType::value_type& reference;
typedef const typename ChunkType::value_type* const_pointer;
typedef const typename ChunkType::value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef unsigned char byte_type;
protected:
LinearAllocatorBase() : m_pRoot(NULL), m_pCurrent(NULL), m_AllocatedNum(0) {}
// LinearAllocatorBase does NOT mean to destroy the allocated memory.
// If you want a memory allocator to release memory at destruction, please
// use GCFactory series.
virtual ~LinearAllocatorBase() {}
public:
pointer address(reference X) const { return &X; }
const_pointer address(const_reference X) const { return &X; }
/// standard construct - constructing an object on the location pointed by
// pPtr, and using its copy constructor to initialized its value to pValue.
//
// @param pPtr the address where the object to be constructed
// @param pValue the value to be constructed
void construct(pointer pPtr, const_reference pValue) {
chunk_type::construct(pPtr, pValue);
}
/// default construct - constructing an object on the location pointed by
// pPtr, and using its default constructor to initialized its value to
// pValue.
//
// @param pPtr the address where the object to be constructed
void construct(pointer pPtr) { chunk_type::construct(pPtr); }
/// standard destroy - destroy data on arbitrary address
// @para pPtr the address where the data to be destruected.
void destroy(pointer pPtr) { chunk_type::destroy(pPtr); }
/// allocate - allocate N data in order.
// - Disallow to allocate a chunk whose size is bigger than a chunk.
//
// @param N the number of allocated data.
// @return the start address of the allocated memory
pointer allocate(size_type N) {
if (N == 0 || N > chunk_type::size())
return 0;
if (empty())
initialize();
size_type rest_num_elem = chunk_type::size() - m_pCurrent->bound;
pointer result = 0;
if (N > rest_num_elem)
getNewChunk();
result = m_pCurrent->data + m_pCurrent->bound;
m_pCurrent->bound += N;
return result;
}
/// allocate - clone function of allocating one datum.
pointer allocate() {
if (empty())
initialize();
pointer result = 0;
if (chunk_type::size() == m_pCurrent->bound)
getNewChunk();
result = m_pCurrent->data + m_pCurrent->bound;
++m_pCurrent->bound;
return result;
}
/// deallocate - deallocate N data from the pPtr
// - if we can simply release some memory, then do it. Otherwise, do
// nothing.
void deallocate(pointer& pPtr, size_type N) {
if (N == 0 || N > chunk_type::size() || m_pCurrent->bound == 0 ||
N >= m_pCurrent->bound)
return;
if (!isAvailable(pPtr))
return;
m_pCurrent->bound -= N;
pPtr = 0;
}
/// deallocate - clone function of deallocating one datum
void deallocate(pointer& pPtr) {
if (m_pCurrent->bound == 0)
return;
if (!isAvailable(pPtr))
return;
m_pCurrent->bound -= 1;
pPtr = 0;
}
/// isIn - whether the pPtr is in the current chunk?
bool isIn(pointer pPtr) const {
if (pPtr >= &(m_pCurrent->data[0]) &&
pPtr <= &(m_pCurrent->data[chunk_type::size() - 1]))
return true;
return false;
}
/// isIn - whether the pPtr is allocated, and can be constructed.
bool isAvailable(pointer pPtr) const {
if (pPtr >= &(m_pCurrent->data[m_pCurrent->bound]) &&
pPtr <= &(m_pCurrent->data[chunk_type::size() - 1]))
return true;
return false;
}
void reset() {
m_pRoot = 0;
m_pCurrent = 0;
m_AllocatedNum = 0;
}
/// clear - clear all chunks
void clear() {
chunk_type* cur = m_pRoot, *prev;
while (cur != 0) {
prev = cur;
cur = cur->next;
for (unsigned int idx = 0; idx != prev->bound; ++idx)
destroy(prev->data + idx);
delete prev;
}
reset();
}
// ----- observers ----- //
bool empty() const { return (m_pRoot == 0); }
size_type max_size() const { return m_AllocatedNum; }
protected:
inline void initialize() {
m_pRoot = new chunk_type();
m_pCurrent = m_pRoot;
m_AllocatedNum += chunk_type::size();
}
inline chunk_type* getNewChunk() {
chunk_type* result = new chunk_type();
m_pCurrent->next = result;
m_pCurrent = result;
m_AllocatedNum += chunk_type::size();
return result;
}
protected:
chunk_type* m_pRoot;
chunk_type* m_pCurrent;
size_type m_AllocatedNum;
private:
DISALLOW_COPY_AND_ASSIGN(LinearAllocatorBase);
};
/** \class LinearAllocator
* \brief LinearAllocator is another bump pointer allocator which should be
* limited in use of two-phase memory allocation.
*
* Two-phase memory allocation clear separates the use of memory into 'claim'
* and 'release' phases. There are no interleaving allocation and
* deallocation. Interleaving 'allocate' and 'deallocate' increases the size
* of allocated memory, and causes bad locality.
*
* The underlying concept of LinearAllocator is a memory pool. LinearAllocator
* is a simple implementation of boost::pool's ordered_malloc() and
* ordered_free().
*
* template argument DataType is the DataType to be allocated
* template argument ChunkSize is the number of bytes of a chunk
*/
template <typename DataType, size_t ChunkSize>
class LinearAllocator
: public LinearAllocatorBase<Chunk<DataType, ChunkSize> > {
public:
template <typename NewDataType>
struct rebind {
typedef LinearAllocator<NewDataType, ChunkSize> other;
};
public:
LinearAllocator() : LinearAllocatorBase<Chunk<DataType, ChunkSize> >() {}
virtual ~LinearAllocator() {}
};
template <typename DataType>
class LinearAllocator<DataType, 0>
: public LinearAllocatorBase<Chunk<DataType, 0> > {
public:
template <typename NewDataType>
struct rebind {
typedef LinearAllocator<NewDataType, 0> other;
};
public:
explicit LinearAllocator(size_t pNum)
: LinearAllocatorBase<Chunk<DataType, 0> >() {
Chunk<DataType, 0>::setSize(pNum);
}
virtual ~LinearAllocator() {}
};
template <typename DataType>
class MallocAllocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef DataType* pointer;
typedef const DataType* const_pointer;
typedef DataType& reference;
typedef const DataType& const_reference;
typedef DataType value_type;
template <typename OtherDataType>
struct rebind {
typedef MallocAllocator<OtherDataType> other;
};
public:
MallocAllocator() throw() {}
MallocAllocator(const MallocAllocator&) throw() {}
~MallocAllocator() throw() {}
pointer address(reference X) const { return &X; }
const_pointer address(const_reference X) const { return &X; }
pointer allocate(size_type pNumOfElements, const void* = 0) {
return static_cast<DataType*>(
std::malloc(pNumOfElements * sizeof(DataType)));
}
void deallocate(pointer pObject, size_type) {
std::free(static_cast<void*>(pObject));
}
size_type max_size() const throw() { return size_t(-1) / sizeof(DataType); }
void construct(pointer pObject, const DataType& pValue) {
::new (reinterpret_cast<void*>(pObject)) value_type(pValue);
}
void destroy(pointer pObject) { pObject->~DataType(); }
};
template <>
class MallocAllocator<void> {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef void* pointer;
typedef const void* const_pointer;
typedef void* reference;
typedef const void* const_reference;
typedef void* value_type;
template <typename OtherDataType>
struct rebind {
typedef MallocAllocator<OtherDataType> other;
};
public:
MallocAllocator() throw() {}
MallocAllocator(const MallocAllocator&) throw() {}
~MallocAllocator() throw() {}
size_type max_size() const throw() { return size_t(-1) / sizeof(void*); }
pointer address(reference X) const { return X; }
const_pointer address(const_reference X) const { return X; }
template <typename DataType>
DataType* allocate(size_type pNumOfElements, const void* = 0) {
return static_cast<DataType*>(
std::malloc(pNumOfElements * sizeof(DataType)));
}
pointer allocate(size_type pNumOfElements, const void* = 0) {
return std::malloc(pNumOfElements);
}
template <typename DataType>
void deallocate(DataType* pObject, size_type) {
std::free(static_cast<void*>(pObject));
}
void deallocate(pointer pObject, size_type) { std::free(pObject); }
template <typename DataType>
void construct(DataType* pObject, const DataType& pValue) { /* do nothing */
}
void construct(pointer pObject, const_reference pValue) { /* do nothing */
}
template <typename DataType>
void destroy(DataType* pObject) { /* do nothing */
}
void destroy(pointer pObject) { /* do nothing */
}
};
} // namespace mcld
#endif // MCLD_SUPPORT_ALLOCATORS_H_