/******************************************************************************* * Copyright (c) 2008-2009 Robert Fraser * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ module candy.util.memory; import tango.core.Memory : GC; 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 void* next; // Next available block private void* end; // End of the current block private void*[] blocks; public void* alloc(size_t sz) { sz = ((sz + 7) & ~7); // Next multiple of 8 if this isn't a multiple of 8 if (this.next + sz >= this.end) { void* blk = GC.calloc(BLOCK_SIZE); this.blocks.length = this.blocks.length + 1; this.blocks[$ - 1] = blk; this.next = blk; this.end = blk + BLOCK_SIZE; } void* ret = this.next; this.next += sz; return ret; } public void free() { foreach(blk; this.blocks) GC.free(blk); this.blocks = null; this.blocks.length = 0; this.next = null; this.end = null; } } /** * Wrapper for MemPool that allocates the given struct */ public struct StructPool(T) { private MemPool!() pool; public T* alloc() { return cast(T*) pool.alloc(T.sizeof); } } public struct MemStack(size_t BLOCK_SIZE = 1 << 14) { private Stack!(MemPool!(BLOCK_SIZE)*, 16, true, true) stack; public static const size_t MAX_ALLOC = BLOCK_SIZE; public void* alloc(size_t sz) { return stack.peek().alloc(sz); } public void push() { stack.push(new MemPool!(BLOCK_SIZE)); } public void pop() { stack.pop().free(); } } /** * Placement new mixin for allocating from a memory pool. Benchmarks show this * as faster than the D new in real usage (i.e. the parser runs about 1.2x * faster using this). */ public template MemPoolNew(alias Pool) { version(NoMemPool) { } else { public final new(uint sz) { return Pool.alloc(sz); } public final delete(void *p) { } } }