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