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