Line data Source code
1 : // Copyright (c) 2014, 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 : import 'dart:collection';
6 :
7 : /// A class that efficiently implements both [Queue] and [List].
8 : // TODO(nweiz): Currently this code is copied almost verbatim from
9 : // dart:collection. The only changes are to implement List and to remove methods
10 : // that are redundant with ListMixin. Remove or simplify it when issue 21330 is
11 : // fixed.
12 : class QueueList<E> extends Object with ListMixin<E> implements Queue<E> {
13 : /// Adapts [source] to be a `QueueList<T>`.
14 : ///
15 : /// Any time the class would produce an element that is not a [T], the element
16 : /// access will throw.
17 : ///
18 : /// Any time a [T] value is attempted stored into the adapted class, the store
19 : /// will throw unless the value is also an instance of [S].
20 : ///
21 : /// If all accessed elements of [source] are actually instances of [T] and if
22 : /// all elements stored in the returned are actually instance of [S],
23 : /// then the returned instance can be used as a `QueueList<T>`.
24 0 : static QueueList<T> _castFrom<S, T>(QueueList<S> source) {
25 0 : return _CastQueueList<S, T>(source);
26 : }
27 :
28 : /// Default and minimal initial capacity of the queue-list.
29 : static const int _initialCapacity = 8;
30 : List<E?> _table;
31 : int _head;
32 : int _tail;
33 :
34 : /// Creates an empty queue.
35 : ///
36 : /// If [initialCapacity] is given, prepare the queue for at least that many
37 : /// elements.
38 11 : QueueList([int? initialCapacity])
39 22 : : this._init(_computeInitialCapacity(initialCapacity));
40 :
41 : /// Creates an empty queue with the specific initial capacity.
42 11 : QueueList._init(int initialCapacity)
43 11 : : assert(_isPowerOf2(initialCapacity)),
44 11 : _table = List<E?>.filled(initialCapacity, null),
45 : _head = 0,
46 : _tail = 0;
47 :
48 : /// An internal constructor for use by [_CastQueueList].
49 0 : QueueList._(this._head, this._tail, this._table);
50 :
51 : /// Create a queue initially containing the elements of [source].
52 0 : factory QueueList.from(Iterable<E> source) {
53 0 : if (source is List) {
54 0 : var length = source.length;
55 0 : var queue = QueueList<E>(length + 1);
56 0 : assert(queue._table.length > length);
57 : var sourceList = source;
58 0 : queue._table.setRange(0, length, sourceList, 0);
59 0 : queue._tail = length;
60 : return queue;
61 : } else {
62 0 : return QueueList<E>()..addAll(source);
63 : }
64 : }
65 :
66 : /// Computes the actual initial capacity based on the constructor parameter.
67 11 : static int _computeInitialCapacity(int? initialCapacity) {
68 0 : if (initialCapacity == null || initialCapacity < _initialCapacity) {
69 : return _initialCapacity;
70 : }
71 0 : initialCapacity += 1;
72 0 : if (_isPowerOf2(initialCapacity)) {
73 : return initialCapacity;
74 : }
75 0 : return _nextPowerOf2(initialCapacity);
76 : }
77 :
78 : // Collection interface.
79 :
80 11 : @override
81 : void add(E element) {
82 11 : _add(element);
83 : }
84 :
85 0 : @override
86 : void addAll(Iterable<E> iterable) {
87 0 : if (iterable is List) {
88 : var list = iterable;
89 0 : var addCount = list.length;
90 0 : var length = this.length;
91 0 : if (length + addCount >= _table.length) {
92 0 : _preGrow(length + addCount);
93 : // After preGrow, all elements are at the start of the list.
94 0 : _table.setRange(length, length + addCount, list, 0);
95 0 : _tail += addCount;
96 : } else {
97 : // Adding addCount elements won't reach _head.
98 0 : var endSpace = _table.length - _tail;
99 0 : if (addCount < endSpace) {
100 0 : _table.setRange(_tail, _tail + addCount, list, 0);
101 0 : _tail += addCount;
102 : } else {
103 0 : var preSpace = addCount - endSpace;
104 0 : _table.setRange(_tail, _tail + endSpace, list, 0);
105 0 : _table.setRange(0, preSpace, list, endSpace);
106 0 : _tail = preSpace;
107 : }
108 : }
109 : } else {
110 0 : for (var element in iterable) {
111 0 : _add(element);
112 : }
113 : }
114 : }
115 :
116 0 : QueueList<T> cast<T>() => QueueList._castFrom<E, T>(this);
117 :
118 0 : @deprecated
119 0 : QueueList<T> retype<T>() => cast<T>();
120 :
121 0 : @override
122 0 : String toString() => IterableBase.iterableToFullString(this, '{', '}');
123 :
124 : // Queue interface.
125 :
126 0 : @override
127 : void addLast(E element) {
128 0 : _add(element);
129 : }
130 :
131 0 : @override
132 : void addFirst(E element) {
133 0 : _head = (_head - 1) & (_table.length - 1);
134 0 : _table[_head] = element;
135 0 : if (_head == _tail) _grow();
136 : }
137 :
138 11 : @override
139 : E removeFirst() {
140 33 : if (_head == _tail) throw StateError('No element');
141 33 : var result = _table[_head] as E;
142 33 : _table[_head] = null;
143 77 : _head = (_head + 1) & (_table.length - 1);
144 : return result;
145 : }
146 :
147 0 : @override
148 : E removeLast() {
149 0 : if (_head == _tail) throw StateError('No element');
150 0 : _tail = (_tail - 1) & (_table.length - 1);
151 0 : var result = _table[_tail] as E;
152 0 : _table[_tail] = null;
153 : return result;
154 : }
155 :
156 : // List interface.
157 :
158 11 : @override
159 77 : int get length => (_tail - _head) & (_table.length - 1);
160 :
161 0 : @override
162 : set length(int value) {
163 0 : if (value < 0) throw RangeError('Length $value may not be negative.');
164 0 : if (value > length && null is! E) {
165 0 : throw UnsupportedError(
166 : 'The length can only be increased when the element type is '
167 : 'nullable, but the current element type is `$E`.');
168 : }
169 :
170 0 : var delta = value - length;
171 0 : if (delta >= 0) {
172 0 : if (_table.length <= value) {
173 0 : _preGrow(value);
174 : }
175 0 : _tail = (_tail + delta) & (_table.length - 1);
176 : return;
177 : }
178 :
179 0 : var newTail = _tail + delta; // [delta] is negative.
180 0 : if (newTail >= 0) {
181 0 : _table.fillRange(newTail, _tail, null);
182 : } else {
183 0 : newTail += _table.length;
184 0 : _table.fillRange(0, _tail, null);
185 0 : _table.fillRange(newTail, _table.length, null);
186 : }
187 0 : _tail = newTail;
188 : }
189 :
190 0 : @override
191 : E operator [](int index) {
192 0 : if (index < 0 || index >= length) {
193 0 : throw RangeError('Index $index must be in the range [0..$length).');
194 : }
195 :
196 0 : return _table[(_head + index) & (_table.length - 1)] as E;
197 : }
198 :
199 0 : @override
200 : void operator []=(int index, E value) {
201 0 : if (index < 0 || index >= length) {
202 0 : throw RangeError('Index $index must be in the range [0..$length).');
203 : }
204 :
205 0 : _table[(_head + index) & (_table.length - 1)] = value;
206 : }
207 :
208 : // Internal helper functions.
209 :
210 : /// Whether [number] is a power of two.
211 : ///
212 : /// Only works for positive numbers.
213 44 : static bool _isPowerOf2(int number) => (number & (number - 1)) == 0;
214 :
215 : /// Rounds [number] up to the nearest power of 2.
216 : ///
217 : /// If [number] is a power of 2 already, it is returned.
218 : ///
219 : /// Only works for positive numbers.
220 0 : static int _nextPowerOf2(int number) {
221 0 : assert(number > 0);
222 0 : number = (number << 1) - 1;
223 : for (;;) {
224 0 : var nextNumber = number & (number - 1);
225 0 : if (nextNumber == 0) return number;
226 : number = nextNumber;
227 : }
228 : }
229 :
230 : /// Adds element at end of queue. Used by both [add] and [addAll].
231 11 : void _add(E element) {
232 33 : _table[_tail] = element;
233 77 : _tail = (_tail + 1) & (_table.length - 1);
234 33 : if (_head == _tail) _grow();
235 : }
236 :
237 : /// Grow the table when full.
238 0 : void _grow() {
239 0 : var newTable = List<E?>.filled(_table.length * 2, null);
240 0 : var split = _table.length - _head;
241 0 : newTable.setRange(0, split, _table, _head);
242 0 : newTable.setRange(split, split + _head, _table, 0);
243 0 : _head = 0;
244 0 : _tail = _table.length;
245 0 : _table = newTable;
246 : }
247 :
248 0 : int _writeToList(List<E?> target) {
249 0 : assert(target.length >= length);
250 0 : if (_head <= _tail) {
251 0 : var length = _tail - _head;
252 0 : target.setRange(0, length, _table, _head);
253 : return length;
254 : } else {
255 0 : var firstPartSize = _table.length - _head;
256 0 : target.setRange(0, firstPartSize, _table, _head);
257 0 : target.setRange(firstPartSize, firstPartSize + _tail, _table, 0);
258 0 : return _tail + firstPartSize;
259 : }
260 : }
261 :
262 : /// Grows the table even if it is not full.
263 0 : void _preGrow(int newElementCount) {
264 0 : assert(newElementCount >= length);
265 :
266 : // Add 1.5x extra room to ensure that there's room for more elements after
267 : // expansion.
268 0 : newElementCount += newElementCount >> 1;
269 0 : var newCapacity = _nextPowerOf2(newElementCount);
270 0 : var newTable = List<E?>.filled(newCapacity, null);
271 0 : _tail = _writeToList(newTable);
272 0 : _table = newTable;
273 0 : _head = 0;
274 : }
275 : }
276 :
277 : class _CastQueueList<S, T> extends QueueList<T> {
278 : final QueueList<S> _delegate;
279 :
280 : // Assigns invalid values for head/tail because it uses the delegate to hold
281 : // the real values, but they are non-null fields.
282 0 : _CastQueueList(this._delegate) : super._(-1, -1, _delegate._table.cast<T>());
283 :
284 0 : @override
285 0 : int get _head => _delegate._head;
286 :
287 0 : @override
288 0 : set _head(int value) => _delegate._head = value;
289 :
290 0 : @override
291 0 : int get _tail => _delegate._tail;
292 :
293 0 : @override
294 0 : set _tail(int value) => _delegate._tail = value;
295 : }
|