2002-08-11 05:49:45 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The Loki Library
|
|
|
|
// Copyright (c) 2001 by Andrei Alexandrescu
|
|
|
|
// This code accompanies the book:
|
|
|
|
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
|
|
|
|
// Patterns Applied". Copyright (c) 2001. Addison-Wesley.
|
|
|
|
// Permission to use, copy, modify, distribute and sell this software for any
|
|
|
|
// purpose is hereby granted without fee, provided that the above copyright
|
|
|
|
// notice appear in all copies and that both that copyright notice and this
|
|
|
|
// permission notice appear in supporting documentation.
|
|
|
|
// The author or Addison-Wesley Longman make no representations about the
|
|
|
|
// suitability of this software for any purpose. It is provided "as is"
|
|
|
|
// without express or implied warranty.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2005-09-26 07:33:05 +00:00
|
|
|
#ifndef LOKI_SMALLOBJ_INC_
|
|
|
|
#define LOKI_SMALLOBJ_INC_
|
2002-08-11 05:49:45 +00:00
|
|
|
|
2006-10-17 19:48:40 +00:00
|
|
|
// $Id$
|
|
|
|
|
|
|
|
|
2010-04-19 03:09:59 +00:00
|
|
|
#include <loki/LokiExport.h>
|
|
|
|
#include <loki/Threads.h>
|
|
|
|
#include <loki/Singleton.h>
|
2002-08-11 05:49:45 +00:00
|
|
|
#include <cstddef>
|
2005-07-31 13:51:31 +00:00
|
|
|
#include <new> // needed for std::nothrow_t parameter.
|
2002-08-11 05:49:45 +00:00
|
|
|
|
2005-09-26 07:33:05 +00:00
|
|
|
#ifndef LOKI_DEFAULT_CHUNK_SIZE
|
|
|
|
#define LOKI_DEFAULT_CHUNK_SIZE 4096
|
2002-08-11 05:49:45 +00:00
|
|
|
#endif
|
|
|
|
|
2005-09-26 07:33:05 +00:00
|
|
|
#ifndef LOKI_MAX_SMALL_OBJECT_SIZE
|
|
|
|
#define LOKI_MAX_SMALL_OBJECT_SIZE 256
|
2005-07-31 13:51:31 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef LOKI_DEFAULT_OBJECT_ALIGNMENT
|
|
|
|
#define LOKI_DEFAULT_OBJECT_ALIGNMENT 4
|
2002-08-11 05:49:45 +00:00
|
|
|
#endif
|
|
|
|
|
2005-11-01 11:11:52 +00:00
|
|
|
#ifndef LOKI_DEFAULT_SMALLOBJ_LIFETIME
|
2006-10-26 10:58:19 +00:00
|
|
|
#define LOKI_DEFAULT_SMALLOBJ_LIFETIME ::Loki::LongevityLifetime::DieAsSmallObjectParent
|
2005-11-01 11:11:52 +00:00
|
|
|
#endif
|
|
|
|
|
2005-10-29 08:10:13 +00:00
|
|
|
#if defined(LOKI_SMALL_OBJECT_USE_NEW_ARRAY) && defined(_MSC_VER)
|
2006-02-20 21:56:06 +00:00
|
|
|
#pragma message("Don't define LOKI_SMALL_OBJECT_USE_NEW_ARRAY when using a Microsoft compiler to prevent memory leaks.")
|
2005-10-29 08:10:13 +00:00
|
|
|
#pragma message("now calling '#undef LOKI_SMALL_OBJECT_USE_NEW_ARRAY'")
|
|
|
|
#undef LOKI_SMALL_OBJECT_USE_NEW_ARRAY
|
|
|
|
#endif
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-11-02 20:01:11 +00:00
|
|
|
/// \defgroup SmallObjectGroup Small objects
|
|
|
|
///
|
|
|
|
/// \defgroup SmallObjectGroupInternal Internals
|
|
|
|
/// \ingroup SmallObjectGroup
|
|
|
|
|
2002-08-11 05:49:45 +00:00
|
|
|
namespace Loki
|
|
|
|
{
|
2005-11-07 12:06:43 +00:00
|
|
|
namespace LongevityLifetime
|
|
|
|
{
|
|
|
|
/** @struct DieAsSmallObjectParent
|
2005-11-13 16:51:22 +00:00
|
|
|
@ingroup SmallObjectGroup
|
|
|
|
Lifetime policy to manage lifetime dependencies of
|
|
|
|
SmallObject base and child classes.
|
|
|
|
The Base class should have this lifetime
|
|
|
|
*/
|
2005-11-07 12:06:43 +00:00
|
|
|
template <class T>
|
|
|
|
struct DieAsSmallObjectParent : DieLast<T> {};
|
|
|
|
|
|
|
|
/** @struct DieAsSmallObjectChild
|
|
|
|
@ingroup SmallObjectGroup
|
2005-11-13 16:51:22 +00:00
|
|
|
Lifetime policy to manage lifetime dependencies of
|
|
|
|
SmallObject base and child classes.
|
|
|
|
The Child class should have this lifetime
|
|
|
|
*/
|
2005-11-07 12:06:43 +00:00
|
|
|
template <class T>
|
|
|
|
struct DieAsSmallObjectChild : DieDirectlyBeforeLast<T> {};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-09-08 01:03:21 +00:00
|
|
|
namespace Private
|
|
|
|
{
|
|
|
|
class FixedAllocator;
|
|
|
|
}; // end namespace Private
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-10-26 00:50:44 +00:00
|
|
|
/** @class SmallObjAllocator
|
2005-11-02 20:01:11 +00:00
|
|
|
@ingroup SmallObjectGroupInternal
|
2005-10-26 00:50:44 +00:00
|
|
|
Manages pool of fixed-size allocators.
|
2005-09-26 21:38:54 +00:00
|
|
|
Designed to be a non-templated base class of AllocatorSingleton so that
|
|
|
|
implementation details can be safely hidden in the source code file.
|
|
|
|
*/
|
2006-02-27 19:59:20 +00:00
|
|
|
class LOKI_EXPORT SmallObjAllocator
|
2002-08-11 05:49:45 +00:00
|
|
|
{
|
2005-07-31 13:51:31 +00:00
|
|
|
protected:
|
2005-09-26 21:38:54 +00:00
|
|
|
/** The only available constructor needs certain parameters in order to
|
|
|
|
initialize all the FixedAllocator's. This throws only if
|
|
|
|
@param pageSize # of bytes in a page of memory.
|
|
|
|
@param maxObjectSize Max # of bytes which this may allocate.
|
|
|
|
@param objectAlignSize # of bytes between alignment boundaries.
|
|
|
|
*/
|
2010-09-08 01:03:21 +00:00
|
|
|
SmallObjAllocator( ::std::size_t pageSize, ::std::size_t maxObjectSize,
|
|
|
|
::std::size_t objectAlignSize );
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/** Destructor releases all blocks, all Chunks, and FixedAllocator's.
|
|
|
|
Any outstanding blocks are unavailable, and should not be used after
|
2005-10-06 00:19:56 +00:00
|
|
|
this destructor is called. The destructor is deliberately non-virtual
|
|
|
|
because it is protected, not public.
|
2005-09-26 21:38:54 +00:00
|
|
|
*/
|
2005-07-31 13:51:31 +00:00
|
|
|
~SmallObjAllocator( void );
|
|
|
|
|
2002-08-11 05:49:45 +00:00
|
|
|
public:
|
2005-09-26 21:38:54 +00:00
|
|
|
/** Allocates a block of memory of requested size. Complexity is often
|
|
|
|
constant-time, but might be O(C) where C is the number of Chunks in a
|
|
|
|
FixedAllocator.
|
|
|
|
|
|
|
|
@par Exception Safety Level
|
|
|
|
Provides either strong-exception safety, or no-throw exception-safety
|
|
|
|
level depending upon doThrow parameter. The reason it provides two
|
|
|
|
levels of exception safety is because it is used by both the nothrow
|
|
|
|
and throwing new operators. The underlying implementation will never
|
|
|
|
throw of its own accord, but this can decide to throw if it does not
|
|
|
|
allocate. The only exception it should emit is std::bad_alloc.
|
|
|
|
|
|
|
|
@par Allocation Failure
|
|
|
|
If it does not allocate, it will call TrimExcessMemory and attempt to
|
|
|
|
allocate again, before it decides to throw or return NULL. Many
|
|
|
|
allocators loop through several new_handler functions, and terminate
|
|
|
|
if they can not allocate, but not this one. It only makes one attempt
|
|
|
|
using its own implementation of the new_handler, and then returns NULL
|
|
|
|
or throws so that the program can decide what to do at a higher level.
|
|
|
|
(Side note: Even though the C++ Standard allows allocators and
|
|
|
|
new_handlers to terminate if they fail, the Loki allocator does not do
|
|
|
|
that since that policy is not polite to a host program.)
|
|
|
|
|
|
|
|
@param size # of bytes needed for allocation.
|
|
|
|
@param doThrow True if this should throw if unable to allocate, false
|
|
|
|
if it should provide no-throw exception safety level.
|
|
|
|
@return NULL if nothing allocated and doThrow is false. Else the
|
|
|
|
pointer to an available block of memory.
|
|
|
|
*/
|
2005-07-31 13:51:31 +00:00
|
|
|
void * Allocate( std::size_t size, bool doThrow );
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/** Deallocates a block of memory at a given place and of a specific
|
|
|
|
size. Complexity is almost always constant-time, and is O(C) only if
|
|
|
|
it has to search for which Chunk deallocates. This never throws.
|
|
|
|
*/
|
2005-07-31 13:51:31 +00:00
|
|
|
void Deallocate( void * p, std::size_t size );
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/** Deallocates a block of memory at a given place but of unknown size
|
|
|
|
size. Complexity is O(F + C) where F is the count of FixedAllocator's
|
|
|
|
in the pool, and C is the number of Chunks in all FixedAllocator's. This
|
|
|
|
does not throw exceptions. This overloaded version of Deallocate is
|
|
|
|
called by the nothow delete operator - which is called when the nothrow
|
|
|
|
new operator is used, but a constructor throws an exception.
|
|
|
|
*/
|
2005-09-09 00:25:00 +00:00
|
|
|
void Deallocate( void * p );
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Returns max # of bytes which this can allocate.
|
2010-09-08 01:03:21 +00:00
|
|
|
inline ::std::size_t GetMaxObjectSize() const
|
2005-12-08 22:09:08 +00:00
|
|
|
{ return maxSmallObjectSize_; }
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Returns # of bytes between allocation boundaries.
|
2005-07-31 13:51:31 +00:00
|
|
|
inline std::size_t GetAlignment() const { return objectAlignSize_; }
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/** Releases empty Chunks from memory. Complexity is O(F + C) where F
|
|
|
|
is the count of FixedAllocator's in the pool, and C is the number of
|
|
|
|
Chunks in all FixedAllocator's. This will never throw. This is called
|
|
|
|
by AllocatorSingleto::ClearExtraMemory, the new_handler function for
|
|
|
|
Loki's allocator, and is called internally when an allocation fails.
|
|
|
|
@return True if any memory released, or false if none released.
|
|
|
|
*/
|
2005-09-09 00:25:00 +00:00
|
|
|
bool TrimExcessMemory( void );
|
|
|
|
|
2005-12-08 22:09:08 +00:00
|
|
|
/** Returns true if anything in implementation is corrupt. Complexity
|
|
|
|
is O(F + C + B) where F is the count of FixedAllocator's in the pool,
|
|
|
|
C is the number of Chunks in all FixedAllocator's, and B is the number
|
|
|
|
of blocks in all Chunks. If it determines any data is corrupted, this
|
|
|
|
will return true in release version, but assert in debug version at
|
|
|
|
the line where it detects the corrupted data. If it does not detect
|
|
|
|
any corrupted data, it returns false.
|
|
|
|
*/
|
|
|
|
bool IsCorrupt( void ) const;
|
|
|
|
|
2005-07-31 13:51:31 +00:00
|
|
|
private:
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Default-constructor is not implemented.
|
|
|
|
SmallObjAllocator( void );
|
2005-07-31 13:51:31 +00:00
|
|
|
/// Copy-constructor is not implemented.
|
|
|
|
SmallObjAllocator( const SmallObjAllocator & );
|
|
|
|
/// Copy-assignment operator is not implemented.
|
|
|
|
SmallObjAllocator & operator = ( const SmallObjAllocator & );
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Pointer to array of fixed-size allocators.
|
2010-09-08 01:03:21 +00:00
|
|
|
::Loki::Private::FixedAllocator * pool_;
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Largest object size supported by allocators.
|
2010-09-08 01:03:21 +00:00
|
|
|
const ::std::size_t maxSmallObjectSize_;
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Size of alignment boundaries.
|
2010-09-08 01:03:21 +00:00
|
|
|
const ::std::size_t objectAlignSize_;
|
2002-08-11 05:49:45 +00:00
|
|
|
};
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-10-26 00:50:44 +00:00
|
|
|
/** @class AllocatorSingleton
|
2005-11-02 20:01:11 +00:00
|
|
|
@ingroup SmallObjectGroupInternal
|
2005-10-26 00:50:44 +00:00
|
|
|
This template class is derived from
|
2005-10-07 01:22:09 +00:00
|
|
|
SmallObjAllocator in order to pass template arguments into it, and still
|
|
|
|
have a default constructor for the singleton. Each instance is a unique
|
|
|
|
combination of all the template parameters, and hence is singleton only
|
|
|
|
with respect to those parameters. The template parameters have default
|
|
|
|
values and the class has typedefs identical to both SmallObject and
|
|
|
|
SmallValueObject so that this class can be used directly instead of going
|
|
|
|
through SmallObject or SmallValueObject. That design feature allows
|
|
|
|
clients to use the new_handler without having the name of the new_handler
|
|
|
|
function show up in classes derived from SmallObject or SmallValueObject.
|
|
|
|
Thus, the only functions in the allocator which show up in SmallObject or
|
2005-11-02 20:01:11 +00:00
|
|
|
SmallValueObject inheritance hierarchies are the new and delete
|
2005-10-07 01:22:09 +00:00
|
|
|
operators.
|
2005-09-26 21:38:54 +00:00
|
|
|
*/
|
2005-07-31 13:51:31 +00:00
|
|
|
template
|
|
|
|
<
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
|
2005-09-26 07:33:05 +00:00
|
|
|
std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE,
|
|
|
|
std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE,
|
2005-09-09 00:25:00 +00:00
|
|
|
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME,
|
2006-06-19 12:39:09 +00:00
|
|
|
class MutexPolicy = LOKI_DEFAULT_MUTEX
|
2005-07-31 13:51:31 +00:00
|
|
|
>
|
|
|
|
class AllocatorSingleton : public SmallObjAllocator
|
2002-08-11 05:49:45 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-09-09 00:25:00 +00:00
|
|
|
|
|
|
|
/// Defines type of allocator.
|
|
|
|
typedef AllocatorSingleton< ThreadingModel, chunkSize,
|
|
|
|
maxSmallObjectSize, objectAlignSize, LifetimePolicy > MyAllocator;
|
|
|
|
|
|
|
|
/// Defines type for thread-safety locking mechanism.
|
2006-01-22 13:31:45 +00:00
|
|
|
typedef ThreadingModel< MyAllocator, MutexPolicy > MyThreadingModel;
|
2005-09-09 00:25:00 +00:00
|
|
|
|
|
|
|
/// Defines singleton made from allocator.
|
|
|
|
typedef Loki::SingletonHolder< MyAllocator, Loki::CreateStatic,
|
|
|
|
LifetimePolicy, ThreadingModel > MyAllocatorSingleton;
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Returns reference to the singleton.
|
2005-09-09 00:25:00 +00:00
|
|
|
inline static AllocatorSingleton & Instance( void )
|
|
|
|
{
|
|
|
|
return MyAllocatorSingleton::Instance();
|
|
|
|
}
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// The default constructor is not meant to be called directly.
|
2005-07-31 13:51:31 +00:00
|
|
|
inline AllocatorSingleton() :
|
|
|
|
SmallObjAllocator( chunkSize, maxSmallObjectSize, objectAlignSize )
|
|
|
|
{}
|
2005-09-26 21:38:54 +00:00
|
|
|
|
|
|
|
/// The destructor is not meant to be called directly.
|
2005-07-31 13:51:31 +00:00
|
|
|
inline ~AllocatorSingleton( void ) {}
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/** Clears any excess memory used by the allocator. Complexity is
|
|
|
|
O(F + C) where F is the count of FixedAllocator's in the pool, and C
|
|
|
|
is the number of Chunks in all FixedAllocator's. This never throws.
|
|
|
|
@note This function can be used as a new_handler when Loki and other
|
|
|
|
memory allocators can no longer allocate. Although the C++ Standard
|
|
|
|
allows new_handler functions to terminate the program when they can
|
|
|
|
not release any memory, this will not do so.
|
|
|
|
*/
|
2005-09-09 00:25:00 +00:00
|
|
|
static void ClearExtraMemory( void );
|
|
|
|
|
2005-12-08 22:09:08 +00:00
|
|
|
/** Returns true if anything in implementation is corrupt. Complexity
|
|
|
|
is O(F + C + B) where F is the count of FixedAllocator's in the pool,
|
|
|
|
C is the number of Chunks in all FixedAllocator's, and B is the number
|
|
|
|
of blocks in all Chunks. If it determines any data is corrupted, this
|
|
|
|
will return true in release version, but assert in debug version at
|
|
|
|
the line where it detects the corrupted data. If it does not detect
|
|
|
|
any corrupted data, it returns false.
|
|
|
|
*/
|
|
|
|
static bool IsCorrupted( void );
|
|
|
|
|
2002-08-11 05:49:45 +00:00
|
|
|
private:
|
2005-07-31 13:51:31 +00:00
|
|
|
/// Copy-constructor is not implemented.
|
|
|
|
AllocatorSingleton( const AllocatorSingleton & );
|
|
|
|
/// Copy-assignment operator is not implemented.
|
|
|
|
AllocatorSingleton & operator = ( const AllocatorSingleton & );
|
2002-08-11 05:49:45 +00:00
|
|
|
};
|
|
|
|
|
2005-09-09 00:25:00 +00:00
|
|
|
template
|
|
|
|
<
|
2006-11-09 13:26:08 +00:00
|
|
|
template <class, class> class T,
|
|
|
|
std::size_t C,
|
|
|
|
std::size_t M,
|
|
|
|
std::size_t O,
|
|
|
|
template <class> class L,
|
|
|
|
class X
|
2005-09-09 00:25:00 +00:00
|
|
|
>
|
2006-11-09 13:26:08 +00:00
|
|
|
void AllocatorSingleton< T, C, M, O, L, X >::ClearExtraMemory( void )
|
2005-09-09 00:25:00 +00:00
|
|
|
{
|
|
|
|
typename MyThreadingModel::Lock lock;
|
|
|
|
(void)lock; // get rid of warning
|
|
|
|
Instance().TrimExcessMemory();
|
|
|
|
}
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-12-08 22:09:08 +00:00
|
|
|
template
|
|
|
|
<
|
2006-11-09 13:26:08 +00:00
|
|
|
template <class, class> class T,
|
|
|
|
std::size_t C,
|
|
|
|
std::size_t M,
|
|
|
|
std::size_t O,
|
|
|
|
template <class> class L,
|
|
|
|
class X
|
2005-12-08 22:09:08 +00:00
|
|
|
>
|
2006-11-09 13:26:08 +00:00
|
|
|
bool AllocatorSingleton< T, C, M, O, L, X >::IsCorrupted( void )
|
2005-12-08 22:09:08 +00:00
|
|
|
{
|
|
|
|
typename MyThreadingModel::Lock lock;
|
|
|
|
(void)lock; // get rid of warning
|
|
|
|
return Instance().IsCorrupt();
|
|
|
|
}
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-10-07 01:22:09 +00:00
|
|
|
/** This standalone function provides the longevity level for Small-Object
|
2005-10-13 22:43:03 +00:00
|
|
|
Allocators which use the Loki::SingletonWithLongevity policy. The
|
|
|
|
SingletonWithLongevity class can find this function through argument-
|
|
|
|
dependent lookup.
|
|
|
|
|
|
|
|
@par Longevity Levels
|
|
|
|
No Small-Object Allocator depends on any other Small-Object allocator, so
|
|
|
|
this does not need to calculate dependency levels among allocators, and
|
|
|
|
it returns just a constant. All allocators must live longer than the
|
|
|
|
objects which use the allocators, it must return a longevity level higher
|
|
|
|
than any such object.
|
2005-10-07 01:22:09 +00:00
|
|
|
*/
|
|
|
|
template
|
|
|
|
<
|
2006-11-09 13:26:08 +00:00
|
|
|
template <class, class> class T,
|
|
|
|
std::size_t C,
|
|
|
|
std::size_t M,
|
|
|
|
std::size_t O,
|
|
|
|
template <class> class L,
|
|
|
|
class X
|
2005-10-07 01:22:09 +00:00
|
|
|
>
|
|
|
|
inline unsigned int GetLongevity(
|
2006-11-09 13:26:08 +00:00
|
|
|
AllocatorSingleton< T, C, M, O, L, X > * )
|
2005-10-07 01:22:09 +00:00
|
|
|
{
|
|
|
|
// Returns highest possible value.
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-26 00:50:44 +00:00
|
|
|
/** @class SmallObjectBase
|
2005-11-13 16:51:22 +00:00
|
|
|
@ingroup SmallObjectGroup
|
2005-10-26 00:50:44 +00:00
|
|
|
Base class for small object allocation classes.
|
2005-09-26 21:38:54 +00:00
|
|
|
The shared implementation of the new and delete operators are here instead
|
2005-11-13 16:51:22 +00:00
|
|
|
of being duplicated in both SmallObject or SmallValueObject, later just
|
|
|
|
called Small-Objects. This class is not meant to be used directly by clients,
|
|
|
|
or derived from by clients. Class has no data members so compilers can
|
|
|
|
use Empty-Base-Optimization.
|
|
|
|
|
2006-11-03 00:52:31 +00:00
|
|
|
@par ThreadingModel
|
|
|
|
This class doesn't support ObjectLevelLockable policy for ThreadingModel.
|
|
|
|
The allocator is a singleton, so a per-instance mutex is not necessary.
|
|
|
|
Nor is using ObjectLevelLockable recommended with SingletonHolder since
|
|
|
|
the SingletonHolder::MakeInstance function requires a mutex that exists
|
|
|
|
prior to when the object is created - which is not possible if the mutex
|
|
|
|
is inside the object, such as required for ObjectLevelLockable. If you
|
|
|
|
attempt to use ObjectLevelLockable, the compiler will emit errors because
|
|
|
|
it can't use the default constructor in ObjectLevelLockable. If you need
|
|
|
|
a thread-safe allocator, use the ClassLevelLockable policy.
|
|
|
|
|
2005-11-13 16:51:22 +00:00
|
|
|
@par Lifetime Policy
|
|
|
|
|
|
|
|
The SmallObjectBase template needs a lifetime policy because it owns
|
|
|
|
a singleton of SmallObjAllocator which does all the low level functions.
|
|
|
|
When using a Small-Object in combination with the SingletonHolder template
|
|
|
|
you have to choose two lifetimes, that of the Small-Object and that of
|
|
|
|
the singleton. The rule is: The Small-Object lifetime must be greater than
|
|
|
|
the lifetime of the singleton hosting the Small-Object. Violating this rule
|
|
|
|
results in a crash on exit, because the hosting singleton tries to delete
|
|
|
|
the Small-Object which is then already destroyed.
|
|
|
|
|
|
|
|
The lifetime policies recommended for use with Small-Objects hosted
|
|
|
|
by a SingletonHolder template are
|
|
|
|
- LongevityLifetime::DieAsSmallObjectParent / LongevityLifetime::DieAsSmallObjectChild
|
|
|
|
- SingletonWithLongevity
|
|
|
|
- FollowIntoDeath (not supported by MSVC 7.1)
|
|
|
|
- NoDestroy
|
|
|
|
|
|
|
|
The default lifetime of Small-Objects is
|
|
|
|
LongevityLifetime::DieAsSmallObjectParent to
|
|
|
|
insure that memory is not released before a object with the lifetime
|
|
|
|
LongevityLifetime::DieAsSmallObjectChild using that
|
|
|
|
memory is destroyed. The LongevityLifetime::DieAsSmallObjectParent
|
|
|
|
lifetime has the highest possible value of a SetLongevity lifetime, so
|
|
|
|
you can use it in combination with your own lifetime not having also
|
|
|
|
the highest possible value.
|
|
|
|
|
|
|
|
The DefaultLifetime and PhoenixSingleton policies are *not* recommended
|
|
|
|
since they can cause the allocator to be destroyed and release memory
|
|
|
|
for singletons hosting a object which inherit from either SmallObject
|
|
|
|
or SmallValueObject.
|
|
|
|
|
|
|
|
@par Lifetime usage
|
|
|
|
|
|
|
|
- LongevityLifetime: The Small-Object has
|
|
|
|
LongevityLifetime::DieAsSmallObjectParent policy and the Singleton
|
|
|
|
hosting the Small-Object has LongevityLifetime::DieAsSmallObjectChild.
|
|
|
|
The child lifetime has a hard coded SetLongevity lifetime which is
|
|
|
|
shorter than the lifetime of the parent, thus the child dies
|
|
|
|
before the parent.
|
|
|
|
|
|
|
|
- Both Small-Object and Singleton use SingletonWithLongevity policy.
|
|
|
|
The longevity level for the singleton must be lower than that for the
|
|
|
|
Small-Object. This is why the AllocatorSingleton's GetLongevity function
|
|
|
|
returns the highest value.
|
|
|
|
|
|
|
|
- FollowIntoDeath lifetime: The Small-Object has
|
|
|
|
FollowIntoDeath::With<LIFETIME>::AsMasterLiftime
|
|
|
|
policy and the Singleton has
|
|
|
|
FollowIntoDeath::AfterMaster<MASTERSINGLETON>::IsDestroyed policy,
|
|
|
|
where you could choose the LIFETIME.
|
|
|
|
|
|
|
|
- Both Small-Object and Singleton use NoDestroy policy.
|
|
|
|
Since neither is ever destroyed, the destruction order does not matter.
|
2006-11-03 00:52:31 +00:00
|
|
|
Note: you will get memory leaks!
|
2005-11-13 16:51:22 +00:00
|
|
|
|
|
|
|
- The Small-Object has NoDestroy policy but the Singleton has
|
2006-11-03 00:52:31 +00:00
|
|
|
SingletonWithLongevity policy. Note: you will get memory leaks!
|
2005-11-13 16:51:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
You should *not* use NoDestroy for the singleton, and then use
|
|
|
|
SingletonWithLongevity for the Small-Object.
|
|
|
|
|
|
|
|
@par Examples:
|
|
|
|
|
|
|
|
- test/SmallObj/SmallSingleton.cpp
|
|
|
|
- test/Singleton/Dependencies.cpp
|
2005-09-26 21:38:54 +00:00
|
|
|
*/
|
2002-08-11 05:49:45 +00:00
|
|
|
template
|
|
|
|
<
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class, class> class ThreadingModel,
|
2005-07-31 13:51:31 +00:00
|
|
|
std::size_t chunkSize,
|
|
|
|
std::size_t maxSmallObjectSize,
|
|
|
|
std::size_t objectAlignSize,
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class> class LifetimePolicy,
|
2006-06-19 12:39:09 +00:00
|
|
|
class MutexPolicy
|
2002-08-11 05:49:45 +00:00
|
|
|
>
|
2005-10-30 14:03:23 +00:00
|
|
|
class SmallObjectBase
|
2002-08-11 05:49:45 +00:00
|
|
|
{
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-09-26 07:33:05 +00:00
|
|
|
#if (LOKI_MAX_SMALL_OBJECT_SIZE != 0) && (LOKI_DEFAULT_CHUNK_SIZE != 0) && (LOKI_DEFAULT_OBJECT_ALIGNMENT != 0)
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-11-01 11:11:52 +00:00
|
|
|
public:
|
|
|
|
/// Defines type of allocator singleton, must be public
|
|
|
|
/// to handle singleton lifetime dependencies.
|
2005-07-31 13:51:31 +00:00
|
|
|
typedef AllocatorSingleton< ThreadingModel, chunkSize,
|
2005-11-01 11:11:52 +00:00
|
|
|
maxSmallObjectSize, objectAlignSize, LifetimePolicy > ObjAllocatorSingleton;
|
|
|
|
|
|
|
|
private:
|
2005-07-31 13:51:31 +00:00
|
|
|
|
|
|
|
/// Defines type for thread-safety locking mechanism.
|
2006-01-22 13:31:45 +00:00
|
|
|
typedef ThreadingModel< ObjAllocatorSingleton, MutexPolicy > MyThreadingModel;
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-11-01 11:11:52 +00:00
|
|
|
/// Use singleton defined in AllocatorSingleton.
|
|
|
|
typedef typename ObjAllocatorSingleton::MyAllocatorSingleton MyAllocatorSingleton;
|
2005-10-30 14:03:23 +00:00
|
|
|
|
2002-08-11 05:49:45 +00:00
|
|
|
public:
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Throwing single-object new throws bad_alloc when allocation fails.
|
2005-09-01 22:01:33 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
/// @note MSVC complains about non-empty exception specification lists.
|
|
|
|
static void * operator new ( std::size_t size )
|
|
|
|
#else
|
|
|
|
static void * operator new ( std::size_t size ) throw ( std::bad_alloc )
|
|
|
|
#endif
|
2002-08-11 05:49:45 +00:00
|
|
|
{
|
|
|
|
typename MyThreadingModel::Lock lock;
|
|
|
|
(void)lock; // get rid of warning
|
2005-07-31 13:51:31 +00:00
|
|
|
return MyAllocatorSingleton::Instance().Allocate( size, true );
|
2002-08-11 05:49:45 +00:00
|
|
|
}
|
2005-07-31 13:51:31 +00:00
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Non-throwing single-object new returns NULL if allocation fails.
|
2005-07-31 13:51:31 +00:00
|
|
|
static void * operator new ( std::size_t size, const std::nothrow_t & ) throw ()
|
2002-08-11 05:49:45 +00:00
|
|
|
{
|
|
|
|
typename MyThreadingModel::Lock lock;
|
|
|
|
(void)lock; // get rid of warning
|
2005-07-31 13:51:31 +00:00
|
|
|
return MyAllocatorSingleton::Instance().Allocate( size, false );
|
|
|
|
}
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Placement single-object new merely calls global placement new.
|
2005-07-31 13:51:31 +00:00
|
|
|
inline static void * operator new ( std::size_t size, void * place )
|
|
|
|
{
|
|
|
|
return ::operator new( size, place );
|
2002-08-11 05:49:45 +00:00
|
|
|
}
|
2005-07-31 13:51:31 +00:00
|
|
|
|
|
|
|
/// 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 );
|
|
|
|
}
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/** Non-throwing single-object delete is only called when nothrow
|
|
|
|
new operator is used, and the constructor throws an exception.
|
|
|
|
*/
|
2005-09-09 00:25:00 +00:00
|
|
|
static void operator delete ( void * p, const std::nothrow_t & ) throw()
|
2005-07-31 13:51:31 +00:00
|
|
|
{
|
|
|
|
typename MyThreadingModel::Lock lock;
|
|
|
|
(void)lock; // get rid of warning
|
2005-09-09 00:25:00 +00:00
|
|
|
MyAllocatorSingleton::Instance().Deallocate( p );
|
2005-07-31 13:51:31 +00:00
|
|
|
}
|
|
|
|
|
2005-09-26 21:38:54 +00:00
|
|
|
/// Placement single-object delete merely calls global placement delete.
|
2005-07-31 13:51:31 +00:00
|
|
|
inline static void operator delete ( void * p, void * place )
|
|
|
|
{
|
|
|
|
::operator delete ( p, place );
|
|
|
|
}
|
|
|
|
|
2005-09-27 00:41:13 +00:00
|
|
|
#ifdef LOKI_SMALL_OBJECT_USE_NEW_ARRAY
|
|
|
|
|
|
|
|
/// Throwing array-object new throws bad_alloc when allocation fails.
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
/// @note MSVC complains about non-empty exception specification lists.
|
|
|
|
static void * operator new [] ( std::size_t size )
|
|
|
|
#else
|
|
|
|
static void * operator new [] ( std::size_t size )
|
|
|
|
throw ( std::bad_alloc )
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
typename MyThreadingModel::Lock lock;
|
|
|
|
(void)lock; // get rid of warning
|
|
|
|
return MyAllocatorSingleton::Instance().Allocate( size, true );
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Non-throwing array-object new returns NULL if allocation fails.
|
|
|
|
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 array-object new merely calls global placement new.
|
|
|
|
inline static void * operator new [] ( std::size_t size, void * place )
|
|
|
|
{
|
|
|
|
return ::operator new( size, place );
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Array-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 array-object delete is only called when nothrow
|
|
|
|
new operator is used, and the constructor throws an exception.
|
|
|
|
*/
|
|
|
|
static void operator delete [] ( void * p,
|
|
|
|
const std::nothrow_t & ) throw()
|
|
|
|
{
|
|
|
|
typename MyThreadingModel::Lock lock;
|
|
|
|
(void)lock; // get rid of warning
|
|
|
|
MyAllocatorSingleton::Instance().Deallocate( p );
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Placement array-object delete merely calls global placement delete.
|
|
|
|
inline static void operator delete [] ( void * p, void * place )
|
|
|
|
{
|
|
|
|
::operator delete ( p, place );
|
|
|
|
}
|
|
|
|
#endif // #if use new array functions.
|
|
|
|
|
2005-07-31 13:51:31 +00:00
|
|
|
#endif // #if default template parameters are not zero
|
|
|
|
|
|
|
|
protected:
|
|
|
|
inline SmallObjectBase( void ) {}
|
|
|
|
inline SmallObjectBase( const SmallObjectBase & ) {}
|
2007-02-03 00:01:52 +00:00
|
|
|
inline SmallObjectBase & operator = ( const SmallObjectBase & )
|
|
|
|
{ return *this; }
|
2005-07-31 13:51:31 +00:00
|
|
|
inline ~SmallObjectBase() {}
|
|
|
|
}; // end class SmallObjectBase
|
|
|
|
|
|
|
|
|
2005-11-02 20:01:11 +00:00
|
|
|
/** @class SmallObject
|
|
|
|
@ingroup SmallObjectGroup
|
2005-10-26 00:50:44 +00:00
|
|
|
SmallObject Base class for polymorphic small objects, offers fast
|
2005-09-26 21:38:54 +00:00
|
|
|
allocations & deallocations. Destructor is virtual and public. Default
|
|
|
|
constructor is trivial. Copy-constructor and copy-assignment operator are
|
|
|
|
not implemented since polymorphic classes almost always disable those
|
|
|
|
operations. Class has no data members so compilers can use
|
|
|
|
Empty-Base-Optimization.
|
|
|
|
*/
|
2005-07-31 13:51:31 +00:00
|
|
|
template
|
|
|
|
<
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
|
2005-09-26 07:33:05 +00:00
|
|
|
std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE,
|
|
|
|
std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE,
|
2005-07-31 13:51:31 +00:00
|
|
|
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME,
|
2006-06-19 12:39:09 +00:00
|
|
|
class MutexPolicy = LOKI_DEFAULT_MUTEX
|
2005-07-31 13:51:31 +00:00
|
|
|
>
|
|
|
|
class SmallObject : public SmallObjectBase< ThreadingModel, chunkSize,
|
2006-01-22 13:31:45 +00:00
|
|
|
maxSmallObjectSize, objectAlignSize, LifetimePolicy, MutexPolicy >
|
2005-07-31 13:51:31 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
public:
|
2002-08-11 05:49:45 +00:00
|
|
|
virtual ~SmallObject() {}
|
2005-07-31 13:51:31 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2005-11-02 20:01:11 +00:00
|
|
|
/** @class SmallValueObject
|
|
|
|
@ingroup SmallObjectGroup
|
2005-10-26 00:50:44 +00:00
|
|
|
SmallValueObject Base class for small objects with value-type
|
2005-09-26 21:38:54 +00:00
|
|
|
semantics - offers fast allocations & deallocations. Destructor is
|
|
|
|
non-virtual, inline, and protected to prevent unintentional destruction
|
|
|
|
through base class. Default constructor is trivial. Copy-constructor
|
|
|
|
and copy-assignment operator are trivial since value-types almost always
|
|
|
|
need those operations. Class has no data members so compilers can use
|
|
|
|
Empty-Base-Optimization.
|
|
|
|
*/
|
2005-07-31 13:51:31 +00:00
|
|
|
template
|
|
|
|
<
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
|
2005-09-26 07:33:05 +00:00
|
|
|
std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE,
|
|
|
|
std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE,
|
2005-07-31 13:51:31 +00:00
|
|
|
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT,
|
2006-01-22 13:31:45 +00:00
|
|
|
template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME,
|
2006-06-19 12:39:09 +00:00
|
|
|
class MutexPolicy = LOKI_DEFAULT_MUTEX
|
2005-07-31 13:51:31 +00:00
|
|
|
>
|
|
|
|
class SmallValueObject : public SmallObjectBase< ThreadingModel, chunkSize,
|
2006-01-22 13:31:45 +00:00
|
|
|
maxSmallObjectSize, objectAlignSize, LifetimePolicy, MutexPolicy >
|
2005-07-31 13:51:31 +00:00
|
|
|
{
|
|
|
|
protected:
|
|
|
|
inline SmallValueObject( void ) {}
|
|
|
|
inline SmallValueObject( const SmallValueObject & ) {}
|
2007-02-03 00:01:52 +00:00
|
|
|
inline SmallValueObject & operator = ( const SmallValueObject & )
|
|
|
|
{ return *this; }
|
2005-07-31 13:51:31 +00:00
|
|
|
inline ~SmallValueObject() {}
|
|
|
|
}; // end class SmallValueObject
|
|
|
|
|
2002-08-11 05:49:45 +00:00
|
|
|
} // namespace Loki
|
|
|
|
|
2006-10-17 19:30:16 +00:00
|
|
|
#endif // end file guardian
|
2005-08-27 13:22:56 +00:00
|
|
|
|