< Summary

Line coverage
100%
Covered lines: 303
Uncovered lines: 0
Coverable lines: 303
Total lines: 892
Line coverage: 100%
Branch coverage
100%
Covered branches: 112
Total branches: 112
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .cctor()100%11100%
File 1: .ctor()100%11100%
File 1: .ctor(...)100%44100%
File 1: .ctor(...)100%66100%
File 1: InitializeFromKnownCountRange(...)100%66100%
File 1: .ctor(...)100%11100%
File 1: get_InnerArray()100%11100%
File 1: get_Count()100%11100%
File 1: get_Capacity()100%11100%
File 1: get_IsSynchronized()100%11100%
File 1: get_SyncRoot()100%22100%
File 1: get_IsReadOnly()100%11100%
File 1: get_Item(...)100%11100%
File 1: set_Item(...)100%11100%
File 1: get_State()100%22100%
File 1: set_State(...)100%44100%
File 1: System.Collections.Generic.ICollection<T>.Add(...)100%11100%
File 1: Enqueue(...)100%22100%
File 1: EnqueueRange(...)100%66100%
File 1: EnqueueKnownCountRange(...)100%44100%
File 1: EnqueueRange(...)100%11100%
File 1: EnqueueRange(...)100%44100%
File 1: EnsureAdditionalCapacity(...)100%11100%
File 1: Dequeue()100%22100%
File 1: TryDequeue(...)100%44100%
File 1: System.Collections.Generic.ICollection<T>.Remove(...)100%11100%
File 1: Peek()100%11100%
File 1: TryPeek(...)100%22100%
File 1: PeekTail()100%11100%
File 1: Contains(...)100%66100%
File 1: Exists(...)100%44100%
File 1: Find(...)100%44100%
File 1: Clear()100%66100%
File 1: Clear(...)100%44100%
File 1: FastClear()100%11100%
File 1: EnsureCapacity(...)100%22100%
File 1: Resize(...)100%66100%
File 1: TrimExcessCapacity()100%88100%
File 1: ToArray()100%44100%
File 1: GetSegments(...)100%44100%
File 1: CopyTo(...)100%22100%
File 1: CopyTo(...)100%22100%
File 1: CopyTo(...)100%22100%
File 1: CopyToInternal(...)100%22100%
File 1: CloneTo(...)100%22100%
File 1: GetEnumerator()100%11100%
File 1: System.Collections.Generic.IEnumerable<T>.GetEnumerator()100%11100%
File 1: System.Collections.IEnumerable.GetEnumerator()100%11100%
File 2: .ctor(...)100%11100%
File 2: get_Current()100%11100%
File 2: System.Collections.IEnumerator.get_Current()100%22100%
File 2: MoveNext()100%44100%
File 2: Reset()100%11100%
File 2: Dispose()100%11100%

File(s)

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Collection/SwiftQueue.cs

#LineLine coverage
 1//=======================================================================
 2// SwiftQueue.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Collections;
 10using System.Collections.Generic;
 11using System.Runtime.CompilerServices;
 12using System.Text.Json.Serialization;
 13using Chronicler;
 14using Chronicler.Diagnostics;
 15using Chronicler.Serialization;
 16using MemoryPack;
 17using SwiftCollections.Utility;
 18
 19namespace SwiftCollections;
 20
 21/// <summary>
 22/// <c>SwiftQueue&lt;T&gt;</c> is a high-performance, circular buffer-based queue designed for ultra-low-latency enqueue
 23/// <para>
 24/// It leverages power-of-two capacities and bitwise arithmetic to eliminate expensive modulo operations, enhancing perf
 25/// By managing memory efficiently with a wrap-around technique and custom capacity growth strategies, SwiftQueue minimi
 26/// Aggressive inlining and optimized exception handling further reduce overhead, making SwiftQueue outperform tradition
 27/// especially in scenarios with high-frequency additions and removals.
 28/// </para>
 29/// </summary>
 30/// <typeparam name="T">Specifies the type of elements in the queue.</typeparam>
 31[Serializable]
 32[JsonConverter(typeof(StateJsonConverterFactory))]
 33[MemoryPackable]
 34public sealed partial class SwiftQueue<T> : IStateBacked<SwiftArrayState<T>>, ISwiftCloneable<T>, IEnumerable<T>, IEnume
 35{
 36    #region Constants
 37
 38    /// <summary>
 39    /// The default initial capacity of the SwiftQueue if none is specified.
 40    /// Used to allocate a reasonable starting size to minimize resizing operations.
 41    /// </summary>
 42    public const int DefaultCapacity = 8;
 43
 444    private static readonly T[] _emptyArray = Array.Empty<T>();
 445    private static readonly bool _clearReleasedSlots = RuntimeHelpers.IsReferenceOrContainsReferences<T>();
 46
 47    #endregion
 48
 49    #region Fields
 50
 51    /// <summary>
 52    /// The internal array that stores elements of the SwiftQueue. Resized as needed to
 53    /// accommodate additional elements. Not directly exposed outside the queue.
 54    /// </summary>
 55    private T[] _innerArray;
 56
 57    /// <summary>
 58    /// The current number of elements in the SwiftQueue. Represents the total count of
 59    /// valid elements stored in the queue, also indicating the arrayIndex of the next insertion point.
 60    /// </summary>
 61    private int _count;
 62
 63    /// <summary>
 64    /// The arrayIndex of the first element in the queue. Adjusts as elements are dequeued.
 65    /// </summary>
 66    private int _head;
 67
 68    /// <summary>
 69    /// The arrayIndex at which the next element will be enqueued, wrapping around as needed.
 70    /// </summary>
 71    private int _tail;
 72
 73    /// <summary>
 74    /// A bitmask used for efficient modulo operations, derived from the capacity of the internal array.
 75    /// </summary>
 76    private int _mask;
 77
 78    /// <summary>
 79    /// A version number used to track modifications to the SwiftQueue to help detect changes during enumeration and ens
 80    /// </summary>
 81    [NonSerialized]
 82    private uint _version;
 83
 84    /// <summary>
 85    /// An object used to synchronize access to the SwiftQueue, ensuring thread safety.
 86    /// </summary>
 87    [NonSerialized]
 88    private object? _syncRoot;
 89
 90    #endregion
 91
 92    #region Constructors
 93
 94    /// <summary>
 95    /// Initializes a new, empty instance of SwiftQueue.
 96    /// </summary>
 10097    public SwiftQueue() : this(0) { }
 98
 99    /// <summary>
 100    /// Initializes a new, empty instance of SwiftQueue with the specified initial capacity.
 101    /// </summary>
 95102    public SwiftQueue(int capacity)
 103    {
 95104        if (capacity == 0)
 105        {
 50106            _innerArray = _emptyArray;
 50107            _mask = 0;
 108        }
 109        else
 110        {
 45111            capacity = capacity < DefaultCapacity ? DefaultCapacity : SwiftHashTools.NextPowerOfTwo(capacity);
 45112            _innerArray = new T[capacity];
 45113            _mask = _innerArray.Length - 1;
 114        }
 45115    }
 116
 117    /// <summary>
 118    /// Initializes a new instance of SwiftQueue that contains elements copied from the provided items.
 119    /// </summary>
 5120    public SwiftQueue(IEnumerable<T> items)
 121    {
 5122        ChronicleGuard.ThrowIfNull(items, nameof(items));
 5123        _innerArray = _emptyArray;
 124
 5125        if (items is ICollection<T> collection)
 126        {
 3127            InitializeFromKnownCountRange(collection, collection.Count);
 3128            return;
 129        }
 130
 2131        if (items is IReadOnlyCollection<T> readOnlyCollection)
 132        {
 1133            InitializeFromKnownCountRange(readOnlyCollection, readOnlyCollection.Count);
 1134            return;
 135        }
 136
 1137        _innerArray = new T[DefaultCapacity];
 1138        _mask = _innerArray.Length - 1;
 139
 8140        foreach (T item in items)
 3141            Enqueue(item);
 1142    }
 143
 144    private void InitializeFromKnownCountRange(IEnumerable<T> items, int count)
 145    {
 4146        if (count == 0)
 147        {
 1148            _innerArray = _emptyArray;
 1149            _mask = 0;
 150        }
 151        else
 152        {
 3153            int capacity = count < DefaultCapacity ? DefaultCapacity : SwiftHashTools.NextPowerOfTwo(count);
 3154            _innerArray = new T[capacity];
 3155            _mask = _innerArray.Length - 1;
 156
 34157            foreach (T item in items)
 14158                _innerArray[_count++] = item;
 159
 3160            _tail = _count & _mask;
 161        }
 3162    }
 163
 164    ///  <summary>
 165    ///  Initializes a new instance of the <see cref="SwiftQueue{T}"/> class with the specified <see cref="SwiftArraySta
 166    ///  </summary>
 167    ///  <param name="state">The state containing the internal array, count, offset, and version for initialization.</pa
 168    [MemoryPackConstructor]
 5169    public SwiftQueue(SwiftArrayState<T> state)
 170    {
 5171        State = state;
 172
 5173        ChronicleGuard.ThrowIfNull(_innerArray, nameof(_innerArray));
 5174    }
 175
 176    #endregion
 177
 178    #region Properties
 179
 180    /// <inheritdoc cref="_innerArray"/>
 181    [JsonIgnore]
 182    [MemoryPackIgnore]
 12183    public T[] InnerArray => _innerArray;
 184
 185    /// <inheritdoc cref="_count"/>
 186    [JsonIgnore]
 187    [MemoryPackIgnore]
 137188    public int Count => _count;
 189
 190    /// <summary>
 191    /// Gets the total number of elements the SwiftQueue can hold without resizing.
 192    /// Reflects the current allocated size of the internal array.
 193    /// </summary>
 194    [JsonIgnore]
 195    [MemoryPackIgnore]
 16196    public int Capacity => _innerArray.Length;
 197
 198    /// <inheritdoc/>
 199    [JsonIgnore]
 200    [MemoryPackIgnore]
 1201    public bool IsSynchronized => false;
 202
 203    /// <inheritdoc/>
 204    [JsonIgnore]
 205    [MemoryPackIgnore]
 3206    public object SyncRoot => _syncRoot ??= new object();
 207
 208    /// <inheritdoc/>
 209    [JsonIgnore]
 210    [MemoryPackIgnore]
 1211    public bool IsReadOnly => false;
 212
 213    /// <summary>
 214    /// Gets the element at the specified arrayIndex.
 215    /// </summary>
 216    [JsonIgnore]
 217    [MemoryPackIgnore]
 218    public T this[int index]
 219    {
 220        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 221        get
 222        {
 201223            ChronicleGuard.ThrowIfListIndexInvalid(index, _count);
 200224            return _innerArray[(_head + index) & _mask];
 225        }
 226        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 227        set
 228        {
 2229            ChronicleGuard.ThrowIfListIndexInvalid(index, _count);
 1230            _innerArray[(_head + index) & _mask] = value;
 1231        }
 232    }
 233
 234    /// <summary>
 235    /// Gets or sets the current state of the collection, including its items and order.
 236    /// </summary>
 237    /// <remarks>
 238    /// Setting this property replaces the entire contents of the collection with the items from the specified state.
 239    /// Getting this property returns a snapshot of the collection's current items and their order.
 240    /// This property is intended for serialization and deserialization scenarios.
 241    /// </remarks>
 242    [JsonInclude]
 243    [MemoryPackInclude]
 244    public SwiftArrayState<T> State
 245    {
 246        get
 247        {
 2248            var items = new T[_count];
 249
 404250            for (int i = 0; i < _count; i++)
 200251                items[i] = _innerArray[(_head + i) & _mask];
 252
 2253            return new SwiftArrayState<T>(items);
 254        }
 255        internal set
 256        {
 5257            ChronicleGuard.ThrowIfNull(value.Items, nameof(value.Items));
 258
 5259            int count = value.Items.Length;
 260
 5261            if (count == 0)
 262            {
 1263                _innerArray = _emptyArray;
 1264                _count = 0;
 1265                _head = 0;
 1266                _tail = 0;
 1267                _mask = 0;
 1268                _version = 0;
 1269                return;
 270            }
 271
 4272            int capacity = SwiftHashTools.NextPowerOfTwo(count <= DefaultCapacity ? DefaultCapacity : count);
 273
 4274            _innerArray = new T[capacity];
 4275            Array.Copy(value.Items, 0, _innerArray, 0, count);
 276
 4277            _count = count;
 4278            _head = 0;
 4279            _tail = count;
 4280            _mask = capacity - 1;
 281
 4282            _version = 0;
 4283        }
 284    }
 285
 286    #endregion
 287
 288    #region Collection Management
 289
 290    /// <inheritdoc/>
 1291    void ICollection<T>.Add(T item) => Enqueue(item);
 292
 293    /// <summary>
 294    /// Adds an item to the end of the queue. Automatically resizes the queue if the capacity is exceeded.
 295    /// </summary>
 296    /// <param name="item">The item to add to the queue.</param>
 297    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 298    public void Enqueue(T item)
 299    {
 623300        if ((uint)_count >= (uint)_innerArray.Length)
 37301            Resize(_innerArray.Length * 2);
 623302        _innerArray[_tail] = item;
 623303        _tail = (_tail + 1) & _mask;
 623304        _count++;
 623305        _version++;
 623306    }
 307
 308    /// <summary>
 309    /// Adds the elements of the specified collection to the end of the queue.
 310    /// </summary>
 311    /// <remarks>
 312    /// Known-count sources reserve capacity before enumeration to avoid repeated growth.
 313    /// </remarks>
 314    /// <param name="items">The collection of elements to add to the queue. Cannot be null.</param>
 315    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 316    public void EnqueueRange(IEnumerable<T> items)
 317    {
 5318        ChronicleGuard.ThrowIfNull(items, nameof(items));
 319
 5320        if (items is ICollection<T> collection)
 321        {
 1322            EnqueueKnownCountRange(collection, collection.Count);
 1323            return;
 324        }
 325
 4326        if (items is IReadOnlyCollection<T> readOnlyCollection)
 327        {
 2328            EnqueueKnownCountRange(readOnlyCollection, readOnlyCollection.Count);
 2329            return;
 330        }
 331
 16332        foreach (T item in items)
 6333            Enqueue(item);
 2334    }
 335
 336    private void EnqueueKnownCountRange(IEnumerable<T> items, int count)
 337    {
 3338        if (count > 0)
 339        {
 2340            EnsureAdditionalCapacity(count);
 341
 2342            int appendedCount = 0;
 28343            foreach (T item in items)
 344            {
 12345                _innerArray[_tail] = item;
 12346                _tail = (_tail + 1) & _mask;
 12347                appendedCount++;
 348            }
 349
 2350            _count += appendedCount;
 2351            _version++;
 352        }
 3353    }
 354
 355    /// <summary>
 356    /// Adds the elements of the specified array to the end of the queue in queue order.
 357    /// </summary>
 358    /// <param name="items">The array whose elements should be enqueued.</param>
 359    public void EnqueueRange(T[] items)
 360    {
 7361        ChronicleGuard.ThrowIfNull(items, nameof(items));
 7362        EnqueueRange(items.AsSpan());
 7363    }
 364
 365    /// <summary>
 366    /// Adds the elements of the specified span to the end of the queue in queue order.
 367    /// </summary>
 368    /// <param name="items">The span whose elements should be enqueued.</param>
 369    public void EnqueueRange(ReadOnlySpan<T> items)
 370    {
 30371        if (items.Length == 0)
 1372            return;
 373
 29374        EnsureAdditionalCapacity(items.Length);
 375
 316376        for (int i = 0; i < items.Length; i++)
 377        {
 129378            _innerArray[_tail] = items[i];
 129379            _tail = (_tail + 1) & _mask;
 380        }
 381
 29382        _count += items.Length;
 29383        _version++;
 29384    }
 385
 386    private void EnsureAdditionalCapacity(int additionalCount)
 387    {
 31388        long requiredCount = (long)_count + additionalCount;
 31389        ChronicleGuard.ThrowIfTrue(requiredCount > int.MaxValue, message: "The collection is too large.");
 31390        EnsureCapacity((int)requiredCount);
 31391    }
 392
 393    /// <summary>
 394    /// Removes and returns the item at the front of the queue.
 395    /// Throws an InvalidOperationException if the queue is empty.
 396    /// </summary>
 397    /// <returns>The item at the front of the queue.</returns>
 398    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 399    public T Dequeue()
 400    {
 196401        ChronicleGuard.ThrowIfTrue((uint)_count == 0, message: "Queue is Empty");
 195402        T item = _innerArray[_head];
 195403        if (_clearReleasedSlots)
 10404            _innerArray[_head] = default!;
 195405        _head = (_head + 1) & _mask;
 195406        _count--;
 195407        _version++;
 195408        return item;
 409    }
 410
 411    /// <summary>
 412    /// Tries to remove and return the item at the front of the queue.
 413    /// </summary>
 414    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 415    public bool TryDequeue(out T item)
 416    {
 3417        if ((uint)_count == 0)
 418        {
 1419            item = default!;
 1420            return false;
 421        }
 422
 2423        item = _innerArray[_head];
 2424        if (_clearReleasedSlots)
 1425            _innerArray[_head] = default!;
 2426        _head = (_head + 1) & _mask;
 2427        _count--;
 2428        _version++;
 2429        return true;
 430    }
 431
 1432    bool ICollection<T>.Remove(T item) => throw new NotSupportedException("Remove is not supported for SwiftQueue.");
 433
 434    /// <summary>
 435    /// Returns the item at the front of the queue without removing it.
 436    /// Throws an InvalidOperationException if the queue is empty.
 437    /// </summary>
 438    /// <returns>The item at the front of the queue.</returns>
 439    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 440    public T Peek()
 441    {
 5442        ChronicleGuard.ThrowIfTrue((uint)_count == 0, message: "Queue is Empty");
 3443        return _innerArray[_head];
 444    }
 445
 446    /// <summary>
 447    /// Tries to return the item at the front of the queue without removing it.
 448    /// </summary>
 449    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 450    public bool TryPeek(out T item)
 451    {
 2452        if ((uint)_count == 0)
 453        {
 1454            item = default!;
 1455            return false;
 456        }
 457
 1458        item = _innerArray[_head];
 1459        return true;
 460    }
 461
 462    /// <summary>
 463    /// Returns the item at the end of the queue without removing it.
 464    /// Throws an InvalidOperationException if the queue is empty.
 465    /// </summary>
 466    /// <returns>The item at the end of the queue.</returns>
 467    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 468    public T PeekTail()
 469    {
 4470        ChronicleGuard.ThrowIfTrue((uint)_count == 0, message: "Queue is Empty");
 3471        int tailIndex = (_tail - 1) & _mask;
 3472        return _innerArray[tailIndex];
 473    }
 474
 475    /// <inheritdoc/>
 476    public bool Contains(T item)
 477    {
 4478        if ((uint)_count == 0) return false;
 479
 2480        int index = _head;
 20481        for (int i = 0; i < _count; i++)
 482        {
 9483            if (Equals(_innerArray[index], item))
 1484                return true;
 485
 8486            index = (index + 1) & _mask;
 487        }
 488
 1489        return false;
 490    }
 491
 492    /// <summary>
 493    /// Determines whether the <see cref="SwiftQueue{T}"/> contains an element that matches the conditions defined by th
 494    /// </summary>
 495    /// <param name="match">The predicate that defines the conditions of the element to search for.</param>
 496    /// <returns><c>true</c> if the <see cref="SwiftQueue{T}"/> contains one or more elements that match the specified p
 497    public bool Exists(Predicate<T> match)
 498    {
 3499        ChronicleGuard.ThrowIfNull(match, nameof(match));
 500
 2501        int index = _head;
 20502        for (int i = 0; i < _count; i++)
 503        {
 9504            if (match(_innerArray[index]))
 1505                return true;
 506
 8507            index = (index + 1) & _mask;
 508        }
 509
 1510        return false;
 511    }
 512
 513    /// <summary>
 514    /// Searches for an element that matches the conditions defined by the specified predicate, and returns the first ma
 515    /// </summary>
 516    /// <param name="match">The predicate that defines the conditions of the element to search for.</param>
 517    /// <returns>The first element that matches the conditions defined by the specified predicate, if found; otherwise, 
 518    public T Find(Predicate<T> match)
 519    {
 2520        ChronicleGuard.ThrowIfNull(match, nameof(match));
 521
 2522        int index = _head;
 22523        for (int i = 0; i < _count; i++)
 524        {
 10525            T item = _innerArray[index];
 10526            if (match(item))
 1527                return item;
 528
 9529            index = (index + 1) & _mask;
 530        }
 531
 1532        return default!;
 533    }
 534
 535    /// <summary>
 536    /// Removes all elements from the SwiftQueue, resetting its count to zero.
 537    /// </summary>
 538    public void Clear()
 539    {
 18540        if (_count == 0) return;
 541
 8542        if (_clearReleasedSlots)
 543        {
 3544            if ((uint)_head < (uint)_tail)
 2545                Array.Clear(_innerArray, _head, _count);
 546            else
 547            {
 1548                Array.Clear(_innerArray, _head, _innerArray.Length - _head);
 1549                Array.Clear(_innerArray, 0, _tail);
 550            }
 551        }
 552
 8553        _count = 0;
 8554        _head = 0;
 8555        _tail = 0;
 8556        _version++;
 8557    }
 558
 559    /// <summary>
 560    /// Removes all elements, optionally releasing references throughout retained backing storage.
 561    /// </summary>
 562    /// <param name="clearRetainedReferences">If true, also releases references outside the live range; otherwise uses o
 563    /// <remarks>Capacity is preserved. Full reference cleanup can take time proportional to retained capacity.</remarks
 564    public void Clear(bool clearRetainedReferences)
 565    {
 142566        if (clearRetainedReferences && _clearReleasedSlots)
 567        {
 136568            Array.Clear(_innerArray, 0, _innerArray.Length);
 136569            FastClear();
 136570            return;
 571        }
 6572        Clear();
 6573    }
 574
 575    /// <summary>
 576    /// Clears the SwiftQueue without releasing the reference to the stored elements.
 577    /// Use FastClear() when you want to quickly reset the list without reallocating memory.
 578    /// </summary>
 579    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 580    public void FastClear()
 581    {
 270582        _count = 0;
 270583        _tail = 0;
 270584        _head = 0;
 270585        _version++;
 270586    }
 587
 588    #endregion
 589
 590    #region Capacity Management
 591
 592    /// <summary>
 593    /// Ensures that the internal storage has at least the specified capacity, resizing if necessary.
 594    /// </summary>
 595    /// <remarks>
 596    /// If the specified capacity is not a power of two, it is rounded up to the next power of two to optimize internal 
 597    /// </remarks>
 598    /// <param name="capacity">The minimum number of elements that the internal storage should be able to hold. Must be 
 599    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 600    public void EnsureCapacity(int capacity)
 601    {
 33602        capacity = SwiftHashTools.NextPowerOfTwo(capacity);  // Capacity must be a power of 2 for proper masking
 33603        if (capacity > _innerArray.Length)
 9604            Resize(capacity);
 33605    }
 606
 607    /// <summary>
 608    /// Ensures that the capacity of the queue is sufficient to accommodate the specified number of elements.
 609    /// The capacity increases to the next power of two greater than or equal to the required minimum capacity.
 610    /// </summary>
 611    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 612    private void Resize(int newSize)
 613    {
 46614        var newArray = new T[newSize <= DefaultCapacity ? DefaultCapacity : newSize];
 46615        if ((uint)_count > 0)
 616        {
 617            // If we are not wrapped around...
 10618            if ((uint)_head < (uint)_tail)
 619            {
 620                // ...copy from head to tail into new array starting at arrayIndex 0
 1621                Array.Copy(_innerArray, _head, newArray, 0, _count);
 622            }
 623            // Else if we are wrapped around...
 624            else
 625            {
 626                // ...copy from head to end of old array to beginning of new array
 9627                Array.Copy(_innerArray, _head, newArray, 0, _innerArray.Length - _head);
 628                // ...copy from start of old array to tail into new array
 9629                Array.Copy(_innerArray, 0, newArray, _innerArray.Length - _head, _tail);
 630            }
 631        }
 632
 46633        _innerArray = newArray;
 46634        _mask = _innerArray.Length - 1;
 46635        _head = 0;
 46636        _tail = _count & _mask;
 46637        _version++;
 46638    }
 639
 640    /// <summary>
 641    /// Reduces the capacity of the SwiftQueue if the element count is significantly less than the current capacity.
 642    /// This method resizes the internal array to the next power of two greater than or equal to the current count,
 643    /// optimizing memory usage.
 644    /// </summary>
 645    public void TrimExcessCapacity()
 646    {
 5647        int newSize = _count < DefaultCapacity ? DefaultCapacity : SwiftHashTools.NextPowerOfTwo(_count);
 6648        if (newSize >= _innerArray.Length) return;
 649
 4650        var newArray = new T[newSize];
 651
 4652        if ((uint)_count != 0)
 653        {
 3654            if ((uint)_head < (uint)_tail)
 655            {
 656                // No wrap-around, simple copy
 2657                Array.Copy(_innerArray, _head, newArray, 0, _count);
 658            }
 659            else
 660            {
 661                // Wrap-around, copy in two parts
 1662                Array.Copy(_innerArray, _head, newArray, 0, _innerArray.Length - _head);
 1663                Array.Copy(_innerArray, 0, newArray, _innerArray.Length - _head, _tail);
 664            }
 665        }
 666
 4667        _innerArray = newArray;
 4668        _mask = _innerArray.Length - 1;
 4669        _head = 0;
 4670        _tail = _count & _mask;
 4671        _version++;
 4672    }
 673
 674    #endregion
 675
 676    #region Utility Methods
 677
 678    /// <summary>
 679    /// Copies the elements of the SwiftQueue to a new array.
 680    /// </summary>
 681    public T[] ToArray()
 682    {
 20683        var result = new T[_count];
 21684        if ((uint)_count == 0) return result;
 19685        if ((uint)_head < (uint)_tail)
 17686            Array.Copy(_innerArray, _head, result, 0, _count);
 687        else
 688        {
 2689            int firstPartLength = _innerArray.Length - _head;
 2690            Array.Copy(_innerArray, _head, result, 0, firstPartLength);
 2691            Array.Copy(_innerArray, 0, result, firstPartLength, _tail);
 692        }
 19693        return result;
 694    }
 695
 696    /// <summary>
 697    /// Returns the current queue contents as up to two read-only spans.
 698    /// </summary>
 699    /// <param name="first">The first contiguous queue segment.</param>
 700    /// <param name="second">The wrapped tail segment, if any.</param>
 701    public void GetSegments(out ReadOnlySpan<T> first, out ReadOnlySpan<T> second)
 702    {
 5703        if ((uint)_count == 0)
 704        {
 1705            first = ReadOnlySpan<T>.Empty;
 1706            second = ReadOnlySpan<T>.Empty;
 1707            return;
 708        }
 709
 4710        if ((uint)_head < (uint)_tail)
 711        {
 2712            first = _innerArray.AsSpan(_head, _count);
 2713            second = ReadOnlySpan<T>.Empty;
 2714            return;
 715        }
 716
 2717        int firstPartLength = _innerArray.Length - _head;
 2718        first = _innerArray.AsSpan(_head, firstPartLength);
 2719        second = _innerArray.AsSpan(0, _tail);
 2720    }
 721
 722    /// <inheritdoc/>
 723    public void CopyTo(Array array, int arrayIndex)
 724    {
 6725        ChronicleGuard.ThrowIfNull(array, nameof(array));
 6726        ChronicleGuard.ThrowIfArgument((uint)array.Rank != 1, nameof(array), "Array must be single dimensional.");
 5727        ChronicleGuard.ThrowIfArgument((uint)array.GetLowerBound(0) != 0, nameof(array), "Array must have zero-based ind
 4728        ChronicleGuard.ThrowIfArrayIndexInvalid(arrayIndex, array.Length);
 4729        ChronicleGuard.ThrowIfArgument((uint)(array.Length - arrayIndex) < _count, nameof(array), "Destination array is 
 730
 4731        if ((uint)_count == 0)
 1732            return;
 733
 734        try
 735        {
 3736            CopyToInternal(array, arrayIndex);
 2737        }
 1738        catch (ArrayTypeMismatchException)
 739        {
 1740            throw new ArgumentException("Invalid array type.", nameof(array));
 741        }
 2742    }
 743
 744    /// <inheritdoc/>
 745    public void CopyTo(T[] array, int arrayIndex)
 746    {
 3747        ChronicleGuard.ThrowIfNull(array, nameof(array));
 3748        ChronicleGuard.ThrowIfArgument((uint)array.Rank != 1, nameof(array), "Array must be single dimensional.");
 3749        ChronicleGuard.ThrowIfArgument((uint)array.GetLowerBound(0) != 0, nameof(array), "Array must have zero-based ind
 3750        ChronicleGuard.ThrowIfArrayIndexInvalid(arrayIndex, array.Length);
 3751        ChronicleGuard.ThrowIfArgument((uint)(array.Length - arrayIndex) < _count, nameof(array), "Destination array is 
 752
 3753        if ((uint)_count == 0) return;
 754
 1755        CopyToInternal(array, arrayIndex);
 1756    }
 757
 758    /// <summary>
 759    /// Copies the elements of the SwiftQueue into the specified destination span.
 760    /// </summary>
 761    /// <param name="destination">The destination span.</param>
 762    public void CopyTo(Span<T> destination)
 763    {
 3764        ChronicleGuard.ThrowIfArgument((uint)destination.Length < _count, nameof(destination), "Destination span is not 
 765
 2766        GetSegments(out ReadOnlySpan<T> first, out ReadOnlySpan<T> second);
 2767        first.CopyTo(destination);
 768
 2769        if (second.Length > 0)
 1770            second.CopyTo(destination[first.Length..]);
 2771    }
 772
 773    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 774    private void CopyToInternal(Array destination, int arrayIndex)
 775    {
 4776        if ((uint)_head < (uint)_tail)
 777        {
 2778            Array.Copy(_innerArray, _head, destination, arrayIndex, _count);
 779        }
 780        else
 781        {
 2782            int firstPartLength = _innerArray.Length - _head;
 2783            Array.Copy(_innerArray, _head, destination, arrayIndex, firstPartLength);
 2784            Array.Copy(_innerArray, 0, destination, arrayIndex + firstPartLength, _tail);
 785        }
 2786    }
 787
 788    /// <inheritdoc/>
 789    public void CloneTo(ICollection<T> output)
 790    {
 1791        ChronicleGuard.ThrowIfNull(output, nameof(output));
 1792        output.Clear();
 12793        foreach (var item in this)
 5794            output.Add(item);
 1795    }
 796
 797    #endregion
 798
 799    #region Enumerators
 800
 801    /// <summary>
 802    /// Returns an enumerator that iterates through the SwiftList.
 803    /// </summary>
 57804    public SwiftQueueEnumerator GetEnumerator() => new(this);
 33805    IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
 20806    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 807
 808
 809
 810    #endregion
 811}

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Collection/SwiftQueue.SwiftQueueEnumerator.cs

#LineLine coverage
 1//=======================================================================
 2// SwiftQueue.SwiftQueueEnumerator.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Collections;
 10using System.Collections.Generic;
 11using System.Runtime.CompilerServices;
 12using Chronicler.Diagnostics;
 13
 14namespace SwiftCollections;
 15
 16public sealed partial class SwiftQueue<T>
 17{
 18    /// <summary>
 19    /// Enumerates the elements of a <see cref="SwiftQueue{T}"/> in the order they would be dequeued.
 20    /// </summary>
 21    public struct SwiftQueueEnumerator : IEnumerator<T>, IEnumerator, IDisposable
 22    {
 23        private readonly SwiftQueue<T> _queue;
 24        private readonly T[] _array;
 25        private readonly uint _version;
 26        private uint _index;
 27        private uint _currentIndex;
 28
 29        private T _current;
 30
 31        internal SwiftQueueEnumerator(SwiftQueue<T> queue)
 32        {
 5733            _queue = queue;
 5734            _array = queue._innerArray;
 5735            _version = queue._version;
 5736            _index = 0;
 5737            _currentIndex = (uint)queue._head - 1;
 5738            _current = default!;
 5739        }
 40
 41        /// <inheritdoc/>
 44042        public readonly T Current => _current;
 43
 44        readonly object IEnumerator.Current
 45        {
 46            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 47            get
 48            {
 3349                ChronicleGuard.ThrowIfTrue(_index == 0 || _index > (uint)_queue._count, message: "Bad enumeration");
 1450                return _current!;
 51            }
 52        }
 53
 54        /// <inheritdoc/>
 55        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 56        public bool MoveNext()
 57        {
 32258            ChronicleGuard.ThrowIfTrue(_version != _queue._version, message: "Collection was modified during enumeration
 59
 31960            _index++;
 37261            if (_index > (uint)_queue._count) return false;
 26662            _currentIndex++;
 27663            if (_currentIndex == _array.Length) _currentIndex = 0;
 26664            _current = _array[_currentIndex];
 26665            return true;
 66        }
 67
 68        /// <inheritdoc/>
 69        public void Reset()
 70        {
 1171            ChronicleGuard.ThrowIfTrue(_version != _queue._version, message: "Collection was modified during enumeration
 72
 873            _index = 0;
 874            _currentIndex = (uint)_queue._head - 1;
 875            _current = default!;
 876        }
 77
 78        /// <inheritdoc/>
 3879        public void Dispose() => _index = 0;
 80    }
 81}

Methods/Properties

.cctor()
.ctor()
.ctor(System.Int32)
.ctor(System.Collections.Generic.IEnumerable`1<T>)
InitializeFromKnownCountRange(System.Collections.Generic.IEnumerable`1<T>,System.Int32)
.ctor(SwiftCollections.SwiftArrayState`1<T>)
get_InnerArray()
get_Count()
get_Capacity()
get_IsSynchronized()
get_SyncRoot()
get_IsReadOnly()
get_Item(System.Int32)
set_Item(System.Int32,T)
get_State()
set_State(SwiftCollections.SwiftArrayState`1<T>)
System.Collections.Generic.ICollection<T>.Add(T)
Enqueue(T)
EnqueueRange(System.Collections.Generic.IEnumerable`1<T>)
EnqueueKnownCountRange(System.Collections.Generic.IEnumerable`1<T>,System.Int32)
EnqueueRange(T[])
EnqueueRange(System.ReadOnlySpan`1<T>)
EnsureAdditionalCapacity(System.Int32)
Dequeue()
TryDequeue(T&)
System.Collections.Generic.ICollection<T>.Remove(T)
Peek()
TryPeek(T&)
PeekTail()
Contains(T)
Exists(System.Predicate`1<T>)
Find(System.Predicate`1<T>)
Clear()
Clear(System.Boolean)
FastClear()
EnsureCapacity(System.Int32)
Resize(System.Int32)
TrimExcessCapacity()
ToArray()
GetSegments(System.ReadOnlySpan`1<T>&,System.ReadOnlySpan`1<T>&)
CopyTo(System.Array,System.Int32)
CopyTo(T[],System.Int32)
CopyTo(System.Span`1<T>)
CopyToInternal(System.Array,System.Int32)
CloneTo(System.Collections.Generic.ICollection`1<T>)
GetEnumerator()
System.Collections.Generic.IEnumerable<T>.GetEnumerator()
System.Collections.IEnumerable.GetEnumerator()
.ctor(SwiftCollections.SwiftQueue`1<T>)
get_Current()
System.Collections.IEnumerator.get_Current()
MoveNext()
Reset()
Dispose()