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