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) {                        }
+	}
+}