1 // This file is part of Visual D 2 // 3 // Visual D integrates the D programming language into Visual Studio 4 // Copyright (c) 2010 by Rainer Schuetze, All Rights Reserved 5 // 6 // Distributed under the Boost Software License, Version 1.0. 7 // See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt 8 9 // simple double linked list 10 11 module c2d.dlist; 12 13 struct DListNode(T) 14 { 15 T data; 16 17 DListNode!(T)* _next; 18 DListNode!(T)* _prev; 19 } 20 21 class DList(T) 22 { 23 DListNode!(T) root; 24 25 this() 26 { 27 root._next = &root; 28 root._prev = &root; 29 } 30 31 bool empty() 32 { 33 return root._next == &root; 34 } 35 36 int count() 37 { 38 int cnt = 0; 39 for(auto p = root._next; p != &root; p = p._next) 40 cnt++; 41 return cnt; 42 } 43 44 void append(T item) 45 { 46 insertBefore(item, &root); 47 } 48 49 void prepend(T item) 50 { 51 insertAfter(item, &root); 52 } 53 54 DListNode!(T)* insertBefore(T data, DListNode!(T)* ins) 55 { 56 DListNode!(T) *node = new DListNode!(T); 57 node.data = data; 58 insertBefore(node, ins); 59 return node; 60 } 61 62 DListNode!(T)* insertAfter(T data, DListNode!(T)* ins) 63 { 64 DListNode!(T) *node = new DListNode!(T); 65 node.data = data; 66 insertAfter(node, ins); 67 return node; 68 } 69 70 void insertAfter(DListNode!(T)* node, DListNode!(T)* ins) 71 { 72 insertBefore(node, ins._next); 73 } 74 75 void insertBefore(DListNode!(T) *node, DListNode!(T)* ins) 76 { 77 node._next = ins; 78 node._prev = ins._prev; 79 ins._prev._next = node; 80 ins._prev = node; 81 } 82 83 void remove(DListNode!(T)* node) 84 { 85 node._prev._next = node._next; 86 node._next._prev = node._prev; 87 node._next = null; 88 node._prev = null; 89 } 90 91 // removes entries from list 92 void appendList(DList!(T) list) 93 { 94 insertListAfter(root._prev, list); 95 } 96 97 // removes entries from list 98 void insertListAfter(DListNode!(T)* node, DList!(T) list) 99 { 100 if(list.empty()) 101 return; 102 103 DListNode!(T)* first = list.root._next; 104 DListNode!(T)* last = list.root._prev; 105 106 // wipe the list 107 list.root._next = &list.root; 108 list.root._prev = &list.root; 109 110 node._next._prev = last; 111 last._next = node._next; 112 first._prev = node; 113 node._next = first; 114 } 115 116 // insert entries to list, return node to beginning of inserted list 117 DListNode!(T)* insertListBefore(DListNode!(T)* node, DList!(T) list) 118 { 119 if(node is &root) 120 { 121 insertListAfter(node._prev, list); 122 return &root; 123 } 124 else 125 { 126 DListNode!(T)* _prev = node._prev; 127 insertListAfter(node._prev, list); 128 return _prev._next; 129 } 130 } 131 132 void insertListAfter(ref DListIterator!(T) it, DList!(T) list) 133 { 134 assert(it._list is this); 135 insertListAfter(it._pos, list); 136 } 137 138 void insertListBefore(ref DListIterator!(T) it, DList!(T) list) 139 { 140 assert(it._list is this); 141 insertListBefore(it._pos, list); 142 } 143 144 DList!(T) remove(DListNode!(T)* from, DListNode!(T)* to) 145 { 146 DList!(T) list = new DList!(T); 147 if (from is to) 148 return list; 149 150 assert(from != &root); 151 152 DListNode!(T)* last = to._prev; 153 154 from._prev._next = to; 155 to._prev = from._prev; 156 157 list.root._next = from; 158 list.root._prev = last; 159 160 from._prev = &list.root; 161 last._next = &list.root; 162 163 return list; 164 } 165 166 DList!(T) remove(ref DListIterator!(T) from, ref DListIterator!(T) to) 167 { 168 DList!(T) list = remove(from._pos, to._pos); 169 from._pos = to._pos; 170 return list; 171 } 172 173 DListIterator!(T) find(T data) 174 { 175 DListIterator!(T) it = begin(); 176 while(!it.atEnd()) 177 { 178 if(*it == data) 179 break; 180 it.advance(); 181 } 182 return it; 183 } 184 185 DListIterator!(T) begin() 186 { 187 DListIterator!(T) it = DListIterator!(T)(this); 188 it._pos = root._next; 189 return it; 190 } 191 192 DListIterator!(T) end() 193 { 194 DListIterator!(T) it = DListIterator!(T)(this); 195 it._pos = &root; 196 return it; 197 } 198 199 ref T opIndex(int idx) 200 { 201 DListIterator!(T) it = begin(); 202 it += idx; 203 return *it; 204 } 205 } 206 207 struct DListIterator(T) 208 { 209 DListNode!(T)* _pos; 210 DList!(T) _list; 211 212 this(DList!(T) list) 213 { 214 _list = list; 215 } 216 217 bool valid() const 218 { 219 return _list !is null; 220 } 221 222 void setList(DList!(T) list) 223 { 224 _list = list; 225 } 226 227 DList!(T) getList() 228 { 229 return _list; 230 } 231 232 version(none) // opDot deprecated 233 { 234 alias opStar this; 235 236 // https://issues.dlang.org/show_bug.cgi?id=16657 need to define opEquals with alias this 237 bool opEquals(const typeof(this) other) const 238 { 239 return _pos == other._pos; // no need to compare lists, nodes belong to only one list 240 } 241 } 242 else version(all) // alias this too broken with operator overloads 243 { 244 ref auto opDispatch(string op, ARGS...)(auto ref ARGS args) if (ARGS.length == 0) 245 { 246 enum sym = "_pos.data." ~ op; 247 return mixin(sym); 248 } 249 auto opDispatch(string op, ARGS...)(auto ref ARGS args) if (ARGS.length == 1) // could be field = value 250 { 251 enum sym = "_pos.data." ~ op; 252 static if (__traits(compiles, mixin(sym) = args[0])) 253 return mixin(sym) = args[0]; 254 else 255 return mixin(sym)(args); 256 } 257 auto opDispatch(string op, ARGS...)(auto ref ARGS args) if (ARGS.length > 1) 258 { 259 enum sym = "_pos.data." ~ op; 260 return mixin(sym)(args); 261 } 262 } 263 else 264 { 265 ref T opDot() 266 { 267 return _pos.data; 268 } 269 } 270 271 ref T opUnary(string op)() if(op == "*") 272 { 273 return _pos.data; 274 } 275 276 void opUnary(string op)() if(op == "++") 277 { 278 advance(); 279 } 280 281 void opUnary(string op)() if(op == "--") 282 { 283 retreat(); 284 } 285 286 ref T opIndex(int idx) 287 { 288 DListIterator!(T) it = this; 289 it += idx; 290 return *it; 291 } 292 293 DListIterator!(T) opBinary(string op)(int cnt) if(op == "+") 294 { 295 DListIterator!(T) it = this; 296 it += cnt; 297 return it; 298 } 299 300 DListIterator!(T) opBinary(string op)(int cnt) if(op == "-") 301 { 302 DListIterator!(T) it = this; 303 it += -cnt; 304 return it; 305 } 306 307 void advance() 308 { 309 assert(_pos !is &_list.root); 310 _pos = _pos._next; 311 } 312 void retreat() 313 { 314 _pos = _pos._prev; 315 assert(_pos !is &_list.root); 316 } 317 318 bool atEnd() 319 { 320 return _pos is &_list.root; 321 } 322 bool atBegin() 323 { 324 return _pos is _list.root._next; 325 } 326 327 void opOpAssign(string op)(int cnt) if(op == "+") 328 { 329 while(cnt > 0) 330 { 331 advance(); 332 cnt--; 333 } 334 while(cnt < 0) 335 { 336 retreat(); 337 cnt++; 338 } 339 } 340 void opOpAssign(string op)(int cnt) if(op == "-") 341 { 342 opOpAssign!"+"(-cnt); 343 } 344 345 void insertAfter(T data) 346 { 347 _list.insertAfter(data, _pos); 348 } 349 void insertBefore(T data) 350 { 351 _list.insertBefore(data, _pos); 352 } 353 354 // insert entries to list, return iterator to beginning of inserted list 355 DListIterator!(T) insertListBefore(DList!(T) list) 356 { 357 DListNode!(T)* beg = _list.insertListBefore(_pos, list); 358 DListIterator!(T) begIt = DListIterator!(T)(_list); 359 begIt._pos = beg; 360 return begIt; 361 } 362 363 // moves iterator to _next entry 364 void erase() 365 { 366 assert(_pos !is &_list.root); 367 368 DListNode!(T)* pos = _pos; 369 advance(); 370 _list.remove(pos); 371 } 372 373 DList!(T) eraseUntil(DListIterator!(T) end) 374 { 375 assert(_pos !is &_list.root); 376 assert(_list is end._list); 377 378 DListNode!(T)* pos = _pos; 379 _pos = end._pos; 380 return _list.remove(pos, _pos); 381 } 382 } 383 384 unittest 385 { 386 DList!(int) list = new DList!(int); 387 388 list.append(1); 389 list.append(2); 390 list.prepend(0); 391 list.append(3); 392 393 DListIterator!(int) it = list.begin(); 394 assert(*it == 0); 395 assert(it[2] == 2); 396 it.advance(); 397 assert(*it == 1); 398 it.advance(); 399 assert(*it == 2); 400 it.advance(); 401 assert(*it == 3); 402 assert(it[-1] == 2); 403 ++it; 404 assert(it == list.end()); 405 --it; 406 it.retreat(); 407 assert(*it == 2); 408 it.erase(); 409 assert(*it == 3); 410 --it; 411 assert(*it == 1); 412 } 413 414 unittest 415 { 416 DList!(int) list = new DList!(int); 417 418 list.append(1); 419 list.append(2); 420 list.prepend(0); 421 list.append(3); 422 423 DListIterator!(int) it1 = list.begin(); 424 it1 += 1; 425 DListIterator!(int) it2 = it1; 426 it2 += 2; 427 428 DList!(int) slice = list.remove(it1, it2); 429 assert(*it1 == 3); 430 --it1; 431 assert(*it1 == 0); 432 433 assert(*slice.begin() == 1); 434 DListIterator!(int) it3 = slice.end(); 435 --it3; 436 assert(*it3 == 2); 437 --it3; 438 assert(*it3 == 1); 439 440 }