blob: f5539279991b6e28dde14c3fa000d3f4e69f9c6b [file]
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:math';
/// A circular buffer with a fixed [bufferSize].
class RingBuffer<T> {
RingBuffer(this._bufferSize) : _buffer = List<T?>.filled(_bufferSize, null);
/// Iterates through elements currently stored in the [RingBuffer] from oldest
/// to newest.
Iterable<T> call() sync* {
for (var i = _size - 1; i >= 0; --i) {
yield _buffer[(_count - i - 1) % _bufferSize]!;
}
}
/// Inserts a new element into the [RingBuffer].
///
/// Returns the element evicted as a result of adding the new element if the
/// buffer is at max capacity, null otherwise.
T? add(T element) {
if (_buffer.isEmpty) {
return null;
}
T? evicted;
final index = _count % _bufferSize;
if (index < _count) {
evicted = _buffer[index];
}
_buffer[index] = element;
_count++;
return evicted;
}
/// Resizes the buffer capacity to [size].
void resize(int size) {
assert(size >= 0);
if (size == _bufferSize) {
return;
}
final resized = List<T?>.filled(size, null);
var count = 0;
if (size > 0) {
for (final e in this()) {
resized[count++ % size] = e;
}
}
_count = count;
_bufferSize = size;
_buffer = resized;
}
/// Returns true if elements have been evicted from the buffer due to capacity
/// limits.
bool get isTruncated => _count > bufferSize;
/// The maximum number of elements the buffer can hold.
int get bufferSize => _bufferSize;
int get _size => min(_count, _bufferSize);
int _bufferSize;
int _count = 0;
List<T?> _buffer;
}