1 /******************************************************************************* 2 3 copyright: Copyright (c) 2008 Kris Bell. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Apr 2008: Initial release 8 9 authors: Kris 10 11 Since: 0.99.7 12 13 Based upon Doug Lea's Java collection package 14 15 *******************************************************************************/ 16 17 module tango.util.container.LinkedList; 18 19 private import tango.util.container.Slink; 20 21 public import tango.util.container.Container; 22 23 private import tango.util.container.model.IContainer; 24 25 /******************************************************************************* 26 27 List of singly-linked values 28 29 --- 30 Iterator iterator () 31 int opApply (scope int delegate(ref V value) dg) 32 33 V head () 34 V tail () 35 V head (V value) 36 V tail (V value) 37 V removeHead () 38 V removeTail () 39 40 bool contains (V value) 41 size_t first (V value, size_t startingIndex = 0) 42 size_t last (V value, size_t startingIndex = 0) 43 44 LinkedList add (V value) 45 LinkedList prepend (V value) 46 size_t prepend (IContainer!(V) e) 47 LinkedList append (V value) 48 size_t append (IContainer!(V) e) 49 LinkedList addAt (size_t index, V value) 50 size_t addAt (size_t index, IContainer!(V) e) 51 52 V get (size_t index) 53 bool take (ref V v) 54 size_t remove (V value, bool all) 55 bool removeAt (size_t index) 56 size_t removeRange (size_t fromIndex, size_t toIndex) 57 size_t replace (V oldElement, V newElement, bool all) 58 bool replaceAt (size_t index, V value) 59 60 LinkedList clear () 61 LinkedList reset () 62 63 LinkedList subset (size_t from, size_t length = size_t.max) 64 LinkedList dup () 65 66 size_t size () 67 bool isEmpty () 68 V[] toArray (V[] dst) 69 LinkedList sort (Compare!(V) cmp) 70 LinkedList check () 71 --- 72 73 *******************************************************************************/ 74 75 class LinkedList (V, alias Reap = Container.reap, 76 alias Heap = Container.DefaultCollect) 77 : IContainer!(V) 78 { 79 // use this type for Allocator configuration 80 private alias Slink!(V) Type; 81 82 private alias Type* Ref; 83 private alias V* VRef; 84 85 private alias Heap!(Type) Alloc; 86 87 // number of elements contained 88 private size_t count; 89 90 // configured heap manager 91 private Alloc heap; 92 93 // mutation tag updates on each change 94 private size_t mutation; 95 96 // head of the list. Null if empty 97 private Ref list; 98 99 /*********************************************************************** 100 101 Create a new empty list 102 103 ***********************************************************************/ 104 105 this () 106 { 107 this (null, 0); 108 } 109 110 /*********************************************************************** 111 112 Special version of constructor needed by dup 113 114 ***********************************************************************/ 115 116 protected this (Ref l, size_t c) 117 { 118 list = l; 119 count = c; 120 } 121 122 /*********************************************************************** 123 124 Clean up when deleted 125 126 ***********************************************************************/ 127 128 ~this () 129 { 130 reset; 131 } 132 133 /*********************************************************************** 134 135 Return a generic iterator for contained elements 136 137 ***********************************************************************/ 138 139 final Iterator iterator () 140 { 141 Iterator i = void; 142 i.mutation = mutation; 143 i.node = list ? *(i.hook = &list) : null; 144 i.prior = null; 145 i.owner = this; 146 return i; 147 } 148 149 /*********************************************************************** 150 151 Configure the assigned allocator with the size of each 152 allocation block (number of nodes allocated at one time) 153 and the number of nodes to pre-populate the cache with. 154 155 Time complexity: O(n) 156 157 ***********************************************************************/ 158 159 final LinkedList cache (size_t chunk, size_t count=0) 160 { 161 heap.config (chunk, count); 162 return this; 163 } 164 165 /*********************************************************************** 166 167 168 ***********************************************************************/ 169 170 final int opApply (scope int delegate(ref V value) dg) 171 { 172 return iterator.opApply (dg); 173 } 174 175 /*********************************************************************** 176 177 Return the number of elements contained 178 179 ***********************************************************************/ 180 181 @property final const size_t size () 182 { 183 return count; 184 } 185 186 /*********************************************************************** 187 188 Build an independent copy of the list. 189 The elements themselves are not cloned 190 191 ***********************************************************************/ 192 193 @property final LinkedList dup () 194 { 195 return new LinkedList!(V, Reap, Heap) (list ? list.copy(&heap.allocate) : null, count); 196 } 197 198 /*********************************************************************** 199 200 Time complexity: O(n) 201 202 ***********************************************************************/ 203 204 final bool contains (V value) 205 { 206 if (count is 0) 207 return false; 208 209 return list.find(value) !is null; 210 } 211 212 /*********************************************************************** 213 214 Time complexity: O(1) 215 216 ***********************************************************************/ 217 218 final V head () 219 { 220 return firstCell.value; 221 } 222 223 /*********************************************************************** 224 225 Time complexity: O(n) 226 227 ***********************************************************************/ 228 229 final V tail () 230 { 231 return lastCell.value; 232 } 233 234 /*********************************************************************** 235 236 Time complexity: O(n) 237 238 ***********************************************************************/ 239 240 final V get (size_t index) 241 { 242 return cellAt(index).value; 243 } 244 245 /*********************************************************************** 246 247 Time complexity: O(n) 248 Returns size_t.max if no element found. 249 250 ***********************************************************************/ 251 252 final size_t first (V value, size_t startingIndex = 0) 253 { 254 if (list is null || startingIndex >= count) 255 return size_t.max; 256 257 if (startingIndex < 0) 258 startingIndex = 0; 259 260 auto p = list.nth (startingIndex); 261 if (p) 262 { 263 auto i = p.index (value); 264 if (i >= 0) 265 return i + startingIndex; 266 } 267 return size_t.max; 268 } 269 270 /*********************************************************************** 271 272 Time complexity: O(n) 273 Returns size_t.max if no element found. 274 275 ***********************************************************************/ 276 277 final size_t last (V value, size_t startingIndex = 0) 278 { 279 if (list is null) 280 return size_t.max; 281 282 auto i = 0; 283 if (startingIndex >= count) 284 startingIndex = count - 1; 285 286 auto index = size_t.max; 287 auto p = list; 288 while (i <= startingIndex && p) 289 { 290 if (p.value == value) 291 index = i; 292 ++i; 293 p = p.next; 294 } 295 return index; 296 } 297 298 /*********************************************************************** 299 300 Time complexity: O(length) 301 302 ***********************************************************************/ 303 304 final LinkedList subset (size_t from, size_t length = size_t.max) 305 { 306 Ref newlist = null; 307 308 if (length > 0) 309 { 310 auto p = cellAt (from); 311 auto current = newlist = heap.allocate.set (p.value, null); 312 313 for (auto i = 1; i < length; ++i) 314 if ((p = p.next) is null) 315 length = i; 316 else 317 { 318 current.attach (heap.allocate.set (p.value, null)); 319 current = current.next; 320 } 321 } 322 323 return new LinkedList (newlist, length); 324 } 325 326 /*********************************************************************** 327 328 Time complexity: O(n) 329 330 ***********************************************************************/ 331 332 final LinkedList clear () 333 { 334 return clear (false); 335 } 336 337 /*********************************************************************** 338 339 Reset the HashMap contents and optionally configure a new 340 heap manager. We cannot guarantee to clean up reconfigured 341 allocators, so be sure to invoke reset() before discarding 342 this class 343 344 Time complexity: O(n) 345 346 ***********************************************************************/ 347 348 final LinkedList reset () 349 { 350 return clear (true); 351 } 352 353 /*********************************************************************** 354 355 Takes the first value on the list 356 357 Time complexity: O(1) 358 359 ***********************************************************************/ 360 361 final bool take (ref V v) 362 { 363 if (count) 364 { 365 v = head; 366 removeHead; 367 return true; 368 } 369 return false; 370 } 371 372 /*********************************************************************** 373 374 Uses a merge-sort-based algorithm. 375 376 Time complexity: O(n log n) 377 378 ***********************************************************************/ 379 380 final LinkedList sort (Compare!(V) cmp) 381 { 382 if (list) 383 { 384 list = Ref.sort (list, cmp); 385 mutate; 386 } 387 return this; 388 } 389 390 /*********************************************************************** 391 392 Time complexity: O(1) 393 394 ***********************************************************************/ 395 396 final LinkedList add (V value) 397 { 398 return prepend (value); 399 } 400 401 /*********************************************************************** 402 403 Time complexity: O(1) 404 405 ***********************************************************************/ 406 407 final LinkedList prepend (V value) 408 { 409 list = heap.allocate.set (value, list); 410 increment; 411 return this; 412 } 413 414 /*********************************************************************** 415 416 Time complexity: O(n) 417 418 ***********************************************************************/ 419 420 final size_t remove (V value, bool all = false) 421 { 422 auto c = count; 423 if (c) 424 { 425 auto p = list; 426 auto trail = p; 427 428 while (p) 429 { 430 auto n = p.next; 431 if (p.value == value) 432 { 433 decrement (p); 434 if (p is list) 435 { 436 list = n; 437 trail = n; 438 } 439 else 440 trail.next = n; 441 442 if (!all || count is 0) 443 break; 444 else 445 p = n; 446 } 447 else 448 { 449 trail = p; 450 p = n; 451 } 452 } 453 } 454 return c - count; 455 } 456 457 /*********************************************************************** 458 459 Time complexity: O(n) 460 461 ***********************************************************************/ 462 463 final size_t replace (V oldElement, V newElement, bool all = false) 464 { 465 size_t c; 466 if (count && oldElement != newElement) 467 { 468 auto p = list.find (oldElement); 469 while (p) 470 { 471 ++c; 472 mutate; 473 p.value = newElement; 474 if (!all) 475 break; 476 p = p.find (oldElement); 477 } 478 } 479 return c; 480 } 481 482 /*********************************************************************** 483 484 Time complexity: O(1) 485 486 ***********************************************************************/ 487 488 final V head (V value) 489 { 490 auto cell = firstCell; 491 auto v = cell.value; 492 cell.value = value; 493 mutate; 494 return v; 495 } 496 497 /*********************************************************************** 498 499 Time complexity: O(1) 500 501 ***********************************************************************/ 502 503 final V removeHead () 504 { 505 auto p = firstCell; 506 auto v = p.value; 507 list = p.next; 508 decrement (p); 509 return v; 510 } 511 512 /*********************************************************************** 513 514 Time complexity: O(n) 515 516 ***********************************************************************/ 517 518 final LinkedList append (V value) 519 { 520 if (list is null) 521 prepend (value); 522 else 523 { 524 list.tail.next = heap.allocate.set (value, null); 525 increment; 526 } 527 return this; 528 } 529 530 /*********************************************************************** 531 532 Time complexity: O(n) 533 534 ***********************************************************************/ 535 536 final V tail (V value) 537 { 538 auto p = lastCell; 539 auto v = p.value; 540 p.value = value; 541 mutate; 542 return v; 543 } 544 545 /*********************************************************************** 546 547 Time complexity: O(n) 548 549 ***********************************************************************/ 550 551 final V removeTail () 552 { 553 if (firstCell.next is null) 554 return removeHead; 555 556 auto trail = list; 557 auto p = trail.next; 558 559 while (p.next) 560 { 561 trail = p; 562 p = p.next; 563 } 564 trail.next = null; 565 auto v = p.value; 566 decrement (p); 567 return v; 568 } 569 570 /*********************************************************************** 571 572 Time complexity: O(n) 573 574 ***********************************************************************/ 575 576 final LinkedList addAt (size_t index, V value) 577 { 578 if (index is 0) 579 prepend (value); 580 else 581 { 582 cellAt(index - 1).attach (heap.allocate.set(value, null)); 583 increment; 584 } 585 return this; 586 } 587 588 /*********************************************************************** 589 590 Time complexity: O(n) 591 592 ***********************************************************************/ 593 594 final LinkedList removeAt (size_t index) 595 { 596 if (index is 0) 597 removeHead; 598 else 599 { 600 auto p = cellAt (index - 1); 601 auto t = p.next; 602 p.detachNext; 603 decrement (t); 604 } 605 return this; 606 } 607 608 /*********************************************************************** 609 610 Time complexity: O(n) 611 612 ***********************************************************************/ 613 614 final LinkedList replaceAt (size_t index, V value) 615 { 616 cellAt(index).value = value; 617 mutate; 618 return this; 619 } 620 621 /*********************************************************************** 622 623 Time complexity: O(number of elements in e) 624 625 ***********************************************************************/ 626 627 final size_t prepend (IContainer!(V) e) 628 { 629 auto c = count; 630 splice_ (e, null, list); 631 return count - c; 632 } 633 634 /*********************************************************************** 635 636 Time complexity: O(n + number of elements in e) 637 638 ***********************************************************************/ 639 640 final size_t append (IContainer!(V) e) 641 { 642 auto c = count; 643 if (list is null) 644 splice_ (e, null, null); 645 else 646 splice_ (e, list.tail, null); 647 return count - c; 648 } 649 650 /*********************************************************************** 651 652 Time complexity: O(n + number of elements in e) 653 654 ***********************************************************************/ 655 656 final size_t addAt (size_t index, IContainer!(V) e) 657 { 658 auto c = count; 659 if (index is 0) 660 splice_ (e, null, list); 661 else 662 { 663 auto p = cellAt (index - 1); 664 splice_ (e, p, p.next); 665 } 666 return count - c; 667 } 668 669 /*********************************************************************** 670 671 Time complexity: O(n) 672 673 ***********************************************************************/ 674 675 final size_t removeRange (size_t fromIndex, size_t toIndex) 676 { 677 auto c = count; 678 if (fromIndex <= toIndex) 679 { 680 if (fromIndex is 0) 681 { 682 auto p = firstCell; 683 for (size_t i = fromIndex; i <= toIndex; ++i) 684 p = p.next; 685 list = p; 686 } 687 else 688 { 689 auto f = cellAt (fromIndex - 1); 690 auto p = f; 691 for (size_t i = fromIndex; i <= toIndex; ++i) 692 p = p.next; 693 f.next = p.next; 694 } 695 696 count -= (toIndex - fromIndex + 1); 697 mutate; 698 } 699 return c - count; 700 } 701 702 /*********************************************************************** 703 704 Copy and return the contained set of values in an array, 705 using the optional dst as a recipient (which is resized 706 as necessary). 707 708 Returns a slice of dst representing the container values. 709 710 Time complexity: O(n) 711 712 ***********************************************************************/ 713 714 final V[] toArray (V[] dst = null) 715 { 716 if (dst.length < count) 717 dst.length = count; 718 719 size_t i = 0; 720 foreach (v; this) 721 dst[i++] = v; 722 return dst [0 .. count]; 723 } 724 725 /*********************************************************************** 726 727 Is this container empty? 728 729 Time complexity: O(1) 730 731 ***********************************************************************/ 732 733 final const bool isEmpty () 734 { 735 return count is 0; 736 } 737 738 /*********************************************************************** 739 740 ***********************************************************************/ 741 742 final LinkedList check () 743 { 744 assert(((count is 0) is (list is null))); 745 assert((list is null || list.count is size)); 746 747 size_t c = 0; 748 for (Ref p = list; p; p = p.next) 749 { 750 assert(instances(p.value) > 0); 751 assert(contains(p.value)); 752 ++c; 753 } 754 assert(c is count); 755 return this; 756 } 757 758 /*********************************************************************** 759 760 Time complexity: O(n) 761 762 ***********************************************************************/ 763 764 private size_t instances (V value) 765 { 766 if (count is 0) 767 return 0; 768 769 return list.count (value); 770 } 771 772 /*********************************************************************** 773 774 ***********************************************************************/ 775 776 private Ref firstCell () 777 { 778 checkIndex (0); 779 return list; 780 } 781 782 /*********************************************************************** 783 784 ***********************************************************************/ 785 786 private Ref lastCell () 787 { 788 checkIndex (0); 789 return list.tail; 790 } 791 792 /*********************************************************************** 793 794 ***********************************************************************/ 795 796 private Ref cellAt (size_t index) 797 { 798 checkIndex (index); 799 return list.nth (index); 800 } 801 802 /*********************************************************************** 803 804 ***********************************************************************/ 805 806 private void checkIndex (size_t index) 807 { 808 if (index >= count) 809 throw new Exception ("out of range"); 810 } 811 812 /*********************************************************************** 813 814 Splice elements of e between hd and tl. If hd 815 is null return new hd 816 817 Returns the count of new elements added 818 819 ***********************************************************************/ 820 821 private void splice_ (IContainer!(V) e, Ref hd, Ref tl) 822 { 823 Ref newlist = null; 824 Ref current = null; 825 826 foreach (v; e) 827 { 828 increment; 829 830 auto p = heap.allocate.set (v, null); 831 if (newlist is null) 832 newlist = p; 833 else 834 current.next = p; 835 current = p; 836 } 837 838 if (current) 839 { 840 current.next = tl; 841 842 if (hd is null) 843 list = newlist; 844 else 845 hd.next = newlist; 846 } 847 } 848 849 /*********************************************************************** 850 851 Time complexity: O(n) 852 853 ***********************************************************************/ 854 855 private LinkedList clear (bool all) 856 { 857 mutate; 858 859 // collect each node if we can't collect all at once 860 if (heap.collect(all) is false && count) 861 { 862 auto p = list; 863 while (p) 864 { 865 auto n = p.next; 866 decrement (p); 867 p = n; 868 } 869 } 870 871 list = null; 872 count = 0; 873 return this; 874 } 875 876 /*********************************************************************** 877 878 new element was added 879 880 ***********************************************************************/ 881 882 private void increment () 883 { 884 ++mutation; 885 ++count; 886 } 887 888 /*********************************************************************** 889 890 element was removed 891 892 ***********************************************************************/ 893 894 private void decrement (Ref p) 895 { 896 Reap (p.value); 897 heap.collect (p); 898 ++mutation; 899 --count; 900 } 901 902 /*********************************************************************** 903 904 set was changed 905 906 ***********************************************************************/ 907 908 private void mutate () 909 { 910 ++mutation; 911 } 912 913 /*********************************************************************** 914 915 List iterator 916 917 ***********************************************************************/ 918 919 private struct Iterator 920 { 921 Ref node; 922 Ref* hook, 923 prior; 924 LinkedList owner; 925 size_t mutation; 926 927 /*************************************************************** 928 929 Did the container change underneath us? 930 931 ***************************************************************/ 932 933 bool valid () 934 { 935 return owner.mutation is mutation; 936 } 937 938 /*************************************************************** 939 940 Accesses the next value, and returns false when 941 there are no further values to traverse 942 943 ***************************************************************/ 944 945 bool next (ref V v) 946 { 947 auto n = next; 948 return (n) ? v = *n, true : false; 949 } 950 951 /*************************************************************** 952 953 Return a pointer to the next value, or null when 954 there are no further values to traverse 955 956 ***************************************************************/ 957 958 V* next () 959 { 960 V* r; 961 if (node) 962 { 963 prior = hook; 964 r = &node.value; 965 node = *(hook = &node.next); 966 } 967 return r; 968 } 969 970 /*************************************************************** 971 972 Insert a new value before the node about to be 973 iterated (or after the node that was just iterated). 974 975 ***************************************************************/ 976 977 void insert(V value) 978 { 979 // insert a node previous to the node that we are 980 // about to iterate. 981 *hook = owner.heap.allocate.set(value, *hook); 982 node = *hook; 983 next(); 984 985 // update the count of the owner, and ignore this 986 // change in the mutation. 987 owner.increment; 988 mutation++; 989 } 990 991 /*************************************************************** 992 993 Insert a new value before the value that was just 994 iterated. 995 996 Returns true if the prior node existed and the 997 insertion worked. False otherwise. 998 999 ***************************************************************/ 1000 1001 bool insertPrior(V value) 1002 { 1003 if(prior) 1004 { 1005 // insert a node previous to the node that we just 1006 // iterated. 1007 *prior = owner.heap.allocate.set(value, *prior); 1008 prior = &(*prior).next; 1009 1010 // update the count of the owner, and ignore this 1011 // change in the mutation. 1012 owner.increment; 1013 mutation++; 1014 return true; 1015 } 1016 return false; 1017 } 1018 1019 /*************************************************************** 1020 1021 Foreach support 1022 1023 ***************************************************************/ 1024 1025 int opApply (scope int delegate(ref V value) dg) 1026 { 1027 int result; 1028 1029 auto n = node; 1030 while (n) 1031 { 1032 prior = hook; 1033 hook = &n.next; 1034 if ((result = dg(n.value)) != 0) 1035 break; 1036 n = *hook; 1037 } 1038 node = n; 1039 return result; 1040 } 1041 1042 /*************************************************************** 1043 1044 Remove value at the current iterator location 1045 1046 ***************************************************************/ 1047 1048 bool remove () 1049 { 1050 if (prior) 1051 { 1052 auto p = *prior; 1053 *prior = p.next; 1054 owner.decrement (p); 1055 hook = prior; 1056 prior = null; 1057 1058 // ignore this change 1059 ++mutation; 1060 return true; 1061 } 1062 return false; 1063 } 1064 } 1065 } 1066 1067 1068 /******************************************************************************* 1069 1070 *******************************************************************************/ 1071 1072 debug (LinkedList) 1073 { 1074 import tango.io.Stdout; 1075 import tango.core.Thread; 1076 import tango.time.StopWatch; 1077 1078 void main() 1079 { 1080 // usage examples ... 1081 auto set = new LinkedList!(char[]); 1082 set.add ("foo"); 1083 set.add ("bar"); 1084 set.add ("wumpus"); 1085 1086 // implicit generic iteration 1087 foreach (value; set) 1088 Stdout (value).newline; 1089 1090 // explicit generic iteration 1091 foreach (value; set.iterator) 1092 Stdout.formatln ("{}", value); 1093 1094 // generic iteration with optional remove and insert 1095 auto s = set.iterator; 1096 foreach (value; s) 1097 { 1098 if (value == "foo") 1099 s.remove; 1100 if (value == "bar") 1101 s.insertPrior("bloomper"); 1102 if (value == "wumpus") 1103 s.insert("rumple"); 1104 } 1105 1106 set.check(); 1107 1108 // incremental iteration, with optional remove 1109 char[] v; 1110 auto iterator = set.iterator; 1111 while (iterator.next(v)) 1112 {} //iterator.remove; 1113 1114 // incremental iteration, with optional failfast 1115 auto it = set.iterator; 1116 while (it.valid && it.next(v)) 1117 {} 1118 1119 // remove specific element 1120 set.remove ("wumpus"); 1121 1122 // remove first element ... 1123 while (set.take(v)) 1124 Stdout.formatln ("taking {}, {} left", v, set.size); 1125 1126 1127 // setup for benchmark, with a set of integers. We 1128 // use a chunk allocator, and presize the bucket[] 1129 auto test = new LinkedList!(int, Container.reap, Container.Chunk); 1130 test.cache (2000, 1_000_000); 1131 const count = 1_000_000; 1132 StopWatch w; 1133 1134 // benchmark adding 1135 w.start; 1136 for (int i=count; i--;) 1137 test.prepend(i); 1138 Stdout.formatln ("{} adds: {}/s", test.size, test.size/w.stop); 1139 1140 // benchmark adding without allocation overhead 1141 test.clear; 1142 w.start; 1143 for (int i=count; i--;) 1144 test.prepend(i); 1145 Stdout.formatln ("{} adds (after clear): {}/s", test.size, test.size/w.stop); 1146 1147 // benchmark duplication 1148 w.start; 1149 auto dup = test.dup; 1150 Stdout.formatln ("{} element dup: {}/s", dup.size, dup.size/w.stop); 1151 1152 // benchmark iteration 1153 w.start; 1154 auto xx = test.iterator; 1155 int ii; 1156 while (xx.next()) {} 1157 Stdout.formatln ("{} element iteration: {}/s", test.size, test.size/w.stop); 1158 1159 // benchmark iteration 1160 w.start; 1161 foreach (v; test) {} 1162 Stdout.formatln ("{} foreach iteration: {}/s", test.size, test.size/w.stop); 1163 1164 1165 // benchmark iteration 1166 w.start; 1167 foreach (ref iii; test) {} 1168 Stdout.formatln ("{} pointer iteration: {}/s", test.size, test.size/w.stop); 1169 1170 test.check; 1171 } 1172 } 1173