Mercurial > projects > hoofbaby
view 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 source
/** * 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); } } }