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