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