khanat-opennel-code/code/nel/include/nel/3d/ps_allocator.h

269 lines
8 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_PS_ALLOCATOR_H
#define NL_PS_ALLOCATOR_H
#include "nel/misc/time_nl.h"
#include "nel/misc/contiguous_block_allocator.h"
//
#include <map>
namespace NL3D
{
#ifdef NL_OS_WINDOWS
# if (__SGI_STL_PORT > 0x449) && (__SGI_STL_PORT < 0x460) || !defined(NL_DONT_USE_EXTERNAL_CODE)
// fast mem alloc of particle systems only on windows for now
//
// PS_FAST_ALLOC // for fast alloc
//# define PS_FAST_ALLOC
# endif
#endif // NL_OS_WINDOWS
#ifndef PS_FAST_ALLOC
// the following macros, that redefines new & delete for classes of ps, is now empty
// NB : When using NL_MEMORY, we solve the redefinition of new errors as follow :
//
// PS_FAST_OBJ_ALLOC
# define PS_FAST_OBJ_ALLOC
// Partial specialization tips for vectors. For non-windows version it just fallback on the default allocator
// To define a vector of type T, one must do : CPSVector<T>::V MyVector;
template <class T> struct CPSVector
{
typedef std::vector<T, std::allocator<T> > V;
};
// partial specialisation tips for multimap
template <class T, class U, class Pr = std::less<T> > struct CPSMultiMap
{
#ifdef NL_OS_MAC
typedef std::multimap<T, U, Pr > M;
#else
typedef std::multimap<T, U, Pr, std::allocator<T> > M;
#endif
};
#else
// current contiguous block allocator to be used by the particle system allocator. std::allocator is used if no such allocator is provided
extern NLMISC::CContiguousBlockAllocator *PSBlockAllocator;
// an stl allocator for objects used in particle systems (vectors ..)
// STLPort 4.5.x version of allocator : written by Nevrax
#if(__SGI_STL_PORT > 0x449) && (__SGI_STL_PORT < 0x460)
template<class T> class CPSAllocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
CPSAllocator() {}
CPSAllocator<T>& operator=(const CPSAllocator<T> &other) { return *this; }
private:
typedef NLMISC::CContiguousBlockAllocator *TBlocAllocPtr;
public:
pointer allocate(size_type n, const void *hint)
{
++NumPSAlloc;
TBlocAllocPtr *result;
// prefix the block to say it comes from a contiguous block allocator or not
if (PSBlockAllocator)
{
result = (TBlocAllocPtr *) PSBlockAllocator->alloc(n * sizeof(T) + sizeof(TBlocAllocPtr *));
*result = PSBlockAllocator; // mark as a block from block allocator
}
else
{
result = (TBlocAllocPtr *) _Alloc.allocate(n * sizeof(T) + sizeof(TBlocAllocPtr *));
*result = NULL; // mark as a stl block
}
return (pointer) (result + 1); // usable space starts after header
}
void deallocate(pointer p, size_type n)
{
++NumDealloc;
--NumPSAlloc;
if (!p) return;
pointer realAddress = (pointer) ((uint8 *) p - sizeof(TBlocAllocPtr *));
if (* (TBlocAllocPtr *) realAddress)
{
// block comes from a block allocator
(*(TBlocAllocPtr *) realAddress)->free((void *) realAddress, n * sizeof(T) + sizeof(TBlocAllocPtr *));
}
else
{
// block comes from the stl allocator
_Alloc.deallocate((uint8 *) realAddress, n * sizeof(T) + sizeof(TBlocAllocPtr *));
}
}
void construct(pointer p, const T& val) { new (p) T(val); }
void destroy(pointer p) { p->~T(); }
// stl rebind
template <class _Tp, class U>
CPSAllocator<U>& __stl_alloc_rebind(CPSAllocator<_Tp>& __a, const U*)
{
return (CPSAllocator<U>&)(__a);
}
template <class _Tp, class U>
CPSAllocator<U> __stl_alloc_create(const CPSAllocator<_Tp>&, const U*)
{
return CPSAllocator<U>();
}
private:
std::allocator<uint8> _Alloc;
};
// STLPort 4.6.x and 5.0.x version of allocator : written by Neverborn Entertainment
#elif(__SGI_STL_PORT > 0x459)
template<class T> class CPSAllocator
{
public:
typedef T value_type;
typedef value_type *pointer;
typedef const T *const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
#ifdef _STLP_MEMBER_TEMPLATE_CLASSES
template <class U> struct rebind {
typedef CPSAllocator<U> other;
};
#endif
CPSAllocator() _STLP_NOTHROW {}
#ifdef _STLP_MEMBER_TEMPLATES
template <class U> CPSAllocator(const CPSAllocator<U>&) _STLP_NOTHROW {}
#endif
CPSAllocator(const CPSAllocator<T>&) _STLP_NOTHROW {}
CPSAllocator<T>& operator=(const CPSAllocator<T> &other) { return *this; }
~CPSAllocator() _STLP_NOTHROW {}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
private:
typedef NLMISC::CContiguousBlockAllocator *TBlocAllocPtr;
public:
pointer allocate(size_type n, const void* = 0)
{
++NumPSAlloc;
TBlocAllocPtr *result;
// prefix the block to say it comes from a contiguous block allocator or not
if (PSBlockAllocator)
{
result = (TBlocAllocPtr *) PSBlockAllocator->alloc(n * sizeof(T) + sizeof(TBlocAllocPtr *));
*result = PSBlockAllocator; // mark as a block from block allocator
}
else
{
result = (TBlocAllocPtr *) _Alloc.allocate(n * sizeof(T) + sizeof(TBlocAllocPtr *));
*result = NULL; // mark as a stl block
}
return (pointer) (result + 1); // usable space starts after header
}
void deallocate(pointer p, size_type n)
{
++NumDealloc;
--NumPSAlloc;
if (!p) return;
pointer realAddress = (pointer) ((uint8 *) p - sizeof(TBlocAllocPtr *));
if (* (TBlocAllocPtr *) realAddress)
{
// block comes from a block allocator
(*(TBlocAllocPtr *) realAddress)->free((void *) realAddress, n * sizeof(T) + sizeof(TBlocAllocPtr *));
}
else
{
// block comes from the stl allocator
_Alloc.deallocate((uint8 *) realAddress, n * sizeof(T) + sizeof(TBlocAllocPtr *));
}
}
void construct(pointer p, const T& val) { new (p) T(val); }
void destroy(pointer p) { p->~T(); }
size_type max_size() const _STLP_NOTHROW { return size_t(-1) / sizeof(value_type); }
// stl rebind
template <class _Tp, class U> CPSAllocator<U>& __stl_alloc_rebind(CPSAllocator<_Tp>& __a, const U*)
{
return (CPSAllocator<U>&)(__a);
}
// stl create
template <class _Tp, class U> CPSAllocator<U> __stl_alloc_create(const CPSAllocator<_Tp>&, const U*)
{
return CPSAllocator<U>();
}
private:
std::allocator<uint8> _Alloc;
};
#endif
// allocation of objects of ps (to be used inside base class declaration, replaces operator new & delete)
# define PS_FAST_OBJ_ALLOC \
void *operator new(size_t size) { return PSFastMemAlloc((uint) size); }\
void operator delete(void *block) { PSFastMemFree(block); }
// Partial specialization tips for vectors
// To define a vector of type T, one must do : CPSVector<T>::V MyVector;
template <class T> struct CPSVector
{
typedef std::vector<T, CPSAllocator<T> > V;
};
// partial specialisation tips for multimap
template <class T, class U, class Pr = std::less<T> > struct CPSMultiMap
{
typedef std::multimap<T, U, Pr, CPSAllocator<T> > M;
};
extern uint NumPSAlloc;
extern uint NumDealloc;
// allocation of memory block for objects of a particle system
void *PSFastMemAlloc(uint numBytes);
void PSFastMemFree(void *block);
#endif // PS_FAST_ALLOC
} // NL3D
#endif // NL_PS_ALLOCATOR_H