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