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