1 module collections.linkedhashmap;
2 
3 import collections.commons;
4 import std.functional : binaryFun;
5 import std.traits;
6 
7 import collections.linkedmap;
8 
9 /**
10  * Implements a linked hashmap.
11  * If retainKeys enabled, the map will retain the original keys and hash collisions can be resorted, but can be disabled
12  * by setting keyEqual to null.
13  * It is a modified linked map, and the `ovrwrtBhvr` still works as with the linked map.
14  */
15 public struct LinkedHashMap(K, E, alias hashFunc = defaultHash128!(K), alias equal = "a == b", bool retainKeys = false,
16 		alias keyEqual = "a == b", bool ovrwrtBhvr = true) {
17 	///true if nogc Indexing is enabled.
18 	static enum bool nogcIndexing = hasFunctionAttributes!(hashFunc, "@nogc");
19 	alias HashType = ReturnType!hashFunc;
20 	
21 	private struct Node {
22 		HashType	hashCode;	///Identifier hash
23 		static if (retainKeys) {
24 			K			key;		///The key for this node
25 		}
26 		E			elem;		///Element stored within the node
27 		Node*		next;		///Next node, null if none exists
28 		Node*		prev;		///Previous node, null if none exists
29 		///Keturns a string representation of the node.
30 		string toString() const {
31 			import std.conv : to;
32 			string result = "hashCode: " ~ to!string(hashCode) ~ " ; elem: " ~ to!string(elem);
33 			static if (retainKeys) result ~= " ; key: " ~ to!string(key);
34 			if (next) result ~= " ; next: [" ~ next.toString ~ "]";
35 			return result;
36 		}
37 	}
38 	
39 	protected Node*		root;	///Root element.
40 	protected Node*		last;	///Last element.
41 	protected size_t	_length;///N. of currently stored elements
42 	static if (retainKeys) {
43 		/**
44 		 * opApply override for foreach
45 		 */
46 		int opApply(scope int delegate(ref E) dg) {
47 			Node* crnt = root;
48 			while (crnt) {
49 				if (dg(crnt.elem)) return 1;
50 				crnt = crnt.next;
51 			}
52 			return 0;
53 		}
54 		/**
55 		 * opApply override for foreach
56 		 */
57 		int opApply(scope int delegate(K, ref E) dg) {
58 			Node* crnt = root;
59 			while (crnt) {
60 				if (dg(crnt.key, crnt.elem)) return 1;
61 				crnt = crnt.next;
62 			}
63 			return 0;
64 		}
65 		/**
66 		 * opApplyReverse override for foreach_reverse
67 		 */
68 		int opApplyReverse(scope int delegate(ref E) dg) {
69 			Node* crnt = last;
70 			while (crnt) {
71 				if (dg(crnt.elem)) return 1;
72 				crnt = crnt.prev;
73 			}
74 			return 0;
75 		}
76 		/**
77 		 * opApplyReverse override for foreach_reverse
78 		 */
79 		int opApplyReverse(scope int delegate(K, ref E) dg) {
80 			Node* crnt = last;
81 			while (crnt) {
82 				if (dg(crnt.key, crnt.elem)) return 1;
83 				crnt = crnt.prev;
84 			}
85 			return 0;
86 		}
87 		package static string makeFunc() {
88 			string makeFuncIndiv(string args) {
89 				return `
90 				int opApply(scope int delegate(ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
91 					Node* crnt = root;
92 					while (crnt) {
93 						if (dg(crnt.elem)) return 1;
94 						crnt = crnt.next;
95 					}
96 					return 0;
97 				}
98 				int opApply(scope int delegate(K, ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
99 					Node* crnt = root;
100 					while (crnt) {
101 						if (dg(crnt.key, crnt.elem)) return 1;
102 						crnt = crnt.next;
103 					}
104 					return 0;
105 				}
106 				int opApplyReverse(scope int delegate(ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
107 					Node* crnt = last;
108 					while (crnt) {
109 						if (dg(crnt.elem)) return 1;
110 						crnt = crnt.prev;
111 					}
112 					return 0;
113 				}
114 				int opApplyReverse(scope int delegate(K, ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
115 					Node* crnt = last;
116 					while (crnt) {
117 						if (dg(crnt.key, crnt.elem)) return 1;
118 						crnt = crnt.prev;
119 					}
120 					return 0;
121 				}`;
122 			}
123 			string result;
124 			foreach (attr; attrList) {
125 				result ~= makeFuncIndiv(attr);
126 			}
127 			return result;
128 		}
129 		mixin(makeFunc);
130 		/**
131 		 * Assigns a value to the given key.
132 		 */
133 		auto opIndexAssign(E value, K key) @safe pure nothrow {
134 			const HashType hashCode = hashFunc(key);
135 			Node** crnt = &root;
136 			while (*crnt) {
137 				static if (ovrwrtBhvr) {
138 					static if (keyEqual !is null) {
139 						if (binaryFun!equal((*crnt).hashCode, hashCode) && binaryFun!keyEqual((*crnt).key, key)) {
140 							return (*crnt).elem = value;
141 						}
142 					} else {
143 						if (binaryFun!equal((*crnt).hashCode, hashCode)) {
144 							(*crnt).key = key;
145 							return (*crnt).elem = value;
146 						}
147 					}
148 				} else {
149 					if (binaryFun!equal((*crnt).hashCode, hashCode)) {
150 						if ((*crnt).prev) (*crnt).prev.next = (*crnt).next;
151 						*crnt = (*crnt).next;
152 						_length--;
153 					}
154 				}
155 				crnt = &(*crnt).next;
156 			}
157 			//prev.next = new Node(key, value, null);
158 			*crnt = new Node(hashCode, key, value, null, *crnt);
159 			last = *crnt;
160 			_length++;
161 			return value;
162 		}
163 		static if (nogcIndexing) {
164 			
165 			/**
166 			 * Returns true if key is found.
167 			 */
168 			bool has(K key) @nogc @safe pure nothrow {
169 				const HashType hash = hashFunc(key);
170 				Node* crnt = root;
171 				while (crnt) {
172 					static if (keyEqual !is null) { 
173 						if (binaryFun!equal(crnt.hashCode, hash) && binaryFun!keyEqual(crnt.key , key)) {
174 							return true;
175 						}
176 					} else {
177 						if (binaryFun!equal(crnt.hashCode, hash)) {
178 							return true;
179 						}
180 					}
181 					crnt = crnt.next;
182 				}
183 				return false;
184 			}
185 		} else {
186 			/**
187 			 * Returns true if key is found.
188 			 */
189 			bool has(K key) @safe pure nothrow {
190 				const HashType hash = hashFunc(key);
191 				Node* crnt = root;
192 				while (crnt) {
193 					static if (keyEqual !is null) { 
194 						if (binaryFun!equal(crnt.hashCode, hash) && binaryFun!keyEqual(crnt.key , key)) {
195 							return true;
196 						}
197 					} else {
198 						if (binaryFun!equal(crnt.hashCode, hash)) {
199 							return true;
200 						}
201 					}
202 					crnt = crnt.next;
203 				}
204 				return false;
205 			}
206 		}
207 	} else {
208 		/**
209 		 * Removes the element with the specified key.
210 		 * Returns the removed element.
211 		 */
212 		E remove(K key) @safe pure nothrow {
213 			return remove(hashFunc(key));
214 		}
215 		/**
216 		 * Removes the element with the specified hashcode.
217 		 * Returns the removed element.
218 		 */
219 		E remove(HashType hashcode) @safe pure nothrow {
220 			Node** crnt = &root;
221 			while (*crnt) {
222 				if (binaryFun!equal((*crnt).hashCode, hashcode)) {
223 					E result = (*crnt).elem;
224 					//if ((*crnt).prev) (*crnt).prev.next = (*crnt).next;
225 					if ((*crnt).next is null) last = (*crnt).prev;
226 					else (*crnt).next.prev = (*crnt).prev;
227 					*crnt = (*crnt).next;
228 					_length--;
229 					return result;
230 				}
231 				crnt = &(*crnt).next;
232 			}
233 			return E.init;
234 		}
235 		/**
236 		 * opApply override for foreach
237 		 */
238 		int opApply(scope int delegate(ref E) dg) {
239 			Node* crnt = root;
240 			while (crnt) {
241 				if (dg(crnt.elem)) return 1;
242 				crnt = crnt.next;
243 			}
244 			return 0;
245 		}
246 		/**
247 		 * opApply override for foreach
248 		 */
249 		int opApply(scope int delegate(HashType, ref E) dg) {
250 			Node* crnt = root;
251 			while (crnt) {
252 				if (dg(crnt.hashCode, crnt.elem)) return 1;
253 				crnt = crnt.next;
254 			}
255 			return 0;
256 		}
257 		/**
258 		 * opApplyReverse override for foreach_reverse
259 		 */
260 		int opApplyReverse(scope int delegate(ref E) dg) {
261 			Node* crnt = last;
262 			while (crnt) {
263 				if (dg(crnt.elem)) return 1;
264 				crnt = crnt.prev;
265 			}
266 			return 0;
267 		}
268 		/**
269 		 * opApplyReverse override for foreach_reverse
270 		 */
271 		int opApplyReverse(scope int delegate(HashType, ref E) dg) {
272 			Node* crnt = last;
273 			while (crnt) {
274 				if (dg(crnt.hashCode, crnt.elem)) return 1;
275 				crnt = crnt.prev;
276 			}
277 			return 0;
278 		}
279 		package static string makeFunc() {
280 			string makeFuncIndiv(string args) {
281 				return `
282 				int opApply(scope int delegate(ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
283 					Node* crnt = root;
284 					while (crnt) {
285 						if (dg(crnt.elem)) return 1;
286 						crnt = crnt.next;
287 					}
288 					return 0;
289 				}
290 				int opApply(scope int delegate(HashType, ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
291 					Node* crnt = root;
292 					while (crnt) {
293 						if (dg(crnt.hashCode, crnt.elem)) return 1;
294 						crnt = crnt.next;
295 					}
296 					return 0;
297 				}
298 				int opApplyReverse(scope int delegate(ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
299 					Node* crnt = last;
300 					while (crnt) {
301 						if (dg(crnt.elem)) return 1;
302 						crnt = crnt.prev;
303 					}
304 					return 0;
305 				}
306 				int opApplyReverse(scope int delegate(HashType, ref E) ` ~ args ~ ` dg) ` ~ args ~ ` {
307 					Node* crnt = last;
308 					while (crnt) {
309 						if (dg(crnt.hashCode, crnt.elem)) return 1;
310 						crnt = crnt.prev;
311 					}
312 					return 0;
313 				}`;
314 			}
315 			string result;
316 			foreach (attr; attrList) {
317 				result ~= makeFuncIndiv(attr);
318 			}
319 			return result;
320 		}
321 		mixin(makeFunc);
322 		/**
323 		 * Assigns a value to the given key.
324 		 */
325 		auto opIndexAssign(E value, K key) @safe pure nothrow {
326 			const HashType hashCode = hashFunc(key);
327 			Node** crnt = &root;
328 			while (*crnt) {
329 				static if (ovrwrtBhvr) {
330 					if (binaryFun!equal((*crnt).hashCode, hashCode)) return (*crnt).elem = value;
331 				} else {
332 					if (binaryFun!equal((*crnt).hashCode, hashCode)) {
333 						if (&(*crnt).prev) (*crnt).prev.next = (*crnt).next;
334 						*crnt = &(*crnt).next;
335 						length--;
336 					}
337 				}
338 				crnt = &(*crnt).next;
339 			}
340 			//prev.next = new Node(key, value, null);
341 			*crnt = new Node(hashCode, value, null, last);
342 			last = *crnt;
343 			_length++;
344 			return value;
345 		}
346 		static if (nogcIndexing) {
347 			/**
348 			 * Returns true if key is found.
349 			 */
350 			bool has(K key) @nogc @safe pure nothrow {
351 				return has(hashFunc(key));
352 			}
353 		} else {
354 			/**
355 			 * Returns true if key is found.
356 			 */
357 			bool has(K key) @safe pure {
358 				return has(hashFunc(key));
359 			}
360 		}
361 	}
362 	static if (!retainKeys || keyEqual !is null) {
363 		static if (nogcIndexing) {
364 			/**
365 			 * Returns the element with the given key, or E.init if key is not found.
366 			 */
367 			E opIndex(K key) @nogc @safe pure nothrow {
368 				const HashType hashCode = hashFunc(key);
369 				Node* crnt = root;
370 				while (crnt) {
371 					if (binaryFun!equal(crnt.hashCode, hashCode)) return crnt.elem;
372 					crnt = crnt.next;
373 				}
374 				return E.init;
375 			}
376 			/**
377 			 * Returns the element with the given key, or E.init if key is not found.
378 			 */
379 			E opIndex(HashType hashCode) @nogc @safe pure nothrow {
380 				Node* crnt = root;
381 				while (crnt) {
382 					if (binaryFun!equal(crnt.hashCode, hashCode)) return crnt.elem;
383 					crnt = crnt.next;
384 				}
385 				return E.init;
386 			}
387 			/**
388 			 * Returns the pointer to the element with the given key, of null if key is not found.
389 			 */
390 			E* getPtr(K key) @nogc @safe pure nothrow {
391 				const HashType hashCode = hashFunc(key);
392 				Node* crnt = root;
393 				while (crnt) {
394 					if (binaryFun!equal(crnt.hashCode, hashCode)) return &(crnt.elem);
395 					crnt = crnt.next;
396 				}
397 				return null;
398 			}
399 			/**
400 			 * Returns the pointer to the element with the given key, of null if key is not found.
401 			 */
402 			E* getPtr(HashType hashCode) @nogc @safe pure nothrow {
403 				Node* crnt = root;
404 				while (crnt) {
405 					if (binaryFun!equal(crnt.hashCode, hashCode)) return &(crnt.elem);
406 					crnt = crnt.next;
407 				}
408 				return null;
409 			}
410 		} else {
411 			/**
412 			 * Returns the element with the given key, or E.init if key is not found.
413 			 */
414 			ref E opIndex(K key) @safe pure {
415 				const HashType hashCode = hashFunc(key);
416 				Node* crnt = root;
417 				while (crnt) {
418 					if (binaryFun!equal(crnt.hashCode, hashCode)) return crnt.elem;
419 					crnt = crnt.next;
420 				}
421 				throw new ElementNotFoundException("Key not found!");
422 			}
423 			/**
424 			 * Returns the element with the given key, or E.init if key is not found.
425 			 */
426 			ref E opIndex(HashType hashCode) @safe pure {
427 				Node* crnt = root;
428 				while (crnt) {
429 					if (binaryFun!equal(crnt.hashCode, hashCode)) return crnt.elem;
430 					crnt = crnt.next;
431 				}
432 				throw new ElementNotFoundException("Key not found!");
433 			}
434 		}
435 	} else {
436 		static if (nogcIndexing) {
437 			/**
438 			 * Returns the element with the given key, or E.init if key is not found.
439 			 */
440 			E opIndex(K key) @nogc @safe pure nothrow {
441 				const HashType hashCode = hashFunc(key);
442 				Node* crnt = root;
443 				while (crnt) {
444 					if (binaryFun!equal(crnt.hashCode, hashCode) && binaryFun!keyEqual(crnt.key, key)) return crnt.elem;
445 					crnt = crnt.next;
446 				}
447 				return E.init;
448 			}
449 			/**
450 			 * Returns the pointer to the element with the given key, of null if key is not found.
451 			 */
452 			E* getPtr(K key) @nogc @safe pure nothrow {
453 				const HashType hashCode = hashFunc(key);
454 				Node* crnt = root;
455 				while (crnt) {
456 					if (binaryFun!equal(crnt.hashCode, hashCode) && binaryFun!keyEqual(crnt.key, key)) return &(crnt.elem);
457 					crnt = crnt.next;
458 				}
459 				return null;
460 			}
461 		} else {
462 			/**
463 			 * Returns the element with the given key, or E.init if key is not found.
464 			 */
465 			ref E opIndex(K key) @safe pure {
466 				const HashType hashCode = hashFunc(key);
467 				Node* crnt = root;
468 				while (crnt) {
469 					if (binaryFun!equal(crnt.hashCode, hashCode) && binaryFun!keyEqual(crnt.key, key)) return crnt.elem;
470 					crnt = crnt.next;
471 				}
472 				throw new ElementNotFoundException("Key not found!");
473 			}
474 		}
475 	}
476 	/**
477 	 * Returns true if key is found.
478 	 */
479 	bool has(HashType hashCode) @nogc @safe pure nothrow {
480 		Node* crnt = root;
481 		while (crnt) {
482 			if (binaryFun!equal(crnt.hashCode, hashCode)) return true;
483 			crnt = crnt.next;
484 		}
485 		return false;
486 	}
487 	/**
488 	 * Returns the number of elements in the LinkedMap.
489 	 */
490 	@property size_t length() @nogc @safe pure nothrow const {
491 		return _length;
492 	}
493 	///Returns the string representation of this container format
494 	string toString() const {
495 		if (root) return root.toString;
496 		else return "empty";
497 	}
498 }
499 
500 unittest {
501 	import std.random : uniform;
502 	import std.exception : assertThrown;
503 	import std.stdio : writeln;
504 	{
505 		alias StringMap = LinkedHashMap!(string, string);
506 		StringMap d;
507 		d["AAAAAAAAA"] = "AAAAAAAAA";
508 		d["Hello World!"] = "Hello Vilag!";
509 		assert(d["AAAAAAAAA"] == "AAAAAAAAA");
510 		assert(d["Hello World!"] == "Hello Vilag!");
511 		assert(d.remove("AAAAAAAAA") == "AAAAAAAAA");
512 		assert(d.remove("a") == string.init);
513 		foreach (key; d) {}
514 	}
515 	{
516 		alias StringMap = LinkedHashMap!(string, string, defaultHash128!(string), "a == b", true, "a == b", true);
517 		StringMap d;
518 		d["AAAA"] = "AAAA";
519 		d["BBBB"] = "BBBB";
520 		d["CCCC"] = "CCCC";
521 		d["DDDD"] = "DDDD";
522 		assert("AAAA" == "AAAA");
523 		assert("BBBB" == "BBBB");
524 		assert("CCCC" == "CCCC");
525 		assert("DDDD" == "DDDD");
526 		writeln(d);
527 		d["CCCC"] = "eeee";
528 		writeln(d);
529 		foreach (key, elem; d) {}
530 		foreach_reverse (key, elem; d) {}
531 		foreach (key; d) {}
532 		foreach_reverse (key; d) {}
533 	}
534 	{
535 		alias StringMap = LinkedHashMap!(string, string, defaultHash128!(string), "a == b", true, "a == b", false);
536 		StringMap d;
537 		d["AAAA"] = "AAAA";
538 		d["BBBB"] = "BBBB";
539 		d["CCCC"] = "CCCC";
540 		d["DDDD"] = "DDDD";
541 		assert("AAAA" == "AAAA");
542 		assert("BBBB" == "BBBB");
543 		assert("CCCC" == "CCCC");
544 		assert("DDDD" == "DDDD");
545 		writeln(d);
546 		d["CCCC"] = "eeee";
547 		writeln(d);
548 		foreach (key, elem; d) {}
549 		foreach_reverse (key, elem; d) {}
550 		foreach (key; d) {}
551 		foreach_reverse (key; d) {}
552 	}
553 }