mirror of
https://github.com/ppy/osu.git
synced 2024-12-21 14:52:55 +08:00
136 lines
4.2 KiB
C#
136 lines
4.2 KiB
C#
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
#nullable disable
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace osu.Game.Rulesets.Difficulty.Utils
|
|
{
|
|
/// <summary>
|
|
/// An indexed queue where items are indexed beginning from the most recently enqueued item.
|
|
/// Enqueuing an item pushes all existing indexes up by one and inserts the item at index 0.
|
|
/// Dequeuing an item removes the item from the highest index and returns it.
|
|
/// </summary>
|
|
public class ReverseQueue<T> : IEnumerable<T>
|
|
{
|
|
/// <summary>
|
|
/// The number of elements in the <see cref="ReverseQueue{T}"/>.
|
|
/// </summary>
|
|
public int Count { get; private set; }
|
|
|
|
private T[] items;
|
|
private int capacity;
|
|
private int start;
|
|
|
|
public ReverseQueue(int initialCapacity)
|
|
{
|
|
if (initialCapacity <= 0)
|
|
throw new ArgumentOutOfRangeException(nameof(initialCapacity));
|
|
|
|
items = new T[initialCapacity];
|
|
capacity = initialCapacity;
|
|
start = 0;
|
|
Count = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the item at an index in the <see cref="ReverseQueue{T}"/>.
|
|
/// </summary>
|
|
/// <param name="index">The index of the item to retrieve. The most recently enqueued item is at index 0.</param>
|
|
public T this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (index < 0 || index > Count - 1)
|
|
throw new ArgumentOutOfRangeException(nameof(index));
|
|
|
|
int reverseIndex = Count - 1 - index;
|
|
return items[(start + reverseIndex) % capacity];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enqueues an item to this <see cref="ReverseQueue{T}"/>.
|
|
/// </summary>
|
|
/// <param name="item">The item to enqueue.</param>
|
|
public void Enqueue(T item)
|
|
{
|
|
if (Count == capacity)
|
|
{
|
|
// Double the buffer size
|
|
var buffer = new T[capacity * 2];
|
|
|
|
// Copy items to new queue
|
|
for (int i = 0; i < Count; i++)
|
|
{
|
|
buffer[i] = items[(start + i) % capacity];
|
|
}
|
|
|
|
// Replace array with new buffer
|
|
items = buffer;
|
|
capacity *= 2;
|
|
start = 0;
|
|
}
|
|
|
|
items[(start + Count) % capacity] = item;
|
|
Count++;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dequeues the least recently enqueued item from the <see cref="ReverseQueue{T}"/> and returns it.
|
|
/// </summary>
|
|
/// <returns>The item dequeued from the <see cref="ReverseQueue{T}"/>.</returns>
|
|
public T Dequeue()
|
|
{
|
|
var item = items[start];
|
|
start = (start + 1) % capacity;
|
|
Count--;
|
|
return item;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears the <see cref="ReverseQueue{T}"/> of all items.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
start = 0;
|
|
Count = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an enumerator which enumerates items in the <see cref="ReverseQueue{T}"/> starting from the most recently enqueued item.
|
|
/// </summary>
|
|
public IEnumerator<T> GetEnumerator() => new Enumerator(this);
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
|
|
public struct Enumerator : IEnumerator<T>
|
|
{
|
|
private ReverseQueue<T> reverseQueue;
|
|
private int currentIndex;
|
|
|
|
internal Enumerator(ReverseQueue<T> reverseQueue)
|
|
{
|
|
this.reverseQueue = reverseQueue;
|
|
currentIndex = -1; // The first MoveNext() should bring the iterator to 0
|
|
}
|
|
|
|
public bool MoveNext() => ++currentIndex < reverseQueue.Count;
|
|
|
|
public void Reset() => currentIndex = -1;
|
|
|
|
public readonly T Current => reverseQueue[currentIndex];
|
|
|
|
readonly object IEnumerator.Current => Current;
|
|
|
|
public void Dispose()
|
|
{
|
|
reverseQueue = null;
|
|
}
|
|
}
|
|
}
|
|
}
|