1 module reggae.ctaa;
2 
3 import std.traits;
4 
5 /**
6 An implementation of an associative array useable at compile-time.
7 Shameless copy of association lists from Lisp.
8  */
9 
10 
11 @safe:
12 
13 
14 struct AssocList(K, V) {
15     import std.algorithm: find, canFind;
16     import std.array: empty, front;
17 
18     AssocEntry!(K, V)[] entries;
19 
20     const(V) opIndex(in K key) pure const nothrow {
21         auto res = entries.find!(a => a.key == key);
22         assert(!res.empty, "AssocList does not contain key " ~ key);
23         return res.front.value;
24     }
25 
26     void opIndexAssign(V value, K key) {
27         entries ~= AssocEntry!(K, V)(key, value);
28     }
29 
30     T get(T)(in K key, T defaultValue) pure const {
31         import std.conv: to;
32         auto res = entries.find!(a => a.key == key);
33         return res.empty ? defaultValue : res.front.value.to!T;
34     }
35 
36     const(K)[] keys() pure const nothrow {
37         import std.algorithm: map;
38         import std.array: array;
39         return entries.map!(a => a.key).array;
40     }
41 
42     bool opBinaryRight(string op)(in K key) pure const if(op == "in") {
43         return entries.canFind!(a => a.key == key);
44     }
45 
46     V[K] toAA() {
47         V[K] ret;
48         foreach(entry; entries) {
49             ret[entry.key] = entry.value;
50         }
51         return ret;
52     }
53 
54     string toString() const pure @safe {
55         import std.conv;
56         import std.algorithm;
57         import std.range;
58         return `{` ~ entries.map!(a => text(a.key, ": ", a.value)).join(", ") ~ `}`;
59     }
60 }
61 
62 AssocList!(K, V) fromAA(K, V)(V[K] aa) {
63     AssocEntry!(K, V)[] entries;
64     foreach(k, v; aa) entries ~= assocEntry(k, v);
65     return AssocList!(K, V)(entries);
66 }
67 
68 struct AssocEntry(K, V) {
69     K key;
70     V value;
71 }
72 
73 
74 AssocEntry!(K, V) assocEntry(K, V)(K key, V value) {
75     return AssocEntry!(K, V)(key, value);
76 }
77 
78 AssocList!(K, V) assocList(K, V)(AssocEntry!(K, V)[] entries = []) {
79     return AssocList!(K, V)(entries);
80 }
81 
82 auto assocListT(T...)(T args) if(T.length % 2 == 0 && T.length > 0) {
83     alias K = T[0];
84     alias V = T[1];
85     AssocEntry!(K, V)[] entries;
86     foreach(i, elt; args) {
87         static if(i % 2 == 0) entries ~= assocEntry(args[i], args[i+1]);
88     }
89     return AssocList!(K, V)(entries);
90 }