< Summary

Line coverage
100%
Covered lines: 268
Uncovered lines: 0
Coverable lines: 268
Total lines: 891
Line coverage: 100%
Branch coverage
100%
Covered branches: 86
Total branches: 86
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%44100%
File 1: .ctor(...)100%11100%
File 1: get_InnerArray()100%11100%
File 1: get_Capacity()100%11100%
File 1: get_Count()100%11100%
File 1: get_IsReadOnly()100%11100%
File 1: get_IsSynchronized()100%11100%
File 1: get_SyncRoot()100%22100%
File 1: get_IsFixedSize()100%11100%
File 1: System.Collections.IList.get_Item(...)100%22100%
File 1: System.Collections.IList.set_Item(...)100%11100%
File 1: get_Item(...)100%11100%
File 1: set_Item(...)100%11100%
File 1: get_State()100%11100%
File 1: set_State(...)100%44100%
File 1: Add(...)100%22100%
File 1: System.Collections.IList.Add(...)100%11100%
File 1: AddRange(...)100%88100%
File 1: AddKnownCountRange(...)100%44100%
File 1: AddRange(...)100%11100%
File 1: AddRange(...)100%22100%
File 1: EnsureAdditionalCapacity(...)100%11100%
File 1: Remove(...)100%22100%
File 1: System.Collections.IList.Remove(...)100%11100%
File 1: RemoveAt(...)100%22100%
File 1: RemoveAll(...)100%22100%
File 1: IndexOfFirstMatch(...)100%44100%
File 1: CompactUnmatchedItems(...)100%44100%
File 1: ClearReleasedSlots(...)100%22100%
File 1: Insert(...)100%44100%
File 1: System.Collections.IList.Insert(...)100%11100%
File 1: Reverse()100%11100%
File 1: SortInPlace(...)100%11100%
File 1: SortInPlace(...)100%11100%
File 1: Clear()100%44100%
File 1: Clear(...)100%44100%
File 1: FastClear()100%11100%
File 1: EnsureCapacity(...)100%22100%
File 1: Resize(...)100%44100%
File 1: TrimExcessCapacity()100%22100%
File 1: IndexOf(...)100%11100%
File 1: System.Collections.IList.IndexOf(...)100%11100%
File 1: ToArray()100%11100%
File 1: AsSpan()100%11100%
File 1: AsReadOnlySpan()100%11100%
File 1: ToString()100%22100%
File 1: Contains(...)100%11100%
File 1: Exists(...)100%44100%
File 1: Find(...)100%44100%
File 1: System.Collections.IList.Contains(...)100%11100%
File 1: Swap(...)100%11100%
File 1: CopyTo(...)100%22100%
File 1: CopyTo(...)100%11100%
File 1: CopyTo(...)100%11100%
File 1: CopyTo(...)100%11100%
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%22100%
File 2: Reset()100%11100%
File 2: Dispose()100%11100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// SwiftList.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>SwiftList&lt;T&gt;</c> is a high-performance, memory-efficient dynamic list designed to outperform
 23/// traditional generic lists in speed-critical applications.
 24/// <para>
 25/// By utilizing custom growth and
 26/// shrink strategies, SwiftList optimizes memory allocation and minimizes resizing overhead,
 27/// all while maintaining compact storage. With aggressive inlining and optimized algorithms,
 28/// SwiftList delivers faster iteration, insertion, and overall memory management compared to
 29/// standard List. It is ideal for scenarios where predictable performance and minimal
 30/// memory allocations are essential.
 31/// </para>
 32/// <para>
 33/// This implementation is optimized for performance and does not perform versioning checks.
 34/// Modifying the list during enumeration may result in undefined behavior.
 35/// </para>
 36/// </summary>
 37/// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
 38[Serializable]
 39[JsonConverter(typeof(StateJsonConverterFactory))]
 40[MemoryPackable]
 41public partial class SwiftList<T> : IStateBacked<SwiftArrayState<T>>, ISwiftCloneable<T>, IEnumerable<T>, IEnumerable, I
 42{
 43    #region Constants
 44
 45    /// <summary>
 46    /// The default initial capacity of the <see cref="SwiftList{T}"/> if none is specified.
 47    /// Used to allocate a reasonable starting size to minimize resizing operations.
 48    /// </summary>
 49    public const int DefaultCapacity = 8;
 50
 351    private static readonly T[] _emptyArray = Array.Empty<T>();
 352    private static readonly bool _clearReleasedSlots = RuntimeHelpers.IsReferenceOrContainsReferences<T>();
 53
 54    #endregion
 55
 56    #region Fields
 57
 58    /// <summary>
 59    /// The internal array that stores elements of the SwiftList. Resized as needed to
 60    /// accommodate additional elements. Not directly exposed outside the list.
 61    /// </summary>
 62    protected T[] _innerArray;
 63
 64    /// <summary>
 65    /// The current number of elements in the SwiftList. Represents the total count of
 66    /// valid elements stored in the list, also indicating the arrayIndex of the next insertion point.
 67    /// </summary>
 68    protected int _count;
 69
 70    /// <summary>
 71    /// The version of the SwiftList, used to track modifications.
 72    /// </summary>
 73    [NonSerialized]
 74    protected uint _version;
 75
 76    /// <summary>
 77    /// An object that can be used to synchronize access to the SwiftList.
 78    /// </summary>
 79    [NonSerialized]
 80    private object? _syncRoot;
 81
 82    #endregion
 83
 84    #region Constructors
 85
 86    /// <summary>
 87    /// Initializes a new instance of the SwiftList class that is empty and has the default initial capacity.
 88    /// </summary>
 72489    public SwiftList() : this(0) { }
 90
 91    /// <summary>
 92    /// Initializes a new, empty instance of <see cref="SwiftList{T}"/> with the specified initial capacity.
 93    /// </summary>
 60794    public SwiftList(int capacity)
 95    {
 60796        if (capacity == 0)
 36297            _innerArray = _emptyArray;
 98        else
 99        {
 245100            capacity = SwiftHashTools.NextPowerOfTwo(capacity <= DefaultCapacity ? DefaultCapacity : capacity);
 245101            _innerArray = new T[capacity];
 102        }
 245103    }
 104
 105    /// <summary>
 106    /// Initializes a new instance of the <see cref="SwiftList{T}"/> class with elements from the specified collection.
 107    /// The collection must have a known count for optimized memory allocation.
 108    /// </summary>
 109    /// <exception cref="ArgumentException">Thrown if the input collection does not have a known count.</exception>
 55110    public SwiftList(IEnumerable<T> items)
 111    {
 55112        ChronicleGuard.ThrowIfNull(items, nameof(items));
 113
 55114        if (items is ICollection<T> collection)
 115        {
 52116            int count = collection.Count;
 52117            if (count == 0)
 13118                _innerArray = _emptyArray;
 119            else
 120            {
 39121                _innerArray = new T[count];
 39122                collection.CopyTo(_innerArray, 0);
 39123                _count = count;
 124            }
 125        }
 126        else
 127        {
 3128            _innerArray = new T[DefaultCapacity];
 3129            AddRange(items); // Will handle capacity increases as needed
 130        }
 3131    }
 132
 133    ///  <summary>
 134    ///  Initializes a new instance of the <see cref="SwiftList{T}"/> class with the specified <see cref="SwiftArrayStat
 135    ///  </summary>
 136    ///  <param name="state">The state containing the internal array, count, offset, and version for initialization.</pa
 137    [MemoryPackConstructor]
 10138    public SwiftList(SwiftArrayState<T> state)
 139    {
 10140        State = state;
 141
 142        // Validate that the internal array is not null after deserialization
 10143        ChronicleGuard.ThrowIfNull(_innerArray, nameof(_innerArray));
 10144    }
 145
 146    #endregion
 147
 148    #region Properties
 149
 150    /// <summary>
 151    /// Gets the underlying array that stores the elements of the collection.
 152    /// </summary>
 153    [JsonIgnore]
 154    [MemoryPackIgnore]
 15155    public T[] InnerArray => _innerArray;
 156
 157    /// <summary>
 158    /// Gets the total number of elements the SwiftList can hold without resizing.
 159    /// Reflects the current allocated size of the internal array.
 160    /// </summary>
 161    [JsonIgnore]
 162    [MemoryPackIgnore]
 22163    public int Capacity => _innerArray.Length;
 164
 165    /// <inheritdoc cref="_count"/>
 166    [JsonIgnore]
 167    [MemoryPackIgnore]
 6114168    public int Count => _count;
 169
 170    /// <inheritdoc/>
 171    [JsonIgnore]
 172    [MemoryPackIgnore]
 1173    public bool IsReadOnly => false;
 174
 175    /// <inheritdoc/>
 176    [JsonIgnore]
 177    [MemoryPackIgnore]
 1178    public bool IsSynchronized => false;
 179
 180    /// <inheritdoc/>
 181    [JsonIgnore]
 182    [MemoryPackIgnore]
 3183    public object SyncRoot => _syncRoot ??= new object();
 184
 185    /// <inheritdoc/>
 186    [JsonIgnore]
 187    [MemoryPackIgnore]
 1188    public bool IsFixedSize => false;
 189
 190    [JsonIgnore]
 191    [MemoryPackIgnore]
 192    object? IList.this[int index]
 193    {
 2194        get => this[index] ?? default!;
 195        set
 196        {
 197            try
 198            {
 2199                this[index] = (T)value!;
 1200            }
 1201            catch
 202            {
 1203                throw new NotSupportedException($"Unsupported value type for {value}");
 204            }
 1205        }
 206    }
 207
 208    /// <summary>
 209    /// Gets the element at the specified arrayIndex.
 210    /// </summary>
 211    [JsonIgnore]
 212    [MemoryPackIgnore]
 213    public T this[int index]
 214    {
 215        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 216        get
 217        {
 5631218            ChronicleGuard.ThrowIfListIndexInvalid(index, _count);
 5627219            return _innerArray[index];
 220        }
 221        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 222        set
 223        {
 1514224            ChronicleGuard.ThrowIfListIndexInvalid(index, _count);
 1514225            _innerArray[index] = value;
 1514226        }
 227    }
 228
 229    /// <summary>
 230    /// Gets or sets the current state of the array, including its items and count.
 231    /// </summary>
 232    /// <remarks>
 233    /// Setting this property replaces the entire contents of the array with the items from the specified state.
 234    /// The previous contents are discarded.
 235    /// The version is reset when the state is set.
 236    /// </remarks>
 237    [JsonInclude]
 238    [MemoryPackInclude]
 239    public SwiftArrayState<T> State
 240    {
 241        get
 242        {
 9243            var items = new T[_count];
 9244            Array.Copy(_innerArray, 0, items, 0, _count);
 9245            return new SwiftArrayState<T>(items);
 246        }
 247        internal set
 248        {
 10249            ChronicleGuard.ThrowIfNull(value.Items, nameof(value.Items));
 250
 10251            int count = value.Items.Length;
 252
 10253            if (count == 0)
 254            {
 1255                _innerArray = _emptyArray;
 1256                _count = 0;
 257            }
 258            else
 259            {
 9260                _innerArray = new T[count <= DefaultCapacity ? DefaultCapacity : count];
 9261                Array.Copy(value.Items, 0, _innerArray, 0, count);
 9262                _count = count;
 263            }
 264
 10265            _version = 0;
 10266        }
 267    }
 268
 269    #endregion
 270
 271    #region Collection Manipulation
 272
 273    /// <summary>
 274    /// Adds an object to the end of the SwiftList.
 275    /// </summary>
 276    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 277    public virtual void Add(T item)
 278    {
 112045279        if ((uint)_count == (uint)_innerArray.Length)
 223280            Resize(_innerArray.Length * 2);
 112045281        _innerArray[_count++] = item;
 112045282        _version++;
 112045283    }
 284
 285    int IList.Add(object? value)
 286    {
 287        try
 288        {
 2289            Add((T)value!);
 1290        }
 1291        catch (InvalidCastException)
 292        {
 1293            throw new NotSupportedException($"Wrong value type for {value}");
 294        }
 295
 1296        return _count - 1;
 297    }
 298
 299    /// <summary>
 300    /// Adds the elements of the specified collection to the end of the SwiftList.
 301    /// </summary>
 302    /// <remarks>
 303    /// Known-count sources reserve capacity before enumeration to avoid repeated growth.
 304    /// </remarks>
 305    public virtual void AddRange(IEnumerable<T> items)
 306    {
 10307        ChronicleGuard.ThrowIfNull(items, nameof(items));
 308
 10309        if (items is ICollection<T> collection)
 310        {
 4311            int count = collection.Count;
 4312            if (count > 0)
 313            {
 3314                EnsureAdditionalCapacity(count);
 3315                collection.CopyTo(_innerArray, _count);
 3316                _count += count;
 3317                _version++;
 318            }
 319
 4320            return;
 321        }
 322
 6323        if (items is IReadOnlyCollection<T> readOnlyCollection)
 324        {
 5325            AddKnownCountRange(readOnlyCollection, readOnlyCollection.Count);
 5326            return;
 327        }
 328
 8329        foreach (T item in items)
 3330            Add(item);
 1331    }
 332
 333    private void AddKnownCountRange(IEnumerable<T> items, int count)
 334    {
 5335        if (count > 0)
 336        {
 4337            EnsureAdditionalCapacity(count);
 338
 50339            foreach (T item in items)
 21340                _innerArray[_count++] = item;
 341
 4342            _version++;
 343        }
 5344    }
 345
 346    /// <summary>
 347    /// Adds the elements of the specified array to the end of the SwiftList.
 348    /// </summary>
 349    /// <param name="items">The array whose elements should be appended.</param>
 350    public virtual void AddRange(T[] items)
 351    {
 2352        ChronicleGuard.ThrowIfNull(items, nameof(items));
 2353        AddRange(items.AsSpan());
 2354    }
 355
 356    /// <summary>
 357    /// Adds the elements of the specified span to the end of the SwiftList.
 358    /// </summary>
 359    /// <param name="items">The span whose elements should be appended.</param>
 360    public virtual void AddRange(ReadOnlySpan<T> items)
 361    {
 18362        if (items.Length == 0)
 1363            return;
 364
 17365        EnsureAdditionalCapacity(items.Length);
 366
 17367        items.CopyTo(_innerArray.AsSpan(_count, items.Length));
 17368        _count += items.Length;
 17369        _version++;
 17370    }
 371
 372    private void EnsureAdditionalCapacity(int additionalCount)
 373    {
 24374        long requiredCount = (long)_count + additionalCount;
 24375        ChronicleGuard.ThrowIfTrue(requiredCount > int.MaxValue, message: "The collection is too large.");
 24376        EnsureCapacity((int)requiredCount);
 24377    }
 378
 379    /// <summary>
 380    /// Removes the first occurrence of a specific object from the SwiftList.
 381    /// </summary>
 382    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 383    public virtual bool Remove(T item)
 384    {
 3385        int index = IndexOf(item);
 4386        if (index < 0) return false; // Item not found return false;
 2387        RemoveAt(index);
 2388        return true;
 389    }
 390
 391    void IList.Remove(object? value)
 392    {
 393        try
 394        {
 2395            Remove((T)value!);
 1396        }
 1397        catch (InvalidCastException)
 398        {
 1399            throw new NotSupportedException($"Wrong value type for {value}");
 400        }
 1401    }
 402
 403    /// <summary>
 404    /// Removes the element at the specified arrayIndex of the SwiftList.
 405    /// </summary>
 406    public virtual void RemoveAt(int index)
 407    {
 637408        ChronicleGuard.ThrowIfListIndexInvalid(index, _count);
 636409        Array.Copy(_innerArray, index + 1, _innerArray, index, _count - index - 1);
 636410        _count--;
 636411        if (_clearReleasedSlots)
 2412            _innerArray[_count] = default!;
 636413        _version++;
 636414    }
 415
 416    /// <summary>
 417    /// Removes all the elements that match the conditions defined by the specified predicate.
 418    /// </summary>
 419    public virtual int RemoveAll(Predicate<T> match)
 420    {
 11421        ChronicleGuard.ThrowIfNull(match, nameof(match));
 422
 10423        int firstMatchIndex = IndexOfFirstMatch(match);
 10424        if (firstMatchIndex >= _count)
 3425            return 0;
 426
 7427        int newCount = CompactUnmatchedItems(firstMatchIndex, match);
 7428        int removedCount = _count - newCount;
 7429        ClearReleasedSlots(newCount, removedCount);
 7430        _count = newCount;
 7431        _version++;
 432
 7433        return removedCount;
 434    }
 435
 436    private int IndexOfFirstMatch(Predicate<T> match)
 437    {
 10438        int index = 0;
 25439        while (index < _count && !match(_innerArray[index]))
 15440            index++;
 441
 10442        return index;
 443    }
 444
 445    private int CompactUnmatchedItems(int writeIndex, Predicate<T> match)
 446    {
 200042447        for (int readIndex = writeIndex + 1; readIndex < _count; readIndex++)
 448        {
 100014449            if (!match(_innerArray[readIndex]))
 50006450                _innerArray[writeIndex++] = _innerArray[readIndex];
 451        }
 452
 7453        return writeIndex;
 454    }
 455
 456    private void ClearReleasedSlots(int startIndex, int count)
 457    {
 7458        if (_clearReleasedSlots)
 2459            Array.Clear(_innerArray, startIndex, count);
 7460    }
 461
 462    /// <summary>
 463    /// Inserts an element into the SwiftList at the specified arrayIndex.
 464    /// </summary>
 465    public virtual void Insert(int index, T item)
 466    {
 7467        ChronicleGuard.ThrowIfArrayIndexInvalid(index, _count);
 6468        if ((uint)_count == (uint)_innerArray.Length)
 1469            Resize(_innerArray.Length * 2);
 6470        if ((uint)index < (uint)_count)
 4471            Array.Copy(_innerArray, index, _innerArray, index + 1, _count - index);
 6472        _innerArray[index] = item;
 6473        _count++;
 6474        _version++;
 6475    }
 476
 477    void IList.Insert(int index, object? value)
 478    {
 479        try
 480        {
 2481            Insert(index, (T)value!);
 1482        }
 1483        catch (InvalidCastException)
 484        {
 1485            throw new NotSupportedException($"Wrong value type for {value}");
 486        }
 1487    }
 488
 489    /// <summary>
 490    /// Reverses the order of the elements in the entire <see cref="SwiftList{T}"/>.
 491    /// </summary>
 492    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 493    public void Reverse()
 494    {
 1495        Array.Reverse(_innerArray, 0, _count);
 1496        _version++;
 1497    }
 498
 499    /// <summary>
 500    /// Sorts the populated elements of the <see cref="SwiftList{T}"/> in place.
 501    /// </summary>
 502    /// <remarks>
 503    /// The sort is performed over the active <c>[0..Count)</c> range of the backing array and does not
 504    /// allocate additional collection storage. Pass a comparer to define a custom order; otherwise the
 505    /// default comparer for <typeparamref name="T"/> is used.
 506    /// </remarks>
 507    /// <param name="comparer">The comparer to use, or <c>null</c> to use the default comparer.</param>
 508    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 509    public void SortInPlace(IComparer<T>? comparer = null)
 510    {
 14511        SwiftArraySortHelper.Sort(_innerArray, 0, _count, comparer);
 14512        _version++;
 14513    }
 514
 515    /// <summary>
 516    /// Sorts the populated elements of the <see cref="SwiftList{T}"/> in place using a struct comparer.
 517    /// </summary>
 518    /// <remarks>
 519    /// This overload avoids boxing struct comparers and lets the JIT devirtualize comparer calls in hot paths.
 520    /// </remarks>
 521    /// <param name="comparer">The comparer to use.</param>
 522    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 523    public void SortInPlace<TComparer>(TComparer comparer)
 524        where TComparer : struct, IComparer<T>
 525    {
 11526        SwiftArraySortHelper.Sort(_innerArray, 0, _count, comparer);
 11527        _version++;
 11528    }
 529
 530    /// <summary>
 531    /// Removes all elements from the <see cref="SwiftList{T}"/>, resetting its count to zero.
 532    /// </summary>
 533    public virtual void Clear()
 534    {
 154535        if (_count != 0 && _clearReleasedSlots)
 11536            Array.Clear(_innerArray, 0, _count);
 154537        _count = 0;
 154538        _version++;
 154539    }
 540
 541    /// <summary>
 542    /// Removes all elements, optionally releasing references throughout retained backing storage.
 543    /// </summary>
 544    /// <param name="clearRetainedReferences">If true, also releases references outside the live range; otherwise uses o
 545    /// <remarks>Capacity is preserved. Full reference cleanup can take time proportional to retained capacity.</remarks
 546    public void Clear(bool clearRetainedReferences)
 547    {
 149548        if (clearRetainedReferences && _clearReleasedSlots)
 140549            Array.Clear(_innerArray, _count, _innerArray.Length - _count);
 149550        Clear();
 149551    }
 552
 553    /// <summary>
 554    /// Clears the <see cref="SwiftList{T}"/> without releasing the reference to the stored elements.
 555    /// Use FastClear() when you want to quickly reset the list without reallocating memory.
 556    /// </summary>
 557    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 558    public void FastClear()
 559    {
 150560        _count = 0;
 150561        _version++;
 150562    }
 563
 564    #endregion
 565
 566    #region Capacity Management
 567
 568    /// <summary>
 569    /// Ensures that the capacity of <see cref="SwiftList{T}"/> is sufficient to accommodate the specified number of ele
 570    /// The capacity can increase by double to balance memory allocation efficiency and space.
 571    /// </summary>
 572    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 573    public void EnsureCapacity(int capacity)
 574    {
 30575        capacity = SwiftHashTools.NextPowerOfTwo(capacity);
 30576        if (capacity > _innerArray.Length)
 8577            Resize(capacity);
 30578    }
 579
 580    /// <summary>
 581    /// Resizes the internal array to accommodate the specified number of elements.
 582    /// </summary>
 583    /// <remarks>
 584    /// If the specified size is less than or equal to the default capacity, the internal array is
 585    /// set to the default capacity.
 586    /// Existing elements are preserved up to the current count.
 587    /// </remarks>
 588    /// <param name="newSize">The desired new size of the internal array. Must be greater than or equal to zero.</param>
 589    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 590    protected void Resize(int newSize)
 591    {
 233592        int newCapacity = newSize <= DefaultCapacity ? DefaultCapacity : newSize;
 593
 233594        T[] newArray = new T[newCapacity];
 233595        if (_count > 0)
 49596            Array.Copy(_innerArray, 0, newArray, 0, _count);
 233597        _innerArray = newArray;
 233598        _version++;
 233599    }
 600
 601    /// <summary>
 602    /// Reduces the capacity of the SwiftList if the element count falls below 50% of the current capacity.
 603    /// Ensures efficient memory usage by resizing the internal array to match the current count when necessary.
 604    /// </summary>
 605    public void TrimExcessCapacity()
 606    {
 2607        int newCapacity = _count < DefaultCapacity ? DefaultCapacity : SwiftHashTools.NextPowerOfTwo(_count);
 2608        Array.Resize(ref _innerArray, newCapacity);
 2609        _version++;
 2610    }
 611
 612    #endregion
 613
 614    #region Utility Methods
 615
 616    /// <summary>
 617    /// Searches for the specified object and returns the zero-based arrayIndex of the first occurrence within the Swift
 618    /// </summary>
 619    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 574620    public int IndexOf(T item) => Array.IndexOf(_innerArray, item, 0, _count);
 621
 622    int IList.IndexOf(object? value)
 623    {
 624        int index;
 625        try
 626        {
 2627            index = Array.IndexOf(_innerArray, (T)value!, 0, _count);
 1628        }
 1629        catch
 630        {
 1631            throw new NotSupportedException($"Unsupported value type for {value}");
 632        }
 1633        return index;
 634    }
 635
 636    /// <summary>
 637    /// Copies the elements of the SwiftList to a new array.
 638    /// </summary>
 639    public T[] ToArray()
 640    {
 41641        T[] result = new T[_count];
 41642        Array.Copy(_innerArray, result, _count);
 41643        return result;
 644    }
 645
 646    /// <summary>
 647    /// Returns a mutable span over the populated portion of the list.
 648    /// </summary>
 649    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2650    public Span<T> AsSpan() => _innerArray.AsSpan(0, _count);
 651
 652    /// <summary>
 653    /// Returns a read-only span over the populated portion of the list.
 654    /// </summary>
 655    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1656    public ReadOnlySpan<T> AsReadOnlySpan() => _innerArray.AsSpan(0, _count);
 657
 658    /// <summary>
 659    /// Returns a string that represents the current collection.
 660    /// </summary>
 661    /// <remarks>
 662    /// This method provides a human-readable representation of the collection's contents,
 663    /// which can be useful for debugging or logging purposes.
 664    /// </remarks>
 665    /// <returns>A comma-separated list of the collection's elements, or the default string representation if the collec
 666    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2667    public override string ToString() => _count == 0
 2668        ? base.ToString()!
 2669        : string.Join(", ", this);
 670
 671    /// <summary>
 672    /// Determines whether an element is in the SwiftList.
 673    /// </summary>
 674    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 3675    public bool Contains(T item) => IndexOf(item) != -1;
 676
 677    /// <summary>
 678    /// Determines whether the <see cref="SwiftList{T}"/> contains an element that matches the conditions defined by the
 679    /// </summary>
 680    /// <param name="match">The predicate that defines the conditions of the element to search for.</param>
 681    /// <returns><c>true</c> if the <see cref="SwiftList{T}"/> contains one or more elements that match the specified pr
 682    public bool Exists(Predicate<T> match)
 683    {
 3684        ChronicleGuard.ThrowIfNull(match, nameof(match));
 685
 14686        for (int i = 0; i < _count; i++)
 687        {
 6688            if (match(_innerArray[i]))
 1689                return true;
 690        }
 691
 1692        return false;
 693    }
 694
 695    /// <summary>
 696    /// Searches for an element that matches the conditions defined by the specified predicate, and returns the first oc
 697    /// </summary>
 698    /// <param name="match">The predicate that defines the conditions of the element to search for.</param>
 699    /// <returns>The first element that matches the conditions defined by the specified predicate, if found; otherwise, 
 700    public T Find(Predicate<T> match)
 701    {
 4702        ChronicleGuard.ThrowIfNull(match, nameof(match));
 703
 20704        for (int i = 0; i < _count; i++)
 705        {
 8706            if (match(_innerArray[i]))
 1707                return _innerArray[i];
 708        }
 709
 2710        return default!;
 711    }
 712
 713    bool IList.Contains(object? value)
 714    {
 715        int index;
 716        try
 717        {
 2718            index = IndexOf((T)value!);
 1719        }
 1720        catch
 721        {
 1722            throw new NotSupportedException($"Unsupported value type for {value}");
 723        }
 1724        return index != -1;
 725    }
 726
 727    /// <summary>
 728    /// Swaps the values of two elements in the SwiftList.
 729    /// This method exchanges the values referenced by two variables.
 730    /// </summary>
 731    /// <param name="indexA">The first element to swap.</param>
 732    /// <param name="indexB">The second element to swap.</param>
 733    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1734    public void Swap(int indexA, int indexB) => (_innerArray[indexB], _innerArray[indexA]) = (_innerArray[indexA], _inne
 735
 736    /// <summary>
 737    /// Copies the elements of the SwiftList to the specified target SwiftList.
 738    /// The target list will resize if it lacks sufficient capacity,
 739    /// but retains any existing elements beyond the copied range.
 740    /// </summary>
 741    public void CopyTo(SwiftList<T> target)
 742    {
 2743        if (_count + 1 > target._innerArray.Length)
 1744            target.Resize(target._innerArray.Length * 2);
 2745        Array.Copy(_innerArray, 0, target._innerArray, 0, _count);
 2746        target._count = _count;
 2747        target._version++;
 2748    }
 749
 750    /// <inheritdoc/>
 751    public void CopyTo(T[] array, int arrayIndex)
 752    {
 4753        ChronicleGuard.ThrowIfNull(array, nameof(array));
 4754        ChronicleGuard.ThrowIfArrayIndexInvalid(arrayIndex, array.Length);
 4755        ChronicleGuard.ThrowIfArgument(array.Length - arrayIndex < _count, nameof(array), "Destination array is not long
 756
 2757        Array.Copy(_innerArray, 0, array, arrayIndex, _count);
 2758    }
 759
 760    /// <summary>
 761    /// Copies the populated elements of the SwiftList into the specified destination span.
 762    /// </summary>
 763    /// <param name="destination">The destination span.</param>
 764    public void CopyTo(Span<T> destination)
 765    {
 2766        ChronicleGuard.ThrowIfArgument(destination.Length < _count, nameof(destination), "Destination span is not long e
 767
 1768        AsSpan().CopyTo(destination);
 1769    }
 770
 771    /// <inheritdoc/>
 772    public void CopyTo(Array array, int arrayIndex)
 773    {
 3774        ChronicleGuard.ThrowIfNull(array, nameof(array));
 3775        ChronicleGuard.ThrowIfArgument(array.Rank != 1, nameof(array), "Array must be single dimensional.");
 2776        ChronicleGuard.ThrowIfArgument(array.GetLowerBound(0) != 0, nameof(array), "Array must have zero-based indexing.
 1777        ChronicleGuard.ThrowIfArrayIndexInvalid(arrayIndex, array.Length);
 1778        ChronicleGuard.ThrowIfArgument(array.Length - arrayIndex < _count, nameof(array), "Destination array is not long
 779
 1780        Array.Copy(_innerArray, 0, array, arrayIndex, _count);
 1781    }
 782
 783    /// <inheritdoc/>
 784    public void CloneTo(ICollection<T> output)
 785    {
 1786        output.Clear();
 8787        foreach (var item in this)
 3788            output.Add(item);
 1789    }
 790
 791    #endregion
 792
 793    #region Enumerators
 794
 795    /// <summary>
 796    /// Returns an enumerator that iterates through the <see cref="SwiftList{T}"/>.
 797    /// </summary>
 69798    public SwiftListEnumerator GetEnumerator() => new(this);
 26799    IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
 38800    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 801
 802
 803
 804    #endregion
 805}

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Collection/SwiftList.SwiftListEnumerator.cs

#LineLine coverage
 1//=======================================================================
 2// SwiftList.SwiftListEnumerator.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 partial class SwiftList<T>
 17{
 18    /// <summary>
 19    /// Enumerates the elements of a <see cref="SwiftList{T}"/> collection.
 20    /// </summary>
 21    /// <remarks>
 22    /// The enumerator provides read-only, forward-only iteration over the collection.
 23    /// The enumerator is invalidated if the collection is modified after the enumerator is created.
 24    /// In such cases, calling MoveNext or Reset will throw an InvalidOperationException.
 25    /// </remarks>
 26    public struct SwiftListEnumerator : IEnumerator<T>, IEnumerator, IDisposable
 27    {
 28        private readonly SwiftList<T> _list;
 29        private readonly T[] _array;
 30        private readonly uint _count;
 31        private readonly uint _version;
 32        private uint _index;
 33
 34        private T _current;
 35
 36        internal SwiftListEnumerator(SwiftList<T> list)
 37        {
 6938            _list = list;
 6939            _array = list._innerArray;
 6940            _count = (uint)list._count;
 6941            _version = list._version;
 6942            _index = 0;
 6943            _current = default!;
 6944        }
 45
 46        /// <inheritdoc/>
 43747        public T Current => _current;
 48
 49        object IEnumerator.Current
 50        {
 51            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 52            get
 53            {
 6354                ChronicleGuard.ThrowIfTrue(_index == 0 || _index > _count, message: "Enumeration has either not started 
 2655                return _current!;
 56            }
 57        }
 58
 59        /// <inheritdoc/>
 60        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 61        public bool MoveNext()
 62        {
 33563            ChronicleGuard.ThrowIfTrue(_version != _list._version, message: "Collection was modified during enumeration.
 64
 32765            if (_index >= _count)
 66            {
 6067                _index = _count + 1;
 6068                return false;
 69            }
 26770            _current = _array[_index++];
 26771            return true;
 72        }
 73
 74        /// <inheritdoc/>
 75        public void Reset()
 76        {
 2077            ChronicleGuard.ThrowIfTrue(_version != _list._version, message: "Collection was modified during enumeration.
 78
 1379            _index = 0;
 1380            _current = default!;
 1381        }
 82
 83        /// <inheritdoc/>
 3384        public void Dispose() => _index = 0;
 85    }
 86}

Methods/Properties

.cctor()
.ctor()
.ctor(System.Int32)
.ctor(System.Collections.Generic.IEnumerable`1<T>)
.ctor(SwiftCollections.SwiftArrayState`1<T>)
get_InnerArray()
get_Capacity()
get_Count()
get_IsReadOnly()
get_IsSynchronized()
get_SyncRoot()
get_IsFixedSize()
System.Collections.IList.get_Item(System.Int32)
System.Collections.IList.set_Item(System.Int32,System.Object)
get_Item(System.Int32)
set_Item(System.Int32,T)
get_State()
set_State(SwiftCollections.SwiftArrayState`1<T>)
Add(T)
System.Collections.IList.Add(System.Object)
AddRange(System.Collections.Generic.IEnumerable`1<T>)
AddKnownCountRange(System.Collections.Generic.IEnumerable`1<T>,System.Int32)
AddRange(T[])
AddRange(System.ReadOnlySpan`1<T>)
EnsureAdditionalCapacity(System.Int32)
Remove(T)
System.Collections.IList.Remove(System.Object)
RemoveAt(System.Int32)
RemoveAll(System.Predicate`1<T>)
IndexOfFirstMatch(System.Predicate`1<T>)
CompactUnmatchedItems(System.Int32,System.Predicate`1<T>)
ClearReleasedSlots(System.Int32,System.Int32)
Insert(System.Int32,T)
System.Collections.IList.Insert(System.Int32,System.Object)
Reverse()
SortInPlace(System.Collections.Generic.IComparer`1<T>)
SortInPlace(TComparer)
Clear()
Clear(System.Boolean)
FastClear()
EnsureCapacity(System.Int32)
Resize(System.Int32)
TrimExcessCapacity()
IndexOf(T)
System.Collections.IList.IndexOf(System.Object)
ToArray()
AsSpan()
AsReadOnlySpan()
ToString()
Contains(T)
Exists(System.Predicate`1<T>)
Find(System.Predicate`1<T>)
System.Collections.IList.Contains(System.Object)
Swap(System.Int32,System.Int32)
CopyTo(SwiftCollections.SwiftList`1<T>)
CopyTo(T[],System.Int32)
CopyTo(System.Span`1<T>)
CopyTo(System.Array,System.Int32)
CloneTo(System.Collections.Generic.ICollection`1<T>)
GetEnumerator()
System.Collections.Generic.IEnumerable<T>.GetEnumerator()
System.Collections.IEnumerable.GetEnumerator()
.ctor(SwiftCollections.SwiftList`1<T>)
get_Current()
System.Collections.IEnumerator.get_Current()
MoveNext()
Reset()
Dispose()