using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Robust.Shared.Collections;
///
/// A fixed-size queue that discards the oldest entry if a new entry is enqueued when the queue is full.
///
///
public sealed class OverflowQueue
{
private readonly T[] _queue;
private int _currentIdx = 0;
private int _length = 0;
///
/// The size of the queue-buffer.
///
public int Size => _queue.Length;
/// size of the queue-buffer
public OverflowQueue(int size)
{
_queue = new T[size];
}
///
/// Enqueues the . Overrides the oldest item if the queue is full.
///
/// The item to enqueue
public void Enqueue(T item)
{
_queue[_currentIdx++] = item;
if(_length < Size)
_length++;
if (_currentIdx == Size)
{
_currentIdx = 0;
}
}
///
/// Removes the item at the head of the queue and returns it. If the queue is empty, this method throws an InvalidOperationException.
///
/// The dequeued item.
/// Thrown if the queue is empty.
public T Dequeue()
{
if (!TryDequeue(out var item))
{
throw new InvalidOperationException($"{nameof(OverflowQueue)} has no more items to dequeue.");
}
return item;
}
///
/// Tries to dequeue an item.
///
/// The item which got dequeued. Null if the queue was empty
/// True if an item was dequeued, false if not.
public bool TryDequeue([NotNullWhen(true)] out T? item)
{
if (_length == 0)
{
item = default;
return false;
}
item = _queue[GetCurrentIndex()]!;
_length--;
return true;
}
private int GetCurrentIndex()
{
Debug.Assert(_length > 0);
var idx = _currentIdx - _length;
if (idx < 0)
{
return idx + Size;
}
return idx;
}
///
/// Returns the item at the head of the queue. The object remains in the queue. If the queue is empty, this method throws an InvalidOperationException.
///
/// The item at the head of the queue.
/// Thrown if the queue is empty.
public T Peek()
{
if (_length == 0)
{
throw new InvalidOperationException($"{nameof(OverflowQueue)} has no more items to dequeue.");
}
return _queue[GetCurrentIndex()];
}
///
/// Returns true if the queue contains at least one object equal to item. Equality is determined using EqualityComparer.Default.Equals().
///
/// Item to look for.
/// True if the queue contains the item, false if not.
public bool Contains(T item)
{
for (int i = 0; i < _length; i++)
{
var actualIndex = _currentIdx + i;
if (actualIndex >= _length)
actualIndex -= _length;
if (EqualityComparer.Default.Equals(item, _queue[actualIndex])) return true;
}
return false;
}
///
/// Returns the queue contents first to last as an array.
///
/// The array containing the queue contents.
public T[] ToArray()
{
if (_length == 0)
{
return Array.Empty();
}
var res = new T[_length];
var startIdx = _currentIdx - _length;
if (startIdx < 0)
{
Array.Copy(_queue, startIdx + Size, res, 0, -1 * startIdx);
Array.Copy(_queue, 0, res, -1 * startIdx, startIdx + Size);
}
else
{
Array.Copy(_queue, startIdx, res, 0, _length);
}
return res;
}
}