Mercurial > projects > hoofbaby
diff src/impl/hoofbaby/util/set.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/set.d Mon Jul 06 08:06:28 2009 -0700 @@ -0,0 +1,186 @@ +/** + * 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.set; + +import tango.core.Traits; +import candy.util.redblack; +import candy.util.memory; +import candy.util.array; + +/** + * Basic set implementation using Tango's RedBlack struct with my memory + * allocator. Since Tango's RedBlack is package-access only, I copied it + * to candy.util.RedBlack. + */ +public struct Set(T) +{ + private alias RedBlack!(T) TreeNode; + + private StructPool!(TreeNode) pool; + private TreeNode* root; + private size_t count = 0; + + public bool add(T value) + { + return add(value, null); + } + + private bool add(T value, TreeNode* node) + { + if(root is null) + { + root = node ? node : pool.alloc.set(value); + } + else + { + TreeNode* t = root; + while(true) + { + int diff = cmp(value, t.value); + if(0 == diff) + { + return false; + } + else if(diff < 0) + { + if(t.left) + t = t.left; + else + { + root = t.insertLeft(node ? node : pool.alloc.set(value), root); + break; + } + } + else + { + if(t.right) + t = t.right; + else + { + root = t.insertRight(node ? node : pool.alloc.set(value), root); + break; + } + } + } + } + count++; + return true; + } + + public void addAll(Iterable)(Iterable iter) + { + foreach(e; iter) + add(e); + } + + // TODO find out if there's a better way to do this + public alias addAll merge; + + public int opApply(int delegate(ref T value) dg) + { + int result = 0; + if(!root) + return result; + TreeNode* node = root.leftmost(); + while(node) + { + result = dg(node.value); + if(result) + break; + node = node.successor(); + } + return result; + } + + public char[] toString() + { + if(!root) + return "{}"; + bool comma = false; + Array!(char) r; + r ~= "{"; + TreeNode* node = root.leftmost(); + while(node) + { + if(comma) + r ~= ", "; + r ~= node.value.toString(); + node = node.successor(); + comma = true; + } + r ~= "}"; + return r.toArray(); + } + + public T[] toArray() + { + if(!root) + return null; + T[] arr = new T[count]; + TreeNode* node = root.leftmost(); + size_t i = 0; + while(node) + { + arr[i] = node.value; + node = node.successor(); + i++; + } + assert(i == count); + return arr; + } + + public size_t length() + { + return count; + } + + public bool contains(T value) + { + return root.find(value, &cmp) !is null; + } + + final bool remove(T value) + { + TreeNode* node = root.find(value, &cmp); + if(value) + { + root = node.remove(root); + count--; + return true; + } + else + return false; + } + + static if(isReferenceType!(T) && !is(typeof(&((new T).opCmp)))) + { + // Hack to allow classes/structs without an opCmp to be compared by their address + private static int cmp(ref T a, ref T b) + { + return cast(void*) a - cast(void*) b; + } + } + else + { + private static int cmp(ref T a, ref T b) + { + if(a is b) + return 0; + return typeid(T).compare(&a, &b); + } + } + +} \ No newline at end of file