| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- import 'dart:collection';
- class CircularList<T> with ListMixin<T> {
- CircularList(int maxLength) : _array = List<T?>.filled(maxLength, null);
- late List<T?> _array;
- var _length = 0;
- var _startIndex = 0;
- // Gets the cyclic index for the specified regular index. The cyclic index can then be used on the
- // backing array to get the element associated with the regular index.
- int _getCyclicIndex(int index) {
- return (_startIndex + index) % _array.length;
- }
- int get maxLength {
- return _array.length;
- }
- set maxLength(int value) {
- if (value <= 0)
- throw ArgumentError.value(
- value, 'value', 'maxLength can\'t be negative!');
- if (value == _array.length) return;
- // Reconstruct array, starting at index 0. Only transfer values from the
- // indexes 0 to length.
- final newArray = List<T?>.generate(
- value,
- (index) => index < _array.length ? _array[_getCyclicIndex(index)] : null,
- );
- _startIndex = 0;
- _array = newArray;
- }
- int get length {
- return _length;
- }
- set length(int value) {
- if (value > _length) {
- for (int i = length; i < value; i++) {
- _array[i] = null;
- }
- }
- _length = value;
- }
- // void forEach(
- // void Function(T? item, int index) callback, [
- // bool includeBuffer = false,
- // ]) {
- // final len = includeBuffer ? _array.length : _length;
- // for (int i = 0; i < len; i++) {
- // callback(_array[_getCyclicIndex(i)], i);
- // }
- // }
- T operator [](int index) {
- if (index >= length) {
- throw RangeError.range(index, 0, length - 1);
- }
- return _array[_getCyclicIndex(index)]!;
- }
- operator []=(int index, T value) {
- if (index >= length) {
- throw RangeError.range(index, 0, length - 1);
- }
- _array[_getCyclicIndex(index)] = value;
- }
- void clear() {
- _startIndex = 0;
- _length = 0;
- }
- void push(T value) {
- _array[_getCyclicIndex(_length)] = value;
- if (_length == _array.length) {
- _startIndex++;
- if (_startIndex == _array.length) {
- _startIndex = 0;
- }
- } else {
- _length++;
- }
- }
- /// Removes and returns the last value on the list
- T pop() {
- return _array[_getCyclicIndex(_length-- - 1)]!;
- }
- /// Deletes item at [index].
- void remove(int index, [int count = 1]) {
- if (count > 0) {
- for (var i = index; i < _length - count; i++) {
- _array[_getCyclicIndex(i)] = _array[_getCyclicIndex(i + count)];
- }
- length -= count;
- }
- }
- /// Inserts [item] at [index].
- void insert(int index, T item) {
- for (var i = _length - 1; i >= index; i--) {
- _array[_getCyclicIndex(i + 1)] = _array[_getCyclicIndex(i)];
- }
- _array[_getCyclicIndex(index)] = item;
- if (_length + 1 > _array.length) {
- _startIndex += 1;
- onTrimmed?.call(1);
- } else {
- _length++;
- }
- }
- /// Inserts [items] at [index] in order.
- void insertAll(int index, List<T> items) {
- for (var i = _length - 1; i >= index; i--) {
- _array[_getCyclicIndex(i + 1)] = _array[_getCyclicIndex(i)];
- }
- for (var i = 0; i < items.length; i++) {
- _array[_getCyclicIndex(index + i)] = items[i];
- }
- if (_length + items.length > _array.length) {
- final countToTrim = _length + items.length - _array.length;
- _startIndex += countToTrim;
- length = _array.length;
- } else {
- _length += items.length;
- }
- }
- void trimStart(int count) {
- if (count > _length) count = _length;
- _startIndex += count;
- _startIndex %= _array.length;
- _length -= count;
- }
- void shiftElements(int start, int count, int offset) {
- if (count < 0) return;
- if (start < 0 || start >= _length)
- throw Exception('Start argument is out of range');
- if (start + offset < 0)
- throw Exception('Can not shift elements in list beyond index 0');
- if (offset > 0) {
- for (var i = count - 1; i >= 0; i--) {
- this[start + i + offset] = this[start + i];
- }
- var expandListBy = (start + count + offset) - _length;
- if (expandListBy > 0) {
- _length += expandListBy;
- while (_length > _array.length) {
- length--;
- _startIndex++;
- }
- }
- } else {
- for (var i = 0; i < count; i++) {
- this[start + i + offset] = this[start + i];
- }
- }
- }
- bool get isFull => length == maxLength;
- }
|