replace old implementation with the ingeious from Rich Sposato

git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@200 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
syntheticpp 2005-07-31 13:51:31 +00:00
parent 8d3a79495c
commit 7382c3dde0
2 changed files with 590 additions and 320 deletions

View file

@ -13,7 +13,8 @@
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
// $Header$
#ifndef SMALLOBJ_INC_
#define SMALLOBJ_INC_
@ -21,161 +22,249 @@
#include "Threads.h"
#include "Singleton.h"
#include <cstddef>
#include <vector>
#include <new> // needed for std::nothrow_t parameter.
#ifndef DEFAULT_CHUNK_SIZE
#define DEFAULT_CHUNK_SIZE 4096
#endif
#ifndef MAX_SMALL_OBJECT_SIZE
#define MAX_SMALL_OBJECT_SIZE 64
#define MAX_SMALL_OBJECT_SIZE 256
#endif
#ifndef LOKI_DEFAULT_OBJECT_ALIGNMENT
#define LOKI_DEFAULT_OBJECT_ALIGNMENT 4
#endif
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class FixedAllocator
// Offers services for allocating fixed-sized objects
////////////////////////////////////////////////////////////////////////////////
class FixedAllocator;
class FixedAllocator
{
private:
struct Chunk
{
void Init(std::size_t blockSize, unsigned char blocks);
void* Allocate(std::size_t blockSize);
void Deallocate(void* p, std::size_t blockSize);
void Reset(std::size_t blockSize, unsigned char blocks);
void Release();
unsigned char* pData_;
unsigned char
firstAvailableBlock_,
blocksAvailable_;
};
// Internal functions
void DoDeallocate(void* p);
Chunk* VicinityFind(void* p);
// Data
std::size_t blockSize_;
unsigned char numBlocks_;
typedef std::vector<Chunk> Chunks;
Chunks chunks_;
Chunk* allocChunk_;
Chunk* deallocChunk_;
// For ensuring proper copy semantics
mutable const FixedAllocator* prev_;
mutable const FixedAllocator* next_;
public:
// Create a FixedAllocator able to manage blocks of 'blockSize' size
explicit FixedAllocator(std::size_t blockSize = 0);
FixedAllocator(const FixedAllocator&);
FixedAllocator& operator=(const FixedAllocator&);
~FixedAllocator();
void Swap(FixedAllocator& rhs);
// Allocate a memory block
void* Allocate();
// Deallocate a memory block previously allocated with Allocate()
// (if that's not the case, the behavior is undefined)
void Deallocate(void* p);
// Returns the block size with which the FixedAllocator was initialized
std::size_t BlockSize() const
{ return blockSize_; }
};
////////////////////////////////////////////////////////////////////////////////
// class SmallObjAllocator
// Offers services for allocating small-sized objects
// Manages pool of fixed-size allocators.
////////////////////////////////////////////////////////////////////////////////
class SmallObjAllocator
{
protected:
SmallObjAllocator( std::size_t pageSize, std::size_t maxObjectSize,
std::size_t objectAlignSize );
~SmallObjAllocator( void );
public:
SmallObjAllocator(
std::size_t chunkSize,
std::size_t maxObjectSize);
void* Allocate(std::size_t numBytes);
void Deallocate(void* p, std::size_t size);
void * Allocate( std::size_t size, bool doThrow );
void Deallocate( void * p, std::size_t size );
inline std::size_t GetMaxObjectSize() const { return maxSmallObjectSize_; }
inline std::size_t GetAlignment() const { return objectAlignSize_; }
private:
SmallObjAllocator(const SmallObjAllocator&);
SmallObjAllocator& operator=(const SmallObjAllocator&);
typedef std::vector<FixedAllocator> Pool;
Pool pool_;
FixedAllocator* pLastAlloc_;
FixedAllocator* pLastDealloc_;
std::size_t chunkSize_;
std::size_t maxObjectSize_;
/// Copy-constructor is not implemented.
SmallObjAllocator( const SmallObjAllocator & );
/// Copy-assignment operator is not implemented.
SmallObjAllocator & operator = ( const SmallObjAllocator & );
Loki::FixedAllocator * pool_;
std::size_t maxSmallObjectSize_;
std::size_t objectAlignSize_;
};
////////////////////////////////////////////////////////////////////////////////
// class AllocatorSingleton
// This template class is derived from SmallObjAllocator in order to pass template
// arguments into SmallObjAllocator, and still have a default constructor for the
// singleton.
////////////////////////////////////////////////////////////////////////////////
template
<
template <class> class ThreadingModel,
std::size_t chunkSize,
std::size_t maxSmallObjectSize,
std::size_t objectAlignSize
>
class AllocatorSingleton : public SmallObjAllocator
{
public:
inline AllocatorSingleton() :
SmallObjAllocator( chunkSize, maxSmallObjectSize, objectAlignSize )
{}
inline ~AllocatorSingleton( void ) {}
private:
/// Copy-constructor is not implemented.
AllocatorSingleton( const AllocatorSingleton & );
/// Copy-assignment operator is not implemented.
AllocatorSingleton & operator = ( const AllocatorSingleton & );
};
////////////////////////////////////////////////////////////////////////////////
// class SmallObjectBase
// Base class for small object allocation classes.
////////////////////////////////////////////////////////////////////////////////
template
<
template <class> class ThreadingModel,
std::size_t chunkSize,
std::size_t maxSmallObjectSize,
std::size_t objectAlignSize,
template <class> class LifetimePolicy
>
class SmallObjectBase
{
#if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0) && (LOKI_DEFAULT_OBJECT_ALIGNMENT != 0)
/// Defines type of allocator.
typedef AllocatorSingleton< ThreadingModel, chunkSize,
maxSmallObjectSize, objectAlignSize > MyAllocator;
/// Defines type for thread-safety locking mechanism.
typedef ThreadingModel< MyAllocator > MyThreadingModel;
/// Defines singleton made from allocator.
typedef Loki::SingletonHolder< MyAllocator, Loki::CreateStatic,
LifetimePolicy, ThreadingModel > MyAllocatorSingleton;
public:
/** Throwing single-object new.
@note The exception specification is commented to prevent warning
from MS compiler.
*/
static void * operator new ( std::size_t size ) // throw ( std::bad_alloc )
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
return MyAllocatorSingleton::Instance().Allocate( size, true );
}
/// Non-throwing single-object new.
static void * operator new ( std::size_t size, const std::nothrow_t & ) throw ()
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
return MyAllocatorSingleton::Instance().Allocate( size, false );
}
/// Placement single-object new.
inline static void * operator new ( std::size_t size, void * place )
{
return ::operator new( size, place );
}
/// Single-object delete.
static void operator delete ( void * p, std::size_t size ) throw ()
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
MyAllocatorSingleton::Instance().Deallocate( p, size );
}
/// Non-throwing single-object delete.
static void operator delete ( void * p, std::size_t size,
const std::nothrow_t & ) throw()
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
MyAllocatorSingleton::Instance().Deallocate( p, size );
}
/// Placement single-object delete.
inline static void operator delete ( void * p, void * place )
{
::operator delete ( p, place );
}
#endif // #if default template parameters are not zero
protected:
inline SmallObjectBase( void ) {}
inline SmallObjectBase( const SmallObjectBase & ) {}
inline SmallObjectBase & operator = ( const SmallObjectBase & ) {}
inline ~SmallObjectBase() {}
}; // end class SmallObjectBase
////////////////////////////////////////////////////////////////////////////////
// class SmallObject
// Base class for polymorphic small objects, offers fast
// allocations/deallocations
// Base class for polymorphic small objects, offers fast allocations &
// deallocations. Destructor is virtual and public.
////////////////////////////////////////////////////////////////////////////////
template
<
template <class> class ThreadingModel = DEFAULT_THREADING,
std::size_t chunkSize = DEFAULT_CHUNK_SIZE,
std::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE
std::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE,
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
template <class> class LifetimePolicy = Loki::NoDestroy
>
class SmallObject : public ThreadingModel<
SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >
class SmallObject : public SmallObjectBase< ThreadingModel, chunkSize,
maxSmallObjectSize, objectAlignSize, LifetimePolicy >
{
typedef ThreadingModel< SmallObject<ThreadingModel,
chunkSize, maxSmallObjectSize> > MyThreadingModel;
struct MySmallObjAllocator : public SmallObjAllocator
{
MySmallObjAllocator()
: SmallObjAllocator(chunkSize, maxSmallObjectSize)
{}
};
// The typedef below would make things much simpler,
// but MWCW won't like it
// typedef SingletonHolder<MySmallObjAllocator/*, CreateStatic,
// DefaultLifetime, ThreadingModel*/> MyAllocator;
public:
static void* operator new(std::size_t size)
{
#if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0)
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
return SingletonHolder<MySmallObjAllocator, CreateStatic,
PhoenixSingleton>::Instance().Allocate(size);
#else
return ::operator new(size);
#endif
}
static void operator delete(void* p, std::size_t size)
{
#if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0)
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
SingletonHolder<MySmallObjAllocator, CreateStatic,
PhoenixSingleton>::Instance().Deallocate(p, size);
#else
::operator delete(p);
#endif
}
virtual ~SmallObject() {}
};
protected:
inline SmallObject( void ) {}
private:
/// Copy-constructor is not implemented.
SmallObject( const SmallObject & );
/// Copy-assignment operator is not implemented.
SmallObject & operator = ( const SmallObject & );
}; // end class SmallObject
////////////////////////////////////////////////////////////////////////////////
// class SmallValueObject
// Base class for small objects with value semantics - offers fast allocations &
// deallocations. Destructor is non-virtual, inline, and protected.
////////////////////////////////////////////////////////////////////////////////
template
<
template <class> class ThreadingModel = DEFAULT_THREADING,
std::size_t chunkSize = DEFAULT_CHUNK_SIZE,
std::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE,
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
template <class> class LifetimePolicy = Loki::NoDestroy
>
class SmallValueObject : public SmallObjectBase< ThreadingModel, chunkSize,
maxSmallObjectSize, objectAlignSize, LifetimePolicy >
{
protected:
inline SmallValueObject( void ) {}
inline SmallValueObject( const SmallValueObject & ) {}
inline SmallValueObject & operator = ( const SmallValueObject & ) {}
inline ~SmallValueObject() {}
}; // end class SmallValueObject
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Nov. 26, 2004: re-implemented by Rich Sposato.
////////////////////////////////////////////////////////////////////////////////
#endif // SMALLOBJ_INC_
// $Log$
// Revision 1.2 2005/07/31 13:51:31 syntheticpp
// replace old implementation with the ingeious from Rich Sposato
//
// Revision 1.2 2005/07/22 00:22:38 rich_sposato
// Added SmallValueObject, SmallObjectBase, and AllocatorSingleton classes.
//