1 module prova.util.linkedlist; 2 3 import std.typecons; 4 import std.exception; 5 6 /** 7 * Linked list node 8 */ 9 class Node(T) 10 { 11 private LinkedList!T list; 12 private Node!T next; 13 private Node!T last; 14 private Nullable!T _value; 15 16 private this(LinkedList!T list, T value) { 17 this.list = list; 18 this.value = value; 19 } 20 21 /** 22 * Retrieves the stored value 23 */ 24 @property T value() 25 { 26 return _value; 27 } 28 29 /** 30 * Modifies the stored value 31 */ 32 @property void value(T value) 33 { 34 _value = value; 35 } 36 37 /** 38 * Gets the node previous in order 39 */ 40 Node!T getLast() 41 { 42 return last; 43 } 44 45 /** 46 * Gets the node next in order 47 */ 48 Node!T getNext() 49 { 50 return next; 51 } 52 53 /** 54 * Detaches the node from the list 55 */ 56 void remove() 57 { 58 if(last) 59 last.next = next; 60 61 if(next) 62 next.last = last; 63 64 if(list.last == this) 65 list.last = null; 66 67 if(list.first == this) 68 list.first = null; 69 70 list.count--; 71 } 72 } 73 74 /** 75 * LinkedList template 76 */ 77 class LinkedList(T) 78 { 79 private Node!T first; 80 private Node!T last; 81 private int count = 0; 82 83 /** 84 * Returns the node count 85 */ 86 @property int length() 87 { 88 return count; 89 } 90 91 /// 92 Node!T getFirstNode() 93 { 94 return first; 95 } 96 97 /// 98 Node!T getLastNode() 99 { 100 return last; 101 } 102 103 /** 104 * Creates a node and places it at the start of the list 105 */ 106 Node!T insertFront(T value) 107 { 108 auto node = new Node!T(this, value); 109 110 if(first) { 111 first.last = node; 112 node.next = first; 113 first = node; 114 } else { 115 first = last = node; 116 } 117 118 return node; 119 } 120 121 /** 122 * Creates a node and places it at the end of the list 123 */ 124 Node!T insertBack(T value) 125 { 126 auto node = new Node!T(this, value); 127 128 if(last) { 129 last.next = node; 130 node.last = last; 131 last = node; 132 } else { 133 first = last = node; 134 } 135 136 return node; 137 } 138 139 /** 140 * Creates a node in the list placed before the reference node 141 */ 142 Node!T insertBefore(T value, Node!T referenceNode) 143 { 144 if(!referenceNode) 145 return insertFront(value); 146 147 auto node = new Node!T(this, value); 148 149 assert(referenceNode.list == this, "Reference node should belong to this list"); 150 151 node.next = referenceNode; 152 node.last = referenceNode.last; 153 154 if(referenceNode.last) 155 referenceNode.last.next = node; 156 157 referenceNode.last = node; 158 159 count++; 160 return node; 161 } 162 163 /** 164 * Creates a node in the list placed after the reference node 165 */ 166 Node!T insertAfter(T value, Node!T referenceNode) 167 { 168 if(!referenceNode) 169 return insertBack(value); 170 171 assert(referenceNode.list == this, "Reference node should belong to this list"); 172 173 auto node = new Node!T(this, value); 174 175 node.last = referenceNode; 176 node.next = referenceNode.next; 177 178 if(referenceNode.next) 179 referenceNode.next.last = node; 180 181 referenceNode.next = node; 182 183 count++; 184 return node; 185 } 186 187 /** 188 * Tests if the list contains a node with the specified value 189 */ 190 bool contains(T value) 191 { 192 foreach(Node!T node; this) 193 if(node.value == value) 194 return true; 195 196 return false; 197 } 198 199 /** 200 * Removes the first node with the specified value 201 */ 202 void remove(T value) 203 { 204 foreach(Node!T node; this) { 205 if(node.value == value) { 206 node.remove(); 207 break; 208 } 209 } 210 } 211 212 /** 213 * Empties the LinkedList 214 */ 215 void clear() 216 { 217 first = null; 218 last = null; 219 count = 0; 220 } 221 222 /// 223 T[] toArray() 224 { 225 T[] array; 226 array.reserve(length); 227 228 foreach(T value; this) { 229 array ~= value; 230 } 231 232 return array; 233 } 234 235 /// 236 LinkedListRange!T toRange() 237 { 238 return LinkedListRange!T(this); 239 } 240 241 /// 242 int opApply(int delegate(Node!T result) dg) 243 { 244 int result = 0; 245 246 for(Node!T node = first; node; node = node.next) { 247 result = dg(node); 248 249 if(result) 250 break; 251 } 252 253 return result; 254 } 255 256 /// 257 int opApply(int delegate(ref T result) dg) 258 { 259 int result = 0; 260 261 for(Node!T node = first; node; node = node.next) { 262 T value = node.value; 263 result = dg(value); 264 node.value = value; 265 266 if(result) 267 break; 268 } 269 270 return result; 271 } 272 } 273 274 /// 275 struct LinkedListRange(T) 276 { 277 Node!T node; 278 279 private this(LinkedList!T list) 280 { 281 this.node = list.getFirstNode(); 282 } 283 284 /// 285 T front() 286 { 287 return node.value; 288 } 289 290 /// 291 void popFront() 292 { 293 node = node.getNext(); 294 } 295 296 /// 297 bool empty() 298 { 299 return node is null; 300 } 301 }