| OLD | NEW |
| (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 value); | |
| 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 class _DoubleLink<E extends _DoubleLink> { | |
| 100 E _previousLink; | |
| 101 E _nextLink; | |
| 102 | |
| 103 void _link(E previous, E next) { | |
| 104 _nextLink = next; | |
| 105 _previousLink = previous; | |
| 106 if (previous != null) previous._nextLink = this; | |
| 107 if (next != null) next._previousLink = this; | |
| 108 } | |
| 109 | |
| 110 void _unlink() { | |
| 111 if (_previousLink != null) _previousLink._nextLink = _nextLink; | |
| 112 if (_nextLink != null) _nextLink._previousLink = _previousLink; | |
| 113 _nextLink = null; | |
| 114 _previousLink = null; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 /** | |
| 119 * An entry in a doubly linked list. It contains a pointer to the next | |
| 120 * entry, the previous entry, and the boxed element. | |
| 121 */ | |
| 122 abstract class DoubleLinkedQueueEntry<E> { | |
| 123 factory DoubleLinkedQueueEntry(E element) = _UserDoubleLinkedQueueEntry<E>; | |
| 124 | |
| 125 /// The element in the queue. | |
| 126 E get element; | |
| 127 | |
| 128 /// Appends the given [e] as entry just after this entry. | |
| 129 void append(E e); | |
| 130 | |
| 131 /// Prepends the given [e] as entry just before this entry. | |
| 132 void prepend(E e); | |
| 133 | |
| 134 /// Returns the previous entry or `null` if there is none. | |
| 135 DoubleLinkedQueueEntry<E> previousEntry(); | |
| 136 | |
| 137 /// Returns the next entry or `null` if there is none. | |
| 138 DoubleLinkedQueueEntry<E> nextEntry(); | |
| 139 } | |
| 140 | |
| 141 /// Default implementation of a doubly linked queue entry. | |
| 142 /// | |
| 143 /// This implementation is only used if a user instantiates a | |
| 144 /// [DoubleLinkedQueueEntry] directly. The internal implementations don't use | |
| 145 /// this class. | |
| 146 class _UserDoubleLinkedQueueEntry<E> | |
| 147 extends _DoubleLink<_UserDoubleLinkedQueueEntry<E>> | |
| 148 implements DoubleLinkedQueueEntry<E> { | |
| 149 E element; | |
| 150 | |
| 151 _UserDoubleLinkedQueueEntry(this.element); | |
| 152 | |
| 153 void append(E e) { | |
| 154 new _UserDoubleLinkedQueueEntry<E>(e)._link(this, _nextLink); | |
| 155 } | |
| 156 | |
| 157 void prepend(E e) { | |
| 158 new _UserDoubleLinkedQueueEntry<E>(e)._link(_previousLink, this); | |
| 159 } | |
| 160 | |
| 161 E remove() { | |
| 162 _unlink(); | |
| 163 return element; | |
| 164 } | |
| 165 | |
| 166 DoubleLinkedQueueEntry<E> previousEntry() => _previousLink; | |
| 167 | |
| 168 DoubleLinkedQueueEntry<E> nextEntry() => _nextLink; | |
| 169 } | |
| 170 | |
| 171 /** | |
| 172 * Interface for the link classes used by [DoubleLinkedQueue]. | |
| 173 * | |
| 174 * Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel] | |
| 175 * implement this interface. | |
| 176 * The entry contains a link back to the queue, so calling `append` | |
| 177 * or `prepend` can correctly update the element count. | |
| 178 */ | |
| 179 abstract class _DoubleLinkedQueueEntry<E> | |
| 180 extends _DoubleLink<_DoubleLinkedQueueEntry<E>> { | |
| 181 DoubleLinkedQueue<E> _queue; | |
| 182 _DoubleLinkedQueueEntry(this._queue); | |
| 183 | |
| 184 DoubleLinkedQueueEntry<E> _asNonSentinelEntry(); | |
| 185 | |
| 186 void _append(E e) { | |
| 187 new _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _nextLink); | |
| 188 } | |
| 189 | |
| 190 void _prepend(E e) { | |
| 191 new _DoubleLinkedQueueElement<E>(e, _queue)._link(_previousLink, this); | |
| 192 } | |
| 193 | |
| 194 E _remove(); | |
| 195 | |
| 196 E get element; | |
| 197 | |
| 198 DoubleLinkedQueueEntry<E> nextEntry() { | |
| 199 return _nextLink._asNonSentinelEntry(); | |
| 200 } | |
| 201 | |
| 202 DoubleLinkedQueueEntry<E> previousEntry() { | |
| 203 return _previousLink._asNonSentinelEntry(); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 /** | |
| 208 * The actual entry type used by the [DoubleLinkedQueue]. | |
| 209 * | |
| 210 * The entry contains a reference to the queue, allowing | |
| 211 * [append]/[prepend] to update the list length. | |
| 212 */ | |
| 213 class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E> | |
| 214 implements DoubleLinkedQueueEntry<E> { | |
| 215 E element; | |
| 216 _DoubleLinkedQueueElement(this.element, DoubleLinkedQueue<E> queue) | |
| 217 : super(queue); | |
| 218 | |
| 219 void append(E e) { | |
| 220 _append(e); | |
| 221 if (_queue != null) _queue._elementCount++; | |
| 222 } | |
| 223 | |
| 224 void prepend(E e) { | |
| 225 _prepend(e); | |
| 226 if (_queue != null) _queue._elementCount++; | |
| 227 } | |
| 228 | |
| 229 E _remove() { | |
| 230 _queue = null; | |
| 231 _unlink(); | |
| 232 return element; | |
| 233 } | |
| 234 | |
| 235 E remove() { | |
| 236 if (_queue != null) _queue._elementCount--; | |
| 237 return _remove(); | |
| 238 } | |
| 239 | |
| 240 _DoubleLinkedQueueElement<E> _asNonSentinelEntry() { | |
| 241 return this; | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 /** | |
| 246 * A sentinel in a double linked list is used to manipulate the list | |
| 247 * at both ends. | |
| 248 * A double linked list has exactly one sentinel, | |
| 249 * which is the only entry when the list is constructed. | |
| 250 * Initially, a sentinel has its next and previous entry point to itself. | |
| 251 * A sentinel does not box any user element. | |
| 252 */ | |
| 253 class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> { | |
| 254 _DoubleLinkedQueueSentinel(DoubleLinkedQueue<E> queue) : super(queue) { | |
| 255 _previousLink = this; | |
| 256 _nextLink = this; | |
| 257 } | |
| 258 | |
| 259 DoubleLinkedQueueEntry<E> _asNonSentinelEntry() { | |
| 260 return null; | |
| 261 } | |
| 262 | |
| 263 /** Hit by, e.g., [DoubleLinkedQueue.removeFirst] if the queue is empty. */ | |
| 264 E _remove() { | |
| 265 throw IterableElementError.noElement(); | |
| 266 } | |
| 267 | |
| 268 /** Hit by, e.g., [DoubleLinkedQueue.first] if the queue is empty. */ | |
| 269 E get element { | |
| 270 throw IterableElementError.noElement(); | |
| 271 } | |
| 272 } | |
| 273 | |
| 274 /** | |
| 275 * A [Queue] implementation based on a double-linked list. | |
| 276 * | |
| 277 * Allows constant time add, remove-at-ends and peek operations. | |
| 278 */ | |
| 279 class DoubleLinkedQueue<E> extends Iterable<E> implements Queue<E> { | |
| 280 _DoubleLinkedQueueSentinel<E> _sentinel; | |
| 281 int _elementCount = 0; | |
| 282 | |
| 283 DoubleLinkedQueue() { | |
| 284 _sentinel = new _DoubleLinkedQueueSentinel<E>(this); | |
| 285 } | |
| 286 | |
| 287 /** | |
| 288 * Creates a double-linked queue containing all [elements]. | |
| 289 * | |
| 290 * The element order in the queue is as if the elements were added using | |
| 291 * [addLast] in the order provided by [elements.iterator]. | |
| 292 */ | |
| 293 factory DoubleLinkedQueue.from(Iterable elements) { | |
| 294 Queue<E> list = new DoubleLinkedQueue<E>(); | |
| 295 for (final e in elements) { | |
| 296 E element = e as Object/*=E*/; | |
| 297 list.addLast(element); | |
| 298 } | |
| 299 return list; | |
| 300 } | |
| 301 | |
| 302 int get length => _elementCount; | |
| 303 | |
| 304 void addLast(E value) { | |
| 305 _sentinel._prepend(value); | |
| 306 _elementCount++; | |
| 307 } | |
| 308 | |
| 309 void addFirst(E value) { | |
| 310 _sentinel._append(value); | |
| 311 _elementCount++; | |
| 312 } | |
| 313 | |
| 314 void add(E value) { | |
| 315 _sentinel._prepend(value); | |
| 316 _elementCount++; | |
| 317 } | |
| 318 | |
| 319 void addAll(Iterable<E> iterable) { | |
| 320 for (final E value in iterable) { | |
| 321 _sentinel._prepend(value); | |
| 322 _elementCount++; | |
| 323 } | |
| 324 } | |
| 325 | |
| 326 E removeLast() { | |
| 327 _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink; | |
| 328 E result = lastEntry._remove(); | |
| 329 _elementCount--; | |
| 330 return result; | |
| 331 } | |
| 332 | |
| 333 E removeFirst() { | |
| 334 _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink; | |
| 335 E result = firstEntry._remove(); | |
| 336 _elementCount--; | |
| 337 return result; | |
| 338 } | |
| 339 | |
| 340 bool remove(Object o) { | |
| 341 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; | |
| 342 while (!identical(entry, _sentinel)) { | |
| 343 if (entry.element == o) { | |
| 344 entry._remove(); | |
| 345 _elementCount--; | |
| 346 return true; | |
| 347 } | |
| 348 entry = entry._nextLink; | |
| 349 } | |
| 350 return false; | |
| 351 } | |
| 352 | |
| 353 void _filter(bool test(E element), bool removeMatching) { | |
| 354 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; | |
| 355 while (!identical(entry, _sentinel)) { | |
| 356 _DoubleLinkedQueueEntry<E> next = entry._nextLink; | |
| 357 if (identical(removeMatching, test(entry.element))) { | |
| 358 entry._remove(); | |
| 359 _elementCount--; | |
| 360 } | |
| 361 entry = next; | |
| 362 } | |
| 363 } | |
| 364 | |
| 365 void removeWhere(bool test(E element)) { | |
| 366 _filter(test, true); | |
| 367 } | |
| 368 | |
| 369 void retainWhere(bool test(E element)) { | |
| 370 _filter(test, false); | |
| 371 } | |
| 372 | |
| 373 E get first { | |
| 374 _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink; | |
| 375 return firstEntry.element; | |
| 376 } | |
| 377 | |
| 378 E get last { | |
| 379 _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink; | |
| 380 return lastEntry.element; | |
| 381 } | |
| 382 | |
| 383 E get single { | |
| 384 // Note that this throws correctly if the queue is empty | |
| 385 // because reading element on the sentinel throws. | |
| 386 if (identical(_sentinel._nextLink, _sentinel._previousLink)) { | |
| 387 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; | |
| 388 return entry.element; | |
| 389 } | |
| 390 throw IterableElementError.tooMany(); | |
| 391 } | |
| 392 | |
| 393 DoubleLinkedQueueEntry<E> lastEntry() { | |
| 394 return _sentinel.previousEntry(); | |
| 395 } | |
| 396 | |
| 397 DoubleLinkedQueueEntry<E> firstEntry() { | |
| 398 return _sentinel.nextEntry(); | |
| 399 } | |
| 400 | |
| 401 bool get isEmpty { | |
| 402 return (identical(_sentinel._nextLink, _sentinel)); | |
| 403 } | |
| 404 | |
| 405 void clear() { | |
| 406 _sentinel._nextLink = _sentinel; | |
| 407 _sentinel._previousLink = _sentinel; | |
| 408 _elementCount = 0; | |
| 409 } | |
| 410 | |
| 411 void forEachEntry(void f(DoubleLinkedQueueEntry<E> element)) { | |
| 412 _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink; | |
| 413 while (!identical(entry, _sentinel)) { | |
| 414 _DoubleLinkedQueueEntry<E> nextEntry = entry._nextLink; | |
| 415 _DoubleLinkedQueueElement<E> element = entry; | |
| 416 f(element); | |
| 417 entry = nextEntry; | |
| 418 } | |
| 419 } | |
| 420 | |
| 421 _DoubleLinkedQueueIterator<E> get iterator { | |
| 422 return new _DoubleLinkedQueueIterator<E>(_sentinel); | |
| 423 } | |
| 424 | |
| 425 String toString() => IterableBase.iterableToFullString(this, '{', '}'); | |
| 426 } | |
| 427 | |
| 428 class _DoubleLinkedQueueIterator<E> implements Iterator<E> { | |
| 429 _DoubleLinkedQueueSentinel<E> _sentinel; | |
| 430 _DoubleLinkedQueueEntry<E> _nextEntry = null; | |
| 431 E _current; | |
| 432 | |
| 433 _DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel) | |
| 434 : _sentinel = sentinel, | |
| 435 _nextEntry = sentinel._nextLink; | |
| 436 | |
| 437 bool moveNext() { | |
| 438 if (identical(_nextEntry, _sentinel)) { | |
| 439 _current = null; | |
| 440 _nextEntry = null; | |
| 441 _sentinel = null; | |
| 442 return false; | |
| 443 } | |
| 444 _DoubleLinkedQueueElement<E> elementEntry = _nextEntry; | |
| 445 if (elementEntry._queue == null) { | |
| 446 throw new ConcurrentModificationError(_sentinel._queue); | |
| 447 } | |
| 448 _current = elementEntry.element; | |
| 449 _nextEntry = elementEntry._nextLink; | |
| 450 return true; | |
| 451 } | |
| 452 | |
| 453 E get current => _current; | |
| 454 } | |
| 455 | |
| 456 /** | |
| 457 * List based [Queue]. | |
| 458 * | |
| 459 * Keeps a cyclic buffer of elements, and grows to a larger buffer when | |
| 460 * it fills up. This guarantees constant time peek and remove operations, and | |
| 461 * amortized constant time add operations. | |
| 462 * | |
| 463 * The structure is efficient for any queue or stack usage. | |
| 464 */ | |
| 465 class ListQueue<E> extends Iterable<E> implements Queue<E> { | |
| 466 static const int _INITIAL_CAPACITY = 8; | |
| 467 List<E> _table; | |
| 468 int _head; | |
| 469 int _tail; | |
| 470 int _modificationCount = 0; | |
| 471 | |
| 472 /** | |
| 473 * Create an empty queue. | |
| 474 * | |
| 475 * If [initialCapacity] is given, prepare the queue for at least that many | |
| 476 * elements. | |
| 477 */ | |
| 478 ListQueue([int initialCapacity]) : _head = 0, _tail = 0 { | |
| 479 if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) { | |
| 480 initialCapacity = _INITIAL_CAPACITY; | |
| 481 } else if (!_isPowerOf2(initialCapacity)) { | |
| 482 initialCapacity = _nextPowerOf2(initialCapacity); | |
| 483 } | |
| 484 assert(_isPowerOf2(initialCapacity)); | |
| 485 _table = new List<E>(initialCapacity); | |
| 486 } | |
| 487 | |
| 488 /** | |
| 489 * Create a `ListQueue` containing all [elements]. | |
| 490 * | |
| 491 * The elements are added to the queue, as by [addLast], in the order given by | |
| 492 * `elements.iterator`. | |
| 493 * | |
| 494 * All `elements` should be assignable to [E]. | |
| 495 */ | |
| 496 factory ListQueue.from(Iterable elements) { | |
| 497 if (elements is List) { | |
| 498 int length = elements.length; | |
| 499 ListQueue<E> queue = new ListQueue(length + 1); | |
| 500 assert(queue._table.length > length); | |
| 501 for (int i = 0; i < length; i++) { | |
| 502 queue._table[i] = elements[i] as Object/*=E*/; | |
| 503 } | |
| 504 queue._tail = length; | |
| 505 return queue; | |
| 506 } else { | |
| 507 int capacity = _INITIAL_CAPACITY; | |
| 508 if (elements is EfficientLength) { | |
| 509 capacity = elements.length; | |
| 510 } | |
| 511 ListQueue<E> result = new ListQueue<E>(capacity); | |
| 512 for (final element in elements) { | |
| 513 result.addLast(element as Object/*=E*/); | |
| 514 } | |
| 515 return result; | |
| 516 } | |
| 517 } | |
| 518 | |
| 519 // Iterable interface. | |
| 520 | |
| 521 Iterator<E> get iterator => new _ListQueueIterator<E>(this); | |
| 522 | |
| 523 void forEach(void action (E element)) { | |
| 524 int modificationCount = _modificationCount; | |
| 525 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { | |
| 526 action(_table[i]); | |
| 527 _checkModification(modificationCount); | |
| 528 } | |
| 529 } | |
| 530 | |
| 531 bool get isEmpty => _head == _tail; | |
| 532 | |
| 533 int get length => (_tail - _head) & (_table.length - 1); | |
| 534 | |
| 535 E get first { | |
| 536 if (_head == _tail) throw IterableElementError.noElement(); | |
| 537 return _table[_head]; | |
| 538 } | |
| 539 | |
| 540 E get last { | |
| 541 if (_head == _tail) throw IterableElementError.noElement(); | |
| 542 return _table[(_tail - 1) & (_table.length - 1)]; | |
| 543 } | |
| 544 | |
| 545 E get single { | |
| 546 if (_head == _tail) throw IterableElementError.noElement(); | |
| 547 if (length > 1) throw IterableElementError.tooMany(); | |
| 548 return _table[_head]; | |
| 549 } | |
| 550 | |
| 551 E elementAt(int index) { | |
| 552 RangeError.checkValidIndex(index, this); | |
| 553 return _table[(_head + index) & (_table.length - 1)]; | |
| 554 } | |
| 555 | |
| 556 List<E> toList({ bool growable: true }) { | |
| 557 List<E> list; | |
| 558 if (growable) { | |
| 559 list = new List<E>()..length = length; | |
| 560 } else { | |
| 561 list = new List<E>(length); | |
| 562 } | |
| 563 _writeToList(list); | |
| 564 return list; | |
| 565 } | |
| 566 | |
| 567 // Collection interface. | |
| 568 | |
| 569 void add(E value) { | |
| 570 _add(value); | |
| 571 } | |
| 572 | |
| 573 void addAll(Iterable<E> elements) { | |
| 574 if (elements is List/*<E>*/) { | |
| 575 List<E> list = elements; | |
| 576 int addCount = list.length; | |
| 577 int length = this.length; | |
| 578 if (length + addCount >= _table.length) { | |
| 579 _preGrow(length + addCount); | |
| 580 // After preGrow, all elements are at the start of the list. | |
| 581 _table.setRange(length, length + addCount, list, 0); | |
| 582 _tail += addCount; | |
| 583 } else { | |
| 584 // Adding addCount elements won't reach _head. | |
| 585 int endSpace = _table.length - _tail; | |
| 586 if (addCount < endSpace) { | |
| 587 _table.setRange(_tail, _tail + addCount, list, 0); | |
| 588 _tail += addCount; | |
| 589 } else { | |
| 590 int preSpace = addCount - endSpace; | |
| 591 _table.setRange(_tail, _tail + endSpace, list, 0); | |
| 592 _table.setRange(0, preSpace, list, endSpace); | |
| 593 _tail = preSpace; | |
| 594 } | |
| 595 } | |
| 596 _modificationCount++; | |
| 597 } else { | |
| 598 for (E element in elements) _add(element); | |
| 599 } | |
| 600 } | |
| 601 | |
| 602 bool remove(Object value) { | |
| 603 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { | |
| 604 E element = _table[i]; | |
| 605 if (element == value) { | |
| 606 _remove(i); | |
| 607 _modificationCount++; | |
| 608 return true; | |
| 609 } | |
| 610 } | |
| 611 return false; | |
| 612 } | |
| 613 | |
| 614 void _filterWhere(bool test(E element), bool removeMatching) { | |
| 615 int modificationCount = _modificationCount; | |
| 616 int i = _head; | |
| 617 while (i != _tail) { | |
| 618 E element = _table[i]; | |
| 619 bool remove = identical(removeMatching, test(element)); | |
| 620 _checkModification(modificationCount); | |
| 621 if (remove) { | |
| 622 i = _remove(i); | |
| 623 modificationCount = ++_modificationCount; | |
| 624 } else { | |
| 625 i = (i + 1) & (_table.length - 1); | |
| 626 } | |
| 627 } | |
| 628 } | |
| 629 | |
| 630 /** | |
| 631 * Remove all elements matched by [test]. | |
| 632 * | |
| 633 * This method is inefficient since it works by repeatedly removing single | |
| 634 * elements, each of which can take linear time. | |
| 635 */ | |
| 636 void removeWhere(bool test(E element)) { | |
| 637 _filterWhere(test, true); | |
| 638 } | |
| 639 | |
| 640 /** | |
| 641 * Remove all elements not matched by [test]. | |
| 642 * | |
| 643 * This method is inefficient since it works by repeatedly removing single | |
| 644 * elements, each of which can take linear time. | |
| 645 */ | |
| 646 void retainWhere(bool test(E element)) { | |
| 647 _filterWhere(test, false); | |
| 648 } | |
| 649 | |
| 650 void clear() { | |
| 651 if (_head != _tail) { | |
| 652 for (int i = _head; i != _tail; i = (i + 1) & (_table.length - 1)) { | |
| 653 _table[i] = null; | |
| 654 } | |
| 655 _head = _tail = 0; | |
| 656 _modificationCount++; | |
| 657 } | |
| 658 } | |
| 659 | |
| 660 String toString() => IterableBase.iterableToFullString(this, "{", "}"); | |
| 661 | |
| 662 // Queue interface. | |
| 663 | |
| 664 void addLast(E value) { _add(value); } | |
| 665 | |
| 666 void addFirst(E value) { | |
| 667 _head = (_head - 1) & (_table.length - 1); | |
| 668 _table[_head] = value; | |
| 669 if (_head == _tail) _grow(); | |
| 670 _modificationCount++; | |
| 671 } | |
| 672 | |
| 673 E removeFirst() { | |
| 674 if (_head == _tail) throw IterableElementError.noElement(); | |
| 675 _modificationCount++; | |
| 676 E result = _table[_head]; | |
| 677 _table[_head] = null; | |
| 678 _head = (_head + 1) & (_table.length - 1); | |
| 679 return result; | |
| 680 } | |
| 681 | |
| 682 E removeLast() { | |
| 683 if (_head == _tail) throw IterableElementError.noElement(); | |
| 684 _modificationCount++; | |
| 685 _tail = (_tail - 1) & (_table.length - 1); | |
| 686 E result = _table[_tail]; | |
| 687 _table[_tail] = null; | |
| 688 return result; | |
| 689 } | |
| 690 | |
| 691 // Internal helper functions. | |
| 692 | |
| 693 /** | |
| 694 * Whether [number] is a power of two. | |
| 695 * | |
| 696 * Only works for positive numbers. | |
| 697 */ | |
| 698 static bool _isPowerOf2(int number) => (number & (number - 1)) == 0; | |
| 699 | |
| 700 /** | |
| 701 * Rounds [number] up to the nearest power of 2. | |
| 702 * | |
| 703 * If [number] is a power of 2 already, it is returned. | |
| 704 * | |
| 705 * Only works for positive numbers. | |
| 706 */ | |
| 707 static int _nextPowerOf2(int number) { | |
| 708 assert(number > 0); | |
| 709 number = (number << 1) - 1; | |
| 710 for(;;) { | |
| 711 int nextNumber = number & (number - 1); | |
| 712 if (nextNumber == 0) return number; | |
| 713 number = nextNumber; | |
| 714 } | |
| 715 } | |
| 716 | |
| 717 /** Check if the queue has been modified during iteration. */ | |
| 718 void _checkModification(int expectedModificationCount) { | |
| 719 if (expectedModificationCount != _modificationCount) { | |
| 720 throw new ConcurrentModificationError(this); | |
| 721 } | |
| 722 } | |
| 723 | |
| 724 /** Adds element at end of queue. Used by both [add] and [addAll]. */ | |
| 725 void _add(E element) { | |
| 726 _table[_tail] = element; | |
| 727 _tail = (_tail + 1) & (_table.length - 1); | |
| 728 if (_head == _tail) _grow(); | |
| 729 _modificationCount++; | |
| 730 } | |
| 731 | |
| 732 /** | |
| 733 * Removes the element at [offset] into [_table]. | |
| 734 * | |
| 735 * Removal is performed by linerarly moving elements either before or after | |
| 736 * [offset] by one position. | |
| 737 * | |
| 738 * Returns the new offset of the following element. This may be the same | |
| 739 * offset or the following offset depending on how elements are moved | |
| 740 * to fill the hole. | |
| 741 */ | |
| 742 int _remove(int offset) { | |
| 743 int mask = _table.length - 1; | |
| 744 int startDistance = (offset - _head) & mask; | |
| 745 int endDistance = (_tail - offset) & mask; | |
| 746 if (startDistance < endDistance) { | |
| 747 // Closest to start. | |
| 748 int i = offset; | |
| 749 while (i != _head) { | |
| 750 int prevOffset = (i - 1) & mask; | |
| 751 _table[i] = _table[prevOffset]; | |
| 752 i = prevOffset; | |
| 753 } | |
| 754 _table[_head] = null; | |
| 755 _head = (_head + 1) & mask; | |
| 756 return (offset + 1) & mask; | |
| 757 } else { | |
| 758 _tail = (_tail - 1) & mask; | |
| 759 int i = offset; | |
| 760 while (i != _tail) { | |
| 761 int nextOffset = (i + 1) & mask; | |
| 762 _table[i] = _table[nextOffset]; | |
| 763 i = nextOffset; | |
| 764 } | |
| 765 _table[_tail] = null; | |
| 766 return offset; | |
| 767 } | |
| 768 } | |
| 769 | |
| 770 /** | |
| 771 * Grow the table when full. | |
| 772 */ | |
| 773 void _grow() { | |
| 774 List<E> newTable = new List<E>(_table.length * 2); | |
| 775 int split = _table.length - _head; | |
| 776 newTable.setRange(0, split, _table, _head); | |
| 777 newTable.setRange(split, split + _head, _table, 0); | |
| 778 _head = 0; | |
| 779 _tail = _table.length; | |
| 780 _table = newTable; | |
| 781 } | |
| 782 | |
| 783 int _writeToList(List<E> target) { | |
| 784 assert(target.length >= length); | |
| 785 if (_head <= _tail) { | |
| 786 int length = _tail - _head; | |
| 787 target.setRange(0, length, _table, _head); | |
| 788 return length; | |
| 789 } else { | |
| 790 int firstPartSize = _table.length - _head; | |
| 791 target.setRange(0, firstPartSize, _table, _head); | |
| 792 target.setRange(firstPartSize, firstPartSize + _tail, _table, 0); | |
| 793 return _tail + firstPartSize; | |
| 794 } | |
| 795 } | |
| 796 | |
| 797 /** Grows the table even if it is not full. */ | |
| 798 void _preGrow(int newElementCount) { | |
| 799 assert(newElementCount >= length); | |
| 800 | |
| 801 // Add some extra room to ensure that there's room for more elements after | |
| 802 // expansion. | |
| 803 newElementCount += newElementCount >> 1; | |
| 804 int newCapacity = _nextPowerOf2(newElementCount); | |
| 805 List<E> newTable = new List<E>(newCapacity); | |
| 806 _tail = _writeToList(newTable); | |
| 807 _table = newTable; | |
| 808 _head = 0; | |
| 809 } | |
| 810 } | |
| 811 | |
| 812 /** | |
| 813 * Iterator for a [ListQueue]. | |
| 814 * | |
| 815 * Considers any add or remove operation a concurrent modification. | |
| 816 */ | |
| 817 class _ListQueueIterator<E> implements Iterator<E> { | |
| 818 final ListQueue<E> _queue; | |
| 819 final int _end; | |
| 820 final int _modificationCount; | |
| 821 int _position; | |
| 822 E _current; | |
| 823 | |
| 824 _ListQueueIterator(ListQueue<E> queue) | |
| 825 : _queue = queue, | |
| 826 _end = queue._tail, | |
| 827 _modificationCount = queue._modificationCount, | |
| 828 _position = queue._head; | |
| 829 | |
| 830 E get current => _current; | |
| 831 | |
| 832 bool moveNext() { | |
| 833 _queue._checkModification(_modificationCount); | |
| 834 if (_position == _end) { | |
| 835 _current = null; | |
| 836 return false; | |
| 837 } | |
| 838 _current = _queue._table[_position]; | |
| 839 _position = (_position + 1) & (_queue._table.length - 1); | |
| 840 return true; | |
| 841 } | |
| 842 } | |
| OLD | NEW |