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