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)(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 	void opAssign(V[K] aa)
154 	{
155 		clear();
156 		foreach (ref k, ref v; aa)
157 		{
158 			index[k] = values.length;
159 			keys ~= k;
160 			values ~= v;
161 		}
162 	}
163 
164 	void clear()
165 	{
166 		keys = null;
167 		values = null;
168 		index = null;
169 	}
170 
171 	ref inout(V) opIndex()(auto ref K k) inout
172 	{
173 		return values[index[k]];
174 	}
175 
176 	ref V opIndexAssign()(auto ref V v, auto ref K k)
177 	{
178 		auto pi = k in index;
179 		if (pi)
180 		{
181 			auto pv = &values[*pi];
182 			*pv = v;
183 			return *pv;
184 		}
185 
186 		index[k] = values.length;
187 		keys ~= k;
188 		values ~= v;
189 		return values[$-1];
190 	}
191 
192 	ref V getOrAdd()(auto ref K k)
193 	{
194 		auto pi = k in index;
195 		V* pv;
196 		if (pi)
197 			pv = &values[*pi];
198 		else
199 		{
200 			index[k] = values.length;
201 			keys ~= k;
202 			values ~= V.init;
203 			pv = &values[$-1];
204 		}
205 		return *pv;
206 	}
207 
208 	ref V opIndexUnary(string op)(auto ref K k)
209 	{
210 		auto pv = &getOrAdd(k);
211 		mixin("(*pv) " ~ op ~ ";");
212 		return *pv;
213 	}
214 
215 	ref V opIndexOpAssign(string op)(auto ref V v, auto ref K k)
216 	{
217 		auto pv = &getOrAdd(k);
218 		mixin("(*pv) " ~ op ~ "= v;");
219 		return *pv;
220 	}
221 
222 	inout(V) get()(auto ref K k, inout(V) defaultValue) inout
223 	{
224 		auto p = k in index;
225 		return p ? values[*p] : defaultValue;
226 	}
227 
228 	inout(V)* opIn_r()(auto ref K k) inout
229 	{
230 		auto p = k in index;
231 		return p ? &values[*p] : null;
232 	}
233 
234 	void remove()(auto ref K k)
235 	{
236 		auto i = index[k];
237 		index.remove(k);
238 		keys = keys.remove(i);
239 		values = values.remove(i);
240 	}
241 
242 	@property size_t length() const { return values.length; }
243 
244 	private int opApplyImpl(this This, Dg)(Dg dg)
245 	{
246 		int result = 0;
247 
248 		foreach (i, ref v; values)
249 		{
250 			result = dg(keys[i], v);
251 			if (result)
252 				break;
253 		}
254 		return result;
255 	}
256 
257 	int opApply(int delegate(ref K k, ref V v) dg)
258 	{
259 		return opApplyImpl(dg);
260 	}
261 
262 	int opApply(int delegate(const ref K k, const ref V v) dg) const
263 	{
264 		return opApplyImpl(dg);
265 	}
266 
267 	@property typeof(this) dup()
268 	{
269 		typeof(this) result;
270 		result.keys = keys.dup;
271 		result.values = values.dup;
272 		result.index = index.dup;
273 		return result;
274 	}
275 }
276 
277 unittest
278 {
279 	OrderedMap!(string, int) m;
280 	m["a"] = 1;
281 	m["b"] = 2;
282 	m["c"] = 3;
283 	assert(m.length == 3);
284 	assert("a" in m);
285 	assert("d" !in m);
286 	m.remove("a");
287 	assert(m.length == 2);
288 	m["x"] -= 1;
289 	assert(m["x"] == -1);
290 	++m["y"];
291 	assert(m["y"] == 1);
292 	auto cm = cast(const)m.dup;
293 	foreach (k, v; cm)
294 		if (k == "x")
295 			assert(v == -1);
296 }
297 
298 // ***************************************************************************
299 
300 /// Helper/wrapper for void[0][T]
301 struct HashSet(T)
302 {
303 	void[0][T] data;
304 
305 	alias data this;
306 
307 	this(R)(R r)
308 	{
309 		foreach (k; r)
310 			add(k);
311 	}
312 
313 	void add(T k)
314 	{
315 		void[0] v;
316 		data[k] = v;
317 	}
318 
319 	void remove(T k)
320 	{
321 		data.remove(k);
322 	}
323 
324 	@property HashSet!T dup() const
325 	{
326 		// Can't use .dup with void[0] value
327 		HashSet!T result;
328 		foreach (k, v; data)
329 			result.add(k);
330 		return result;
331 	}
332 
333 	int opApply(scope int delegate(ref T) dg)
334 	{
335 		int result;
336 		foreach (k, v; data)
337 			if ((result = dg(k)) != 0)
338 				break;
339 		return result;
340 	}
341 }
342 
343 unittest
344 {
345 	HashSet!int s;
346 	assert(s.length == 0);
347 	assert(!(1 in s));
348 	assert(1 !in s);
349 	s.add(1);
350 	assert(1 in s);
351 	assert(s.length == 1);
352 	foreach (k; s)
353 		assert(k == 1);
354 	s.remove(1);
355 	assert(s.length == 0);
356 
357 	s.add(1);
358 	auto t = s.dup;
359 	s.add(2);
360 	assert(t.length==1);
361 	t.remove(1);
362 	assert(t.length==0);
363 }
364 
365 auto toSet(R)(R r)
366 {
367 	alias E = ElementType!R;
368 	return HashSet!E(r);
369 }
370 
371 unittest
372 {
373 	auto set = [1, 2, 3].toSet();
374 	assert(2 in set);
375 	assert(4 !in set);
376 }
377 
378 // ***************************************************************************
379 
380 /// An object which acts mostly as an associative array,
381 /// with the added property of being able to hold keys with
382 /// multiple values. These are only exposed explicitly and
383 /// through iteration
384 struct MultiAA(K, V)
385 {
386 	V[][K] items;
387 
388 	/// If multiple items with this name are present,
389 	/// only the first one is returned.
390 	ref inout(V) opIndex(K key) inout
391 	{
392 		return items[key][0];
393 	}
394 
395 	V opIndexAssign(V value, K key)
396 	{
397 		items[key] = [value];
398 		return value;
399 	}
400 
401 	inout(V)* opIn_r(K key) inout @nogc
402 	{
403 		auto pvalues = key in items;
404 		if (pvalues && (*pvalues).length)
405 			return &(*pvalues)[0];
406 		return null;
407 	}
408 
409 	void remove(K key)
410 	{
411 		items.remove(key);
412 	}
413 
414 	// D forces these to be "ref"
415 	int opApply(int delegate(ref K key, ref V value) dg)
416 	{
417 		int ret;
418 		outer:
419 		foreach (key, values; items)
420 			foreach (ref value; values)
421 			{
422 				ret = dg(key, value);
423 				if (ret)
424 					break outer;
425 			}
426 		return ret;
427 	}
428 
429 	// Copy-paste because of https://issues.dlang.org/show_bug.cgi?id=7543
430 	int opApply(int delegate(ref const(K) key, ref const(V) value) dg) const
431 	{
432 		int ret;
433 		outer:
434 		foreach (key, values; items)
435 			foreach (ref value; values)
436 			{
437 				ret = dg(key, value);
438 				if (ret)
439 					break outer;
440 			}
441 		return ret;
442 	}
443 
444 	void add(K key, V value)
445 	{
446 		if (key !in items)
447 			items[key] = [value];
448 		else
449 			items[key] ~= value;
450 	}
451 
452 	V get(K key, lazy V def) const
453 	{
454 		auto pvalue = key in this;
455 		return pvalue ? *pvalue : def;
456 	}
457 
458 	inout(V)[] getAll(K key) inout
459 	{
460 		inout(V)[] result;
461 		foreach (ref value; items.get(key, null))
462 			result ~= value;
463 		return result;
464 	}
465 
466 	this(typeof(null) Null)
467 	{
468 	}
469 
470 	this(V[K] aa)
471 	{
472 		foreach (ref key, ref value; aa)
473 			add(key, value);
474 	}
475 
476 	this(V[][K] aa)
477 	{
478 		foreach (ref key, values; aa)
479 			foreach (ref value; values)
480 				add(key, value);
481 	}
482 
483 	@property auto keys() inout { return items.keys; }
484 
485 	// https://issues.dlang.org/show_bug.cgi?id=14626
486 
487 	@property V[] values()
488 	{
489 		return items.byValue.join;
490 	}
491 
492 	@property const(V)[] values() const
493 	{
494 		return items.byValue.join;
495 	}
496 
497 	@property typeof(V[K].init.pairs) pairs()
498 	{
499 		alias Pair = typeof(V[K].init.pairs[0]);
500 		Pair[] result;
501 		result.reserve(length);
502 		foreach (ref k, ref v; this)
503 			result ~= Pair(k, v);
504 		return result;
505 	}
506 
507 	@property size_t length() const { return items.byValue.map!(item => item.length).sum(); }
508 
509 	auto byKey() { return items.byKey(); }
510 	auto byValue() { return items.byValue().joiner(); }
511 
512 	bool opCast(T)() inout
513 		if (is(T == bool))
514 	{
515 		return !!items;
516 	}
517 
518 	/// Warning: discards repeating items
519 	V[K] opCast(T)() const
520 		if (is(T == V[K]))
521 	{
522 		V[K] result;
523 		foreach (key, value; this)
524 			result[key] = value;
525 		return result;
526 	}
527 
528 	V[][K] opCast(T)() inout
529 		if (is(T == V[][K]))
530 	{
531 		V[][K] result;
532 		foreach (k, v; this)
533 			result[k] ~= v;
534 		return result;
535 	}
536 }
537 
538 unittest
539 {
540 	MultiAA!(string, string) aa;
541 }