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