"Dinkum/allocators"Include the header "Dinkum/allocators" to define several
templates that help allocate and free memory blocks for
node-based containers.
// MACROS
#define ALLOCATOR_DECL(cache, sync, name) <alloc_template>
#define CACHE_CHUNKLIST <cache_class>
#define CACHE_FREELIST(max) <cache_class>
#define CACHE_SUBALLOC <cache_clsas>
#define SYNC_DEFAULT <sync_template>
namespace Dinkum {
namespace allocators {
// ALLOCATOR TEMPLATES
template <class T>
class allocator_chunklist;
template <class T>
class allocator_fixed_size;
template <class T>
class allocator_newdel;
template <class T>
class allocator_suballoc;
template <class T>
class allocator_unbounded;
template <class T>
class allocator_variable_size;
// SYNCHRONIZATION FILTERS
template <class Cache>
class sync_none;
template <class Cache>
class sync_per_container;
template <class Cache>
class sync_per_thread;
template <class Cache>
class sync_shared;
// CACHES
template <std::size_t sz>
class cache_chunklist;
template <std::size_t sz, class Max>
class cache_freelist;
template <std::size_t sz>
class cache_suballoc;
// MAX CLASSES
class max_none;
template <std::size_t max>
class max_fixed_size;
class max_unbounded;
class max_variable_size;
// SUPPORT CLASSES
template <class T, class Sync>
class allocator_base;
template <std::size_t sz, class Max>
class freelist;
template <class Cache>
class rts_alloc;
// TEMPLATE OPERATORS
template <class T, class Sync>
bool operator==(const allocator_base<T, Sync>&, const allocator_base<T, Sync>&);
template <class T, Sync>
bool operator!=(const allocator_base<T, Sync>&, const allocator_base<T, Sync>&);
} // namespace allocators
} // namespace Dinkum
allocator_basetemplate <class T, class Sync> class allocator_base {
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
allocator_base();
template <class U>
allocator_base(const allocator_base<U, Sync>& x);
pointer address(reference x);
const_pointer address(const_reference x);
template <class U>
pointer allocate(size_type n, const U *hint);
pointer allocate(size_type n);
void deallocate(pointer p, size_type n);
void construct(pointer p, const T& val);
void destroy(pointer p);
size_type max_size() const;
char *_Charalloc(size_type n);
void _Chardealloc(void *p, size_type n);
};
The template provides the boilerplate needed to create an allocator from a synchronization filter.
allocator_base::addresspointer address(reference x);
const_pointer address(const_reference x);
The member functions implement
allocator::address by
returning &x.
allocator_base::allocatetemplate <class U>
pointer allocate(size_type n, const U *hint = 0);
The member function implements
allocator::allocate by
returning the result of a call to
Sync::allocate()
cast to type T* if n == 1, otherwise
by returning the result of a call to
operator new(n * sizeof(T)) cast to type T*.
allocator_base::allocator_baseallocator_base();
template <class U>
allocator_base(const allocator_base<U, Sync>& x);
The first constructor constructs an allocator_base instance. The second constructor
constructs an allocator_base instance such that for any allocator_base<T, Sync>
instance a, allocator_base<T, Sync>(allocator_base<U, Sync>(a)) == a.
allocator_base::const_pointertypedef const T *const_pointer;
The pointer type implements
allocator::const_pointer
as a typedef for const T*.
allocator_base::const_referencetypedef const T& const_reference;
The reference type implements
allocator::const_reference
as a typedef for const T&.
allocator_base::constructvoid construct(pointer p, const T& val);
The member function implements
allocator::construct by
calling new((void*)p T(val).
allocator_base::deallocatevoid deallocate(pointer p, size_type n);
The member function implements
allocator::deallocate by
calling Sync::deallocate(p)
if n == 1, otherwise by calling operator delete(n * p).
allocator_base::destroyvoid destroy(pointer p);
The member function implements
allocator::destroy by
calling p->~T().
allocator_base::difference_typetypedef std::ptrdiff_t difference_type;
The integer type implements
allocator::difference_type
as a typedef for std::ptrdiff_t.
allocator_base::max_size()size_type max_size() const;
The member function implements
allocator::max_size
by returning (size_t)-1 / sizeof(T) if
0 < (size_t)-1 / sizeof(T), otherwise 1.
allocator_base::pointertypedef T *pointer;
The pointer type implements
allocator::pointer
as a typedef for T*.
allocator_base::referencetypedef T& reference;
The reference type implements
allocator::reference
as a typedef for T&.
allocator_base::size_typetypedef std::size_t size_type;
The unsigned integer type implements
allocator::size_type
as a typedef for std::size_t.
allocator_base::value_typetypedef T value_type;
The object type implements
allocator::value_type
as a typedef for T.
allocator_base::_Charallocchar *_Charalloc(size_type n);
The member function implements
allocator::_Charalloc
by returning Sync::allocate(n).
allocator_base::_Chardeallocvoid _Chardealloc(void *p, size_type n);
The member function implements
allocator::_Chardealloc
by calling Sync::deallocate(p, n).
operator==template <class T, class Sync>
bool operator==(const allocator_base<T, Sync>& a1, const allocator_base& T, Sync;sz>& a2);
The template operator returns a1.equals(a2).
operator!=template <class T, class Sync>
bool operator!=(const allocator_base<T, Sync>& a1, const allocator_base<T, Sync>& a2);
The template operator returns !(a1 == a2).
ALLOCATOR_DECL#define ALLOCATOR_DECL(cache, sync, name) <alloc_template>
The macro yields a template definition template <class T>
class name {.....} and a specialization template <>
class name<void> {.....} which together define an
allocator template class that uses
the synchronization filter sync
and a cache of type cache.
For compilers that can compile rebind the resulting template definition looks like this:
template <class T> class name
: public Dinkum::allocators::allocator_base<T, sync<cache > >
{
public:
name() {}
template <class U> name(const name<U>&) {}
template <class U> name& operator = (const name<U>&)
{return *this; }
template <class U> struct rebind
{ /* convert a name<T> to a name<U> */
typedef name<U> other;
};
};
For compilers that cannot compile rebind the resulting template definition looks like this:
template <class T< class name
: public Dinkum::allocators::allocator_base<T,
sync<Dinkum::allocators::rts_alloc<cache > > >
{
public:
name() {}
template <class U> name(const name<U>&) {}
template <class U> name& operator = (const name<U>&)
{return *this; }
};
allocator_chunklistALLOCATOR_DECL(CACHE_CHUNKLIST, SYNC_DEFAULT, allocator_chunklist);
The allocator template class describes an object
that manages storage allocation and freeing for objects of type T using
a cache of type
cache_chunklist.
allocator_fixed_sizeALLOCATOR_DECL(
CACHE_FREELIST(Dinkum::allocators::max_fixed_size<10>),
SYNC_DEFAULT, allocator_fixed_size);
The allocator template class describes an object
that manages storage allocation and freeing for objects of type T using
a cache of type
cache_freelist with a length managed by
max_fixed_size.
allocator_newdelALLOCATOR_DECL(
CACHE_FREELIST(Dinkum::allocators::max_none),
SYNC_DEFAULT, allocator_newdel);
The template allocator_newdel implements an
allocator that uses
operator delete to deallocate a memory block and
operator new to allocate a memory block.
allocator_suballocALLOCATOR_DECL(CACHE_SUBALLOC, SYNC_DEFAULT, allocator_suballoc);
The allocator template class describes an object
that manages storage allocation and freeing for objects of type T using
a cache of type
cache_suballoc.
allocator_unboundedALLOCATOR_DECL(
CACHE_FREELIST(Dinkum::allocators::max_unbounded),
SYNC_DEFAULT, allocator_unbounded);
The allocator template class describes an object
that manages storage allocation and freeing for objects of type T using
a cache of type
cache_freelist with a length managed by
max_unbounded.
allocator_variable_sizeALLOCATOR_DECL(
CACHE_FREELIST(Dinkum::allocators::max_variable_size),
SYNC_DEFAULT, allocator_variable_size);
The allocator template class describes an object
that manages storage allocation and freeing for objects of type T using
a cache of type
cache_freelist with a length managed by
max_variable_size.
CACHE_CHUNKLIST#define CACHE_CHUNKLIST <cache_class>
The macro yields Dinkum::allocators::cache_chunklist<sizeof(T)>.
cache_chunklisttemplate <std::size_t sz, std::size_t NELTS = 20> class cache_chunklist {
public:
cache_chunklist();
template <size_t usz> cache_chunklist(const cache_chunklist<usz>&);
template <size_t usz> cache_chunklist<usz>& operator=(const cache_chunklist<usz>&);
void *allocate(std::size_t);
void deallocate(void *, std::size_t);
};
The cache template class uses operator new to allocate
chunks of raw memory, suballocating blocks to allocate storage for a memory block when needed;
it stores deallocated memory blocks in a separate free list for each chunk, and uses
operator delete to deallocate a chunk when none of its memory blocks is in use.
Overhead: each memory block holds sz bytes of usable
memory and a pointer to the chunk that it belongs to.
Each chunk holds NELTS memory blocks, three pointers, an int
and the data that operator new and
operator delete require.
cache_chunklist::allocatevoid *allocate(std::size_t n);
The member function implements block_allocator::allocate.
cache_chunklist::cache_chunklistcache_chunklist();
template <size_t usz>
cache_chunklist(const cache_chunklist<usz>&);
The constructors construct a cache_chunklist object.
cache_chunklist::deallocatevoid deallocate(void *, std::size_t);
The member function implements block_allocator::deallocate.
cache_chunklist::operator=template <size_t usz> cache_chunklist<usz>& operator=(const cache_chunklist<usz>&);
The template assignment operator does nothing.
CACHE_FREELIST#define CACHE_FREELIST(max) <cache_class>
The macro yields Dinkum::allocators::cache_freelist<sizeof(T), max>.
cache_freelisttemplate <std::size_t sz, class Max> class cache_freelist {
public:
cache_freelist();
template <size_t usz> cache_freelist(const cache_freelist<usz>&);
template <size_t usz> cache_freelist<usz>& operator=(const cache_freelist<usz>&);
void *allocate(std::size_t);
void deallocate(void *, std::size_t);
};
The cache template class maintains a free list of memory blocks
of size sz. When the free list is full it uses operator delete to deallocate
memory blocks. When the free list is empty it uses operator new to allocate
new memory blocks. The maximum size of the free list is determined by the class
max class Max.
Overhead: each memory block holds sz bytes of
usable memory and the data that operator new and
operator delete require.
cache_freelist::allocatevoid *allocate(std::size_t);
The member function implements block_allocator::allocate.
cache_freelist::cache_freelistcache_freelist();
template <size_t usz> cache_freelist(const cache_freelist<usz>&);
The constructors construct a cache_freelist object.
cache_freelist::deallocatevoid deallocate(void *, std::size_t);
The member function implements block_allocator::deallocate.
cache_freelist::operator=template <size_t usz> cache_freelist<usz>& operator=(const cache_freelist<usz>&);
The template assignment operator does nothing.
CACHE_SUBALLOC#define CACHE_SUBALLOC <cache_class>
The macro yields Dinkum::allocators::cache_suballoc<sizeof(T)>.
cache_suballoctemplate <std::size_t sz, size_t NELTS = 20> class cache_suballoc {
public:
cache_suballoc();
template <size_t usz> cache_suballoc(const cache_suballoc<usz>&);
template <size_t usz> cache_suballoc<usz>& operator=(const cache_suballoc<usz>&);
void *allocate(std::size_t);
void deallocate(void *, std::size_t);
};
The cache template class
stores deallocated memory blocks in a free list with unbounded length, using
freelist<sizeof(T),
max_unbounded>,
and suballocates memory blocks from a larger chunk allocated with
operator new when the free list is empty.
Overhead: each chunk holds sz * NELTS bytes of usable
memory and the data that operator new and operator delete
require. Allocated chunks are never freed.
cache_suballoc::allocatevoid *allocate(std::size_t);
The member function implements block_allocator::allocate.
cache_suballoc::cache_suballoccache_suballoc();
template <size_t usz> cache_suballoc(const cache_suballoc<usz>&);
The constructors construct a cache_suballoc object.
cache_suballoc::deallocatevoid deallocate(void *, std::size_t);
The member function implements block_allocator::deallocate.
cache_suballoc::operator=template <size_t usz> cache_suballoc<usz>& operator=(const cache_suballoc<usz>&);
The template assignment operator does nothing.
freelisttemplate <std::size_t sz, class Max> class freelist
: public Max {
public:
freelist();
bool push(void *);
void *pop();
};
The template class freelist manages a list of memory blocks
of size sz with the maximum length of the list determined by
the max class Max.
freelist::freelistfreelist();
The constructor constructs a freelist instance.
freelist::popvoid *pop();
The member function returns NULL if the list is empty.
Otherwise it removes the first memory block from the list and returns
a pointer to that block.
freelist::pushbool push(void *ptr);
The member function returns false if Max::full returns
true. Otherwise it adds the memory block pointed to by ptr
to the head of the list and returns true.
max_fixed_sizetemplate <std::size_t max> class max_fixed_size {
public:
max_fixed_size()
: nblocks(0) {}
bool full()
{return max <= nblocks; }
void saved()
{++nblocks; }
void released()
{--nblocks; }
void allocated(std::size_t = 1) {}
void deallocated(std::size_t = 1) {}
private:
unsigned long nblocks;
};
The template class describes a max class object
that limits a freelist object
to a fixed maximum length max.
max_fixed_size::allocatedvoid allocated(std::size_t = 1) {}
The member function does nothing.
max_fixed_size::deallocatedvoid deallocated(std::size_t = 1) {}
The member function does nothing.
max_fixed_size::fullbool full()
{return max <= nblocks; }
The member function returns true if max <= nblocks.
max_fixed_size::max_fixed_sizemax_fixed_size()
: nblocks(0) {}
The constructor initializes the stored value nblocks to zero.
max_fixed_size::releasedvoid released()
{--nblocks; }
The member function decrements the stored value nblocks.
max_fixed_size::savedvoid saved()
{++nblocks; }
The member function increments the stored value nblocks.
max_nonetemplate <std::size_t max> class max_none {
public:
bool full() {return true; }
void saved() {}
void released() {}
void allocated(std::size_t = 1) {}
void deallocated(std::size_t = 1) {}
};
The template class describes a max class object that limits a freelist object to a maximum length of zero.
max_none::allocatedvoid allocated(std::size_t = 1) {}
The member function does nothing.
max_none::deallocatedvoid deallocated(std::size_t = 1) {}
The member function does nothing.
max_none::fullbool full()
{return true; }
The member function returns true.
max_none::releasedvoid released() {}
The member function does nothing.
max_none::savedvoid saved() {}
The member function does nothing.
max_unboundedclass max_unbounded {
public:
bool full() {return false; }
void saved() {}
void released() {}
void allocated(std::size_t = 1) {}
void deallocated(std::size_t = 1) {}
};
The template class describes a max class object that does not limit the maximum length of a freelist object.
max_unbounded::allocatedvoid allocated(std::size_t = 1) {}
The member function does nothing.
max_unbounded::deallocatedvoid deallocated(std::size_t = 1) {}
The member function does nothing.
max_unbounded::fullbool full()
{return false; }
The member function returns false.
max_unbounded::releasedvoid released() {}
The member function does nothing.
max_unbounded::savedvoid saved() {}
The member function does nothing.
max_variable_sizeclass max_variable_size {
public:
max_variable_size()
: nblocks(0), nallocs(0) {}
bool full()
{return nallocs / 16 + 16 <= nblocks; }
void saved()
{++nblocks; }
void released()
{--nblocks; }
void allocated(std::size_t n = 1)
{nallocs += n; }
void deallocated(std::size_t n = 1);
{nallocs -= n; }
private:
unsigned long nblocks;
unsigned long nallocs;
};
The template class describes a max class object that limits a freelist object to a maximum length that is roughly proportional to the number of allocated memory blocks.
max_variable_size::allocatedvoid allocated(std::size_t n = 1)
{nallocs += n; }
The member function adds n to the stored value nallocs.
max_variable_size::deallocatedvoid deallocated(std::size_t n = 1)
{nallocs -= n; }
The member function subtracts n from the stored value nallocs.
max_variable_size::fullbool full()
{return nallocs / 16 + 16 <= nblocks; }
The member function returns true if nallocs / 16 + 16 <= nblocks.
max_variable_size::max_variable_sizemax_variable_size()
: nblocks(0), nallocs(0) {}
The constructor initializes the stored values nblocks
and nallocs to zero.
max_variable_size::releasedvoid released()
{--nblocks; }
The member function decrements the stored value nblocks.
max_variable_size::savedvoid saved()
{++nblocks; }
The member function increments the stored value nblocks.
rts_alloctemplate <class Cache> class rts_alloc {
public:
void *allocate(std::size_t);
void deallocate(void *, std::size_t);
bool equals(const rts_alloc<Cache>&) const;
private:
Cache caches[COUNT];
};
The template class describes a filter
that holds an array of Cache instances and determines which instance
to use for allocation and deallocation at runtime instead of at compile time. It is
used with compilers that cannot compile rebind.
rts_alloc::allocatevoid *allocate(std::size_t n);
The member function returns cache[idx].allocate(n), where the
index idx is determined by the requested block size n,
or, if n is too large, it returns ::operator new(n).
rts_alloc::deallocatevoid deallocate(void *ptr, std::size_t n);
The member function calls cache[idx].deallocate(ptr, n), where
index idx is determined by the requested block size n,
or, if n is too large, it returns ::operator delete(ptr).
rts_alloc::equalsbool equals(const sync<Cache>& other) const;
The member function returns cache[0].equals(other.cache[0]).
SYNC_DEFAULT#define SYNC_DEFAULT <sync_template>
If a compiler supports compiling both single-threaded and multi-threaded
applications, for single-threaded applications the macro yields
Dinkum::allocators::sync_none; in all other cases it
yields Dinkum::allocators::sync_shared.
sync_nonetemplate <class Cache> class sync_none {
public:
void *allocate(std::size_t n)
{return cache.allocate(n); }
void deallocate(void *ptr, std::size_t n)
{cache.deallocate(ptr, n); }
bool equals(const sync_none<Cache>&) const
{return true; }
private:
static Cache cache;
};
The template class describes a synchronization filter that provides no synchronization.
sync_none::allocatevoid *allocate(std::size_t n)
{return cache.allocate(n); }
The member function returns cache.allocate(n).
sync_none::deallocatevoid deallocate(void *ptr, std::size_t n)
{cache.deallocate(ptr, n); }
The member function calls cache.deallocate(ptr, n).
sync_none::equalsbool equals(const sync<Cache>&) const
[return true; }
The member function returns true.
sync_per_containertemplate <class Cache> class sync_per_container
: public Cache {
public:
bool equals(const sync_per_container<Cache>&) const
{return false; }
};
The template class describes a synchronization filter
that provides a separate Cache object for each allocator object.
sync_per_container::equalsbool equals(const sync<Cache>&) const
[return false; }
The member function returns false.
sync_per_threadtemplate <class Cache> class sync_per_thread {
public:
void *allocate(std::size_t);
void deallocate(void *, std::size_t);
bool equals(const sync_per_thread<Cache>&) const;
private:
static threads::thread_specific_ptr<Cache> cache_ptr;
};
The template class describes a
synchronization filter
that provides a separate Cache object for each thread.
Caution: allocators that use sync_per_thread can
compare equal even though blocks allocated in one thread
cannot be deallocated from another thread. When using one of these allocators memory
blocks allocated in one thread should not be made visible to other threads. In
practice this means that a container that uses one of these allocators should
only be accessed by a single thread.
sync_per_thread::allocatevoid *allocate(std::size_t n);
The member function returns the result of a call to Cache::allocate(n) on the
Cache object belonging to the current thread. If no Cache object
has been allocated for the current thread it first allocates one.
sync_per_thread::deallocatevoid deallocate(void *ptr, std::size_t n);
The member function calls Cache::deallocate(ptr, n) on the
Cache object belonging to the current thread. If no Cache object
has been allocated for the current thread it first allocates one.
sync_per_thread::equalsbool equals(const sync<Cache>& other) const;
The member function returns false if no Cache object has been allocated
for this object or for other in the current thread. Otherwise it returns the result
of applying operator== to the two Cache objects.
sync_sharedtemplate <class Cache> class sync_shared {
public:
void *allocate(std::size_t);
void deallocate(void *, std::size_t);
bool equals(const sync_shared<Cache>&) const;
private:
static Cache cache;
static threads::mutex mutex;
};
The template class describes a synchronization filter
that uses a mutex to control access to a Cache object that is shared by
all allocators.
sync_shared::allocatevoid *allocate(std::size_t n);
The member function locks the mutex, calls cache.allocate(n), unlocks
the mutex, and returns the result of the earlier call to cache.allocate(n).
sync_shared::deallocatevoid deallocate(void *ptr, std::size_t n);
The member function locks the mutex, calls cache.deallocate(ptr, n), and
unlocks the mutex.
sync_shared::equalsbool equals(const sync<Cache>& other) const;
The member function returns cache.equals(other.cache).
See also the Table of Contents and the Index.
Copyright © 1992-2013 by Dinkumware, Ltd. All rights reserved.