LCOV - code coverage report
Current view: top level - collection-1.15.0/lib/src - queue_list.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 20 132 15.2 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          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             : }

Generated by: LCOV version 1.14