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 }