Add STL-compatible pool allocator.

Use pool allocator in serialization code.

This was SVN commit r7584.
This commit is contained in:
Ykkrosh
2010-05-25 19:24:14 +00:00
parent 1e40c8c776
commit ff17691d4f
9 changed files with 148 additions and 11 deletions
+7 -3
View File
@@ -70,11 +70,15 @@ void* pool_alloc(Pool* p, size_t size)
// otherwise the pool el_size setting.
const size_t el_size = p->el_size? p->el_size : mem_RoundUpToAlignment(size);
void* el;
// note: this can never happen in pools with variable-sized elements
// because they disallow pool_free.
void* el = mem_freelist_Detach(p->freelist);
if(el)
goto have_el;
if (p->freelist)
{
el = mem_freelist_Detach(p->freelist);
if(el)
goto have_el;
}
// alloc a new entry
{
+129 -1
View File
@@ -172,6 +172,134 @@ private:
Pool m_pool;
};
#endif
/**
* C++ wrapper on top of pool_alloc for variable-sized allocations.
* Memory is returned uninitialised.
*/
class RawPoolAllocator
{
public:
/**
* @param maxSize maximum size of pool in bytes
*/
explicit RawPoolAllocator(size_t maxSize)
{
(void)pool_create(&m_pool, maxSize, 0);
}
~RawPoolAllocator()
{
(void)pool_destroy(&m_pool);
}
/**
* @param count number of elements of type T to allocate space for
*/
template<typename T>
T* AllocateMemory(size_t count)
{
T* t = (T*)pool_alloc(&m_pool, count*sizeof(T));
if(!t)
throw std::bad_alloc();
return t;
}
private:
Pool m_pool;
};
/**
* STL-compatible allocator based on a RawPoolAllocator.
* (Allocated memory is never freed, until the RawPoolAllocator is destroyed.)
*/
template<typename T>
class pool_allocator
{
private:
// No default constructor
pool_allocator() throw ();
public:
RawPoolAllocator& p;
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
template<class U>
struct rebind
{
typedef pool_allocator<U> other;
};
explicit pool_allocator(RawPoolAllocator& pool) throw () :
p(pool)
{
}
template<typename U>
pool_allocator(const pool_allocator<U>& alloc) throw () :
p(alloc.p)
{
}
pointer address(reference r)
{
return &r;
}
const_pointer address(const_reference s)
{
return &s;
}
size_type max_size() const throw ()
{
return std::numeric_limits<std::size_t>::max() / sizeof(T);
}
void construct(const pointer ptr, const value_type& t)
{
new (ptr) T(t);
}
void destroy(const pointer ptr)
{
ptr->~T();
}
pointer allocate(size_type n)
{
return p.AllocateMemory<value_type> (n);
}
pointer allocate(size_type n, const void* const)
{
return allocate(n);
}
void deallocate(const pointer UNUSED(ptr), const size_type UNUSED(n))
{
// ignore deallocations
}
};
template<class T1, class T2>
bool operator==(const pool_allocator<T1>&, const pool_allocator<T2>&) throw ()
{
return true;
}
template<class T1, class T2>
bool operator!=(const pool_allocator<T1>&, const pool_allocator<T2>&) throw ()
{
return false;
}
#endif // __cplusplus
#endif // #ifndef INCLUDED_POOL
+2
View File
@@ -18,6 +18,8 @@
#ifndef INCLUDED_GRID
#define INCLUDED_GRID
#include <cstring>
#ifdef NDEBUG
#define GRID_BOUNDS_DEBUG 0
#else
@@ -24,7 +24,6 @@
#include "ps/CLogger.h"
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/AutoRooters.h"
// Shut up some warnings triggered by jsobj.h
#if MSC_VERSION
@@ -40,7 +39,8 @@
#endif
CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(ScriptInterface& scriptInterface, ISerializer& serializer) :
m_ScriptInterface(scriptInterface), m_Serializer(serializer), m_ScriptBackrefsNext(1), m_Rooter(m_ScriptInterface)
m_ScriptInterface(scriptInterface), m_Serializer(serializer), m_Rooter(m_ScriptInterface),
m_ScriptBackrefsPool(1*MiB), m_ScriptBackrefs(backrefs_t::key_compare(), ScriptBackrefsAlloc(m_ScriptBackrefsPool)), m_ScriptBackrefsNext(1)
{
}
@@ -23,6 +23,7 @@
#include "scriptinterface/AutoRooters.h"
#include "lib/byte_order.h"
#include "lib/allocators/pool.h"
#include <map>
@@ -41,8 +42,11 @@ private:
ScriptInterface& m_ScriptInterface;
ISerializer& m_Serializer;
typedef std::map<JSObject*, u32> backrefs_t;
// Pooling helps since we do a lot of short-lived allocations
typedef pool_allocator<std::pair<JSObject*, u32> > ScriptBackrefsAlloc;
typedef std::map<JSObject*, u32, std::less<JSObject*>, ScriptBackrefsAlloc> backrefs_t;
RawPoolAllocator m_ScriptBackrefsPool;
backrefs_t m_ScriptBackrefs;
u32 m_ScriptBackrefsNext;
u32 GetScriptBackrefTag(JSObject* obj);
@@ -20,7 +20,6 @@
#include "maths/Fixed.h"
#include "ps/Errors.h"
#include "ps/utf16string.h"
#include "scriptinterface/ScriptTypes.h"
ERROR_GROUP(Deserialize);
@@ -22,6 +22,7 @@
#include "SerializedScriptTypes.h"
#include "scriptinterface/ScriptInterface.h"
#include "js/jsapi.h"
CStdDeserializer::CStdDeserializer(ScriptInterface& scriptInterface, std::istream& stream) :
@@ -20,6 +20,8 @@
#include "IDeserializer.h"
#include "ps/utf16string.h"
#include <map>
class CStdDeserializer : public IDeserializer
@@ -19,9 +19,6 @@
#include "StdSerializer.h"
#include <ostream>
#include <cstring>
CStdSerializerImpl::CStdSerializerImpl(std::ostream& stream) :
m_Stream(stream)
{