/** * Pool allocator for the subtree and parse tree classes (homebrew and not compliant to ANSI allocator requirements) * (c) copyright Maarten Keijzer 1999, 2000 * Permission to copy, use, modify, sell and distribute this software is granted provided * this copyright notice appears in all copies. This software is provided "as is" without * express or implied warranty, and with no claim as to its suitability for * any purpose. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * Special disclaimer and political statement: * In contrast with the rest of the EO package where you might have found this code, this software * does NOT fall under the GNU Lesser Public License or the GNU Public License, nor is anyone allowed * by the copyright holder (that's me) to put it under either license. * Doing this would limit my and your freedom to use this software in any way * you or I see fit, including but not limited to closed-source software. I personally do not adher to * virus-like qualities of the GPL and therefore take the liberty to open this code as wide as I can. * Furthermore, as this work was carried out in an academic environment and thus paid by the public * I do not see the need for the same public (which includes commercial companies) * to be limited in any way to use this software. */ #ifndef node_pool_h #define node_pool_h class MemPool { public : MemPool(unsigned int sz) : esize(sznext; delete p; } } void* allocate() { if (head == 0) grow(); Link* p = head; head = p->next; return static_cast(p); } void deallocate(void* b) { Link* p = static_cast(b); p->next = head; head = p; } private : void grow() { Chunk* n = new Chunk; n->next = chunks; chunks = n; const int nelem = Chunk::size/esize; char* start = n->mem; char* last = &start[(nelem-1)*esize]; for (char* p = start; p < last; p += esize) { reinterpret_cast(p)->next = reinterpret_cast(p + esize); } reinterpret_cast(last)->next = 0; head = reinterpret_cast(start); } struct Link { Link* next; }; struct Chunk { enum {size = 8 * 1024 - 16}; Chunk* next; char mem[size]; }; Chunk* chunks; const unsigned int esize; Link* head; }; template class Node_alloc { public : T* allocate(void) { T* t = static_cast(mem.allocate()); t = new (t) T; return t; } T* construct(const T& org) { T* t = static_cast(mem.allocate()); t = new (t) T(org); return t; } void deallocate(T* t) { t->~T(); // call destructor mem.deallocate(static_cast(t)); } private : static MemPool mem; }; template class Standard_alloc { public : Standard_alloc() {} T* allocate(size_t arity = 1) { if (arity == 0) return 0; return new T [arity]; } T* construct(size_t arity, T* org) { if (arity == 0) return 0; T* t = new T [arity]; for (int i = 0; i < arity; ++i) { t = T(org[i]); } } void deallocate(T* t, size_t arity = 1) { if (arity == 0) return ; delete [] t; } }; template class Standard_Node_alloc { public : Standard_Node_alloc() {} T* allocate(void) { return new T;// [arity]; } T* construct(const T& org) { return new T(org); } void deallocate(T* t) { delete t; } }; template class Tree_alloc { public : Tree_alloc() {} T* allocate(size_t arity) { T* t; switch(arity) { case 0 : return 0; case 1 : { t = static_cast(mem1.allocate()); new (t) T; break; } case 2 : { t = static_cast(mem2.allocate()); new (t) T; new (&t[1]) T; break; } case 3 : { t = static_cast(mem3.allocate()); new (t) T; new (&t[1]) T; new (&t[2]) T; break; } default : { return new T[arity]; } } return t; } T* construct(size_t arity, T* org) { T* t; switch(arity) { case 0 : return 0; case 1 : { t = static_cast(mem1.allocate()); new (t) T(*org); break; } case 2 : { t = static_cast(mem2.allocate()); new (t) T(*org); new (&t[1]) T(org[1]); break; } case 3 : { t = static_cast(mem3.allocate()); new (t) T(*org); new (&t[1]) T(org[1]); new (&t[1]) T(org[2]); break; } default : { t = new T[arity]; // does call default ctor for (int i = 0; i < arity; ++i) { t[i] = T(org[i]); // constructs now } } } return t; } void deallocate(T* t, size_t arity) { switch(arity) { case 0: return; case 3 : { t[2].~T(); t[1].~T(); t[0].~T(); mem3.deallocate(static_cast(t)); return; } case 2 : { t[1].~T(); t[0].~T(); mem2.deallocate(static_cast(t)); return; } case 1 : { t[0].~T(); mem1.deallocate(static_cast(t)); return; } default : { delete [] t; return; } } } private : static MemPool mem1; static MemPool mem2; static MemPool mem3; }; // static (non thread_safe) memory pools template MemPool Node_alloc::mem = sizeof(T); template MemPool Tree_alloc::mem1 = sizeof(T); template MemPool Tree_alloc::mem2 = sizeof(T) * 2; template MemPool Tree_alloc::mem3 = sizeof(T) * 3; #endif