1 module collections.hashmap; 2 3 import collections.treemap; 4 import std.traits; 5 import std.digest.murmurhash; 6 public import collections.commons; 7 /** 8 * Implements a hashmap using collections.treemap as a backend. 9 * See collections.treemap for more info on certain things. 10 */ 11 public struct HashMap(K, E, alias hashFunc = defaultHash!K, alias less = "a < b") { 12 static enum bool nogcIndexing = hasFunctionAttributes!(hashFunc, "@nogc"); 13 alias HashType = ReturnType!hashFunc; 14 private TreeMap!(HashType, E, nogcIndexing, less) backend; 15 16 public void rebalance() @nogc @safe pure nothrow { 17 backend.rebalance(); 18 } 19 static if (nogcIndexing) { 20 /** 21 * @nogc capable indexing. 22 * Returns the found element if match found. 23 * Returns E.init if match not found. 24 */ 25 E opIndex(K key) @nogc @safe pure nothrow { 26 return backend.opIndex(hashFunc(key)); 27 } 28 ///Ditto 29 E opIndex(HashType key) @nogc @safe pure nothrow { 30 return backend.opIndex(key); 31 } 32 /** 33 * Returns the pointer of the element, or null if key not found. 34 */ 35 E* ptrOf(K key) @nogc @safe pure nothrow { 36 return backend.ptrOf(hashFunc(key)); 37 } 38 ///Ditto 39 E* ptrOf(HashType key) @nogc @safe pure nothrow { 40 return backend.ptrOf(key); 41 } 42 /** 43 * Returns true if the element exists within the set, false otherwise. 44 */ 45 bool has(K key) @nogc @safe pure nothrow { 46 return backend.has(hashFunc(key)); 47 } 48 auto opBinaryRight(string op)(const K key) @nogc @safe pure nothrow { 49 static if (op == "in") { 50 return has(key); 51 } else static assert(0, "Operator not supported!"); 52 } 53 /** 54 * Returns true if the element exists within the set, false otherwise. 55 */ 56 bool has(HashType key) @nogc @safe pure nothrow { 57 return backend.has(key); 58 } 59 auto opBinaryRight(string op)(const HashType key) @nogc @safe pure nothrow { 60 static if (op == "in") { 61 return has(key); 62 } else static assert(0, "Operator not supported!"); 63 } 64 } else { 65 /** 66 * Indexing function that relies on the GC, and throws if no match found. 67 * Returns the found element if match found. 68 */ 69 ref E opIndex(K key) @safe pure { 70 return backend.opIndex(hashFunc(key)); 71 } 72 ///Ditto 73 ref E opIndex(HashType key) @safe pure { 74 return backend.opIndex(key); 75 } 76 /** 77 * Returns true if the element exists within the set, false otherwise. 78 */ 79 bool has(K key) @safe pure { 80 return backend.has(hashFunc(key)); 81 } 82 auto opBinaryRight(string op)(const K key) @safe pure { 83 static if (op == "in") { 84 return has(key); 85 } else static assert(0, "Operator not supported!"); 86 } 87 /** 88 * Returns true if the element exists within the set, false otherwise. 89 */ 90 bool has(HashType key) @safe pure { 91 return backend.has(hashFunc(key)); 92 } 93 auto opBinaryRight(string op)(const HashType key) @safe pure { 94 static if (op == "in") { 95 return has(key); 96 } else static assert(0, "Operator not supported!"); 97 } 98 } 99 /** 100 * Assigns an element to the given key. 101 */ 102 E opIndexAssign(E value, K key) @safe pure nothrow{ 103 return backend.opIndexAssign(value, hashFunc(key)); 104 } 105 /** 106 * Implements a simple left-to-right tree traversal. 107 */ 108 int opApply(scope int delegate(ref E) dg) { 109 return backend.opApply(dg); 110 } 111 /** 112 * Implements a simple left-to-right tree traversal. 113 */ 114 int opApply(scope int delegate(HashType, ref E) dg) { 115 return backend.opApply(dg); 116 } 117 /** 118 * Implements a simple right-to-left tree traversal. 119 */ 120 int opApplyReverse(scope int delegate(ref E) dg) { 121 return backend.opApplyReverse(dg); 122 } 123 /** 124 * Implements a simple right-to-left tree traversal. 125 */ 126 int opApplyReverse(scope int delegate(HashType, ref E) dg) { 127 return backend.opApplyReverse(dg); 128 } 129 package static string makeFunc() { 130 string makeFundIndiv(string attr) { 131 return `int opApply(scope int delegate(ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 132 return backend.opApply(dg); 133 } 134 int opApply(scope int delegate(HashType, ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 135 return backend.opApply(dg); 136 } 137 int opApplyReverse(scope int delegate(ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 138 return backend.opApplyReverse(dg); 139 } 140 int opApplyReverse(scope int delegate(HashType, ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 141 return backend.opApplyReverse(dg); 142 }`; 143 } 144 string result; 145 foreach (attr; attrList) result ~= makeFundIndiv(attr); 146 return result; 147 } 148 mixin(makeFunc); 149 /** 150 * Returns the number of currently held elements within the tree. 151 */ 152 public @property size_t length() @nogc @safe pure nothrow const { 153 return backend.length; 154 } 155 /** 156 * returns the string representation of the tree. 157 */ 158 public string toString() const { 159 return backend.toString(); 160 } 161 } 162 163 unittest { 164 alias Dictionary = HashMap!(string, string); 165 Dictionary d; 166 d["AAAAAAAAA"] = "AAAAAAAAA"; 167 d["Hello World!"] = "Hello Vilag!"; 168 assert(!(0 in d)); 169 assert("AAAAAAAAA" in d); 170 assert(d["AAAAAAAAA"] == "AAAAAAAAA"); 171 assert(d["Hello World!"] == "Hello Vilag!"); 172 }