1 module evael.lib.containers.dictionary; 2 3 import evael.lib.memory; 4 import evael.lib.containers.array; 5 6 struct KeyValueNode(K, V) 7 { 8 public K key; 9 public V value; 10 11 private KeyValueNode* next; 12 13 @nogc 14 public this(K key, V value, KeyValueNode* next) 15 { 16 this.key = key; 17 this.value = value; 18 this.next = next; 19 } 20 } 21 22 struct Dictionary(K, V) 23 { 24 alias Node = KeyValueNode!(K, V); 25 26 private Array!(Node*) m_buckets; 27 28 /** 29 * Dictionary constructor. 30 * Params: 31 * capacity : bucket capacity 32 */ 33 @nogc 34 public this(in size_t capacity) 35 { 36 this.m_buckets = Array!(Node*)(capacity, null); 37 } 38 39 /** 40 * Dictionary destructor. 41 */ 42 @nogc 43 public void dispose() 44 { 45 foreach (Node* node; this.m_buckets) 46 { 47 Node* currentNode = node; 48 while (currentNode !is null) 49 { 50 Node* prevNode = currentNode; 51 currentNode = currentNode.next; 52 MemoryHelper.dispose(prevNode); 53 } 54 } 55 56 this.m_buckets.dispose(); 57 } 58 59 /** 60 * Inserts a key and his value. 61 * Params: 62 * key : key 63 * value : value 64 */ 65 @nogc 66 public void insert(K key, V value) 67 { 68 immutable hash = this.getHash(key); 69 70 Node* node = this.m_buckets[hash]; 71 72 if (node is null) 73 { 74 this.m_buckets[hash] = MemoryHelper.create!Node(key, value, null); 75 } 76 else 77 { 78 // We search for the same key and replace his value 79 while (node !is null) 80 { 81 if (node.key == key) 82 { 83 node.value = value; 84 return; 85 } 86 node = node.next; 87 } 88 89 node.next = MemoryHelper.create!Node(key, value, null); 90 } 91 } 92 93 /** 94 * Returns value of key. 95 * Params: 96 * key : key 97 * notFoundValue : value to return if key has not been found 98 */ 99 @nogc 100 public V get(K key, V notFoundValue = V.init) 101 { 102 immutable hash = this.getHash(key); 103 104 Node* currentNode = this.m_buckets[hash]; 105 106 while (currentNode !is null) 107 { 108 if (currentNode.key == key) 109 { 110 return currentNode.value; 111 } 112 currentNode = currentNode.next; 113 } 114 115 return notFoundValue; 116 } 117 118 /** 119 * Removes a key and his value from the dictionary. 120 * Params: 121 * key : key 122 */ 123 @nogc 124 public bool remove(K key) 125 { 126 immutable hash = this.getHash(key); 127 128 Node* prevNode = null; 129 Node* currentNode = this.m_buckets[hash]; 130 131 while (currentNode !is null && currentNode.key != key) 132 { 133 prevNode = currentNode; 134 currentNode = currentNode.next; 135 } 136 137 if (currentNode is null) 138 { 139 return false; 140 } 141 142 if (prevNode is null) 143 { 144 this.m_buckets[hash] = currentNode.next; 145 } 146 else 147 { 148 prevNode.next = currentNode.next; 149 } 150 151 MemoryHelper.dispose(currentNode); 152 153 return true; 154 } 155 156 /** 157 * Index assignment support. 158 */ 159 pragma(inline, true) 160 @nogc 161 public void opIndexAssign(V value, K key) 162 { 163 this.insert(key, value); 164 } 165 166 @nogc 167 private size_t getHash(K)(K key) if(is(K == int)) 168 { 169 return key % this.m_buckets.length; 170 } 171 172 @nogc 173 private size_t getHash(K)(K key) if(is(K == string)) 174 { 175 int hash = 7; 176 foreach (c; key) 177 { 178 hash = hash * 31 + c; 179 } 180 181 return hash % this.m_buckets.length; 182 } 183 }