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