File: Utilities\FixedSizeQueue.cs
Web Access
Project: src\src\Microsoft.ML.Core\Microsoft.ML.Core.csproj (Microsoft.ML.Core)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using Microsoft.ML.Runtime;
 
namespace Microsoft.ML.Internal.Utilities
{
 
    using Conditional = System.Diagnostics.ConditionalAttribute;
 
    /// <summary>
    /// A fixed-length circular array. Items are added at the end. If the array is full, adding
    ///  an item will result in discarding the least recently added item.
    /// </summary>
    [BestFriend]
    internal sealed class FixedSizeQueue<T>
    {
        private readonly T[] _array;
        private int _startIndex;
        private int _count;
 
        public FixedSizeQueue(int capacity)
        {
            Contracts.Assert(capacity > 0, "Array capacity should be greater than zero");
            _array = new T[capacity];
            AssertValid();
        }
 
        [Conditional("DEBUG")]
        private void AssertValid()
        {
            Contracts.Assert(Utils.Size(_array) >= 0);
            Contracts.Assert(0 <= _startIndex && _startIndex < _array.Length);
            Contracts.Assert(0 <= _count && _count <= _array.Length);
        }
 
        public int Count
        {
            get
            {
                AssertValid();
                return _count;
            }
        }
 
        public int Capacity
        {
            get
            {
                AssertValid();
                return _array.Length;
            }
        }
 
        public bool IsFull
        {
            get
            {
                AssertValid();
                return _count == _array.Length;
            }
        }
 
        public T this[int index]
        {
            get
            {
                AssertValid();
                Contracts.Assert(index >= 0 && index < _count);
                return _array[(_startIndex + index) % _array.Length];
            }
        }
 
        public void AddLast(T item)
        {
            AssertValid();
            if (_count == _array.Length)
            {
                // Replace least recently added item (found at _startIndex)
                _array[_startIndex] = item;
                _startIndex = (_startIndex + 1) % _array.Length;
            }
            else
            {
                _array[(_startIndex + _count) % _array.Length] = item;
                _count++;
            }
 
            AssertValid();
        }
 
        public T PeekFirst()
        {
            AssertValid();
            Contracts.Assert(_count != 0, "Array is empty");
            return _array[_startIndex];
        }
 
        public T PeekLast()
        {
            AssertValid();
            Contracts.Assert(_count != 0, "Array is empty");
            return _array[(_startIndex + _count - 1) % _array.Length];
        }
 
        public T RemoveFirst()
        {
            AssertValid();
            Contracts.Assert(_count != 0, "Array is empty");
            T item = _array[_startIndex];
            _array[_startIndex] = default(T);
            _startIndex = (_startIndex + 1) % _array.Length;
            _count--;
            AssertValid();
            return item;
        }
 
        public T RemoveLast()
        {
            AssertValid();
            Contracts.Assert(_count != 0, "Array is empty");
            int lastIndex = (_startIndex + _count - 1) % _array.Length;
            T item = _array[lastIndex];
            _array[lastIndex] = default(T);
            _count--;
            AssertValid();
            return item;
        }
 
        public void Clear()
        {
            AssertValid();
            for (int i = 0; i < _count; i++)
                _array[(_startIndex + i) % _array.Length] = default(T);
            _startIndex = 0;
            _count = 0;
            AssertValid();
        }
 
        public FixedSizeQueue<T> Clone()
        {
            var q = new FixedSizeQueue<T>(Capacity);
            for (int index = 0; index < Count; index++)
                q.AddLast(this[index]);
 
            return q;
        }
 
    }
}