Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(447)

Side by Side Diff: test/generated_sdk/lib/collection/queue.dart

Issue 1162723007: remove generated_sdk from checked in code (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « test/generated_sdk/lib/collection/maps.dart ('k') | test/generated_sdk/lib/collection/set.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.collection;
6
7 /**
8 * A [Queue] is a collection that can be manipulated at both ends. One
9 * can iterate over the elements of a queue through [forEach] or with
10 * an [Iterator].
11 *
12 * It is generally not allowed to modify the queue (add or remove entries) while
13 * an operation on the queue is being performed, for example during a call to
14 * [forEach].
15 * Modifying the queue while it is being iterated will most likely break the
16 * iteration.
17 * This goes both for using the [iterator] directly, or for iterating an
18 * `Iterable` returned by a method like [map] or [where].
19 */
20 abstract class Queue<E> implements Iterable<E>, EfficientLength {
21
22 /**
23 * Creates a queue.
24 */
25 factory Queue() = ListQueue<E>;
26
27 /**
28 * Creates a queue containing all [elements].
29 *
30 * The element order in the queue is as if the elements were added using
31 * [addLast] in the order provided by [elements.iterator].
32 */
33 factory Queue.from(Iterable elements) = ListQueue<E>.from;
34
35 /**
36 * Removes and returns the first element of this queue.
37 *
38 * The queue must not be empty when this method is called.
39 */
40 E removeFirst();
41
42 /**
43 * Removes and returns the last element of the queue.
44 *
45 * The queue must not be empty when this method is called.
46 */
47 E removeLast();
48
49 /**
50 * Adds [value] at the beginning of the queue.
51 */
52 void addFirst(E value);
53
54 /**
55 * Adds [value] at the end of the queue.
56 */
57 void addLast(E value);
58
59 /**
60 * Adds [value] at the end of the queue.
61 */
62 void add(E value);
63
64 /**
65 * Remove a single instance of [value] from the queue.
66 *
67 * Returns `true` if a value was removed, or `false` if the queue
68 * contained no element equal to [value].
69 */
70 bool remove(Object object);
71
72 /**
73 * Adds all elements of [iterable] at the end of the queue. The
74 * length of the queue is extended by the length of [iterable].
75 */
76 void addAll(Iterable<E> iterable);
77
78 /**
79 * Removes all elements matched by [test] from the queue.
80 *
81 * The `test` function must not throw or modify the queue.
82 */
83 void removeWhere(bool test(E element));
84
85 /**
86 * Removes all elements not matched by [test] from the queue.
87 *
88 * The `test` function must not throw or modify the queue.
89 */
90 void retainWhere(bool test(E element));
91
92 /**
93 * Removes all elements in the queue. The size of the queue becomes zero.
94 */
95 void clear();
96 }
97
98
99 /**
100 * An entry in a doubly linked list. It contains a pointer to the next
101 * entry, the previous entry, and the boxed element.
102 */
103 class DoubleLinkedQueueEntry<E> {
104 DoubleLinkedQueueEntry<E> _previous;
105 DoubleLinkedQueueEntry<E> _next;
106 E _element;
107
108 DoubleLinkedQueueEntry(E e) : _element = e;
109
110 void _link(DoubleLinkedQueueEntry<E> previous,
111 DoubleLinkedQueueEntry<E> next) {
112 _next = next;
113 _previous = previous;
114 previous._next = this;
115 next._previous = this;
116 }
117
118 void append(E e) {
119 new DoubleLinkedQueueEntry<E>(e)._link(this, _next);
120 }
121
122 void prepend(E e) {
123 new DoubleLinkedQueueEntry<E>(e)._link(_previous, this);
124 }
125
126 E remove() {
127 _previous._next = _next;
128 _next._previous = _previous;
129 _next = null;
130 _previous = null;
131 return _element;
132 }
133
134 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() {
135 return this;
136 }
137
138 DoubleLinkedQueueEntry<E> previousEntry() {
139 return _previous._asNonSentinelEntry();
140 }
141
142 DoubleLinkedQueueEntry<E> nextEntry() {
143 return _next._asNonSentinelEntry();
144 }
145
146 E get element {
147 return _element;
148 }
149
150 void set element(E e) {
151 _element = e;
152 }
153 }
154
155 /**
156 * A sentinel in a double linked list is used to manipulate the list
157 * at both ends.
158 * A double linked list has exactly one sentinel,
159 * which is the only entry when the list is constructed.
160 * Initially, a sentinel has its next and previous entry point to itself.
161 * A sentinel does not box any user element.
162 */
163 class _DoubleLinkedQueueEntrySentinel<E> extends DoubleLinkedQueueEntry<E> {
164 _DoubleLinkedQueueEntrySentinel() : super(null) {
165 _link(this, this);
166 }
167
168 E remove() {
169 throw IterableElementError.noElement();
170 }
171
172 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() {
173 return null;
174 }
175
176 void set element(E e) {
177 // This setter is unreachable.
178 // TODO(lrn): Don't inherit the field if we don't use it.
179 assert(false);
180 }
181
182 E get element {
183 throw IterableElementError.noElement();
184 }
185 }
186
187 /**
188 * A [Queue] implementation based on a double-linked list.
189 *
190 * Allows constant time add, remove-at-ends and peek operations.
191 */
192 class DoubleLinkedQueue<E> extends IterableBase<E> implements Queue<E> {
193 _DoubleLinkedQueueEntrySentinel<E> _sentinel;
194 int _elementCount = 0;
195
196 DoubleLinkedQueue() {
197 _sentinel = new _DoubleLinkedQueueEntrySentinel<E>();
198 }
199
200 /**
201 * Creates a double-linked queue containing all [elements].
202 *
203 * The element order in the queue is as if the elements were added using
204 * [addLast] in the order provided by [elements.iterator].
205 */
206 factory DoubleLinkedQueue.from(Iterable elements) {
207 Queue<E> list = new DoubleLinkedQueue();
208 for (final E e in elements) {
209 list.addLast(e);
210 }
211 return list;
212 }
213
214 int get length => _elementCount;
215
216 void addLast(E value) {
217 _sentinel.prepend(value);
218 _elementCount++;
219 }
220
221 void addFirst(E value) {
222 _sentinel.append(value);
223 _elementCount++;
224 }
225
226 void add(E value) {
227 _sentinel.prepend(value);
228 _elementCount++;
229 }
230
231 void addAll(Iterable<E> iterable) {
232 for (final E value in iterable) {
233 _sentinel.prepend(value);
234 _elementCount++;
235 }
236 }
237
238 E removeLast() {
239 E result = _sentinel._previous.remove();
240 _elementCount--;
241 return result;
242 }
243
244 E removeFirst() {
245 E result = _sentinel._next.remove();
246 _elementCount--;
247 return result;
248 }
249
250 bool remove(Object o) {
251 DoubleLinkedQueueEntry<E> entry = _sentinel._next;
252 while (!identical(entry, _sentinel)) {
253 if (entry.element == o) {
254 entry.remove();
255 _elementCount--;
256 return true;
257 }
258 entry = entry._next;
259 }
260 return false;
261 }
262
263 void _filter(bool test(E element), bool removeMatching) {
264 DoubleLinkedQueueEntry<E> entry = _sentinel._next;
265 while (!identical(entry, _sentinel)) {
266 DoubleLinkedQueueEntry<E> next = entry._next;
267 if (identical(removeMatching, test(entry.element))) {
268 entry.remove();
269 _elementCount--;
270 }
271 entry = next;
272 }
273 }
274
275 void removeWhere(bool test(E element)) {
276 _filter(test, true);
277 }
278
279 void retainWhere(bool test(E element)) {
280 _filter(test, false);
281 }
282
283 E get first {
284 return _sentinel._next.element;
285 }
286
287 E get last {
288 return _sentinel._previous.element;
289 }
290
291 E get single {
292 // Note that this throws correctly if the queue is empty.
293 if (identical(_sentinel._next, _sentinel._previous)) {
294 return _sentinel._next.element;
295 }
296 throw IterableElementError.tooMany();
297 }
298
299 DoubleLinkedQueueEntry<E> lastEntry() {
300 return _sentinel.previousEntry();
301 }
302
303 DoubleLinkedQueueEntry<E> firstEntry() {
304 return _sentinel.nextEntry();
305 }
306
307 bool get isEmpty {
308 return (identical(_sentinel._next, _sentinel));
309 }
310
311 void clear() {
312 _sentinel._next = _sentinel;
313 _sentinel._previous = _sentinel;
314 _elementCount = 0;
315 }
316
317 void forEachEntry(void f(DoubleLinkedQueueEntry<E> element)) {
318 DoubleLinkedQueueEntry<E> entry = _sentinel._next;
319 while (!identical(entry, _sentinel)) {
320 DoubleLinkedQueueEntry<E> nextEntry = entry._next;
321 f(entry);
322 entry = nextEntry;
323 }
324 }
325
326 _DoubleLinkedQueueIterator<E> get iterator {
327 return new _DoubleLinkedQueueIterator<E>(_sentinel);
328 }
329
330 String toString() => IterableBase.iterableToFullString(this, '{', '}');
331 }
332
333 class _DoubleLinkedQueueIterator<E> implements Iterator<E> {
334 _DoubleLinkedQueueEntrySentinel<E> _sentinel;
335 DoubleLinkedQueueEntry<E> _nextEntry = null;
336 E _current;
337
338 _DoubleLinkedQueueIterator(_DoubleLinkedQueueEntrySentinel<E> sentinel)
339 : _sentinel = sentinel, _nextEntry = sentinel._next;
340
341 bool moveNext() {
342 // When [_currentEntry] it is set to [:null:] then it is at the end.
343 if (!identical(_nextEntry, _sentinel)) {
344 _current = _nextEntry._element;
345 _nextEntry = _nextEntry._next;
346 return true;
347 }
348 _current = null;
349 _nextEntry = _sentinel = null; // Still identical.
350 return false;
351 }
352
353 E get current => _current;
354 }
355
356 /**
357 * List based [Queue].
358 *
359 * Keeps a cyclic buffer of elements, and grows to a larger buffer when
360 * it fills up. This guarantees constant time peek and remove operations, and
361 * amortized constant time add operations.
362 *
363 * The structure is efficient for any queue or stack usage.
364 */
365 class ListQueue<E> extends IterableBase<E> implements Queue<E> {
366 static const int _INITIAL_CAPACITY = 8;
367 List<E> _table;
368 int _head;
369 int _tail;
370 int _modificationCount = 0;
371
372 /**
373 * Create an empty queue.
374 *
375 * If [initialCapacity] is given, prepare the queue for at least that many
376 * elements.
377 */
378 ListQueue([int initialCapacity]) : _head = 0, _tail = 0 {
379 if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) {
380 initialCapacity = _INITIAL_CAPACITY;
381 } else if (!_isPowerOf2(initialCapacity)) {
382 initialCapacity = _nextPowerOf2(initialCapacity);
383 }
384 assert(_isPowerOf2(initialCapacity));
385 _table = new List<E>(initialCapacity);
386 }
387
388 /**
389 * Create a `ListQueue` containing all [elements].
390 *
391 * The elements are added to the queue, as by [addLast], in the order given by
392 * `elements.iterator`.
393 *
394 * All `elements` should be assignable to [E].
395 */
396 factory ListQueue.from(Iterable elements) {
397 if (elements is List) {
398 int length = elements.length;
399 ListQueue<E> queue = new ListQueue(length + 1);
400 assert(queue._table.length > length);
401 List sourceList = elements;
402 queue._table.setRange(0, length, sourceList, 0);
403 queue._tail = length;
404 return queue;
405 } else {
406 int capacity = _INITIAL_CAPACITY;
407 if (elements is EfficientLength) {
408 capacity = elements.length;
409 }
410 ListQueue<E> result = new ListQueue<E>(capacity);
411 for (final E element in elements) {
412 result.addLast(element);
413 }
414 return result;
415 }
416 }
417
418 // Iterable interface.
419
420 Iterator<E> get iterator => new _ListQueueIterator<E>(this);
421
422 void forEach(void action (E element)) {
423 int modificationCount = _modificationCount;
424 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
425 action(_table[i]);
426 _checkModification(modificationCount);
427 }
428 }
429
430 bool get isEmpty => _head == _tail;
431
432 int get length => (_tail - _head) & (_table.length - 1);
433
434 E get first {
435 if (_head == _tail) throw IterableElementError.noElement();
436 return _table[_head];
437 }
438
439 E get last {
440 if (_head == _tail) throw IterableElementError.noElement();
441 return _table[(_tail - 1) & (_table.length - 1)];
442 }
443
444 E get single {
445 if (_head == _tail) throw IterableElementError.noElement();
446 if (length > 1) throw IterableElementError.tooMany();
447 return _table[_head];
448 }
449
450 E elementAt(int index) {
451 RangeError.checkValidIndex(index, this);
452 return _table[(_head + index) & (_table.length - 1)];
453 }
454
455 List<E> toList({ bool growable: true }) {
456 List<E> list;
457 if (growable) {
458 list = new List<E>()..length = length;
459 } else {
460 list = new List<E>(length);
461 }
462 _writeToList(list);
463 return list;
464 }
465
466 // Collection interface.
467
468 void add(E element) {
469 _add(element);
470 }
471
472 void addAll(Iterable<E> elements) {
473 if (elements is List) {
474 List list = elements;
475 int addCount = list.length;
476 int length = this.length;
477 if (length + addCount >= _table.length) {
478 _preGrow(length + addCount);
479 // After preGrow, all elements are at the start of the list.
480 _table.setRange(length, length + addCount, list, 0);
481 _tail += addCount;
482 } else {
483 // Adding addCount elements won't reach _head.
484 int endSpace = _table.length - _tail;
485 if (addCount < endSpace) {
486 _table.setRange(_tail, _tail + addCount, list, 0);
487 _tail += addCount;
488 } else {
489 int preSpace = addCount - endSpace;
490 _table.setRange(_tail, _tail + endSpace, list, 0);
491 _table.setRange(0, preSpace, list, endSpace);
492 _tail = preSpace;
493 }
494 }
495 _modificationCount++;
496 } else {
497 for (E element in elements) _add(element);
498 }
499 }
500
501 bool remove(Object object) {
502 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
503 E element = _table[i];
504 if (element == object) {
505 _remove(i);
506 _modificationCount++;
507 return true;
508 }
509 }
510 return false;
511 }
512
513 void _filterWhere(bool test(E element), bool removeMatching) {
514 int index = _head;
515 int modificationCount = _modificationCount;
516 int i = _head;
517 while (i != _tail) {
518 E element = _table[i];
519 bool remove = identical(removeMatching, test(element));
520 _checkModification(modificationCount);
521 if (remove) {
522 i = _remove(i);
523 modificationCount = ++_modificationCount;
524 } else {
525 i = (i + 1) & (_table.length - 1);
526 }
527 }
528 }
529
530 /**
531 * Remove all elements matched by [test].
532 *
533 * This method is inefficient since it works by repeatedly removing single
534 * elements, each of which can take linear time.
535 */
536 void removeWhere(bool test(E element)) {
537 _filterWhere(test, true);
538 }
539
540 /**
541 * Remove all elements not matched by [test].
542 *
543 * This method is inefficient since it works by repeatedly removing single
544 * elements, each of which can take linear time.
545 */
546 void retainWhere(bool test(E element)) {
547 _filterWhere(test, false);
548 }
549
550 void clear() {
551 if (_head != _tail) {
552 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) {
553 _table[i] = null;
554 }
555 _head = _tail = 0;
556 _modificationCount++;
557 }
558 }
559
560 String toString() => IterableBase.iterableToFullString(this, "{", "}");
561
562 // Queue interface.
563
564 void addLast(E element) { _add(element); }
565
566 void addFirst(E element) {
567 _head = (_head - 1) & (_table.length - 1);
568 _table[_head] = element;
569 if (_head == _tail) _grow();
570 _modificationCount++;
571 }
572
573 E removeFirst() {
574 if (_head == _tail) throw IterableElementError.noElement();
575 _modificationCount++;
576 E result = _table[_head];
577 _table[_head] = null;
578 _head = (_head + 1) & (_table.length - 1);
579 return result;
580 }
581
582 E removeLast() {
583 if (_head == _tail) throw IterableElementError.noElement();
584 _modificationCount++;
585 _tail = (_tail - 1) & (_table.length - 1);
586 E result = _table[_tail];
587 _table[_tail] = null;
588 return result;
589 }
590
591 // Internal helper functions.
592
593 /**
594 * Whether [number] is a power of two.
595 *
596 * Only works for positive numbers.
597 */
598 static bool _isPowerOf2(int number) => (number & (number - 1)) == 0;
599
600 /**
601 * Rounds [number] up to the nearest power of 2.
602 *
603 * If [number] is a power of 2 already, it is returned.
604 *
605 * Only works for positive numbers.
606 */
607 static int _nextPowerOf2(int number) {
608 assert(number > 0);
609 number = (number << 1) - 1;
610 for(;;) {
611 int nextNumber = number & (number - 1);
612 if (nextNumber == 0) return number;
613 number = nextNumber;
614 }
615 }
616
617 /** Check if the queue has been modified during iteration. */
618 void _checkModification(int expectedModificationCount) {
619 if (expectedModificationCount != _modificationCount) {
620 throw new ConcurrentModificationError(this);
621 }
622 }
623
624 /** Adds element at end of queue. Used by both [add] and [addAll]. */
625 void _add(E element) {
626 _table[_tail] = element;
627 _tail = (_tail + 1) & (_table.length - 1);
628 if (_head == _tail) _grow();
629 _modificationCount++;
630 }
631
632 /**
633 * Removes the element at [offset] into [_table].
634 *
635 * Removal is performed by linerarly moving elements either before or after
636 * [offset] by one position.
637 *
638 * Returns the new offset of the following element. This may be the same
639 * offset or the following offset depending on how elements are moved
640 * to fill the hole.
641 */
642 int _remove(int offset) {
643 int mask = _table.length - 1;
644 int startDistance = (offset - _head) & mask;
645 int endDistance = (_tail - offset) & mask;
646 if (startDistance < endDistance) {
647 // Closest to start.
648 int i = offset;
649 while (i != _head) {
650 int prevOffset = (i - 1) & mask;
651 _table[i] = _table[prevOffset];
652 i = prevOffset;
653 }
654 _table[_head] = null;
655 _head = (_head + 1) & mask;
656 return (offset + 1) & mask;
657 } else {
658 _tail = (_tail - 1) & mask;
659 int i = offset;
660 while (i != _tail) {
661 int nextOffset = (i + 1) & mask;
662 _table[i] = _table[nextOffset];
663 i = nextOffset;
664 }
665 _table[_tail] = null;
666 return offset;
667 }
668 }
669
670 /**
671 * Grow the table when full.
672 */
673 void _grow() {
674 List<E> newTable = new List<E>(_table.length * 2);
675 int split = _table.length - _head;
676 newTable.setRange(0, split, _table, _head);
677 newTable.setRange(split, split + _head, _table, 0);
678 _head = 0;
679 _tail = _table.length;
680 _table = newTable;
681 }
682
683 int _writeToList(List<E> target) {
684 assert(target.length >= length);
685 if (_head <= _tail) {
686 int length = _tail - _head;
687 target.setRange(0, length, _table, _head);
688 return length;
689 } else {
690 int firstPartSize = _table.length - _head;
691 target.setRange(0, firstPartSize, _table, _head);
692 target.setRange(firstPartSize, firstPartSize + _tail, _table, 0);
693 return _tail + firstPartSize;
694 }
695 }
696
697 /** Grows the table even if it is not full. */
698 void _preGrow(int newElementCount) {
699 assert(newElementCount >= length);
700
701 // Add some extra room to ensure that there's room for more elements after
702 // expansion.
703 newElementCount += newElementCount >> 1;
704 int newCapacity = _nextPowerOf2(newElementCount);
705 List<E> newTable = new List<E>(newCapacity);
706 _tail = _writeToList(newTable);
707 _table = newTable;
708 _head = 0;
709 }
710 }
711
712 /**
713 * Iterator for a [ListQueue].
714 *
715 * Considers any add or remove operation a concurrent modification.
716 */
717 class _ListQueueIterator<E> implements Iterator<E> {
718 final ListQueue _queue;
719 final int _end;
720 final int _modificationCount;
721 int _position;
722 E _current;
723
724 _ListQueueIterator(ListQueue queue)
725 : _queue = queue,
726 _end = queue._tail,
727 _modificationCount = queue._modificationCount,
728 _position = queue._head;
729
730 E get current => _current;
731
732 bool moveNext() {
733 _queue._checkModification(_modificationCount);
734 if (_position == _end) {
735 _current = null;
736 return false;
737 }
738 _current = _queue._table[_position];
739 _position = (_position + 1) & (_queue._table.length - 1);
740 return true;
741 }
742 }
OLDNEW
« no previous file with comments | « test/generated_sdk/lib/collection/maps.dart ('k') | test/generated_sdk/lib/collection/set.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698