module candy.util.memory; import tango.core.Memory : GC; import tango.stdc.string : memset; import candy.util.array; /** * Provides a pool of GCed memory to allocate things from a block. * This maintains cache coherency for related types (i.e. tree nodes). * It doesn't garuntee any ordering, though, the array struct should be * used for that. Also, everything has to be freed at once, freeing one * portion of this has no effect. * * Based on a similar concept posted by bearophile at: * http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=88227 */ public struct MemPool(size_t BLOCK_SIZE = 1 << 14) { private struct Block { private void[BLOCK_SIZE] data = void; } private void* next; // Next available block private void* end; // End of the current block private Array!(Block*) blocks; public void* alloc(size_t ALLOC_UNIT)() { if (next >= end) { Block* blk = new Block; memset(blk.data.ptr, 0, BLOCK_SIZE); next = blk.data.ptr; end = next + BLOCK_SIZE; } void* ret = next; next += ALLOC_UNIT; return ret; } public void* allocAligned(size_t ALLOC_UNIT) { if (next >= end) { Block* blk = new Block; memset(blk.data.ptr, 0, BLOCK_SIZE); next = blk.data.ptr; end = next + BLOCK_SIZE; } void* ret = next; next += ((ALLOC_UNIT + 7) & ~7); // Next multiple of 8 if this isn't a multiple of 8 return ret; } public void free() { blocks.zero(); next = null; end = null; } } /** * Wrapper for MemPool that allocates the given struct */ public struct StructPool(T, size_t BLOCK_SIZE = 1 << 14) { private MemPool!(BLOCK_SIZE) mem; public T* alloc() { return cast(T*) mem.alloc!(T.sizeof)(); } public void free() { mem.free(); } } /** * Placement new mixin for allocating from a memory pool. If a class type is * going to be created a _lot_ this *might* be better than regular D new. * Also, it can be inlined. */ public template MemPoolNew(size_t BLOCK_SIZE = 1 << 14) { private static MemPool!(BLOCK_SIZE) _memPool; public new(uint size) { return _memPool.allocAligned(size); } public delete(void *p) { } // We can't delete with the pool public static void deleteAllInstances() { _memPool.free(); } }