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 <vladimir@thecybershadow.net>
12  */
13 
14 module ae.utils.aa;
15 
16 import std.algorithm;
17 import std.range;
18 import std.typecons;
19 
20 // ***************************************************************************
21 
22 /// Get a value from an AA, and throw an exception (not an error) if not found
23 ref auto aaGet(AA, K)(auto ref AA aa, auto ref K key)
24 	if (is(typeof(key in aa)))
25 {
26 	import std.conv;
27 
28 	auto p = key in aa;
29 	if (p)
30 		return *p;
31 	else
32 		static if (is(typeof(text(key))))
33 			throw new Exception("Absent value: " ~ text(key));
34 		else
35 			throw new Exception("Absent value");
36 }
37 
38 /// If key is not in aa, add it with defaultValue.
39 /// Returns a reference to the value corresponding to key.
40 ref V getOrAdd(K, V)(ref V[K] aa, auto ref K key, auto ref V defaultValue)
41 {
42 	static if (__traits(hasMember, object, "require"))
43 		return aa.require(key, defaultValue);
44 	else
45 	{
46 		auto p = key in aa;
47 		if (!p)
48 		{
49 			aa[key] = defaultValue;
50 			p = key in aa;
51 		}
52 		return *p;
53 	}
54 }
55 
56 /// ditto
57 ref V getOrAdd(K, V)(ref V[K] aa, auto ref K key)
58 {
59 	return getOrAdd(aa, key, V.init);
60 }
61 
62 unittest
63 {
64 	int[int] aa;
65 	aa.getOrAdd(1, 2) = 3;
66 	assert(aa[1] == 3);
67 	assert(aa.getOrAdd(1, 4) == 3);
68 }
69 
70 /// If key is not in aa, add it with the given value, and return true.
71 /// Otherwise, return false.
72 bool addNew(K, V)(ref V[K] aa, auto ref K key, auto ref V value)
73 {
74 	static if (__traits(hasMember, object, "update"))
75 	{
76 		bool added = void;
77 		aa.update(key,
78 			delegate V(       ) { added = true ; return value; },
79 			delegate V(ref V v) { added = false; return v    ; },
80 		);
81 		return added;
82 	}
83 	else
84 	{
85 		auto p = key in aa;
86 		if (!p)
87 		{
88 			aa[key] = value;
89 			return true;
90 		}
91 		else
92 			return false;
93 	}
94 }
95 
96 unittest
97 {
98 	int[int] aa;
99 	assert( aa.addNew(1, 2));
100 	assert(!aa.addNew(1, 3));
101 	assert(aa[1] == 2);
102 }
103 
104 struct KeyValuePair(K, V) { K key; V value; }
105 
106 /// Get key/value pairs from AA
107 KeyValuePair!(K, V)[] pairs(K, V)(V[K] aa)
108 {
109 	KeyValuePair!(K, V)[] result;
110 	foreach (key, value; aa)
111 		result ~= KeyValuePair!(K, V)(key, value);
112 	return result;
113 }
114 
115 /// Get key/value pairs from AA, sorted by keys
116 KeyValuePair!(K, V)[] sortedPairs(K, V)(V[K] aa)
117 {
118 	KeyValuePair!(K, V)[] result;
119 	foreach (key; aa.keys.sort)
120 		result ~= KeyValuePair!(K, V)(key, aa[key]);
121 	return result;
122 }
123 
124 /// Get values from AA, sorted by keys
125 V[] sortedValues(K, V)(in V[K] aa)
126 {
127 	V[] result;
128 	foreach (key; aa.keys.sort())
129 		result ~= aa[key];
130 	return result;
131 }
132 
133 /// Merge source into target. Return target.
134 V[K] merge(K, V)(auto ref V[K] target, in V[K] source)
135 {
136 	foreach (k, v; source)
137 		target[k] = v;
138 	return target;
139 }
140 
141 unittest
142 {
143 	int[int] target;
144 	int[int] source = [2:4];
145 	merge(target, source);
146 	assert(source == target);
147 
148 	target = [1:1, 2:2, 3:3];
149 	merge(target, source);
150 	assert(target == [1:1, 2:4, 3:3]);
151 
152 	assert(merge([1:1], [2:2]) == [1:1, 2:2]);
153 }
154 
155 /// Slurp a range of two elements (or two-element struct/class) into an AA.
156 auto toAA(R)(R r)
157 	if (is(typeof(r.front[1])))
158 {
159 	alias K = typeof(r.front[0]);
160 	alias V = typeof(r.front[1]);
161 	V[K] result;
162 	foreach (pair; r)
163 	{
164 		assert(pair.length == 2);
165 		result[pair[0]] = pair[1];
166 	}
167 	return result;
168 }
169 
170 /// ditto
171 auto toAA(R)(R r)
172 	if (is(typeof(r.front.tupleof)) && r.front.tupleof.length == 2 && !is(typeof(r.front[1])))
173 {
174 	return r.map!(el => tuple(el.tupleof)).toAA();
175 }
176 
177 unittest
178 {
179 	assert([[2, 4]].toAA() == [2:4]);
180 	assert([2:4].pairs.toAA() == [2:4]);
181 }
182 
183 // ***************************************************************************
184 
185 /// An associative array which retains the order in which elements were added.
186 struct OrderedMap(K, V)
187 {
188 	K[] keys;
189 	V[] values;
190 	size_t[K] index;
191 
192 	/// Convert from regular AA
193 	this(V[K] aa)
194 	{
195 		opAssign(aa);
196 	}
197 
198 	static if (is(typeof(keys.dup && values.dup && index.dup)))
199 	{
200 		this(this)
201 		{
202 			keys = keys.dup;
203 			values = values.dup;
204 			index = index.dup;
205 		}
206 	}
207 	else
208 		@disable this(this);
209 
210 	void opAssign(V[K] aa)
211 	{
212 		clear();
213 		foreach (ref k, ref v; aa)
214 		{
215 			index[k] = values.length;
216 			keys ~= k;
217 			values ~= v;
218 		}
219 	}
220 
221 	void clear()
222 	{
223 		keys = null;
224 		values = null;
225 		index = null;
226 	}
227 
228 	bool opCast(T)() const
229 	if (is(T == bool))
230 	{
231 		return !!index;
232 	}
233 
234 	ref inout(V) opIndex()(auto ref K k) inout
235 	{
236 		return values[index[k]];
237 	}
238 
239 	ref V opIndexAssign()(auto ref V v, auto ref K k)
240 	{
241 		auto pi = k in index;
242 		if (pi)
243 		{
244 			auto pv = &values[*pi];
245 			*pv = v;
246 			return *pv;
247 		}
248 
249 		index[k] = values.length;
250 		keys ~= k;
251 		values ~= v;
252 		return values[$-1];
253 	}
254 
255 	private enum bool haveObjectRequire = is(typeof({ int[int] aa; aa.require(1, 2); }));
256 
257 	ref V require()(auto ref K key, lazy V value = V.init)
258 	{
259 		V* pv;
260 		static if (haveObjectRequire)
261 		{
262 			index.update(
263 				key,
264 				{
265 					auto i = values.length;
266 					keys ~= key;
267 					values ~= value;
268 					pv = &values[i];
269 					return i;
270 				},
271 				(ref size_t i)
272 				{
273 					pv = &values[i];
274 					return i;
275 				}
276 			);
277 		}
278 		else
279 		{
280 			auto pi = key in index;
281 			if (pi)
282 				pv = &values[*pi];
283 			else
284 			{
285 				index[key] = values.length;
286 				keys ~= key;
287 				values ~= value;
288 				pv = &values[$-1];
289 			}
290 		}
291 		return *pv;
292 	}
293 
294 	void update(C, U)(auto ref K key, scope C create, scope U update)
295 	if (is(typeof(create()) : V) && is(typeof(update(*(V*).init)) : V))
296 	{
297 		static if (haveObjectRequire)
298 		{
299 			index.update(
300 				key,
301 				{
302 					auto i = values.length;
303 					keys ~= key;
304 					values ~= create();
305 					return i;
306 				},
307 				(ref size_t i)
308 				{
309 					auto pv = &values[i];
310 					*pv = update(*pv);
311 					return i;
312 				}
313 			);
314 		}
315 		else
316 		{
317 			auto pi = key in index;
318 			if (pi)
319 			{
320 				auto pv = &values[*pi];
321 				*pv = update(*pv);
322 			}
323 			else
324 			{
325 				index[key] = values.length;
326 				keys ~= key;
327 				values ~= create();
328 			}
329 		}
330 	}
331 
332 	ref V getOrAdd()(auto ref K key)
333 	{
334 		return require(key);
335 	}
336 
337 	ref V opIndexUnary(string op)(auto ref K k)
338 	{
339 		auto pv = &getOrAdd(k);
340 		mixin("(*pv) " ~ op ~ ";");
341 		return *pv;
342 	}
343 
344 	ref V opIndexOpAssign(string op)(auto ref V v, auto ref K k)
345 	{
346 		auto pv = &getOrAdd(k);
347 		mixin("(*pv) " ~ op ~ "= v;");
348 		return *pv;
349 	}
350 
351 	inout(V) get()(auto ref K k, inout(V) defaultValue) inout
352 	{
353 		auto p = k in index;
354 		return p ? values[*p] : defaultValue;
355 	}
356 
357 	inout(V)* opBinaryRight(string op)(auto ref in K k) inout
358 	if (op == "in")
359 	{
360 		auto p = k in index;
361 		return p ? &values[*p] : null;
362 	}
363 
364 	void remove()(auto ref K k)
365 	{
366 		auto i = index[k];
367 		index.remove(k);
368 		keys = keys.remove(i);
369 		values = values.remove(i);
370 		foreach (key, ref idx; index)
371 			if (idx > i)
372 				idx--;
373 	}
374 
375 	@property size_t length() const { return values.length; }
376 
377 	private int opApplyImpl(this This, Dg)(Dg dg)
378 	{
379 		int result = 0;
380 
381 		foreach (i, ref v; values)
382 		{
383 			result = dg(keys[i], v);
384 			if (result)
385 				break;
386 		}
387 		return result;
388 	}
389 
390 	int opApply(int delegate(ref K k, ref V v) dg)
391 	{
392 		return opApplyImpl(dg);
393 	}
394 
395 	int opApply(int delegate(const ref K k, const ref V v) dg) const
396 	{
397 		return opApplyImpl(dg);
398 	}
399 
400 	@property typeof(this) dup()
401 	{
402 		typeof(this) result;
403 		result.keys = keys.dup;
404 		result.values = values.dup;
405 		result.index = index.dup;
406 		return result;
407 	}
408 
409 	alias byKey = keys;
410 	alias byValue = values;
411 
412 	auto byKeyValue(this T)()
413 	{
414 		auto instance = this;
415 		struct Range
416 		{
417 			size_t index;
418 			bool empty() const { return index == instance.values.length; }
419 			static struct KeyValue { typeof(instance.keys[0]) key; typeof(instance.values[0]) value; }
420 			KeyValue front() { return KeyValue(instance.keys[index], instance.values[index]); }
421 			void popFront() { index++; }
422 		}
423 		return Range();
424 	}
425 }
426 
427 unittest
428 {
429 	OrderedMap!(string, int) m;
430 	m["a"] = 1;
431 	m["b"] = 2;
432 	m["c"] = 3;
433 	assert(m.length == 3);
434 	assert("a" in m);
435 	assert("d" !in m);
436 
437 	{
438 		auto r = m.byKeyValue;
439 		assert(!r.empty);
440 		assert(r.front.key == "a");
441 		r.popFront();
442 		assert(!r.empty);
443 		assert(r.front.key == "b");
444 		r.popFront();
445 		assert(!r.empty);
446 		assert(r.front.key == "c");
447 		r.popFront();
448 		assert(r.empty);
449 	}
450 
451 	m.remove("a");
452 	assert(m.length == 2);
453 	m["x"] -= 1;
454 	assert(m["x"] == -1);
455 	++m["y"];
456 	assert(m["y"] == 1);
457 	auto cm = cast(const)m.dup;
458 	foreach (k, v; cm)
459 		if (k == "x")
460 			assert(v == -1);
461 }
462 
463 unittest
464 {
465 	OrderedMap!(string, int) m;
466 	m["a"] = 1;
467 	m["b"] = 2;
468 	m.remove("a");
469 	assert(m["b"] == 2);
470 }
471 
472 unittest
473 {
474 	OrderedMap!(string, int) m;
475 	m["a"] = 1;
476 	auto m2 = m;
477 	m2.remove("a");
478 	m2["b"] = 2;
479 	assert(m["a"] == 1);
480 }
481 
482 unittest
483 {
484 	OrderedMap!(string, int) m;
485 	m["a"] = 1;
486 	m["b"] = 2;
487 	auto m2 = m;
488 	m.remove("a");
489 	assert(m2["a"] == 1);
490 }
491 
492 unittest
493 {
494 	class C {}
495 	const OrderedMap!(string, C) m;
496 	m.byKeyValue;
497 }
498 
499 unittest
500 {
501 	OrderedMap!(int, int) m;
502 	m.update(10,
503 		{ return 20; },
504 		(ref int k) { k++; return 30; },
505 	);
506 	assert(m.length == 1 && m[10] == 20);
507 	m.update(10,
508 		{ return 40; },
509 		(ref int k) { k++; return 50; },
510 	);
511 	assert(m.length == 1 && m[10] == 50);
512 }
513 
514 // https://issues.dlang.org/show_bug.cgi?id=18606
515 unittest
516 {
517 	struct S
518 	{
519 		struct T
520 		{
521 			int foo;
522 			int[] bar;
523 		}
524 
525 		OrderedMap!(int, T) m;
526 	}
527 }
528 
529 // ***************************************************************************
530 
531 /// Helper/wrapper for void[0][T]
532 struct HashSet(T)
533 {
534 	void[0][T] data;
535 
536 	alias data this;
537 
538 	this(R)(R r)
539 	{
540 		foreach (k; r)
541 			add(k);
542 	}
543 
544 	void add(T k)
545 	{
546 		void[0] v;
547 		data[k] = v;
548 	}
549 
550 	bool addNew(T k)
551 	{
552 		void[0] v;
553 		return data.addNew(k, v);
554 	}
555 
556 	bool remove(T k)
557 	{
558 		return data.remove(k);
559 	}
560 
561 	@property HashSet!T dup() const
562 	{
563 		// Can't use .dup with void[0] value
564 		HashSet!T result;
565 		foreach (k, v; data)
566 			result.add(k);
567 		return result;
568 	}
569 
570 	int opApply(scope int delegate(ref T) dg)
571 	{
572 		int result;
573 		foreach (k, v; data)
574 			if ((result = dg(k)) != 0)
575 				break;
576 		return result;
577 	}
578 }
579 
580 unittest
581 {
582 	HashSet!int s;
583 	assert(s.length == 0);
584 	assert(!(1 in s));
585 	assert(1 !in s);
586 	s.add(1);
587 	assert(1 in s);
588 	assert(s.length == 1);
589 	foreach (k; s)
590 		assert(k == 1);
591 	s.remove(1);
592 	assert(s.length == 0);
593 
594 	s.add(1);
595 	auto t = s.dup;
596 	s.add(2);
597 	assert(t.length==1);
598 	t.remove(1);
599 	assert(t.length==0);
600 }
601 
602 auto toSet(R)(R r)
603 {
604 	alias E = ElementType!R;
605 	return HashSet!E(r);
606 }
607 
608 unittest
609 {
610 	auto set = [1, 2, 3].toSet();
611 	assert(2 in set);
612 	assert(4 !in set);
613 }
614 
615 // ***************************************************************************
616 
617 struct OrderedSet(T)
618 {
619 	T[] items;
620 	size_t[T] index;
621 
622 	this(R)(R r)
623 	if (isInputRange!R)
624 	{
625 		foreach (k; r)
626 			add(k);
627 	}
628 
629 	static if (is(typeof(items.dup && index.dup)))
630 	{
631 		this(this)
632 		{
633 			items = items.dup;
634 			index = index.dup;
635 		}
636 	}
637 	else
638 		@disable this(this);
639 
640 	void clear()
641 	{
642 		items = null;
643 		index = null;
644 	}
645 
646 	bool opCast(T)() const
647 	if (is(T == bool))
648 	{
649 		return !!index;
650 	}
651 
652 	ref inout(T) opIndex()(size_t i) inout
653 	{
654 		return items[i];
655 	}
656 
657 	ref T opIndexAssign()(auto ref T v, size_t i)
658 	{
659 		assert(i < items.length);
660 		index.remove(items[i]);
661 		items[i] = v;
662 		index[v] = i;
663 		return items[i];
664 	}
665 
666 	bool opBinaryRight(string op)(auto ref in T v) inout
667 	if (op == "in")
668 	{
669 		return !!(v in index);
670 	}
671 
672 	ref T add()(auto ref T v)
673 	{
674 		auto pi = v in index;
675 		if (pi)
676 		{
677 			auto pv = &items[*pi];
678 			*pv = v;
679 			return *pv;
680 		}
681 
682 		index[v] = items.length;
683 		items ~= v;
684 		return items[$-1];
685 	}
686 
687 	void remove()(auto ref T v)
688 	{
689 		auto i = index[v];
690 		index.remove(v);
691 		items = items.remove(i);
692 		foreach (key, ref idx; index)
693 			if (idx > i)
694 				idx--;
695 	}
696 
697 	@property size_t length() const { return items.length; }
698 
699 	private int opApplyImpl(this This, Dg)(Dg dg)
700 	{
701 		int result = 0;
702 
703 		foreach (i, ref v; items)
704 		{
705 			result = dg(v);
706 			if (result)
707 				break;
708 		}
709 		return result;
710 	}
711 
712 	int opApply(int delegate(ref T k) dg)
713 	{
714 		return opApplyImpl(dg);
715 	}
716 
717 	int opApply(int delegate(const ref T k) dg) const
718 	{
719 		return opApplyImpl(dg);
720 	}
721 
722 	@property typeof(this) dup()
723 	{
724 		typeof(this) result;
725 		result.items = items.dup;
726 		result.index = index.dup;
727 		return result;
728 	}
729 }
730 
731 unittest
732 {
733 	OrderedSet!int set;
734 
735 	assert(1 !in set);
736 	set.add(1);
737 	assert(1 in set);
738 	set.remove(1);
739 	assert(1 !in set);
740 
741 	set.add(1);
742 	set.clear();
743 	assert(1 !in set);
744 
745 	set = set.init;
746 	assert(!set);
747 	set.add(1);
748 	assert(!!set);
749 
750 	assert(set[0] == 1);
751 	set[0] = 2;
752 	assert(set[0] == 2);
753 	assert(1 !in set);
754 	assert(2 in set);
755 
756 	assert(set.length == 1);
757 	set.remove(2);
758 	assert(set.length == 0);
759 
760 	set.add(1);
761 	auto set2 = set;
762 	set.remove(1);
763 	set.add(2);
764 	assert(1 !in set && 2 in set);
765 	assert(1 in set2 && 2 !in set2);
766 
767 	foreach (v; set)
768 		assert(v == 2);
769 }
770 
771 // ***************************************************************************
772 
773 /// An object which acts mostly as an associative array,
774 /// with the added property of being able to hold keys with
775 /// multiple values. These are only exposed explicitly and
776 /// through iteration
777 struct MultiAA(K, V)
778 {
779 	V[][K] items;
780 
781 	/// If multiple items with this name are present,
782 	/// only the first one is returned.
783 	ref inout(V) opIndex(K key) inout
784 	{
785 		return items[key][0];
786 	}
787 
788 	V opIndexAssign(V value, K key)
789 	{
790 		items[key] = [value];
791 		return value;
792 	}
793 
794 	inout(V)* opBinaryRight(string op)(K key) inout @nogc
795 	if (op == "in")
796 	{
797 		auto pvalues = key in items;
798 		if (pvalues && (*pvalues).length)
799 			return &(*pvalues)[0];
800 		return null;
801 	}
802 
803 	bool remove(K key)
804 	{
805 		return items.remove(key);
806 	}
807 
808 	// D forces these to be "ref"
809 	int opApply(int delegate(ref K key, ref V value) dg)
810 	{
811 		int ret;
812 		outer:
813 		foreach (key, values; items)
814 			foreach (ref value; values)
815 			{
816 				ret = dg(key, value);
817 				if (ret)
818 					break outer;
819 			}
820 		return ret;
821 	}
822 
823 	// Copy-paste because of https://issues.dlang.org/show_bug.cgi?id=7543
824 	int opApply(int delegate(ref const(K) key, ref const(V) value) dg) const
825 	{
826 		int ret;
827 		outer:
828 		foreach (key, values; items)
829 			foreach (ref value; values)
830 			{
831 				ret = dg(key, value);
832 				if (ret)
833 					break outer;
834 			}
835 		return ret;
836 	}
837 
838 	void add(K key, V value)
839 	{
840 		if (key !in items)
841 			items[key] = [value];
842 		else
843 			items[key] ~= value;
844 	}
845 
846 	V get(K key, lazy V def) const
847 	{
848 		auto pvalue = key in this;
849 		return pvalue ? *pvalue : def;
850 	}
851 
852 	inout(V)[] getAll(K key) inout
853 	{
854 		inout(V)[] result;
855 		foreach (ref value; items.get(key, null))
856 			result ~= value;
857 		return result;
858 	}
859 
860 	this(typeof(null) Null)
861 	{
862 	}
863 
864 	this(V[K] aa)
865 	{
866 		foreach (ref key, ref value; aa)
867 			add(key, value);
868 	}
869 
870 	this(V[][K] aa)
871 	{
872 		foreach (ref key, values; aa)
873 			foreach (ref value; values)
874 				add(key, value);
875 	}
876 
877 	@property auto keys() inout { return items.keys; }
878 
879 	// https://issues.dlang.org/show_bug.cgi?id=14626
880 
881 	@property V[] values()
882 	{
883 		return items.byValue.join;
884 	}
885 
886 	@property const(V)[] values() const
887 	{
888 		return items.byValue.join;
889 	}
890 
891 	@property typeof(V[K].init.pairs) pairs()
892 	{
893 		alias Pair = typeof(V[K].init.pairs[0]);
894 		Pair[] result;
895 		result.reserve(length);
896 		foreach (ref k, ref v; this)
897 			result ~= Pair(k, v);
898 		return result;
899 	}
900 
901 	@property size_t length() const { return items.byValue.map!(item => item.length).sum(); }
902 
903 	auto byKey() { return items.byKey(); }
904 	auto byValue() { return items.byValue().joiner(); }
905 
906 	bool opCast(T)() inout
907 		if (is(T == bool))
908 	{
909 		return !!items;
910 	}
911 
912 	/// Warning: discards repeating items
913 	V[K] opCast(T)() const
914 		if (is(T == V[K]))
915 	{
916 		V[K] result;
917 		foreach (key, value; this)
918 			result[key] = value;
919 		return result;
920 	}
921 
922 	V[][K] opCast(T)() inout
923 		if (is(T == V[][K]))
924 	{
925 		V[][K] result;
926 		foreach (k, v; this)
927 			result[k] ~= v;
928 		return result;
929 	}
930 }
931 
932 unittest
933 {
934 	MultiAA!(string, string) aa;
935 }