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 } else { 43 /** 44 * Indexing function that relies on the GC, and throws if no match found. 45 * Returns the found element if match found. 46 */ 47 ref E opIndex(K key) @safe pure { 48 return backend.opIndex(hashFunc(key)); 49 } 50 ///Ditto 51 ref E opIndex(HashType key) @safe pure { 52 return backend.opIndex(key); 53 } 54 } 55 /** 56 * Assigns an element to the given key. 57 */ 58 E opIndexAssign(E value, K key) @safe pure nothrow{ 59 return backend.opIndexAssign(value, hashFunc(key)); 60 } 61 /** 62 * Implements a simple left-to-right tree traversal. 63 */ 64 int opApply(scope int delegate(ref E) dg) { 65 return backend.opApply(dg); 66 } 67 /** 68 * Implements a simple left-to-right tree traversal. 69 */ 70 int opApply(scope int delegate(HashType, ref E) dg) { 71 return backend.opApply(dg); 72 } 73 /** 74 * Implements a simple right-to-left tree traversal. 75 */ 76 int opApplyReverse(scope int delegate(ref E) dg) { 77 return backend.opApplyReverse(dg); 78 } 79 /** 80 * Implements a simple right-to-left tree traversal. 81 */ 82 int opApplyReverse(scope int delegate(HashType, ref E) dg) { 83 return backend.opApplyReverse(dg); 84 } 85 package static string makeFunc() { 86 string makeFundIndiv(string attr) { 87 return `int opApply(scope int delegate(ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 88 return backend.opApply(dg); 89 } 90 int opApply(scope int delegate(HashType, ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 91 return backend.opApply(dg); 92 } 93 int opApplyReverse(scope int delegate(ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 94 return backend.opApplyReverse(dg); 95 } 96 int opApplyReverse(scope int delegate(HashType, ref E) ` ~ attr ~ ` dg) ` ~ attr ~ ` { 97 return backend.opApplyReverse(dg); 98 }`; 99 } 100 string result; 101 foreach (attr; attrList) result ~= makeFundIndiv(attr); 102 return result; 103 } 104 mixin(makeFunc); 105 /** 106 * Returns the number of currently held elements within the tree. 107 */ 108 public @property size_t length() @nogc @safe pure nothrow const { 109 return backend.length; 110 } 111 /** 112 * returns the string representation of the tree. 113 */ 114 public string toString() const { 115 return backend.toString(); 116 } 117 } 118 119 unittest { 120 alias Dictionary = HashMap!(string, string); 121 Dictionary d; 122 d["AAAAAAAAA"] = "AAAAAAAAA"; 123 d["Hello World!"] = "Hello Vilag!"; 124 assert(d["AAAAAAAAA"] == "AAAAAAAAA"); 125 assert(d["Hello World!"] == "Hello Vilag!"); 126 }