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 }