1 /**
2  * Associative Array utility functions
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.utils.aa;
15 
16 import std.algorithm;
17 import std.range;
18 import std.traits;
19 import std.typecons;
20 
21 // ***************************************************************************
22 
23 /// Polyfill for object.require
24 static if (!__traits(hasMember, object, "require"))
25 ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init)
26 {
27 	auto p = key in aa;
28 	if (p)
29 		return *p;
30 	return aa[key] = value;
31 }
32 
33 unittest
34 {
35 	int[int] aa;
36 	aa.require(1, 2);
37 	assert(aa[1] == 2);
38 	aa.require(2, 3) = 4;
39 	assert(aa[2] == 4);
40 	aa.require(1, 5);
41 	assert(aa[1] == 2);
42 	aa.require(1, 6) = 7;
43 	assert(aa[1] == 7);
44 }
45 
46 static if (!__traits(hasMember, object, "update"))
47 {
48 	/// Polyfill for object.update
49 	void updatePolyfill(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update)
50 	if (is(typeof(create()) : V) && is(typeof(update(aa[K.init])) : V))
51 	{
52 		auto p = key in aa;
53 		if (p)
54 			*p = update(*p);
55 		else
56 			aa[key] = create();
57 	}
58 
59 	/// Work around https://issues.dlang.org/show_bug.cgi?id=15795
60 	alias update = updatePolyfill;
61 }
62 
63 // https://github.com/dlang/druntime/pull/3012
64 private enum haveObjectUpdateWithVoidUpdate = is(typeof({
65 	int[int] aa;
66 	.object.update(aa, 0, { return 0; }, (ref int v) { });
67 }));
68 
69 static if (!haveObjectUpdateWithVoidUpdate)
70 {
71 	/// Polyfill for object.update with void update function
72 	void updateVoid(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update)
73 	if (is(typeof(create()) : V) && is(typeof(update(aa[K.init])) == void))
74 	{
75 		// We can polyfill this in two ways.
76 		// What's more expensive, copying the value, or a second key lookup?
77 		enum haveObjectUpdate = __traits(hasMember, object, "update");
78 		enum valueIsExpensiveToCopy = V.sizeof > string.sizeof
79 			|| hasElaborateCopyConstructor!V
80 			|| hasElaborateDestructor!V;
81 		static if (haveObjectUpdate && !valueIsExpensiveToCopy)
82 		{
83 			.object.update(aa, key,
84 				delegate V() { return create(); },
85 				(ref V v) { update(v); return v; });
86 		}
87 		else
88 		{
89 			auto p = key in aa;
90 			if (p)
91 				update(*p);
92 			else
93 				aa[key] = create();
94 		}
95 	}
96 
97 	/// Work around https://issues.dlang.org/show_bug.cgi?id=15795
98 	alias update = updateVoid;
99 }
100 else
101 	alias updateVoid = object.update; /// Use `object.update` for void update function
102 
103 // Inject overload
104 static if (__traits(hasMember, object, "update"))
105 	private alias update = object.update;
106 
107 // ***************************************************************************
108 
109 /// Get a value from an AA, and throw an exception (not an error) if not found
110 ref auto aaGet(AA, K)(auto ref AA aa, auto ref K key)
111 	if (is(typeof(key in aa)))
112 {
113 	import std.conv;
114 
115 	auto p = key in aa;
116 	if (p)
117 		return *p;
118 	else
119 		static if (is(typeof(text(key))))
120 			throw new Exception("Absent value: " ~ text(key));
121 		else
122 			throw new Exception("Absent value");
123 }
124 
125 /// If key is not in aa, add it with defaultValue.
126 /// Returns a reference to the value corresponding to key.
127 ref V getOrAdd(K, V)(ref V[K] aa, auto ref K key, auto ref V defaultValue)
128 {
129 	return aa.require(key, defaultValue);
130 }
131 
132 /// ditto
133 ref V getOrAdd(K, V)(ref V[K] aa, auto ref K key)
134 {
135 	return getOrAdd(aa, key, V.init);
136 }
137 
138 unittest
139 {
140 	int[int] aa;
141 	aa.getOrAdd(1, 2) = 3;
142 	assert(aa[1] == 3);
143 	assert(aa.getOrAdd(1, 4) == 3);
144 }
145 
146 /// If key is not in aa, add it with the given value, and return true.
147 /// Otherwise, return false.
148 bool addNew(K, V)(ref V[K] aa, auto ref K key, auto ref V value)
149 {
150 	bool added = void;
151 	updateVoid(aa, key,
152 		delegate V   (       ) { added = true ; return value; },
153 		delegate void(ref V v) { added = false;               },
154 	);
155 	return added;
156 }
157 
158 /// ditto
159 bool addNew(K, V, bool ordered, bool multi)(ref HashCollection!(K, V, ordered, multi) aa, auto ref K key, auto ref V value)
160 if (!is(V == void)) // Not a set
161 {
162 	bool added = void;
163 	aa.update(key,
164 		delegate V   (       ) { added = true ; return value; },
165 		delegate void(ref V v) { added = false;               },
166 	);
167 	return added;
168 }
169 
170 unittest
171 {
172 	int[int] aa;
173 	assert( aa.addNew(1, 2));
174 	assert(!aa.addNew(1, 3));
175 	assert(aa[1] == 2);
176 }
177 
178 unittest
179 {
180 	OrderedMap!(int, int) aa;
181 	assert( aa.addNew(1, 2));
182 	assert(!aa.addNew(1, 3));
183 	assert(aa[1] == 2);
184 }
185 
186 // ***************************************************************************
187 
188 /// Key/value pair
189 struct KeyValuePair(K, V) { K key; /***/ V value; /***/ }
190 
191 /// Get key/value pairs from AA
192 deprecated KeyValuePair!(K, V)[] pairs(K, V)(V[K] aa)
193 {
194 	KeyValuePair!(K, V)[] result;
195 	foreach (key, value; aa)
196 		result ~= KeyValuePair!(K, V)(key, value);
197 	return result;
198 }
199 
200 /// Get key/value pairs from AA, sorted by keys
201 KeyValuePair!(K, V)[] sortedPairs(K, V)(V[K] aa)
202 {
203 	KeyValuePair!(K, V)[] result;
204 	foreach (key; aa.keys.sort)
205 		result ~= KeyValuePair!(K, V)(key, aa[key]);
206 	return result;
207 }
208 
209 /// Get values from AA, sorted by keys
210 V[] sortedValues(K, V)(in V[K] aa)
211 {
212 	V[] result;
213 	foreach (key; aa.keys.sort())
214 		result ~= aa[key];
215 	return result;
216 }
217 
218 /// Merge source into target. Return target.
219 V[K] merge(K, V)(auto ref V[K] target, V[K] source)
220 {
221 	foreach (k, v; source)
222 		target[k] = v;
223 	return target;
224 }
225 
226 unittest
227 {
228 	int[int] target;
229 	int[int] source = [2:4];
230 	merge(target, source);
231 	assert(source == target);
232 
233 	target = [1:1, 2:2, 3:3];
234 	merge(target, source);
235 	assert(target == [1:1, 2:4, 3:3]);
236 
237 	assert(merge([1:1], [2:2]) == [1:1, 2:2]);
238 }
239 
240 unittest
241 {
242 	ubyte[][string] a, b;
243 	merge(a, b);
244 }
245 
246 /// Slurp a range of two elements (or two-element struct/class) into an AA.
247 auto toAA(R)(R r)
248 	if (is(typeof(r.front[1])))
249 {
250 	alias K = typeof(r.front[0]);
251 	alias V = typeof(r.front[1]);
252 	V[K] result;
253 	foreach (pair; r)
254 	{
255 		assert(pair.length == 2);
256 		result[pair[0]] = pair[1];
257 	}
258 	return result;
259 }
260 
261 /// ditto
262 auto toAA(R)(R r)
263 	if (is(typeof(r.front.tupleof)) && r.front.tupleof.length == 2 && !is(typeof(r.front[1])))
264 {
265 	return r.map!(el => tuple(el.tupleof)).toAA();
266 }
267 
268 deprecated unittest
269 {
270 	assert([[2, 4]].toAA() == [2:4]);
271 	assert([2:4].pairs.toAA() == [2:4]);
272 }
273 
274 /// Ensure that arr is non-null if empty.
275 V[K] nonNull(K, V)(V[K] aa)
276 {
277 	if (aa !is null)
278 		return aa;
279 	aa[K.init] = V.init;
280 	aa.remove(K.init);
281 	assert(aa !is null);
282 	return aa;
283 }
284 
285 unittest
286 {
287 	int[int] aa;
288 	assert(aa is null);
289 	aa = aa.nonNull;
290 	assert(aa !is null);
291 	assert(aa.length == 0);
292 }
293 
294 // ***************************************************************************
295 
296 // Helpers for HashCollection
297 private
298 {
299 	alias Void = void[0]; // Zero-sized type
300 	static assert(Void.sizeof == 0);
301 
302 	// Abstraction layer for single/multi-value type holding one or many T.
303 	// Optimizer representation for Void.
304 	struct SingleOrMultiValue(bool multi, T)
305 	{
306 		alias ValueType = Select!(multi,
307 			// multi==true
308 			Select!(is(T == Void),
309 				size_t, // "store" the items by keeping track of their count only.
310 				T[],
311 			),
312 
313 			// multi==false
314 			Select!(is(T == Void),
315 				Void,
316 				T[1],
317 			),
318 		);
319 
320 		// Using free functions instead of struct methods,
321 		// as structs always have non-zero size.
322 	static:
323 
324 		size_t length(ref const ValueType v) nothrow
325 		{
326 			static if (is(T == Void))
327 				static if (multi)
328 					return v; // count
329 				else
330 					return 1;
331 			else
332 				return v.length; // static or dynamic array
333 		}
334 	}
335 }
336 
337 /// Base type for ordered/unordered single-value/multi-value map/set
338 /*private*/ struct HashCollection(K, V, bool ordered, bool multi)
339 {
340 private:
341 	enum bool haveValues = !is(V == void); // Not a set
342 
343 	// The type for values used when a value variable is needed
344 	alias ValueVarType = Select!(haveValues, V, Void);
345 
346 	// The type of a single element of the values of `this.lookup`.
347 	// When ordered==true, we use size_t (index into `this.items`).
348 	alias LookupItem = Select!(ordered, size_t, ValueVarType);
349 
350 	// The type of the values of `this.lookup`.
351 	alias SM = SingleOrMultiValue!(multi, LookupItem);
352 	alias LookupValue = SM.ValueType;
353 
354 	static if (haveValues)
355 	{
356 		alias ReturnType(Fallback) = V;
357 		alias OpIndexKeyType = K;
358 		alias OpIndexValueType = V;
359 	}
360 	else
361 	{
362 		static if (ordered)
363 		{
364 			alias OpIndexKeyType = size_t;
365 			alias OpIndexValueType = K;
366 			alias ReturnType(Fallback) = K;
367 		}
368 		else
369 		{
370 			alias OpIndexKeyType = void;
371 			alias OpIndexValueType = void;
372 			alias ReturnType(Fallback) = Fallback;
373 		}
374 	}
375 	enum haveReturnType = !is(ReturnType!void == void);
376 	enum haveIndexing = haveValues || ordered;
377 
378 	alias IK = OpIndexKeyType;
379 	alias IV = OpIndexValueType;
380 
381 	// The contract we try to follow is that adding/removing items in
382 	// one copy of the object will not affect other copies.
383 	// Therefore, when we have array fields, make sure they are dup'd
384 	// on copy, so that we don't trample older copies' data.
385 	enum bool needDupOnCopy = ordered;
386 
387 	static if (haveReturnType)
388 	{
389 		static if (ordered)
390 			/*  */ ref inout(ReturnType!void) lookupToReturnValue(in        LookupItem  lookupItem) inout { return items[lookupItem].returnValue; }
391 		else
392 			static ref inout(ReturnType!void) lookupToReturnValue(ref inout(LookupItem) lookupItem)       { return       lookupItem             ; }
393 	}
394 
395 	// *** Data ***
396 
397 	// This is used for all key hash lookups.
398 	LookupValue[K] lookup;
399 
400 	static if (ordered)
401 	{
402 		struct Item
403 		{
404 			K key;
405 			ValueVarType value;
406 
407 			static if (haveValues)
408 				private alias returnValue = value;
409 			else
410 				private alias returnValue = key;
411 		}
412 		Item[] items;
413 
414 		enum bool canDup = is(typeof(lookup.dup)) && is(typeof(items.dup));
415 	}
416 	else
417 	{
418 		enum bool canDup = is(typeof(lookup.dup));
419 	}
420 
421 public:
422 
423 	// *** Lifetime ***
424 
425 	/// Postblit
426 	static if (needDupOnCopy)
427 	{
428 		static if (canDup)
429 			this(this)
430 			{
431 				lookup = lookup.dup;
432 				items = items.dup;
433 			}
434 		else
435 			@disable this(this);
436 	}
437 
438 	/// Create shallow copy
439 	static if (canDup)
440 	typeof(this) dup()
441 	{
442 		static if (needDupOnCopy)
443 			return this;
444 		else
445 		{
446 			typeof(this) copy;
447 			copy.lookup = lookup.dup;
448 			static if (ordered)
449 				copy.items = items.dup;
450 			return copy;
451 		}
452 	}
453 	
454 	// *** Conversions (from) ***
455 
456 	/// Construct from something else
457 	this(Input)(Input input)
458 	if (is(typeof(opAssign(input))))
459 	{
460 		opAssign(input);
461 	}
462 
463 	/// Null assignment
464 	ref typeof(this) opAssign(typeof(null) _)
465 	{
466 		clear();
467 		return this;
468 	}
469 
470 	/// Convert from an associative type
471 	ref typeof(this) opAssign(AA)(AA aa)
472 	if (haveValues
473 		&& !is(AA : typeof(this))
474 		&& is(typeof({ foreach (ref k, ref v; aa) add(k, v); })))
475 	{
476 		clear();
477 		foreach (ref k, ref v; aa)
478 			add(k, v);
479 		return this;
480 	}
481 
482 	/// Convert from an associative type of multiple items
483 	ref typeof(this) opAssign(AA)(AA aa)
484 	if (haveValues
485 		&& multi
486 		&& !is(AA : typeof(this))
487 		&& is(typeof({ foreach (ref k, ref vs; aa) foreach (ref v; vs) add(k, v); })))
488 	{
489 		clear();
490 		foreach (ref k, ref vs; aa)
491 			foreach (ref v; vs)
492 				add(k, v);
493 		return this;
494 	}
495 
496 	/// Convert from a range of tuples
497 	ref typeof(this) opAssign(R)(R input)
498 	if (haveValues
499 		&& is(typeof({ foreach (ref pair; input) add(pair[0], pair[1]); }))
500 		&& !is(typeof({ foreach (ref k, ref v; input) add(k, v); }))
501 		&& is(typeof(input.front.length))
502 		&& input.front.length == 2)
503 	{
504 		clear();
505 		foreach (ref pair; input)
506 			add(pair[0], pair[1]);
507 		return this;
508 	}
509 
510 	/// Convert from a range of key/value pairs
511 	ref typeof(this) opAssign(R)(R input)
512 	if (haveValues
513 		&& is(typeof({ foreach (ref pair; input) add(pair.key, pair.value); }))
514 		&& !is(typeof({ foreach (ref k, ref v; input) add(k, v); })))
515 	{
516 		clear();
517 		foreach (ref pair; input)
518 			add(pair.key, pair.value);
519 		return this;
520 	}
521 
522 	/// Convert from a range of values
523 	ref typeof(this) opAssign(R)(R input)
524 	if (!haveValues
525 		&& !is(R : typeof(this))
526 		&& is(typeof({ foreach (ref v; input) add(v); })))
527 	{
528 		clear();
529 		foreach (ref v; input)
530 			add(v);
531 		return this;
532 	}
533 
534 	// *** Conversions (to) ***
535 
536 	/// Convert to bool (true if non-null)
537 	bool opCast(T)() const
538 	if (is(T == bool))
539 	{
540 		return lookup !is null;
541 	}
542 
543 	/// Convert to D associative array
544 	static if (!ordered)
545 	{
546 		const(LookupValue[K]) toAA() const
547 		{
548 			return lookup;
549 		}
550 
551 		static if (is(typeof(lookup.dup)))
552 		LookupValue[K] toAA()
553 		{
554 			return lookup.dup;
555 		}
556 
557 		deprecated alias items = toAA;
558 	}
559 
560 	// *** Query (basic) ***
561 
562 	/// True when there are no items.
563 	bool empty() pure const nothrow @nogc @trusted
564 	{
565 		static if (ordered)
566 			return items.length == 0; // optimization
567 		else
568 			return lookup.byKey.empty; // generic version
569 	}
570 
571 	/// Total number of items, including with duplicate keys.
572 	size_t length() pure const nothrow @nogc @trusted
573 	{
574 		static if (ordered)
575 			return items.length; // optimization
576 		else
577 		static if (!multi)
578 			return lookup.length; // optimization
579 		else // generic version
580 		{
581 			size_t result;
582 			foreach (ref v; lookup.byValue)
583 				result += SM.length(v);
584 			return result;
585 		}
586 	}
587 
588 	// *** Query (by key) ***
589 
590 	/// Check if item with this key has been added.
591 	/// When applicable, return a pointer to the last value added with this key.
592 	Select!(haveReturnType, inout(ReturnType!void)*, bool) opBinaryRight(string op : "in", _K)(auto ref _K key) inout
593 	if (is(typeof(key in lookup)))
594 	{
595 		enum missValue = select!haveReturnType(null, false);
596 
597 		auto p = key in lookup;
598 		if (!p)
599 			return missValue;
600 
601 		static if (haveReturnType)
602 			return &lookupToReturnValue((*p)[$-1]);
603 		else
604 			return true;
605 	}
606 
607 	/// Index operator.
608 	/// The key must exist. Indexing with a key which does not exist
609 	/// is an error.
610 	static if (haveIndexing)
611 	ref inout(IV) opIndex()(auto ref IK k) inout
612 	{
613 		static if (haveValues)
614 			return lookupToReturnValue(lookup[k][$-1]);
615 		else
616 			return items[k].returnValue;
617 	}
618 
619 	/// Retrieve last value associated with key, or `defaultValue` if none.
620 	static if (haveIndexing)
621 	auto ref inout(IV) get()(auto ref IK k, auto ref inout(IV) defaultValue) inout
622 	{
623 		static if (haveValues)
624 		{
625 			auto p = k in lookup;
626 			return p ? lookupToReturnValue((*p)[$-1]) : defaultValue;
627 		}
628 		else
629 			return k < items.length ? items[k].returnValue : defaultValue;
630 	}
631 
632 	// *** Query (ranges) ***
633 
634 	/// Return a range which iterates over key/value pairs.
635 	static if (haveValues)
636 	auto byKeyValue(this This)()
637 	{
638 		static if (ordered)
639 			return items;
640 		else
641 		{
642 			return lookup
643 				.byKeyValue
644 				.map!(pair =>
645 					pair
646 					.value
647 					.map!(value => KeyValuePair!(K, V)(pair.key, value))
648 				)
649 				.joiner;
650 		}
651 	}
652 
653 	/// ditto
654 	static if (haveValues)
655 	auto byPair(this This)()
656 	{
657 		return byKeyValue
658 			.map!(pair => tuple!("key", "value")(pair.key, pair.value));
659 	}
660 
661 	/// Return a range which iterates over all keys.
662 	/// Duplicate keys will occur several times in the range.
663 	auto byKey(this This)()
664 	{
665 		static if (ordered)
666 		{
667 			static ref getKey(MItem)(ref MItem item) { return item.key; }
668 			return items.map!getKey;
669 		}
670 		else
671 		{
672 			return lookup
673 				.byKeyValue
674 				.map!(pair =>
675 					pair.key.repeat(SM.length(pair.value))
676 				)
677 				.joiner;
678 		}
679 	}
680 
681 	/// Return a range which iterates over all values.
682 	static if (haveValues)
683 	auto byValue(this This)()
684 	{
685 		static if (ordered)
686 		{
687 			static ref getValue(MItem)(ref MItem item) { return item.value; }
688 			return items.map!getValue;
689 		}
690 		else
691 		{
692 			return lookup
693 				.byKeyValue
694 				.map!(pair =>
695 					pair
696 					.value
697 				)
698 				.joiner;
699 		}
700 	}
701 
702 	/// Returns all keys as an array.
703 	@property auto keys(this This)() { return byKey.array; }
704 
705 	/// Returns all values as an array.
706 	@property auto values(this This)() { return byValue.array; }
707 
708 	// *** Query (search by key) ***
709 
710 	static if (ordered)
711 	{
712 		/// Returns index of key `k`.
713 		sizediff_t indexOf()(auto ref const K k)
714 		{
715 			auto p = k in lookup;
716 			return p ? (*p)[0] : -1;
717 		}
718 
719 		/// Returns all indices of key `k`.
720 		size_t[] indicesOf()(auto ref const K k)
721 		{
722 			auto p = k in lookup;
723 			return p ? (*p)[] : null;
724 		}
725 	}
726 
727 	/// Return the number of items with the given key.
728 	/// When multi==false, always returns 0 or 1.
729 	size_t count()(auto ref K k)
730 	{
731 		static if (ordered)
732 			return indicesOf(k).length;
733 		else
734 		{
735 			auto p = k in lookup;
736 			return p ? SM.length(*p) : 0;
737 		}
738 	}
739 
740 	/// Return a range with all values with the given key.
741 	/// If the key is not present, returns an empty range.
742 	static if (haveValues)
743 	auto byValueOf(this This)(auto ref K k)
744 	{
745 		static if (ordered)
746 			return indicesOf(k).map!(index => items[index].value);
747 		else
748 			return valuesOf(k);
749 	}
750 
751 	/// Return an array with all values with the given key.
752 	/// If the key is not present, returns an empty array.
753 	static if (haveValues)
754 	V[] valuesOf()(auto ref K k)
755 	{
756 		static if (ordered)
757 			return byValueOf(k).array;
758 		else
759 		{
760 			static if (multi)
761 				return lookup.get(k, null);
762 			else
763 			{
764 				auto p = k in lookup;
765 				return p ? (*p)[] : null;
766 			}
767 		}
768 	}
769 
770 	static if (haveValues)
771 	deprecated alias getAll = valuesOf;
772 
773 	// *** Iteration ***
774 
775 	// Note: When iterating over keys in an AA, you must choose
776 	// mutable OR ref, but not both. This is an important reason for
777 	// the complexity below.
778 
779 	private enum isParameterRef(size_t index, fun...) = (){
780 		foreach (keyStorageClass; __traits(getParameterStorageClasses, fun[0], index))
781 			if (keyStorageClass == "ref")
782 				return true;
783 		return false;
784 	}();
785 
786 	private int opApplyImpl(this This, Dg)(scope Dg dg)
787 	{
788 		enum single = arity!dg == 1;
789 
790 		int result = 0;
791 
792 		static if (ordered)
793 		{
794 			foreach (ref item; items)
795 			{
796 				static if (single)
797 					result = dg(item.returnValue);
798 				else
799 					result = dg(item.key, item.value);
800 				if (result)
801 					break;
802 			}
803 		}
804 		else
805 		{
806 			static if (single && haveValues)
807 			{
808 				// Dg accepts value only, so use whatever we want for the key iteration.
809 				alias LK = const(K);
810 				enum useRef = true;
811 			}
812 			else
813 			{
814 				// Dg accepts a key (and maybe a value), so use the Dg signature for iteration.
815 				alias LK = Parameters!Dg[0];
816 				enum useRef = isParameterRef!(0, Dg);
817 			}
818 			// LookupValue or const(LookupValue), depending on the constness of This
819 			alias LV = typeof(lookup.values[0]);
820 
821 			bool handle()(ref LK key, ref LV values)
822 			{
823 				static if (haveValues)
824 				{
825 					foreach (ref value; values)
826 					{
827 						static if (single)
828 							result = dg(value);
829 						else
830 							result = dg(key, value);
831 						if (result)
832 							return false;
833 					}
834 				}
835 				else
836 				{
837 					foreach (iteration; 0 .. SM.length(values))
838 					{
839 						static assert(single);
840 						result = dg(key);
841 						if (result)
842 							return false;
843 					}
844 				}
845 				return true;
846 			}
847 
848 			static if (useRef)
849 			{
850 				foreach (ref LK key, ref LV values; lookup)
851 					if (!handle(key, values))
852 						break;
853 			}
854 			else
855 			{
856 				foreach (LK key, ref LV values; lookup)
857 					if (!handle(key, values))
858 						break;
859 			}
860 		}
861 		return result;
862 	}
863 
864 	private alias KeyIterationType(bool isConst, bool byRef) = typeof(*(){
865 
866 		static if (isConst)
867 			const bool[K] aa;
868 		else
869 			bool[K] aa;
870 
871 		static if (byRef)
872 			foreach (ref k, v; aa)
873 				return &k;
874 		else
875 			foreach (k, v; aa)
876 				return &k;
877 
878 		assert(false);
879 	}());
880 
881 	private enum needRefOverload(bool isConst) =
882 		// Unfortunately this doesn't work: https://issues.dlang.org/show_bug.cgi?id=21683
883 		// !is(KeyIterationType!(isConst, false) == KeyIterationType!(isConst, true));
884 		!isCopyable!K;
885 
886 	private template needIter(bool isConst, bool byRef)
887 	{
888 		static if (!isCopyable!K)
889 			enum needIter = byRef;
890 		else
891 		static if (!byRef)
892 			enum needIter = true;
893 		else
894 			enum needIter = needRefOverload!isConst;
895 	}
896 
897 	static if (haveValues)
898 	{
899 		/// Iterate over values (maps).
900 		int opApply(scope int delegate(      ref V) dg)       { return opApplyImpl(dg); }
901 		int opApply(scope int delegate(const ref V) dg) const { return opApplyImpl(dg); } /// ditto
902 	}
903 	else
904 	{
905 		/// Iterate over keys (sets).
906 		static if (needIter!(false, false)) int opApply(scope int delegate(    KeyIterationType!(false, false)) dg)       { return opApplyImpl(dg); }
907 		static if (needIter!(true , false)) int opApply(scope int delegate(    KeyIterationType!(true , false)) dg) const { return opApplyImpl(dg); } /// ditto
908 		static if (needIter!(false, true )) int opApply(scope int delegate(ref KeyIterationType!(false, true )) dg)       { return opApplyImpl(dg); } /// ditto
909 		static if (needIter!(true , true )) int opApply(scope int delegate(ref KeyIterationType!(true , true )) dg) const { return opApplyImpl(dg); } /// ditto
910 	}
911 
912 	static if (haveValues)
913 	{
914 		/// Iterate over keys and values.
915 		static if (needIter!(false, false)) int opApply(scope int delegate(    KeyIterationType!(false, false),       ref V) dg)       { return opApplyImpl(dg); }
916 		static if (needIter!(true , false)) int opApply(scope int delegate(    KeyIterationType!(true , false), const ref V) dg) const { return opApplyImpl(dg); } /// ditto
917 		static if (needIter!(false, true )) int opApply(scope int delegate(ref KeyIterationType!(false, true ),       ref V) dg)       { return opApplyImpl(dg); } /// ditto
918 		static if (needIter!(true , true )) int opApply(scope int delegate(ref KeyIterationType!(true , true ), const ref V) dg) const { return opApplyImpl(dg); } /// ditto
919 	}
920 
921 	private struct ByRef(bool isConst)
922 	{
923 		static if (isConst)
924 			const(HashCollection)* c;
925 		else
926 			HashCollection* c;
927 
928 		static if (haveValues)
929 		{
930 			static if (isConst)
931 				int opApply(scope int delegate(ref KeyIterationType!(true , true ), const ref V) dg) const { return c.opApplyImpl(dg); }
932 			else
933 				int opApply(scope int delegate(ref KeyIterationType!(false, true ),       ref V) dg)       { return c.opApplyImpl(dg); }
934 		}
935 		else
936 		{
937 			static if (isConst)
938 				int opApply(scope int delegate(ref KeyIterationType!(true , true )) dg) const { return c.opApplyImpl(dg); }
939 			else
940 				int opApply(scope int delegate(ref KeyIterationType!(false, true )) dg)       { return c.opApplyImpl(dg); }
941 		}
942 	}
943 
944 	/// Returns an object that allows iterating over this collection with ref keys.
945 	/// Workaround for https://issues.dlang.org/show_bug.cgi?id=21683
946 	auto byRef()       return { return ByRef!false(&this); }
947 	auto byRef() const return { return ByRef!true (&this); } /// ditto
948 
949 	// *** Mutation (addition) ***
950 
951 	private enum AddMode
952 	{
953 		add,     /// Always add value
954 		replace, /// Replace all previous values
955 		require, /// Only add value if it did not exist before
956 	}
957 
958 	private ref ReturnType!void addImpl(AddMode mode, AK, GV)(ref AK key, scope GV getValue)
959 	if (is(AK : K))
960 	{
961 		static if (ordered)
962 		{
963 			size_t addedIndex;
964 
965 			static if (multi && mode == AddMode.add)
966 			{
967 				addedIndex = items.length;
968 				lookup[key] ~= addedIndex;
969 				items ~= Item(key, getValue());
970 			}
971 			else
972 			{
973 				lookup.updateVoid(key,
974 					delegate LookupValue()
975 					{
976 						addedIndex = items.length;
977 						items ~= Item(key, getValue());
978 						return [addedIndex];
979 					},
980 					delegate void(ref LookupValue existingIndex)
981 					{
982 						addedIndex = existingIndex[0];
983 						static if (mode != AddMode.require)
984 						{
985 							static if (multi)
986 							{
987 								static assert(mode == AddMode.replace);
988 								existingIndex = existingIndex[0 .. 1];
989 							}
990 							items[addedIndex].value = getValue();
991 						}
992 					});
993 			}
994 
995 			return items[addedIndex].returnValue;
996 		}
997 		else // ordered
998 		{
999 			static if (haveValues)
1000 			{
1001 				static if (mode == AddMode.require)
1002 					return (lookup.require(key, [getValue()]))[0];
1003 				else
1004 				static if (multi && mode == AddMode.add)
1005 					return (lookup[key] ~= getValue())[$-1];
1006 				else
1007 					return (lookup[key] = [getValue()])[0];
1008 			}
1009 			else
1010 			{
1011 				static if (multi)
1012 				{
1013 					static if (mode == AddMode.require)
1014 						lookup.require(key, 1);
1015 					else
1016 					static if (mode == AddMode.add)
1017 						lookup[key]++;
1018 					else
1019 						lookup[key] = 1;
1020 				}
1021 				else
1022 					lookup[key] = LookupValue.init;
1023 				// This branch returns void, as there is no reasonable
1024 				// ref to an AA key that we can return here.
1025 			}
1026 		}
1027 	}
1028 
1029 	/*private*/ template _addSetFunc(AddMode mode)
1030 	{
1031 		static if (haveValues)
1032 		{
1033 			ref ReturnType!void _addSetFunc(AK, AV)(auto ref AK key, auto ref AV value)
1034 			if (is(AK : K) && is(AV : V))
1035 			{
1036 				return addImpl!mode(key, () => value);
1037 			}
1038 		}
1039 		else
1040 		{
1041 			ref ReturnType!void _addSetFunc(AK)(auto ref AK key)
1042 			if (is(AK : K))
1043 			{
1044 				ValueVarType value; // void[0]
1045 				return addImpl!mode(key, () => value);
1046 			}
1047 		}
1048 	}
1049 
1050 	/// Add an item.
1051 	alias add = _addSetFunc!(AddMode.add);
1052 
1053 	/// Ensure a key exists (with the given value).
1054 	/// When `multi==true`, replaces all previous entries with this key.
1055 	/// Otherwise, behaves identically to `add`.
1056 	alias set = _addSetFunc!(AddMode.replace);
1057 
1058 	/// Add `value` only if `key` is not present.
1059 	static if (haveValues)
1060 	ref V require()(auto ref K key, lazy V value = V.init)
1061 	{
1062 		return addImpl!(AddMode.require)(key, () => value);
1063 	}
1064 
1065 	deprecated alias getOrAdd = require;
1066 
1067 	private alias UpdateFuncRT(U) = typeof({ U u = void; V v = void; return u(v); }());
1068 
1069 	/// If `key` is present, call `update` for every value;
1070 	/// otherwise, add new value with `create`.
1071 	static if (haveValues)
1072 	void update(C, U)(auto ref K key, scope C create, scope U update)
1073 	if (is(typeof(create()) : V) && (is(UpdateFuncRT!U : V) || is(UpdateFuncRT!U == void)))
1074 	{
1075 		static if (ordered)
1076 		{
1077 			lookup.updateVoid(key,
1078 				delegate LookupValue()
1079 				{
1080 					auto addedIndex = items.length;
1081 					items ~= Item(key, create());
1082 					return [addedIndex];
1083 				},
1084 				delegate void(ref LookupValue existingIndex)
1085 				{
1086 					foreach (i; existingIndex)
1087 						static if (is(UpdateFuncRT!U == void))
1088 							update(items[i].value);
1089 						else
1090 							items[i].value = update(items[i].value);
1091 				});
1092 		}
1093 		else // ordered
1094 		{
1095 			lookup.updateVoid(key,
1096 				delegate LookupValue ()
1097 				{
1098 					return [create()];
1099 				},
1100 				delegate void (ref LookupValue values)
1101 				{
1102 					foreach (ref value; values)
1103 						static if (is(UpdateFuncRT!U == void))
1104 							update(value);
1105 						else
1106 							value = update(value);
1107 				});
1108 		}
1109 	}
1110 
1111 	// *** Mutation (editing) ***
1112 
1113 	static if (haveIndexing)
1114 	{
1115 		static if (haveValues)
1116 		{
1117 			/// Same as `set(k, v)`.
1118 			ref IV opIndexAssign(AK, AV)(auto ref AV v, auto ref AK k)
1119 			if (is(AK : K) && is(AV : V))
1120 			{
1121 				return set(k, v);
1122 			}
1123 
1124 			/// Perform cumulative operation with value
1125 			/// (initialized with `.init` if the key does not exist).
1126 			ref IV opIndexOpAssign(string op, AK, AV)(auto ref AV v, auto ref AK k)
1127 			if (is(AK : K) && is(AV : V))
1128 			{
1129 				auto pv = &require(k);
1130 				return mixin("(*pv) " ~ op ~ "= v");
1131 			}
1132 
1133 			/// Perform unary operation with value
1134 			/// (initialized with `.init` if the key does not exist).
1135 			ref IV opIndexUnary(string op, AK)(auto ref AK k)
1136 			if (is(AK : K))
1137 			{
1138 				auto pv = &require(k);
1139 				mixin("(*pv) " ~ op ~ ";");
1140 				return *pv;
1141 			}
1142 		}
1143 		else
1144 		{
1145 			private ref K editIndex(size_t index, scope void delegate(ref K) edit)
1146 			{
1147 				auto item = &items[index];
1148 				K oldKey = item.key;
1149 				auto pOldIndices = oldKey in lookup;
1150 				assert(pOldIndices);
1151 
1152 				edit(item.key);
1153 
1154 				// Add new value
1155 
1156 				lookup.updateVoid(item.key,
1157 					delegate LookupValue()
1158 					{
1159 						// New value did not exist.
1160 						if ((*pOldIndices).length == 1)
1161 						{
1162 							// Optimization - migrate the Indexes value
1163 							assert((*pOldIndices)[0] == index);
1164 							return *pOldIndices;
1165 						}
1166 						else
1167 							return [index];
1168 					},
1169 					delegate void(ref LookupValue existingIndex)
1170 					{
1171 						// Value(s) with the new key already existed
1172 						static if (multi)
1173 							existingIndex ~= index;
1174 						else
1175 							assert(false, "Collision after in-place edit of a non-multi ordered set element");
1176 					});
1177 
1178 				// Remove old value
1179 
1180 				if ((*pOldIndices).length == 1)
1181 					lookup.remove(oldKey);
1182 				else
1183 				static if (multi)
1184 					*pOldIndices = (*pOldIndices).remove!(i => i == index);
1185 				else
1186 					assert(false); // Should be unreachable (`if` above will always be true)
1187 
1188 				return item.key;
1189 			}
1190 
1191 			/// Allows writing to ordered sets by index.
1192 			/// The total number of elements never changes as a result
1193 			/// of such an operation - a consequence of which is that
1194 			/// if multi==false, changing the value to one that's
1195 			/// already in the set is an error.
1196 			ref IV opIndexAssign()(auto ref IV v, auto ref IK k)
1197 			{
1198 				static if (haveValues)
1199 					return set(k, v);
1200 				else
1201 					return editIndex(k, (ref IV e) { e = v; });
1202 			}
1203 
1204 			/// Perform cumulative operation with value at index.
1205 			ref IV opIndexOpAssign(string op)(auto ref VV v, auto ref IK k)
1206 			{
1207 				return editIndex(k, (ref IV e) { mixin("e " ~ op ~ "= v;"); });
1208 			}
1209 
1210 			/// Perform unary operation with value at index.
1211 			ref IV opIndexUnary(string op)(auto ref IK k)
1212 			{
1213 				return editIndex(k, (ref IV e) { mixin("e " ~ op ~ ";"); });
1214 			}
1215 		}
1216 	}
1217 
1218 	// *** Mutation (removal) ***
1219 
1220 	/// Removes all elements with the given key.
1221 	bool remove(AK)(auto ref AK key)
1222 	if (is(typeof(lookup.remove(key))))
1223 	{
1224 		static if (ordered)
1225 		{
1226 			auto p = key in lookup;
1227 			if (!p)
1228 				return false;
1229 
1230 			auto targets = *p;
1231 			foreach (target; targets)
1232 			{
1233 				items = items.remove!(SwapStrategy.stable)(target);
1234 				foreach (ref k, ref vs; lookup)
1235 					foreach (ref v; vs)
1236 						if (v > target)
1237 							v--;
1238 			}
1239 			auto success = lookup.remove(key);
1240 			assert(success);
1241 			return true;
1242 		}
1243 		else
1244 			return lookup.remove(key);
1245 	}
1246 
1247 	/// Removes all elements.
1248 	void clear()
1249 	{
1250 		lookup.clear();
1251 		static if (ordered)
1252 			items = null;
1253 	}
1254 }
1255 
1256 /// An associative array which retains the order in which elements were added.
1257 alias OrderedMap(K, V) = HashCollection!(K, V, true, false);
1258 
1259 unittest
1260 {
1261 	alias M = OrderedMap!(string, int);
1262 	M m;
1263 	m["a"] = 1;
1264 	m["b"] = 2;
1265 	m["c"] = 3;
1266 	assert(m.length == 3);
1267 	assert("a" in m);
1268 	assert("d" !in m);
1269 
1270 	{
1271 		auto r = m.byKeyValue;
1272 		assert(!r.empty);
1273 		assert(r.front.key == "a");
1274 		r.popFront();
1275 		assert(!r.empty);
1276 		assert(r.front.key == "b");
1277 		r.popFront();
1278 		assert(!r.empty);
1279 		assert(r.front.key == "c");
1280 		r.popFront();
1281 		assert(r.empty);
1282 	}
1283 
1284 	assert(m.byKey.equal(["a", "b", "c"]));
1285 	assert(m.byValue.equal([1, 2, 3]));
1286 	assert(m.byKeyValue.map!(p => p.key).equal(m.byKey));
1287 	assert(m.byKeyValue.map!(p => p.value).equal(m.byValue));
1288 	assert(m.keys == ["a", "b", "c"]);
1289 	assert(m.values == [1, 2, 3]);
1290 
1291 	{
1292 		const(M)* c = &m;
1293 		assert(c.byKey.equal(["a", "b", "c"]));
1294 		assert(c.byValue.equal([1, 2, 3]));
1295 		assert(c.keys == ["a", "b", "c"]);
1296 		assert(c.values == [1, 2, 3]);
1297 	}
1298 
1299 	m.byValue.front = 5;
1300 	assert(m.byValue.equal([5, 2, 3]));
1301 
1302 	m.remove("a");
1303 	assert(m.length == 2);
1304 	m["x"] -= 1;
1305 	assert(m["x"] == -1);
1306 	++m["y"];
1307 	assert(m["y"] == 1);
1308 	auto cm = cast(const)m.dup;
1309 	foreach (k, v; cm)
1310 		if (k == "x")
1311 			assert(v == -1);
1312 }
1313 
1314 unittest
1315 {
1316 	OrderedMap!(string, int) m;
1317 	m["a"] = 1;
1318 	m["b"] = 2;
1319 	m.remove("a");
1320 	assert(m["b"] == 2);
1321 }
1322 
1323 unittest
1324 {
1325 	OrderedMap!(string, int) m;
1326 	m["a"] = 1;
1327 	auto m2 = m;
1328 	m2.remove("a");
1329 	m2["b"] = 2;
1330 	assert(m["a"] == 1);
1331 }
1332 
1333 unittest
1334 {
1335 	OrderedMap!(string, int) m;
1336 	m["a"] = 1;
1337 	m["b"] = 2;
1338 	auto m2 = m;
1339 	m.remove("a");
1340 	assert(m2["a"] == 1);
1341 }
1342 
1343 unittest
1344 {
1345 	class C {}
1346 	const OrderedMap!(string, C) m;
1347 	cast(void)m.byKeyValue;
1348 }
1349 
1350 unittest
1351 {
1352 	OrderedMap!(int, int) m;
1353 	m.update(10,
1354 		{ return 20; },
1355 		(ref int k) { k++; return 30; },
1356 	);
1357 	assert(m.length == 1 && m[10] == 20);
1358 	m.update(10,
1359 		{ return 40; },
1360 		(ref int k) { k++; return 50; },
1361 	);
1362 	assert(m.length == 1 && m[10] == 50);
1363 }
1364 
1365 // https://issues.dlang.org/show_bug.cgi?id=18606
1366 unittest
1367 {
1368 	struct S
1369 	{
1370 		struct T
1371 		{
1372 			int foo;
1373 			int[] bar;
1374 		}
1375 
1376 		OrderedMap!(int, T) m;
1377 	}
1378 }
1379 
1380 unittest
1381 {
1382 	OrderedMap!(string, int) m;
1383 	static assert(is(typeof(m.keys)));
1384 	static assert(is(typeof(m.values)));
1385 }
1386 
1387 unittest
1388 {
1389 	OrderedMap!(string, int) m;
1390 	foreach (k, v; m)
1391 		k = k ~ k;
1392 }
1393 
1394 unittest
1395 {
1396 	struct S { @disable this(); }
1397 	const OrderedMap!(string, S) m;
1398 }
1399 
1400 /// Like assocArray
1401 auto orderedMap(R)(R input)
1402 if (is(typeof(input.front.length) : size_t) && input.front.length == 2)
1403 {
1404 	alias K = typeof(input.front[0]);
1405 	alias V = typeof(input.front[1]);
1406 	return OrderedMap!(K, V)(input);
1407 }
1408 
1409 auto orderedMap(R)(R input)
1410 if (is(typeof(input.front.key)) && is(typeof(input.front.value)) && !is(typeof(input.front.length)))
1411 {
1412 	alias K = typeof(input.front.key);
1413 	alias V = typeof(input.front.value);
1414 	return OrderedMap!(K, V)(input);
1415 } /// ditto
1416 
1417 unittest
1418 {
1419 	auto map = 3.iota.map!(n => tuple(n, n + 1)).orderedMap;
1420 	assert(map.length == 3 && map[1] == 2);
1421 }
1422 
1423 unittest
1424 {
1425 	OrderedMap!(string, int) m;
1426 	m = m.byKeyValue.orderedMap;
1427 	m = m.byPair.orderedMap;
1428 }
1429 
1430 // ***************************************************************************
1431 
1432 /// Helper/wrapper for void[0][T]
1433 alias HashSet(T) = HashCollection!(T, void, false, false);
1434 
1435 unittest
1436 {
1437 	HashSet!int s;
1438 	assert(!s);
1439 	assert(s.length == 0);
1440 	assert(!(1 in s));
1441 	assert(1 !in s);
1442 	s.add(1);
1443 	assert(1 in s);
1444 	assert(s.length == 1);
1445 	foreach (k; s)
1446 		assert(k == 1);
1447 	foreach (ref k; s.byRef)
1448 		assert(k == 1);
1449 	s.remove(1);
1450 	assert(s.length == 0);
1451 
1452 	s.add(1);
1453 	auto t = s.dup;
1454 	s.add(2);
1455 	assert(t.length==1);
1456 	t.remove(1);
1457 	assert(t.length==0);
1458 }
1459 
1460 unittest
1461 {
1462 	struct S { int[int] aa; }
1463 	HashSet!S set;
1464 	S s;
1465 	set.add(s);
1466 	assert(s in set);
1467 }
1468 
1469 /// Construct a set from the range `r`.
1470 auto toSet(R)(R r)
1471 {
1472 	alias E = ElementType!R;
1473 	return HashSet!E(r);
1474 }
1475 
1476 unittest
1477 {
1478 	auto set = [1, 2, 3].toSet();
1479 	assert(2 in set);
1480 	assert(4 !in set);
1481 }
1482 
1483 unittest
1484 {
1485 	HashSet!int m;
1486 	const int i;
1487 	m.remove(i);
1488 }
1489 
1490 unittest
1491 {
1492 	HashSet!Object m;
1493 	Object o;
1494 	m.remove(o);
1495 }
1496 
1497 unittest
1498 {
1499 	struct S
1500 	{
1501 		@disable this(this);
1502 	}
1503 
1504 	HashSet!S set;
1505 }
1506 
1507 // ***************************************************************************
1508 
1509 /// An ordered set of `T`, which retains
1510 /// the order in which elements are added.
1511 alias OrderedSet(T) = HashCollection!(T, void, true, false);
1512 
1513 unittest
1514 {
1515 	OrderedSet!int set;
1516 
1517 	assert(1 !in set);
1518 	set.add(1);
1519 	assert(1 in set);
1520 	set.remove(1);
1521 	assert(1 !in set);
1522 
1523 	set.add(1);
1524 	set.clear();
1525 	assert(1 !in set);
1526 
1527 	set = set.init;
1528 	assert(!set);
1529 	set.add(1);
1530 	assert(!!set);
1531 
1532 	assert(set[0] == 1);
1533 	set[0] = 2;
1534 	assert(set[0] == 2);
1535 	assert(1 !in set);
1536 	assert(2 in set);
1537 
1538 	assert(set.length == 1);
1539 	set.remove(2);
1540 	assert(set.length == 0);
1541 
1542 	set.add(1);
1543 	auto set2 = set;
1544 	set.remove(1);
1545 	set.add(2);
1546 	assert(1 !in set && 2 in set);
1547 	assert(1 in set2 && 2 !in set2);
1548 
1549 	foreach (v; set)
1550 		assert(v == 2);
1551 }
1552 
1553 /// Construct an ordered set from the range `r`.
1554 auto orderedSet(R)(R r)
1555 {
1556 	alias E = ElementType!R;
1557 	return OrderedSet!E(r);
1558 }
1559 
1560 // ***************************************************************************
1561 
1562 /// An object which acts mostly as an associative array,
1563 /// with the added property of being able to hold keys with
1564 /// multiple values. These are only exposed explicitly and
1565 /// through iteration
1566 alias MultiAA(K, V) = HashCollection!(K, V, false, true);
1567 
1568 unittest
1569 {
1570 	alias MASS = MultiAA!(string, int);
1571 	MASS aa;
1572 	aa.add("foo", 42);
1573 	assert(aa["foo"] == 42);
1574 	assert(aa.valuesOf("foo") == [42]);
1575 	assert(aa.byPair.front.key == "foo");
1576 
1577 	auto aa2 = MASS([tuple("foo", 42)]);
1578 	aa2 = ["a":1,"b":2];
1579 
1580 	const int i;
1581 	aa["a"] = i;
1582 }
1583 
1584 unittest
1585 {
1586 	MultiAA!(int, int) m;
1587 	int[][int] a;
1588 	m = a;
1589 }