comparison tango/tango/util/collection/CircularSeq.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
comparison
equal deleted inserted replaced
131:5825d48b27d1 132:1700239cab2e
1 /*
2 File: CircularSeq.d
3
4 Originally written by Doug Lea and released into the public domain.
5 Thanks for the assistance and support of Sun Microsystems Labs, Agorics
6 Inc, Loral, and everyone contributing, testing, and using this code.
7
8 History:
9 Date Who What
10 24Sep95 dl@cs.oswego.edu Create from store.d working file
11 13Oct95 dl Changed protection statuses
12 */
13
14 module tango.util.collection.CircularSeq;
15
16 private import tango.util.collection.model.Iterator,
17 tango.util.collection.model.GuardIterator;
18
19 private import tango.util.collection.impl.CLCell,
20 tango.util.collection.impl.SeqCollection,
21 tango.util.collection.impl.AbstractIterator;
22
23
24 /**
25 * Circular linked lists. Publically Implement only those
26 * methods defined in interfaces.
27 * author: Doug Lea
28 **/
29 public class CircularSeq(T) : SeqCollection!(T)
30 {
31 alias CLCell!(T) CLCellT;
32
33 alias SeqCollection!(T).remove remove;
34 alias SeqCollection!(T).removeAll removeAll;
35
36 // instance variables
37
38 /**
39 * The head of the list. Null if empty
40 **/
41 package CLCellT list;
42
43 // constructors
44
45 /**
46 * Make an empty list with no element screener
47 **/
48 public this ()
49 {
50 this(null, null, 0);
51 }
52
53 /**
54 * Make an empty list with supplied element screener
55 **/
56 public this (Predicate screener)
57 {
58 this(screener, null, 0);
59 }
60
61 /**
62 * Special version of constructor needed by clone()
63 **/
64 protected this (Predicate s, CLCellT h, int c)
65 {
66 super(s);
67 list = h;
68 count = c;
69 }
70
71 /**
72 * Make an independent copy of the list. Elements themselves are not cloned
73 **/
74 public final CircularSeq duplicate()
75 {
76 if (list is null)
77 return new CircularSeq (screener, null, 0);
78 else
79 return new CircularSeq (screener, list.copyList(), count);
80 }
81
82
83 // Collection methods
84
85 /**
86 * Implements tango.util.collection.impl.Collection.Collection.contains
87 * Time complexity: O(n).
88 * See_Also: tango.util.collection.impl.Collection.Collection.contains
89 **/
90 public final bool contains(T element)
91 {
92 if (!isValidArg(element) || list is null)
93 return false;
94 return list.find(element) !is null;
95 }
96
97 /**
98 * Implements tango.util.collection.impl.Collection.Collection.instances
99 * Time complexity: O(n).
100 * See_Also: tango.util.collection.impl.Collection.Collection.instances
101 **/
102 public final uint instances(T element)
103 {
104 if (!isValidArg(element) || list is null)
105 return 0;
106 return list.count(element);
107 }
108
109 /**
110 * Implements tango.util.collection.impl.Collection.Collection.elements
111 * Time complexity: O(1).
112 * See_Also: tango.util.collection.impl.Collection.Collection.elements
113 **/
114 public final GuardIterator!(T) elements()
115 {
116 return new CellIterator!(T)(this);
117 }
118
119 /**
120 * Implements tango.util.collection.model.View.View.opApply
121 * Time complexity: O(n).
122 * See_Also: tango.util.collection.model.View.View.opApply
123 **/
124 int opApply (int delegate (inout T value) dg)
125 {
126 auto scope iterator = new CellIterator!(T)(this);
127 return iterator.opApply (dg);
128 }
129
130
131 // Seq methods
132
133 /**
134 * Implements tango.util.collection.model.Seq.Seq.head.
135 * Time complexity: O(1).
136 * See_Also: tango.util.collection.model.Seq.Seq.head
137 **/
138 public final T head()
139 {
140 return firstCell().element();
141 }
142
143 /**
144 * Implements tango.util.collection.model.Seq.Seq.tail.
145 * Time complexity: O(1).
146 * See_Also: tango.util.collection.model.Seq.Seq.tail
147 **/
148 public final T tail()
149 {
150 return lastCell().element();
151 }
152
153 /**
154 * Implements tango.util.collection.model.Seq.Seq.get.
155 * Time complexity: O(n).
156 * See_Also: tango.util.collection.model.Seq.Seq.get
157 **/
158 public final T get(int index)
159 {
160 return cellAt(index).element();
161 }
162
163 /**
164 * Implements tango.util.collection.model.Seq.Seq.first.
165 * Time complexity: O(n).
166 * See_Also: tango.util.collection.model.Seq.Seq.first
167 **/
168 public final int first(T element, int startingIndex = 0)
169 {
170 if (startingIndex < 0)
171 startingIndex = 0;
172
173 CLCellT p = list;
174 if (p is null || !isValidArg(element))
175 return -1;
176
177 for (int i = 0; true; ++i)
178 {
179 if (i >= startingIndex && p.element() == (element))
180 return i;
181
182 p = p.next();
183 if (p is list)
184 break;
185 }
186 return -1;
187 }
188
189
190 /**
191 * Implements tango.util.collection.model.Seq.Seq.last.
192 * Time complexity: O(n).
193 * See_Also: tango.util.collection.model.Seq.Seq.last
194 **/
195 public final int last(T element, int startingIndex = 0)
196 {
197 if (!isValidArg(element) || count is 0)
198 return -1;
199
200 if (startingIndex >= size())
201 startingIndex = size() - 1;
202
203 if (startingIndex < 0)
204 startingIndex = 0;
205
206 CLCellT p = cellAt(startingIndex);
207 int i = startingIndex;
208 for (;;)
209 {
210 if (p.element() == (element))
211 return i;
212 else
213 if (p is list)
214 break;
215 else
216 {
217 p = p.prev();
218 --i;
219 }
220 }
221 return -1;
222 }
223
224 /**
225 * Implements tango.util.collection.model.Seq.Seq.subseq.
226 * Time complexity: O(length).
227 * See_Also: tango.util.collection.model.Seq.Seq.subseq
228 **/
229 public final CircularSeq subset (int from, int _length)
230 {
231 if (_length > 0)
232 {
233 checkIndex(from);
234 CLCellT p = cellAt(from);
235 CLCellT newlist = new CLCellT(p.element());
236 CLCellT current = newlist;
237
238 for (int i = 1; i < _length; ++i)
239 {
240 p = p.next();
241 if (p is null)
242 checkIndex(from + i); // force exception
243
244 current.addNext(p.element());
245 current = current.next();
246 }
247 return new CircularSeq (screener, newlist, _length);
248 }
249 else
250 return new CircularSeq ();
251 }
252
253 // MutableCollection methods
254
255 /**
256 * Implements tango.util.collection.impl.Collection.Collection.clear.
257 * Time complexity: O(1).
258 * See_Also: tango.util.collection.impl.Collection.Collection.clear
259 **/
260 public final void clear()
261 {
262 list = null;
263 setCount(0);
264 }
265
266 /**
267 * Implements tango.util.collection.impl.Collection.Collection.exclude.
268 * Time complexity: O(n).
269 * See_Also: tango.util.collection.impl.Collection.Collection.exclude
270 **/
271 public final void removeAll (T element)
272 {
273 remove_(element, true);
274 }
275
276 /**
277 * Implements tango.util.collection.impl.Collection.Collection.removeOneOf.
278 * Time complexity: O(n).
279 * See_Also: tango.util.collection.impl.Collection.Collection.removeOneOf
280 **/
281 public final void remove (T element)
282 {
283 remove_(element, false);
284 }
285
286 /**
287 * Implements tango.util.collection.impl.Collection.Collection.replaceOneOf
288 * Time complexity: O(n).
289 * See_Also: tango.util.collection.impl.Collection.Collection.replaceOneOf
290 **/
291 public final void replace (T oldElement, T newElement)
292 {
293 replace_(oldElement, newElement, false);
294 }
295
296 /**
297 * Implements tango.util.collection.impl.Collection.Collection.replaceAllOf.
298 * Time complexity: O(n).
299 * See_Also: tango.util.collection.impl.Collection.Collection.replaceAllOf
300 **/
301 public final void replaceAll (T oldElement, T newElement)
302 {
303 replace_(oldElement, newElement, true);
304 }
305
306
307 /**
308 * Implements tango.util.collection.impl.Collection.Collection.take.
309 * Time complexity: O(1).
310 * takes the last element on the list.
311 * See_Also: tango.util.collection.impl.Collection.Collection.take
312 **/
313 public final T take()
314 {
315 auto v = tail();
316 removeTail();
317 return v;
318 }
319
320
321
322 // MutableSeq methods
323
324 /**
325 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.prepend.
326 * Time complexity: O(1).
327 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.prepend
328 **/
329 public final void prepend(T element)
330 {
331 checkElement(element);
332 if (list is null)
333 list = new CLCellT(element);
334 else
335 list = list.addPrev(element);
336 incCount();
337 }
338
339 /**
340 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.replaceHead.
341 * Time complexity: O(1).
342 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.replaceHead
343 **/
344 public final void replaceHead(T element)
345 {
346 checkElement(element);
347 firstCell().element(element);
348 incVersion();
349 }
350
351 /**
352 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.removeHead.
353 * Time complexity: O(1).
354 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeHead
355 **/
356 public final void removeHead()
357 {
358 if (firstCell().isSingleton())
359 list = null;
360 else
361 {
362 auto n = list.next();
363 list.unlink();
364 list = n;
365 }
366 decCount();
367 }
368
369 /**
370 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.append.
371 * Time complexity: O(1).
372 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.append
373 **/
374 public final void append(T element)
375 {
376 if (list is null)
377 prepend(element);
378 else
379 {
380 checkElement(element);
381 list.prev().addNext(element);
382 incCount();
383 }
384 }
385
386 /**
387 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.replaceTail.
388 * Time complexity: O(1).
389 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.replaceTail
390 **/
391 public final void replaceTail(T element)
392 {
393 checkElement(element);
394 lastCell().element(element);
395 incVersion();
396 }
397
398
399 /**
400 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.removeTail.
401 * Time complexity: O(1).
402 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeTail
403 **/
404 public final void removeTail()
405 {
406 auto l = lastCell();
407 if (l is list)
408 list = null;
409 else
410 l.unlink();
411 decCount();
412 }
413
414 /**
415 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.addAt.
416 * Time complexity: O(n).
417 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.addAt
418 **/
419 public final void addAt(int index, T element)
420 {
421 if (index is 0)
422 prepend(element);
423 else
424 {
425 checkElement(element);
426 cellAt(index - 1).addNext(element);
427 incCount();
428 }
429 }
430
431 /**
432 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.replaceAt.
433 * Time complexity: O(n).
434 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.replaceAt
435 **/
436 public final void replaceAt(int index, T element)
437 {
438 checkElement(element);
439 cellAt(index).element(element);
440 incVersion();
441 }
442
443 /**
444 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.removeAt.
445 * Time complexity: O(n).
446 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeAt
447 **/
448 public final void removeAt(int index)
449 {
450 if (index is 0)
451 removeHead();
452 else
453 {
454 cellAt(index - 1).unlinkNext();
455 decCount();
456 }
457 }
458
459 /**
460 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.prepend.
461 * Time complexity: O(number of elements in e).
462 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.prepend
463 **/
464 public final void prepend(Iterator!(T) e)
465 {
466 CLCellT hd = null;
467 CLCellT current = null;
468
469 while (e.more())
470 {
471 auto element = e.get();
472 checkElement(element);
473 incCount();
474
475 if (hd is null)
476 {
477 hd = new CLCellT(element);
478 current = hd;
479 }
480 else
481 {
482 current.addNext(element);
483 current = current.next();
484 }
485 }
486
487 if (list is null)
488 list = hd;
489 else
490 if (hd !is null)
491 {
492 auto tl = list.prev();
493 current.next(list);
494 list.prev(current);
495 tl.next(hd);
496 hd.prev(tl);
497 list = hd;
498 }
499 }
500
501 /**
502 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.append.
503 * Time complexity: O(number of elements in e).
504 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.append
505 **/
506 public final void append(Iterator!(T) e)
507 {
508 if (list is null)
509 prepend(e);
510 else
511 {
512 CLCellT current = list.prev();
513 while (e.more())
514 {
515 T element = e.get();
516 checkElement(element);
517 incCount();
518 current.addNext(element);
519 current = current.next();
520 }
521 }
522 }
523
524 /**
525 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.addAt.
526 * Time complexity: O(size() + number of elements in e).
527 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.addAt
528 **/
529 public final void addAt(int index, Iterator!(T) e)
530 {
531 if (list is null || index is 0)
532 prepend(e);
533 else
534 {
535 CLCellT current = cellAt(index - 1);
536 while (e.more())
537 {
538 T element = e.get();
539 checkElement(element);
540 incCount();
541 current.addNext(element);
542 current = current.next();
543 }
544 }
545 }
546
547
548 /**
549 * Implements tango.util.collection.impl.SeqCollection.SeqCollection.removeFromTo.
550 * Time complexity: O(n).
551 * See_Also: tango.util.collection.impl.SeqCollection.SeqCollection.removeFromTo
552 **/
553 public final void removeRange (int fromIndex, int toIndex)
554 {
555 checkIndex(toIndex);
556 CLCellT p = cellAt(fromIndex);
557 CLCellT last = list.prev();
558 for (int i = fromIndex; i <= toIndex; ++i)
559 {
560 decCount();
561 CLCellT n = p.next();
562 p.unlink();
563 if (p is list)
564 {
565 if (p is last)
566 {
567 list = null;
568 return ;
569 }
570 else
571 list = n;
572 }
573 p = n;
574 }
575 }
576
577
578 // helper methods
579
580 /**
581 * return the first cell, or throw exception if empty
582 **/
583 private final CLCellT firstCell()
584 {
585 if (list !is null)
586 return list;
587
588 checkIndex(0);
589 return null; // not reached!
590 }
591
592 /**
593 * return the last cell, or throw exception if empty
594 **/
595 private final CLCellT lastCell()
596 {
597 if (list !is null)
598 return list.prev();
599
600 checkIndex(0);
601 return null; // not reached!
602 }
603
604 /**
605 * return the index'th cell, or throw exception if bad index
606 **/
607 private final CLCellT cellAt(int index)
608 {
609 checkIndex(index);
610 return list.nth(index);
611 }
612
613 /**
614 * helper for remove/exclude
615 **/
616 private final void remove_(T element, bool allOccurrences)
617 {
618 if (!isValidArg(element) || list is null)
619 return;
620
621 CLCellT p = list;
622 for (;;)
623 {
624 CLCellT n = p.next();
625 if (p.element() == (element))
626 {
627 decCount();
628 p.unlink();
629 if (p is list)
630 {
631 if (p is n)
632 {
633 list = null;
634 break;
635 }
636 else
637 list = n;
638 }
639
640 if (! allOccurrences)
641 break;
642 else
643 p = n;
644 }
645 else
646 if (n is list)
647 break;
648 else
649 p = n;
650 }
651 }
652
653
654 /**
655 * helper for replace *
656 **/
657 private final void replace_(T oldElement, T newElement, bool allOccurrences)
658 {
659 if (!isValidArg(oldElement) || list is null)
660 return;
661
662 CLCellT p = list;
663 do {
664 if (p.element() == (oldElement))
665 {
666 checkElement(newElement);
667 incVersion();
668 p.element(newElement);
669 if (! allOccurrences)
670 return;
671 }
672 p = p.next();
673 } while (p !is list);
674 }
675
676 // ImplementationCheckable methods
677
678 /**
679 * Implements tango.util.collection.model.View.View.checkImplementation.
680 * See_Also: tango.util.collection.model.View.View.checkImplementation
681 **/
682
683 public override void checkImplementation()
684 {
685 super.checkImplementation();
686
687 assert(((count is 0) is (list is null)));
688 assert((list is null || list._length() is count));
689
690 if (list is null)
691 return;
692
693 int c = 0;
694 CLCellT p = list;
695 do {
696 assert(p.prev().next() is p);
697 assert(p.next().prev() is p);
698 assert(allows(p.element()));
699 assert(instances(p.element()) > 0);
700 assert(contains(p.element()));
701 p = p.next();
702 ++c;
703 } while (p !is list);
704
705 assert(c is count);
706 }
707
708
709 /***********************************************************************
710
711 opApply() has migrated here to mitigate the virtual call
712 on method get()
713
714 ************************************************************************/
715
716 static class CellIterator(T) : AbstractIterator!(T)
717 {
718 private CLCellT cell;
719
720 public this (CircularSeq seq)
721 {
722 super (seq);
723 cell = seq.list;
724 }
725
726 public final T get()
727 {
728 decRemaining();
729 auto v = cell.element();
730 cell = cell.next();
731 return v;
732 }
733
734 int opApply (int delegate (inout T value) dg)
735 {
736 int result;
737
738 for (auto i=remaining(); i--;)
739 {
740 auto value = get();
741 if ((result = dg(value)) != 0)
742 break;
743 }
744 return result;
745 }
746 }
747 }
748
749
750
751 debug (Test)
752 {
753 import tango.io.Console;
754
755 void main()
756 {
757 auto array = new CircularSeq!(char[]);
758 array.append ("foo");
759 array.append ("bar");
760 array.append ("wumpus");
761
762 foreach (value; array.elements) {}
763
764 auto elements = array.elements();
765 while (elements.more)
766 auto v = elements.get();
767
768 foreach (value; array)
769 Cout (value).newline;
770
771 array.checkImplementation();
772 }
773 }