Mercurial > projects > ldc
comparison tango/tango/util/collection/impl/Collection.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 | |
3 File: Collection.d | |
4 | |
5 Originally written by Doug Lea and released into the public domain. | |
6 Thanks for the assistance and support of Sun Microsystems Labs, Agorics | |
7 Inc, Loral, and everyone contributing, testing, and using this code. | |
8 | |
9 History: | |
10 Date Who What | |
11 24Sep95 dl@cs.oswego.edu Create from tango.util.collection.d working file | |
12 13Oct95 dl Add assert | |
13 22Oct95 dl Add excludeElements, removeElements | |
14 28jan97 dl make class public; isolate version changes | |
15 14Dec06 kb Adapted for Tango usage | |
16 | |
17 ********************************************************************************/ | |
18 | |
19 module tango.util.collection.impl.Collection; | |
20 | |
21 private import tango.core.Exception; | |
22 | |
23 private import tango.util.collection.model.View, | |
24 tango.util.collection.model.Iterator, | |
25 tango.util.collection.model.Dispenser; | |
26 | |
27 /******************************************************************************* | |
28 | |
29 Collection serves as a convenient base class for most implementations | |
30 of mutable containers. It maintains a version number and element count. | |
31 It also provides default implementations of many collection operations. | |
32 | |
33 Authors: Doug Lea | |
34 | |
35 ********************************************************************************/ | |
36 | |
37 public abstract class Collection(T) : Dispenser!(T) | |
38 { | |
39 alias View!(T) ViewT; | |
40 | |
41 alias bool delegate(T) Predicate; | |
42 | |
43 | |
44 // instance variables | |
45 | |
46 /*********************************************************************** | |
47 | |
48 version represents the current version number | |
49 | |
50 ************************************************************************/ | |
51 | |
52 protected uint vershion; | |
53 | |
54 /*********************************************************************** | |
55 | |
56 screener hold the supplied element screener | |
57 | |
58 ************************************************************************/ | |
59 | |
60 protected Predicate screener; | |
61 | |
62 /*********************************************************************** | |
63 | |
64 count holds the number of elements. | |
65 | |
66 ************************************************************************/ | |
67 | |
68 protected uint count; | |
69 | |
70 // constructors | |
71 | |
72 /*********************************************************************** | |
73 | |
74 Initialize at version 0, an empty count, and supplied screener | |
75 | |
76 ************************************************************************/ | |
77 | |
78 protected this (Predicate screener = null) | |
79 { | |
80 this.screener = screener; | |
81 } | |
82 | |
83 | |
84 /*********************************************************************** | |
85 | |
86 ************************************************************************/ | |
87 | |
88 protected final static bool isValidArg (T element) | |
89 { | |
90 static if (is (T : Object)) | |
91 { | |
92 if (element is null) | |
93 return false; | |
94 } | |
95 return true; | |
96 } | |
97 | |
98 // Default implementations of Collection methods | |
99 | |
100 /*********************************************************************** | |
101 | |
102 expose collection content as an array | |
103 | |
104 ************************************************************************/ | |
105 | |
106 public T[] toArray () | |
107 { | |
108 auto result = new T[this.size]; | |
109 | |
110 int i = 0; | |
111 foreach (e; this) | |
112 result[i++] = e; | |
113 | |
114 return result; | |
115 } | |
116 | |
117 /*********************************************************************** | |
118 | |
119 Time complexity: O(1). | |
120 See_Also: tango.util.collection.impl.Collection.Collection.drained | |
121 | |
122 ************************************************************************/ | |
123 | |
124 public final bool drained() | |
125 { | |
126 return count is 0; | |
127 } | |
128 | |
129 /*********************************************************************** | |
130 | |
131 Time complexity: O(1). | |
132 Returns: the count of elements currently in the collection | |
133 See_Also: tango.util.collection.impl.Collection.Collection.size | |
134 | |
135 ************************************************************************/ | |
136 | |
137 public final uint size() | |
138 { | |
139 return count; | |
140 } | |
141 | |
142 /*********************************************************************** | |
143 | |
144 Checks if element is an allowed element for this collection. | |
145 This will not throw an exception, but any other attemp to add an | |
146 invalid element will do. | |
147 | |
148 Time complexity: O(1) + time of screener, if present | |
149 | |
150 See_Also: tango.util.collection.impl.Collection.Collection.allows | |
151 | |
152 ************************************************************************/ | |
153 | |
154 public final bool allows (T element) | |
155 { | |
156 return isValidArg(element) && | |
157 (screener is null || screener(element)); | |
158 } | |
159 | |
160 | |
161 /*********************************************************************** | |
162 | |
163 Time complexity: O(n). | |
164 Default implementation. Fairly sleazy approach. | |
165 (Defensible only when you remember that it is just a default impl.) | |
166 It tries to cast to one of the known collection interface types | |
167 and then applies the corresponding comparison rules. | |
168 This suffices for all currently supported collection types, | |
169 but must be overridden if you define new Collection subinterfaces | |
170 and/or implementations. | |
171 | |
172 See_Also: tango.util.collection.impl.Collection.Collection.matches | |
173 | |
174 ************************************************************************/ | |
175 | |
176 public bool matches(ViewT other) | |
177 { | |
178 /+ | |
179 if (other is null) | |
180 return false; | |
181 else | |
182 if (other is this) | |
183 return true; | |
184 else | |
185 if (cast(SortedKeys) this) | |
186 { | |
187 if (!(cast(Map) other)) | |
188 return false; | |
189 else | |
190 return sameOrderedPairs(cast(Map)this, cast(Map)other); | |
191 } | |
192 else | |
193 if (cast(Map) this) | |
194 { | |
195 if (!(cast(Map) other)) | |
196 return false; | |
197 else | |
198 return samePairs(cast(Map)(this), cast(Map)(other)); | |
199 } | |
200 else | |
201 if ((cast(Seq) this) || (cast(SortedValues) this)) | |
202 return sameOrderedElements(this, other); | |
203 else | |
204 if (cast(Bag) this) | |
205 return sameOccurrences(this, other); | |
206 else | |
207 if (cast(Set) this) | |
208 return sameInclusions(this, cast(View)(other)); | |
209 else | |
210 return false; | |
211 +/ | |
212 return false; | |
213 } | |
214 | |
215 // Default implementations of MutableCollection methods | |
216 | |
217 /*********************************************************************** | |
218 | |
219 Time complexity: O(1). | |
220 See_Also: tango.util.collection.impl.Collection.Collection.version | |
221 | |
222 ************************************************************************/ | |
223 | |
224 public final uint mutation() | |
225 { | |
226 return vershion; | |
227 } | |
228 | |
229 // Object methods | |
230 | |
231 /*********************************************************************** | |
232 | |
233 Default implementation of toString for Collections. Not | |
234 very pretty, but parenthesizing each element means that | |
235 for most kinds of elements, it's conceivable that the | |
236 strings could be parsed and used to build other tango.util.collection. | |
237 | |
238 Not a very pretty implementation either. Casts are used | |
239 to get at elements/keys | |
240 | |
241 ************************************************************************/ | |
242 | |
243 public override char[] toString() | |
244 { | |
245 char[16] tmp; | |
246 | |
247 return "<" ~ this.classinfo.name ~ ", size:" ~ itoa(tmp, size()) ~ ">"; | |
248 } | |
249 | |
250 | |
251 /*********************************************************************** | |
252 | |
253 ************************************************************************/ | |
254 | |
255 protected final char[] itoa(char[] buf, uint i) | |
256 { | |
257 auto j = buf.length; | |
258 | |
259 do { | |
260 buf[--j] = i % 10 + '0'; | |
261 } while (i /= 10); | |
262 return buf [j..$]; | |
263 } | |
264 | |
265 // protected operations on version and count | |
266 | |
267 /*********************************************************************** | |
268 | |
269 change the version number | |
270 | |
271 ************************************************************************/ | |
272 | |
273 protected final void incVersion() | |
274 { | |
275 ++vershion; | |
276 } | |
277 | |
278 | |
279 /*********************************************************************** | |
280 | |
281 Increment the element count and update version | |
282 | |
283 ************************************************************************/ | |
284 | |
285 protected final void incCount() | |
286 { | |
287 count++; | |
288 incVersion(); | |
289 } | |
290 | |
291 /*********************************************************************** | |
292 | |
293 Decrement the element count and update version | |
294 | |
295 ************************************************************************/ | |
296 | |
297 protected final void decCount() | |
298 { | |
299 count--; | |
300 incVersion(); | |
301 } | |
302 | |
303 | |
304 /*********************************************************************** | |
305 | |
306 add to the element count and update version if changed | |
307 | |
308 ************************************************************************/ | |
309 | |
310 protected final void addToCount(uint c) | |
311 { | |
312 if (c !is 0) | |
313 { | |
314 count += c; | |
315 incVersion(); | |
316 } | |
317 } | |
318 | |
319 | |
320 /*********************************************************************** | |
321 | |
322 set the element count and update version if changed | |
323 | |
324 ************************************************************************/ | |
325 | |
326 protected final void setCount(uint c) | |
327 { | |
328 if (c !is count) | |
329 { | |
330 count = c; | |
331 incVersion(); | |
332 } | |
333 } | |
334 | |
335 | |
336 /*********************************************************************** | |
337 | |
338 Helper method left public since it might be useful | |
339 | |
340 ************************************************************************/ | |
341 | |
342 public final static bool sameInclusions(ViewT s, ViewT t) | |
343 { | |
344 if (s.size !is t.size) | |
345 return false; | |
346 | |
347 try { // set up to return false on collection exceptions | |
348 auto ts = t.elements(); | |
349 while (ts.more) | |
350 { | |
351 if (!s.contains(ts.get)) | |
352 return false; | |
353 } | |
354 return true; | |
355 } catch (NoSuchElementException ex) | |
356 { | |
357 return false; | |
358 } | |
359 } | |
360 | |
361 /*********************************************************************** | |
362 | |
363 Helper method left public since it might be useful | |
364 | |
365 ************************************************************************/ | |
366 | |
367 public final static bool sameOccurrences(ViewT s, ViewT t) | |
368 { | |
369 if (s.size !is t.size) | |
370 return false; | |
371 | |
372 auto ts = t.elements(); | |
373 T last = T.init; // minor optimization -- skip two successive if same | |
374 | |
375 try { // set up to return false on collection exceptions | |
376 while (ts.more) | |
377 { | |
378 T m = ts.get; | |
379 if (m !is last) | |
380 { | |
381 if (s.instances(m) !is t.instances(m)) | |
382 return false; | |
383 } | |
384 last = m; | |
385 } | |
386 return true; | |
387 } catch (NoSuchElementException ex) | |
388 { | |
389 return false; | |
390 } | |
391 } | |
392 | |
393 | |
394 /*********************************************************************** | |
395 | |
396 Helper method left public since it might be useful | |
397 | |
398 ************************************************************************/ | |
399 | |
400 public final static bool sameOrderedElements(ViewT s, ViewT t) | |
401 { | |
402 if (s.size !is t.size) | |
403 return false; | |
404 | |
405 auto ts = t.elements(); | |
406 auto ss = s.elements(); | |
407 | |
408 try { // set up to return false on collection exceptions | |
409 while (ts.more) | |
410 { | |
411 T m = ts.get; | |
412 T o = ss.get; | |
413 if (m != o) | |
414 return false; | |
415 } | |
416 return true; | |
417 } catch (NoSuchElementException ex) | |
418 { | |
419 return false; | |
420 } | |
421 } | |
422 | |
423 // misc common helper methods | |
424 | |
425 /*********************************************************************** | |
426 | |
427 Principal method to throw a NoSuchElementException. | |
428 Besides index checks in Seqs, you can use it to check for | |
429 operations on empty collections via checkIndex(0) | |
430 | |
431 ************************************************************************/ | |
432 | |
433 protected final void checkIndex(int index) | |
434 { | |
435 if (index < 0 || index >= count) | |
436 { | |
437 char[] msg; | |
438 | |
439 if (count is 0) | |
440 msg = "Element access on empty collection"; | |
441 else | |
442 { | |
443 char[16] idx, cnt; | |
444 msg = "Index " ~ itoa (idx, index) ~ " out of range for collection of size " ~ itoa (cnt, count); | |
445 } | |
446 throw new NoSuchElementException(msg); | |
447 } | |
448 } | |
449 | |
450 | |
451 /*********************************************************************** | |
452 | |
453 Principal method to throw a IllegalElementException | |
454 | |
455 ************************************************************************/ | |
456 | |
457 protected final void checkElement(T element) | |
458 { | |
459 if (! allows(element)) | |
460 { | |
461 throw new IllegalElementException("Attempt to include invalid element _in Collection"); | |
462 } | |
463 } | |
464 | |
465 /*********************************************************************** | |
466 | |
467 See_Also: tango.util.collection.model.View.View.checkImplementation | |
468 | |
469 ************************************************************************/ | |
470 | |
471 public void checkImplementation() | |
472 { | |
473 assert(count >= 0); | |
474 } | |
475 //public override void checkImplementation() //Doesn't compile with the override attribute | |
476 | |
477 /*********************************************************************** | |
478 | |
479 Cause the collection to become empty. | |
480 | |
481 ************************************************************************/ | |
482 | |
483 abstract void clear(); | |
484 | |
485 /*********************************************************************** | |
486 | |
487 Exclude all occurrences of the indicated element from the collection. | |
488 No effect if element not present. | |
489 Params: | |
490 element = the element to exclude. | |
491 --- | |
492 !has(element) && | |
493 size() == PREV(this).size() - PREV(this).instances(element) && | |
494 no other element changes && | |
495 Version change iff PREV(this).has(element) | |
496 --- | |
497 | |
498 ************************************************************************/ | |
499 | |
500 abstract void removeAll(T element); | |
501 | |
502 /*********************************************************************** | |
503 | |
504 Remove an instance of the indicated element from the collection. | |
505 No effect if !has(element) | |
506 Params: | |
507 element = the element to remove | |
508 --- | |
509 let occ = max(1, instances(element)) in | |
510 size() == PREV(this).size() - occ && | |
511 instances(element) == PREV(this).instances(element) - occ && | |
512 no other element changes && | |
513 version change iff occ == 1 | |
514 --- | |
515 | |
516 ************************************************************************/ | |
517 | |
518 abstract void remove (T element); | |
519 | |
520 /*********************************************************************** | |
521 | |
522 Replace an occurrence of oldElement with newElement. | |
523 No effect if does not hold oldElement or if oldElement.equals(newElement). | |
524 The operation has a consistent, but slightly special interpretation | |
525 when applied to Sets. For Sets, because elements occur at | |
526 most once, if newElement is already included, replacing oldElement with | |
527 with newElement has the same effect as just removing oldElement. | |
528 --- | |
529 let int delta = oldElement.equals(newElement)? 0 : | |
530 max(1, PREV(this).instances(oldElement) in | |
531 instances(oldElement) == PREV(this).instances(oldElement) - delta && | |
532 instances(newElement) == (this instanceof Set) ? | |
533 max(1, PREV(this).instances(oldElement) + delta): | |
534 PREV(this).instances(oldElement) + delta) && | |
535 no other element changes && | |
536 Version change iff delta != 0 | |
537 --- | |
538 Throws: IllegalElementException if has(oldElement) and !allows(newElement) | |
539 | |
540 ************************************************************************/ | |
541 | |
542 abstract void replace (T oldElement, T newElement); | |
543 | |
544 /*********************************************************************** | |
545 | |
546 Replace all occurrences of oldElement with newElement. | |
547 No effect if does not hold oldElement or if oldElement.equals(newElement). | |
548 The operation has a consistent, but slightly special interpretation | |
549 when applied to Sets. For Sets, because elements occur at | |
550 most once, if newElement is already included, replacing oldElement with | |
551 with newElement has the same effect as just removing oldElement. | |
552 --- | |
553 let int delta = oldElement.equals(newElement)? 0 : | |
554 PREV(this).instances(oldElement) in | |
555 instances(oldElement) == PREV(this).instances(oldElement) - delta && | |
556 instances(newElement) == (this instanceof Set) ? | |
557 max(1, PREV(this).instances(oldElement) + delta): | |
558 PREV(this).instances(oldElement) + delta) && | |
559 no other element changes && | |
560 Version change iff delta != 0 | |
561 --- | |
562 Throws: IllegalElementException if has(oldElement) and !allows(newElement) | |
563 | |
564 ************************************************************************/ | |
565 | |
566 abstract void replaceAll(T oldElement, T newElement); | |
567 | |
568 /*********************************************************************** | |
569 | |
570 Exclude all occurrences of each element of the Iterator. | |
571 Behaviorally equivalent to | |
572 --- | |
573 while (e.more()) | |
574 removeAll(e.get()); | |
575 --- | |
576 Param : | |
577 e = the enumeration of elements to exclude. | |
578 | |
579 Throws: CorruptedIteratorException is propagated if thrown | |
580 | |
581 See_Also: tango.util.collection.impl.Collection.Collection.removeAll | |
582 | |
583 ************************************************************************/ | |
584 | |
585 abstract void removeAll (Iterator!(T) e); | |
586 | |
587 /*********************************************************************** | |
588 | |
589 Remove an occurrence of each element of the Iterator. | |
590 Behaviorally equivalent to | |
591 | |
592 --- | |
593 while (e.more()) | |
594 remove (e.get()); | |
595 --- | |
596 | |
597 Param: | |
598 e = the enumeration of elements to remove. | |
599 | |
600 Throws: CorruptedIteratorException is propagated if thrown | |
601 | |
602 ************************************************************************/ | |
603 | |
604 abstract void remove (Iterator!(T) e); | |
605 | |
606 /*********************************************************************** | |
607 | |
608 Remove and return an element. Implementations | |
609 may strengthen the guarantee about the nature of this element. | |
610 but in general it is the most convenient or efficient element to remove. | |
611 | |
612 Examples: | |
613 One way to transfer all elements from | |
614 MutableCollection a to MutableBag b is: | |
615 --- | |
616 while (!a.empty()) | |
617 b.add(a.take()); | |
618 --- | |
619 | |
620 Returns: | |
621 an element v such that PREV(this).has(v) | |
622 and the postconditions of removeOneOf(v) hold. | |
623 | |
624 Throws: NoSuchElementException iff drained. | |
625 | |
626 ************************************************************************/ | |
627 | |
628 abstract T take(); | |
629 } | |
630 | |
631 |