1 module kontainer.orderedAssocArray.orderedAssocArray; 2 3 /** 4 * The associative array that an order was guaranteed. 5 * 6 * Why this library was necessary: 7 * D's Associative Array has a (critical) trouble: 8 * int[string] foo = [ 9 * "abc" : 123, 10 * "k" : 3874, 11 * "abcdef" : 0]; 12 * foreach (key, value; foo) { 13 * writeln("[key : value] - ", [key : value]); 14 * } 15 * Then, We(at least I) expect naturally, the above codes will output as: 16 * [key : value] - ["abc":123] 17 * [key : value] - ["k":3874] 18 * [key : value] - ["abcdef":0] 19 * However, the above codes prints: 20 * [key : value] - ["abc":123] 21 * [key : value] - ["abcdef":0] 22 * [key : value] - ["k":3874] 23 * 24 * The result means that D's Associative Array doesn't guarantee to keep the order(insert order). 25 * This container guarantee to keep the order. 26 * 27 * 28 * Simple Usage: 29 * import kontainer.orderedAssocArray; 30 * 31 * void main() { 32 * OrderedAssocArray!(string, int) oaa = new OrderedAssocArray!(string, int); 33 * oaa["abc"] = 123; 34 * oaa["k"] = 3874; 35 * oaa["abcdef"] = 0; 36 * 37 * foreach (pair; oaa) { 38 * // Access key and value with each of it as property. 39 * writeln(pair.key, " - ", pair.value); 40 * } 41 * 42 * // You can modify like D's associative array 43 * oaa["abc"] = 321; 44 * oaa["k"] = 4783; 45 * oaa["abcdef"] = 999; 46 * 47 * // Free the pointer of keys 48 * oaa.free; 49 * } 50 */ 51 52 import std.string, 53 std.conv; 54 import core.memory; 55 import kontainer.linkedlist; 56 57 struct Pair(KeyType, ValueType) { 58 KeyType key; 59 ValueType value; 60 } 61 62 class OrderedAssocArray(KeyType, ValueType) { 63 LinkedList!(KeyType*) _keys; 64 private ValueType[KeyType] assoc; 65 66 this() {} 67 68 this(ValueType[KeyType] asc) { 69 foreach (key, value; asc) { 70 this.add(key, value); 71 } 72 } 73 74 this(typeof(this) at) { 75 foreach (pair; at) { 76 this.add(pair); 77 } 78 } 79 80 void free() { 81 foreach (node; this._keys) { 82 GC.free(node.value); 83 } 84 } 85 86 void add(Pair!(KeyType, ValueType) pair) { 87 this.add(pair.key, pair.value); 88 } 89 90 void add(KeyType key, ValueType value) { 91 KeyType* _key; 92 93 if (key !in this.assoc) { 94 _key = cast(KeyType*)GC.malloc(key.sizeof, GC.BlkAttr.NO_SCAN); 95 *_key = key; 96 this._keys.append(_key); 97 } 98 99 this.assoc[key] = value; 100 } 101 102 @property typeof(this) save() { 103 return new typeof(this)(this); 104 } 105 106 bool contains(KeyType key) { 107 return (key in this.assoc) ? true : false; 108 } 109 110 @property KeyType[] keys() { 111 KeyType[] ar; 112 113 foreach (node; _keys) { 114 ar ~= *node.value; 115 } 116 117 return ar; 118 } 119 120 @property ValueType[] values() { 121 ValueType[] ar; 122 123 foreach (node; _keys) { 124 ar ~= this[*node.value]; 125 } 126 127 return ar; 128 } 129 130 /* Assign Operator Overloadings */ 131 ValueType opIndex(KeyType key) { 132 if (key in this.assoc) { 133 return this.assoc[key]; 134 } else { 135 import std.conv : to; 136 if (cast(ValueType)null) { 137 return null; 138 } else { 139 throw new Error("Nu such a key : " ~ key.to!string); 140 } 141 } 142 } 143 144 typeof(this) opBinary(string s)(typeof(this) that) if (s == "~") { 145 typeof(this) newThis = new typeof(this)(this); 146 147 foreach (pair; that) { 148 newThis.add(pair); 149 } 150 151 return newThis; 152 } 153 154 void opIndexAssign(ValueType value, KeyType key) { 155 this.add(key, value); 156 } 157 158 @property size_t length() { 159 return this._keys.length; 160 } 161 162 @property bool empty() { 163 return this._keys.empty; 164 } 165 166 @property Pair!(KeyType, ValueType) front() { 167 KeyType key = *(this._keys.front.value); 168 return Pair!(KeyType, ValueType)(key, this.assoc[key]); 169 } 170 171 @property void popFront() { 172 this._keys.popFront; 173 } 174 175 @property override string toString() { 176 string[] strs; 177 178 foreach (elem; this) { 179 strs ~= elem.key.to!string ~ ":" ~ elem.value.to!string; 180 } 181 182 return "[" ~ strs.join(", ") ~ "]"; 183 } 184 }