タスク指向プログラミング

D言語では、newやdeleteを書き換えることが出来ます。
そこで、クラスのメモリアロケータを書き換えて、
タスクシステムの高速リストからクラスを生成して使いまわしてみました。
プーリングしているのに、普通にnew, deleteとかけます。
しかも、突然、ガーベジコレクションが起こることもないはず。

/*
タスク指向プログラミング!

カスタムアロケータで、高速リストからクラスを生成する。
高速リストにはオブジェクトが入っていてプールされているのと同じような感じで使える。
ガーベジコレクションも当然発生しない。

プーリングしているのに、プーリングしていないっぽく、普通に、new, delete出来るのが嬉しいかなぁと。

 */
private import std.math2;
private import std.outofmemory;

class TaskList {
	private static int maxSize;
	private static int maxGroup;
	private static int recordSize;
	private byte nodes;
	private int index;
	private int[] last;
	private int empty;

	private struct NODE {
		int prev;
		int next;
	}

	private static this() {
		maxSize = 0;
		maxGroup = 0;
	}

	static void addSize(int size, int group) {
		maxSize = max(maxSize, size);
		maxGroup = max(maxGroup, group);
	}

	void setSize(int size) {
		empty = 0;
		index.length = last.length = maxGroup + 1;
		
		for(int i = 0; i < index.length; i++) {
			index[i] = -1;
			last[i] = -1;
		}
		recordSize = maxSize + NODE.sizeof;
		nodes.length = recordSize * size;
		for (int i = 0; i < size; i++) {
			getNODE(i).prev = i - 1;
			getNODE(i).next = i + 1;
		}
		getNODE(size - 1).next = -1;
	}

	private NODE* getNODE(int no) {
		return (cast(NODE*)&nodes[no * recordSize]);
	}

	void* malloc(int size, int group) {
		if (empty != -1) {
			int newNo = empty;
			int next = getNODE(empty).next;
			if (index[group] == -1) {
				index[group] = empty;
			} else {
				getNODE(last[group]).next = empty;
			}
			getNODE(empty).prev = last[group];
			last[group] = empty;
			getNODE(empty).next = -1;
			empty = next;
			void* n = cast(void*)(&nodes[newNo * recordSize] + NODE.sizeof);
			return n;
		}
		return null;
	}

	void free(void* mem, int group) {
		int no = ((mem - cast(void*)nodes ) - NODE.sizeof) / recordSize;
		int next = getNODE(no).next;
		if (next != -1) {
			getNODE(next).prev = getNODE(no).prev;
		} else {
			last[group] = getNODE(no).prev;
		}
		int prev = getNODE(no).prev;
		if (prev != -1) {
			getNODE(prev).next = next;
		} else {
			index[group] = getNODE(no).next;
		}
		getNODE(no).next = empty;
		empty = no;
	}

	int opApply(int delegate(inout TaskObject) dg) {
		int result = 0;
		for (int i = 0; i < index.length; i++) {
			int no = index[i];
			while (no != -1) {
				void* n = cast(void*)(&nodes[no * recordSize] + NODE.sizeof);
				TaskObject node = cast(TaskObject)n;
				no = getNODE(no).next;
				result = dg(node);
				if (result)	break;
			}
		}
		return result;
	}

	void map(int group, int delegate(inout TaskObject) dg) {
		int result = 0;
		int no = index[group];
		while (no != -1) {
			void* n = cast(void*)(&nodes[no * recordSize] + NODE.sizeof);
			TaskObject node = cast(TaskObject)n;
			no = getNODE(no).next;
			result = dg(node);
			if (result)	break;
		}
		return result;
	}

	void move() {
		foreach(TaskObject o; this) {
			if (o.move) o.move();
		}
	}

	void draw() {
		foreach(TaskObject o; this) {
			if (o.draw) o.draw();
		}
	}
}

template GROUP(int g) {
	static this() {
		TaskList.addSize(typeof(this).classinfo.init.length, g);
	}
	public new(size_t sz) {
		void* p = tl.malloc(sz, g);
		if (!p)
			throw new OutOfMemoryException();
		return p;
	}
	public delete(void* p) {
		printf("delete %d %d\n", p, g);
		if (p) {
			tl.free(p, g);
		}
	}
	this() {
	}
}
TaskList tl;

class TaskObject {
	mixin GROUP!(0);
	public void delegate() move;
	public void delegate() draw;
	void defaultMove() {
		printf("default move %.*s\n", (cast(Object)this).classinfo.name);
	}
	void defaultDraw() {
		printf("default draw %.*s\n", (cast(Object)this).classinfo.name);
	}
}

class Enemy: TaskObject {
	mixin GROUP!(1);
	this() {
		move = &move1;
		draw = &draw1;
	}

	void move1() {
		printf("move1 %.*s\n", (cast(Object)this).classinfo.name);
		move = &move1_1;
	}

	void move1_1() {
		printf("move1_1 %.*s\n", (cast(Object)this).classinfo.name);
		move = &move1;
	}

	void draw1() {
		printf("draw1 %.*s\n", (cast(Object)this).classinfo.name);
	}
}

class Enemy2: TaskObject {
	mixin GROUP!(2);
	this() {
		move = &defaultMove;
		draw = &defaultDraw;
	}
	~this() {
		printf("destractor %.*s\n", (cast(Object)this).classinfo.name);
	}
}

class Enemy3: TaskObject {
	mixin GROUP!(3);
	this() {
		move = &defaultMove;
		draw = &defaultDraw;
	}
	~this() {
		printf("destractor %.*s\n", (cast(Object)this).classinfo.name);
	}
}

void main() {
	tl = new TaskList();
	tl.setSize(6);
	for (int i = 0; i < 3; i++) {
		try{
			new Enemy();
			new Enemy2();
			new Enemy3();
		} catch (OutOfMemoryException o) {
			printf("out of memory %d\n", i);
		}
	}
	for (int i = 0; i < 2; i++) {
		tl.move();
		tl.draw();
		tl.map(2, delegate int(inout TaskObject n) {
			delete n;
			return 0;
		});
		foreach (TaskObject n; tl) {
			if (cast(Enemy3)n) {
				delete n;
			}
		}
	}
}

実行結果はこんなかんじ

out of memory 2
move1 Enemy
move1 Enemy
default move Enemy2
default move Enemy2
default move Enemy3
default move Enemy3
draw1 Enemy
draw1 Enemy
default draw Enemy2
default draw Enemy2
default draw Enemy3
default draw Enemy3
destractor Enemy2
delete 9060136 2
destractor Enemy2
delete 9060232 2
destractor Enemy3
delete 9060168 3
destractor Enemy3
delete 9060264 3
move1_1 Enemy
move1_1 Enemy
draw1 Enemy
draw1 Enemy