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