Mercurial > projects > ldc
comparison tango/tango/util/collection/ArrayBag.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: ArrayBag.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 | |
15 | |
16 module tango.util.collection.ArrayBag; | |
17 | |
18 private import tango.core.Exception; | |
19 | |
20 private import tango.util.collection.model.GuardIterator; | |
21 | |
22 private import tango.util.collection.impl.CLCell, | |
23 tango.util.collection.impl.BagCollection, | |
24 tango.util.collection.impl.AbstractIterator; | |
25 | |
26 | |
27 | |
28 /** | |
29 * | |
30 * Linked Buffer implementation of Bags. The Bag consists of | |
31 * any number of buffers holding elements, arranged in a list. | |
32 * Each buffer holds an array of elements. The size of each | |
33 * buffer is the value of chunkSize that was current during the | |
34 * operation that caused the Bag to grow. The chunkSize() may | |
35 * be adjusted at any time. (It is not considered a version change.) | |
36 * | |
37 * <P> | |
38 * All but the final buffer is always kept full. | |
39 * When a buffer has no elements, it is released (so is | |
40 * available for garbage collection). | |
41 * <P> | |
42 * ArrayBags are good choices for collections in which | |
43 * you merely put a lot of things in, and then look at | |
44 * them via enumerations, but don't often look for | |
45 * particular elements. | |
46 * | |
47 * | |
48 author: Doug Lea | |
49 * @version 0.93 | |
50 * | |
51 * <P> For an introduction to this package see <A HREF="index.html"> Overview </A>. | |
52 **/ | |
53 | |
54 public class ArrayBag(T) : BagCollection!(T) | |
55 { | |
56 alias CLCell!(T[]) CLCellT; | |
57 | |
58 alias BagCollection!(T).remove remove; | |
59 alias BagCollection!(T).removeAll removeAll; | |
60 | |
61 /** | |
62 * The default chunk size to use for buffers | |
63 **/ | |
64 | |
65 public static int defaultChunkSize = 32; | |
66 | |
67 // instance variables | |
68 | |
69 /** | |
70 * The last node of the circular list of chunks. Null if empty. | |
71 **/ | |
72 | |
73 package CLCellT tail; | |
74 | |
75 /** | |
76 * The number of elements of the tail node actually used. (all others | |
77 * are kept full). | |
78 **/ | |
79 protected int lastCount; | |
80 | |
81 /** | |
82 * The chunk size to use for making next buffer | |
83 **/ | |
84 | |
85 protected int chunkSize_; | |
86 | |
87 // constructors | |
88 | |
89 /** | |
90 * Make an empty buffer. | |
91 **/ | |
92 public this () | |
93 { | |
94 this (null, 0, null, 0, defaultChunkSize); | |
95 } | |
96 | |
97 /** | |
98 * Make an empty buffer, using the supplied element screener. | |
99 **/ | |
100 | |
101 public this (Predicate s) | |
102 { | |
103 this (s, 0, null, 0, defaultChunkSize); | |
104 } | |
105 | |
106 /** | |
107 * Special version of constructor needed by clone() | |
108 **/ | |
109 protected this (Predicate s, int n, CLCellT t, int lc, int cs) | |
110 { | |
111 super (s); | |
112 count = n; | |
113 tail = t; | |
114 lastCount = lc; | |
115 chunkSize_ = cs; | |
116 } | |
117 | |
118 /** | |
119 * Make an independent copy. Does not clone elements. | |
120 **/ | |
121 | |
122 public final ArrayBag duplicate () | |
123 { | |
124 if (count is 0) | |
125 return new ArrayBag (screener); | |
126 else | |
127 { | |
128 CLCellT h = tail.copyList(); | |
129 CLCellT p = h; | |
130 | |
131 do { | |
132 T[] obuff = p.element(); | |
133 T[] nbuff = new T[obuff.length]; | |
134 | |
135 for (int i = 0; i < obuff.length; ++i) | |
136 nbuff[i] = obuff[i]; | |
137 | |
138 p.element(nbuff); | |
139 p = p.next(); | |
140 } while (p !is h); | |
141 | |
142 return new ArrayBag (screener, count, h, lastCount, chunkSize_); | |
143 } | |
144 } | |
145 | |
146 | |
147 /** | |
148 * Report the chunk size used when adding new buffers to the list | |
149 **/ | |
150 | |
151 public final int chunkSize() | |
152 { | |
153 return chunkSize_; | |
154 } | |
155 | |
156 /** | |
157 * Set the chunk size to be used when adding new buffers to the | |
158 * list during future add() operations. | |
159 * Any value greater than 0 is OK. (A value of 1 makes this a | |
160 * into very slow simulation of a linked list!) | |
161 **/ | |
162 | |
163 public final void chunkSize (int newChunkSize) | |
164 { | |
165 if (newChunkSize > 0) | |
166 chunkSize_ = newChunkSize; | |
167 else | |
168 throw new IllegalArgumentException("Attempt to set negative chunk size value"); | |
169 } | |
170 | |
171 // Collection methods | |
172 | |
173 /* | |
174 This code is pretty repetitive, but I don't know a nice way to | |
175 separate traversal logic from actions | |
176 */ | |
177 | |
178 /** | |
179 * Implements tango.util.collection.impl.Collection.Collection.contains | |
180 * Time complexity: O(n). | |
181 * See_Also: tango.util.collection.impl.Collection.Collection.contains | |
182 **/ | |
183 public final bool contains(T element) | |
184 { | |
185 if (!isValidArg(element) || count is 0) | |
186 return false; | |
187 | |
188 CLCellT p = tail.next(); | |
189 | |
190 for (;;) | |
191 { | |
192 T[] buff = p.element(); | |
193 bool isLast = p is tail; | |
194 | |
195 int n; | |
196 if (isLast) | |
197 n = lastCount; | |
198 else | |
199 n = buff.length; | |
200 | |
201 for (int i = 0; i < n; ++i) | |
202 { | |
203 if (buff[i] == (element)) | |
204 return true; | |
205 } | |
206 | |
207 if (isLast) | |
208 break; | |
209 else | |
210 p = p.next(); | |
211 } | |
212 return false; | |
213 } | |
214 | |
215 /** | |
216 * Implements tango.util.collection.impl.Collection.Collection.instances | |
217 * Time complexity: O(n). | |
218 * See_Also: tango.util.collection.impl.Collection.instances | |
219 **/ | |
220 public final uint instances(T element) | |
221 { | |
222 if (!isValidArg(element) || count is 0) | |
223 return 0; | |
224 | |
225 uint c = 0; | |
226 CLCellT p = tail.next(); | |
227 | |
228 for (;;) | |
229 { | |
230 T[] buff = p.element(); | |
231 bool isLast = p is tail; | |
232 | |
233 int n; | |
234 if (isLast) | |
235 n = lastCount; | |
236 else | |
237 n = buff.length; | |
238 | |
239 for (int i = 0; i < n; ++i) | |
240 { | |
241 if (buff[i] == (element)) | |
242 ++c; | |
243 } | |
244 | |
245 if (isLast) | |
246 break; | |
247 else | |
248 p = p.next(); | |
249 } | |
250 return c; | |
251 } | |
252 | |
253 /** | |
254 * Implements tango.util.collection.impl.Collection.Collection.elements | |
255 * Time complexity: O(1). | |
256 * See_Also: tango.util.collection.impl.Collection.Collection.elements | |
257 **/ | |
258 public final GuardIterator!(T) elements() | |
259 { | |
260 return new ArrayIterator!(T)(this); | |
261 } | |
262 | |
263 /** | |
264 * Implements tango.util.collection.model.View.View.opApply | |
265 * Time complexity: O(n). | |
266 * See_Also: tango.util.collection.model.View.View.opApply | |
267 **/ | |
268 int opApply (int delegate (inout T value) dg) | |
269 { | |
270 auto scope iterator = new ArrayIterator!(T)(this); | |
271 return iterator.opApply (dg); | |
272 } | |
273 | |
274 // MutableCollection methods | |
275 | |
276 /** | |
277 * Implements tango.util.collection.impl.Collection.Collection.clear. | |
278 * Time complexity: O(1). | |
279 * See_Also: tango.util.collection.impl.Collection.Collection.clear | |
280 **/ | |
281 public final void clear() | |
282 { | |
283 setCount(0); | |
284 tail = null; | |
285 lastCount = 0; | |
286 } | |
287 | |
288 /** | |
289 * Implements tango.util.collection.impl.Collection.Collection.removeAll. | |
290 * Time complexity: O(n). | |
291 * See_Also: tango.util.collection.impl.Collection.Collection.removeAll | |
292 **/ | |
293 public final void removeAll (T element) | |
294 { | |
295 remove_(element, true); | |
296 } | |
297 | |
298 | |
299 /** | |
300 * Implements tango.util.collection.impl.Collection.Collection.removeOneOf. | |
301 * Time complexity: O(n). | |
302 * See_Also: tango.util.collection.impl.Collection.Collection.removeOneOf | |
303 **/ | |
304 public final void remove(T element) | |
305 { | |
306 remove_(element, false); | |
307 } | |
308 | |
309 /** | |
310 * Implements tango.util.collection.impl.Collection.Collection.replaceOneOf | |
311 * Time complexity: O(n). | |
312 * See_Also: tango.util.collection.impl.Collection.Collection.replaceOneOf | |
313 **/ | |
314 public final void replace(T oldElement, T newElement) | |
315 { | |
316 replace_(oldElement, newElement, false); | |
317 } | |
318 | |
319 /** | |
320 * Implements tango.util.collection.impl.Collection.Collection.replaceAllOf. | |
321 * Time complexity: O(n). | |
322 * See_Also: tango.util.collection.impl.Collection.Collection.replaceAllOf | |
323 **/ | |
324 public final void replaceAll(T oldElement, T newElement) | |
325 { | |
326 replace_(oldElement, newElement, true); | |
327 } | |
328 | |
329 /** | |
330 * Implements tango.util.collection.impl.Collection.Collection.take. | |
331 * Time complexity: O(1). | |
332 * Takes the least element. | |
333 * See_Also: tango.util.collection.impl.Collection.Collection.take | |
334 **/ | |
335 public final T take() | |
336 { | |
337 if (count !is 0) | |
338 { | |
339 T[] buff = tail.element(); | |
340 T v = buff[lastCount -1]; | |
341 buff[lastCount -1] = T.init; | |
342 shrink_(); | |
343 return v; | |
344 } | |
345 checkIndex(0); | |
346 return T.init; // not reached | |
347 } | |
348 | |
349 | |
350 | |
351 // MutableBag methods | |
352 | |
353 /** | |
354 * Implements tango.util.collection.MutableBag.addIfAbsent. | |
355 * Time complexity: O(n). | |
356 * See_Also: tango.util.collection.MutableBag.addIfAbsent | |
357 **/ | |
358 public final void addIf(T element) | |
359 { | |
360 if (!contains(element)) | |
361 add (element); | |
362 } | |
363 | |
364 | |
365 /** | |
366 * Implements tango.util.collection.MutableBag.add. | |
367 * Time complexity: O(1). | |
368 * See_Also: tango.util.collection.MutableBag.add | |
369 **/ | |
370 public final void add (T element) | |
371 { | |
372 checkElement(element); | |
373 | |
374 incCount(); | |
375 if (tail is null) | |
376 { | |
377 tail = new CLCellT(new T[chunkSize_]); | |
378 lastCount = 0; | |
379 } | |
380 | |
381 T[] buff = tail.element(); | |
382 if (lastCount is buff.length) | |
383 { | |
384 buff = new T[chunkSize_]; | |
385 tail.addNext(buff); | |
386 tail = tail.next(); | |
387 lastCount = 0; | |
388 } | |
389 | |
390 buff[lastCount++] = element; | |
391 } | |
392 | |
393 /** | |
394 * helper for remove/exclude | |
395 **/ | |
396 | |
397 private final void remove_(T element, bool allOccurrences) | |
398 { | |
399 if (!isValidArg(element) || count is 0) | |
400 return ; | |
401 | |
402 CLCellT p = tail; | |
403 | |
404 for (;;) | |
405 { | |
406 T[] buff = p.element(); | |
407 int i = (p is tail) ? lastCount - 1 : buff.length - 1; | |
408 | |
409 while (i >= 0) | |
410 { | |
411 if (buff[i] == (element)) | |
412 { | |
413 T[] lastBuff = tail.element(); | |
414 buff[i] = lastBuff[lastCount -1]; | |
415 lastBuff[lastCount -1] = T.init; | |
416 shrink_(); | |
417 | |
418 if (!allOccurrences || count is 0) | |
419 return ; | |
420 | |
421 if (p is tail && i >= lastCount) | |
422 i = lastCount -1; | |
423 } | |
424 else | |
425 --i; | |
426 } | |
427 | |
428 if (p is tail.next()) | |
429 break; | |
430 else | |
431 p = p.prev(); | |
432 } | |
433 } | |
434 | |
435 private final void replace_(T oldElement, T newElement, bool allOccurrences) | |
436 { | |
437 if (!isValidArg(oldElement) || count is 0 || oldElement == (newElement)) | |
438 return ; | |
439 | |
440 CLCellT p = tail.next(); | |
441 | |
442 for (;;) | |
443 { | |
444 T[] buff = p.element(); | |
445 bool isLast = p is tail; | |
446 | |
447 int n; | |
448 if (isLast) | |
449 n = lastCount; | |
450 else | |
451 n = buff.length; | |
452 | |
453 for (int i = 0; i < n; ++i) | |
454 { | |
455 if (buff[i] == (oldElement)) | |
456 { | |
457 checkElement(newElement); | |
458 incVersion(); | |
459 buff[i] = newElement; | |
460 if (!allOccurrences) | |
461 return ; | |
462 } | |
463 } | |
464 | |
465 if (isLast) | |
466 break; | |
467 else | |
468 p = p.next(); | |
469 } | |
470 } | |
471 | |
472 private final void shrink_() | |
473 { | |
474 decCount(); | |
475 lastCount--; | |
476 if (lastCount is 0) | |
477 { | |
478 if (count is 0) | |
479 clear(); | |
480 else | |
481 { | |
482 CLCellT tmp = tail; | |
483 tail = tail.prev(); | |
484 tmp.unlink(); | |
485 T[] buff = tail.element(); | |
486 lastCount = buff.length; | |
487 } | |
488 } | |
489 } | |
490 | |
491 // ImplementationCheckable methods | |
492 | |
493 /** | |
494 * Implements tango.util.collection.model.View.View.checkImplementation. | |
495 * See_Also: tango.util.collection.model.View.View.checkImplementation | |
496 **/ | |
497 public override void checkImplementation() | |
498 { | |
499 | |
500 super.checkImplementation(); | |
501 assert(chunkSize_ >= 0); | |
502 assert(lastCount >= 0); | |
503 assert(((count is 0) is (tail is null))); | |
504 | |
505 if (tail is null) | |
506 return ; | |
507 | |
508 int c = 0; | |
509 CLCellT p = tail.next(); | |
510 | |
511 for (;;) | |
512 { | |
513 T[] buff = p.element(); | |
514 bool isLast = p is tail; | |
515 | |
516 int n; | |
517 if (isLast) | |
518 n = lastCount; | |
519 else | |
520 n = buff.length; | |
521 | |
522 c += n; | |
523 for (int i = 0; i < n; ++i) | |
524 { | |
525 auto v = buff[i]; | |
526 assert(allows(v) && contains(v)); | |
527 } | |
528 | |
529 if (isLast) | |
530 break; | |
531 else | |
532 p = p.next(); | |
533 } | |
534 | |
535 assert(c is count); | |
536 | |
537 } | |
538 | |
539 | |
540 | |
541 /*********************************************************************** | |
542 | |
543 opApply() has migrated here to mitigate the virtual call | |
544 on method get() | |
545 | |
546 ************************************************************************/ | |
547 | |
548 static class ArrayIterator(T) : AbstractIterator!(T) | |
549 { | |
550 private CLCellT cell; | |
551 private T[] buff; | |
552 private int index; | |
553 | |
554 public this (ArrayBag bag) | |
555 { | |
556 super(bag); | |
557 cell = bag.tail; | |
558 | |
559 if (cell) | |
560 buff = cell.element(); | |
561 } | |
562 | |
563 public final T get() | |
564 { | |
565 decRemaining(); | |
566 if (index >= buff.length) | |
567 { | |
568 cell = cell.next(); | |
569 buff = cell.element(); | |
570 index = 0; | |
571 } | |
572 return buff[index++]; | |
573 } | |
574 | |
575 int opApply (int delegate (inout T value) dg) | |
576 { | |
577 int result; | |
578 | |
579 for (auto i=remaining(); i--;) | |
580 { | |
581 auto value = get(); | |
582 if ((result = dg(value)) != 0) | |
583 break; | |
584 } | |
585 return result; | |
586 } | |
587 } | |
588 } | |
589 | |
590 | |
591 | |
592 | |
593 debug (Test) | |
594 { | |
595 import tango.io.Console; | |
596 | |
597 void main() | |
598 { | |
599 auto bag = new ArrayBag!(char[]); | |
600 bag.add ("foo"); | |
601 bag.add ("bar"); | |
602 bag.add ("wumpus"); | |
603 | |
604 foreach (value; bag.elements) {} | |
605 | |
606 auto elements = bag.elements(); | |
607 while (elements.more) | |
608 auto v = elements.get(); | |
609 | |
610 foreach (value; bag) | |
611 Cout (value).newline; | |
612 | |
613 bag.checkImplementation(); | |
614 | |
615 Cout (bag).newline; | |
616 } | |
617 } |