Mercurial > projects > hoofbaby
diff src/impl/hoofbaby/util/memory.d @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/impl/hoofbaby/util/memory.d Mon Jul 06 08:06:28 2009 -0700 @@ -0,0 +1,96 @@ +/** + * Hoofbaby -- http://www.dsource.org/projects/hoofbaby + * Copyright (C) 2009 Robert Fraser + * + * This program is free software; you can redistribute it andor + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 General Public License for more details. + */ + +module hoofbaby.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) { } + } +}