Index: mojo/public/dart/third_party/collection/lib/src/queue_list.dart |
diff --git a/mojo/public/dart/third_party/collection/lib/src/queue_list.dart b/mojo/public/dart/third_party/collection/lib/src/queue_list.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0ef888f9c1fb9f666f8463e5d4c0b2925b2e0803 |
--- /dev/null |
+++ b/mojo/public/dart/third_party/collection/lib/src/queue_list.dart |
@@ -0,0 +1,231 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+import 'dart:collection'; |
+ |
+/** |
+ * A class that efficiently implements both [Queue] and [List]. |
+ */ |
+// TODO(nweiz): Currently this code is copied almost verbatim from |
+// dart:collection. The only changes are to implement List and to remove methods |
+// that are redundant with ListMixin. Remove or simplify it when issue 21330 is |
+// fixed. |
+class QueueList<E> extends Object with ListMixin<E> implements Queue<E> { |
+ static const int _INITIAL_CAPACITY = 8; |
+ List<E> _table; |
+ int _head; |
+ int _tail; |
+ |
+ /** |
+ * Create an empty queue. |
+ * |
+ * If [initialCapacity] is given, prepare the queue for at least that many |
+ * elements. |
+ */ |
+ QueueList([int initialCapacity]) : _head = 0, _tail = 0 { |
+ if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) { |
+ initialCapacity = _INITIAL_CAPACITY; |
+ } else if (!_isPowerOf2(initialCapacity)) { |
+ initialCapacity = _nextPowerOf2(initialCapacity); |
+ } |
+ assert(_isPowerOf2(initialCapacity)); |
+ _table = new List<E>(initialCapacity); |
+ } |
+ |
+ /** |
+ * Create a queue initially containing the elements of [source]. |
+ */ |
+ factory QueueList.from(Iterable<E> source) { |
+ if (source is List) { |
+ int length = source.length; |
+ QueueList<E> queue = new QueueList(length + 1); |
+ assert(queue._table.length > length); |
+ List sourceList = source; |
+ queue._table.setRange(0, length, sourceList, 0); |
+ queue._tail = length; |
+ return queue; |
+ } else { |
+ return new QueueList<E>()..addAll(source); |
+ } |
+ } |
+ |
+ // Collection interface. |
+ |
+ void add(E element) { |
+ _add(element); |
+ } |
+ |
+ void addAll(Iterable<E> elements) { |
+ if (elements is List) { |
+ List list = elements; |
+ int addCount = list.length; |
+ int length = this.length; |
+ if (length + addCount >= _table.length) { |
+ _preGrow(length + addCount); |
+ // After preGrow, all elements are at the start of the list. |
+ _table.setRange(length, length + addCount, list, 0); |
+ _tail += addCount; |
+ } else { |
+ // Adding addCount elements won't reach _head. |
+ int endSpace = _table.length - _tail; |
+ if (addCount < endSpace) { |
+ _table.setRange(_tail, _tail + addCount, list, 0); |
+ _tail += addCount; |
+ } else { |
+ int preSpace = addCount - endSpace; |
+ _table.setRange(_tail, _tail + endSpace, list, 0); |
+ _table.setRange(0, preSpace, list, endSpace); |
+ _tail = preSpace; |
+ } |
+ } |
+ } else { |
+ for (E element in elements) _add(element); |
+ } |
+ } |
+ |
+ String toString() => IterableBase.iterableToFullString(this, "{", "}"); |
+ |
+ // Queue interface. |
+ |
+ void addLast(E element) { _add(element); } |
+ |
+ void addFirst(E element) { |
+ _head = (_head - 1) & (_table.length - 1); |
+ _table[_head] = element; |
+ if (_head == _tail) _grow(); |
+ } |
+ |
+ E removeFirst() { |
+ if (_head == _tail) throw new StateError("No element"); |
+ E result = _table[_head]; |
+ _table[_head] = null; |
+ _head = (_head + 1) & (_table.length - 1); |
+ return result; |
+ } |
+ |
+ E removeLast() { |
+ if (_head == _tail) throw new StateError("No element"); |
+ _tail = (_tail - 1) & (_table.length - 1); |
+ E result = _table[_tail]; |
+ _table[_tail] = null; |
+ return result; |
+ } |
+ |
+ // List interface. |
+ |
+ int get length => (_tail - _head) & (_table.length - 1); |
+ |
+ void set length(int value) { |
+ if (value < 0) throw new RangeError("Length $value may not be negative."); |
+ |
+ int delta = value - length; |
+ if (delta >= 0) { |
+ if (_table.length <= value) { |
+ _preGrow(value); |
+ } |
+ _tail = (_tail + delta) & (_table.length - 1); |
+ return; |
+ } |
+ |
+ int newTail = _tail + delta; // [delta] is negative. |
+ if (newTail >= 0) { |
+ _table.fillRange(newTail, _tail, null); |
+ } else { |
+ newTail += _table.length; |
+ _table.fillRange(0, _tail, null); |
+ _table.fillRange(newTail, _table.length, null); |
+ } |
+ _tail = newTail; |
+ } |
+ |
+ E operator [](int index) { |
+ if (index < 0 || index >= length) { |
+ throw new RangeError("Index $index must be in the range [0..$length)."); |
+ } |
+ |
+ return _table[(_head + index) & (_table.length - 1)]; |
+ } |
+ |
+ void operator[]=(int index, E value) { |
+ if (index < 0 || index >= length) { |
+ throw new RangeError("Index $index must be in the range [0..$length)."); |
+ } |
+ |
+ _table[(_head + index) & (_table.length - 1)] = value; |
+ } |
+ |
+ // Internal helper functions. |
+ |
+ /** |
+ * Whether [number] is a power of two. |
+ * |
+ * Only works for positive numbers. |
+ */ |
+ static bool _isPowerOf2(int number) => (number & (number - 1)) == 0; |
+ |
+ /** |
+ * Rounds [number] up to the nearest power of 2. |
+ * |
+ * If [number] is a power of 2 already, it is returned. |
+ * |
+ * Only works for positive numbers. |
+ */ |
+ static int _nextPowerOf2(int number) { |
+ assert(number > 0); |
+ number = (number << 1) - 1; |
+ for(;;) { |
+ int nextNumber = number & (number - 1); |
+ if (nextNumber == 0) return number; |
+ number = nextNumber; |
+ } |
+ } |
+ |
+ /** Adds element at end of queue. Used by both [add] and [addAll]. */ |
+ void _add(E element) { |
+ _table[_tail] = element; |
+ _tail = (_tail + 1) & (_table.length - 1); |
+ if (_head == _tail) _grow(); |
+ } |
+ |
+ /** |
+ * Grow the table when full. |
+ */ |
+ void _grow() { |
+ List<E> newTable = new List<E>(_table.length * 2); |
+ int split = _table.length - _head; |
+ newTable.setRange(0, split, _table, _head); |
+ newTable.setRange(split, split + _head, _table, 0); |
+ _head = 0; |
+ _tail = _table.length; |
+ _table = newTable; |
+ } |
+ |
+ int _writeToList(List<E> target) { |
+ assert(target.length >= length); |
+ if (_head <= _tail) { |
+ int length = _tail - _head; |
+ target.setRange(0, length, _table, _head); |
+ return length; |
+ } else { |
+ int firstPartSize = _table.length - _head; |
+ target.setRange(0, firstPartSize, _table, _head); |
+ target.setRange(firstPartSize, firstPartSize + _tail, _table, 0); |
+ return _tail + firstPartSize; |
+ } |
+ } |
+ |
+ /** Grows the table even if it is not full. */ |
+ void _preGrow(int newElementCount) { |
+ assert(newElementCount >= length); |
+ |
+ // Add 1.5x extra room to ensure that there's room for more elements after |
+ // expansion. |
+ newElementCount += newElementCount >> 1; |
+ int newCapacity = _nextPowerOf2(newElementCount); |
+ List<E> newTable = new List<E>(newCapacity); |
+ _tail = _writeToList(newTable); |
+ _table = newTable; |
+ _head = 0; |
+ } |
+} |