78 lines
1.5 KiB
Dart
78 lines
1.5 KiB
Dart
import 'dart:async' as async;
|
|
|
|
class RuntimeSerialQueue<T> {
|
|
RuntimeSerialQueue({required this.onItem, bool Function()? shouldContinue})
|
|
: _shouldContinue = shouldContinue;
|
|
|
|
final void Function(T item) onItem;
|
|
final bool Function()? _shouldContinue;
|
|
final List<T> _queue = [];
|
|
int _head = 0;
|
|
bool _disposed = false;
|
|
bool _draining = false;
|
|
|
|
int get pendingCount => _queue.length - _head;
|
|
|
|
bool get isDraining => _draining;
|
|
|
|
bool get isDisposed => _disposed;
|
|
|
|
void enqueue(T item) {
|
|
if (_disposed || !_canContinue()) {
|
|
return;
|
|
}
|
|
_queue.add(item);
|
|
_scheduleDrain();
|
|
}
|
|
|
|
void clear() {
|
|
_queue.clear();
|
|
_head = 0;
|
|
}
|
|
|
|
void dispose() {
|
|
_disposed = true;
|
|
clear();
|
|
}
|
|
|
|
void _scheduleDrain() {
|
|
if (_draining) {
|
|
return;
|
|
}
|
|
_draining = true;
|
|
async.scheduleMicrotask(_drain);
|
|
}
|
|
|
|
void _drain() {
|
|
try {
|
|
while (pendingCount > 0 && !_disposed && _canContinue()) {
|
|
onItem(_queue[_head++]);
|
|
_compactIfNeeded();
|
|
}
|
|
} finally {
|
|
_draining = false;
|
|
}
|
|
|
|
if (pendingCount > 0 && !_disposed && _canContinue()) {
|
|
_scheduleDrain();
|
|
}
|
|
}
|
|
|
|
void _compactIfNeeded() {
|
|
if (_head == 0) {
|
|
return;
|
|
}
|
|
if (_head == _queue.length) {
|
|
clear();
|
|
return;
|
|
}
|
|
if (_head < 32 || _head * 2 < _queue.length) {
|
|
return;
|
|
}
|
|
_queue.removeRange(0, _head);
|
|
_head = 0;
|
|
}
|
|
|
|
bool _canContinue() => _shouldContinue?.call() ?? true;
|
|
}
|