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        Workaround for weird CTFE bug
21      */
22     private bool _isEmpty;
23 
24     this(AssocEntry!(K, V)[] entries) pure {
25         this.entries = entries;
26         _isEmpty = entries.empty;
27     }
28 
29     const(V) opIndex(in K key) pure const nothrow {
30         auto res = entries.find!(a => a.key == key);
31         assert(!res.empty, "AssocList does not contain key " ~ key);
32         return res.front.value;
33     }
34 
35     void opIndexAssign(V value, K key) {
36         entries ~= AssocEntry!(K, V)(key, value);
37     }
38 
39     T get(T)(in K key, T defaultValue) pure const {
40         import std.conv: to;
41         // workaround for a bug
42         if(__ctfe && _isEmpty) return defaultValue;
43         auto res = entries.find!(a => a.key == key);
44         return res.empty ? defaultValue : res.front.value.to!T;
45     }
46 
47     const(K)[] keys() pure const nothrow {
48         import std.algorithm: map;
49         import std.array: array;
50         return entries.map!(a => a.key).array;
51     }
52 
53     bool opBinaryRight(string op)(in K key) pure const if(op == "in") {
54         return entries.canFind!(a => a.key == key);
55     }
56 
57     V[K] toAA() {
58         V[K] ret;
59         foreach(entry; entries) {
60             ret[entry.key] = entry.value;
61         }
62         return ret;
63     }
64 
65     string toString() const pure @safe {
66         import std.conv;
67         import std.algorithm;
68         import std.range;
69         return `{` ~ entries.map!(a => text(a.key, ": ", a.value)).join(", ") ~ `}`;
70     }
71 }
72 
73 AssocList!(K, V) fromAA(K, V)(V[K] aa) {
74     AssocEntry!(K, V)[] entries;
75     foreach(k, v; aa) entries ~= assocEntry(k, v);
76     return AssocList!(K, V)(entries);
77 }
78 
79 struct AssocEntry(K, V) {
80     K key;
81     V value;
82 }
83 
84 
85 AssocEntry!(K, V) assocEntry(K, V)(K key, V value) {
86     return AssocEntry!(K, V)(key, value);
87 }
88 
89 AssocList!(K, V) assocList(K, V)(AssocEntry!(K, V)[] entries = []) {
90     return AssocList!(K, V)(entries);
91 }
92 
93 auto assocListT(T...)(T args) if(T.length % 2 == 0 && T.length > 0) {
94     alias K = T[0];
95     alias V = T[1];
96     AssocEntry!(K, V)[] entries;
97     foreach(i, elt; args) {
98         static if(i % 2 == 0) entries ~= assocEntry(args[i], args[i+1]);
99     }
100     return AssocList!(K, V)(entries);
101 }