< Summary

Line coverage
99%
Covered lines: 243
Uncovered lines: 1
Coverable lines: 244
Total lines: 532
Line coverage: 99.5%
Branch coverage
97%
Covered branches: 94
Total branches: 96
Branch coverage: 97.9%
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 2: .cctor()100%11100%
File 2: .ctor()100%11100%
File 2: .ctor(...)100%22100%
File 2: .ctor(...)100%11100%
File 2: get_Count()100%11100%
File 2: get_Capacity()100%11100%
File 2: get_IsSynchronized()100%11100%
File 2: get_SyncRoot()100%22100%
File 2: get_Dense()100%11100%
File 2: get_IsReadOnly()100%11100%
File 2: get_State()100%11100%
File 2: set_State(...)87.5%88100%
File 2: Contains(...)100%11100%
File 2: AsReadOnlySpan()100%11100%
File 2: Exists(...)100%44100%
File 2: Find(...)100%44100%
File 2: Add(...)100%22100%
File 2: System.Collections.Generic.ICollection<T>.Add(...)100%11100%
File 2: Remove(...)100%66100%
File 2: Clear()100%44100%
File 2: EnsureCapacity(...)100%22100%
File 2: GetEnumerator()100%11100%
File 2: System.Collections.Generic.IEnumerable<T>.GetEnumerator()100%11100%
File 2: 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%11100%
File 2: MoveNext()100%44100%
File 2: Reset()100%22100%
File 2: Dispose()100%11100%
File 2: CloneTo(...)100%22100%
File 2: CopyTo(...)100%44100%
File 2: ExceptWith(...)100%44100%
File 2: IntersectWith(...)100%66100%
File 2: IsProperSubsetOf(...)83.33%6690%
File 2: IsProperSupersetOf(...)100%66100%
File 2: IsSubsetOf(...)100%66100%
File 2: IsSupersetOf(...)100%44100%
File 2: Overlaps(...)100%44100%
File 2: SetEquals(...)100%66100%
File 2: SymmetricExceptWith(...)100%66100%
File 2: UnionWith(...)100%22100%

File(s)

/_/src/SwiftCollections/obj/Debug/net8.0/MemoryPack.Generator/MemoryPack.Generator.MemoryPackGenerator/SwiftCollections.SwiftPackedSet_T_.MemoryPackFormatter.g.cs

File '/_/src/SwiftCollections/obj/Debug/net8.0/MemoryPack.Generator/MemoryPack.Generator.MemoryPackGenerator/SwiftCollections.SwiftPackedSet_T_.MemoryPackFormatter.g.cs' does not exist (any more).

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

#LineLine coverage
 1using MemoryPack;
 2using System;
 3using System.Collections;
 4using System.Collections.Generic;
 5using System.Runtime.CompilerServices;
 6using System.Text.Json.Serialization;
 7
 8namespace SwiftCollections;
 9
 10/// <summary>
 11/// Represents a high-performance set that stores unique values in a densely packed array
 12/// while providing O(1) lookups via an internal hash map.
 13/// </summary>
 14/// <remarks>
 15/// <para>
 16/// <see cref="SwiftPackedSet{T}"/> maintains values in a contiguous array for extremely
 17/// cache-friendly iteration while using a hash-based lookup table to guarantee fast
 18/// membership tests and removals.
 19/// </para>
 20/// <para>
 21/// Removal uses a swap-back strategy that keeps the dense storage contiguous but does not
 22/// preserve ordering. As a result, iteration order is not guaranteed to remain stable.
 23/// </para>
 24/// <para>
 25/// This structure is commonly used in high-performance systems such as ECS (Entity Component Systems)
 26/// where dense iteration speed is critical.
 27/// </para>
 28/// </remarks>
 29/// <typeparam name="T">The type of elements contained in the set.</typeparam>
 30[Serializable]
 31[JsonConverter(typeof(SwiftStateJsonConverterFactory))]
 32[MemoryPackable]
 33public sealed partial class SwiftPackedSet<T> :
 34    ISwiftCloneable<T>,
 35    ISet<T>,
 36    IEnumerable<T>,
 37    IEnumerable
 38{
 39    #region Constants
 40
 41    public const int DefaultCapacity = 8;
 242    private static readonly bool _clearReleasedSlots = RuntimeHelpers.IsReferenceOrContainsReferences<T>();
 43
 44    #endregion
 45
 46    #region Fields
 47
 48    private T[] _dense;
 49    private SwiftDictionary<T, int> _lookup;
 50    private int _count;
 51
 52    [NonSerialized]
 53    private uint _version;
 54
 55    [NonSerialized]
 56    private object _syncRoot;
 57
 58    #endregion
 59
 60    #region Constructors
 61
 13862    public SwiftPackedSet() : this(DefaultCapacity) { }
 63
 4764    public SwiftPackedSet(int capacity)
 4765    {
 4766        capacity = capacity <= DefaultCapacity
 4767            ? DefaultCapacity
 4768            : SwiftHashTools.NextPowerOfTwo(capacity);
 69
 4770        _dense = new T[capacity];
 4771        _lookup = new SwiftDictionary<T, int>(capacity);
 4772    }
 73
 74    [MemoryPackConstructor]
 775    public SwiftPackedSet(SwiftArrayState<T> state)
 776    {
 777        State = state;
 778    }
 79
 80    #endregion
 81
 82    #region Properties
 83
 84    [JsonIgnore]
 85    [MemoryPackIgnore]
 1986    public int Count => _count;
 87
 88    [JsonIgnore]
 89    [MemoryPackIgnore]
 490    public int Capacity => _dense.Length;
 91
 92    [JsonIgnore]
 93    [MemoryPackIgnore]
 194    public bool IsSynchronized => false;
 95
 96    [JsonIgnore]
 97    [MemoryPackIgnore]
 198    public object SyncRoot => _syncRoot ??= new object();
 99
 100    [JsonIgnore]
 101    [MemoryPackIgnore]
 8102    public T[] Dense => _dense;
 103
 104    [JsonIgnore]
 105    [MemoryPackIgnore]
 1106    public bool IsReadOnly => false;
 107
 108    [JsonInclude]
 109    [MemoryPackInclude]
 110    public SwiftArrayState<T> State
 111    {
 112        get
 6113        {
 6114            var values = new T[_count];
 6115            Array.Copy(_dense, values, _count);
 116
 6117            return new SwiftArrayState<T>(values);
 6118        }
 119        internal set
 7120        {
 7121            var values = value.Items ?? Array.Empty<T>();
 122
 7123            int n = values.Length;
 7124            int newCapacity = n < DefaultCapacity
 7125                ? DefaultCapacity
 7126                : SwiftHashTools.NextPowerOfTwo(n);
 127
 7128            _dense = new T[newCapacity];
 7129            _lookup = new SwiftDictionary<T, int>(newCapacity);
 130
 7131            if (n > 0)
 4132            {
 4133                Array.Copy(values, _dense, n);
 134
 2022135                for (int i = 0; i < n; i++)
 1007136                    _lookup.Add(values[i], i);
 4137            }
 138
 7139            _count = n;
 7140            _version++;
 7141        }
 142    }
 143
 144    #endregion
 145
 146    #region Core Operations
 147
 148    public bool Contains(T value)
 1035149        => _lookup.ContainsKey(value);
 150
 151    /// <summary>
 152    /// Returns a read-only span over the populated dense portion of the set.
 153    /// </summary>
 1154    public ReadOnlySpan<T> AsReadOnlySpan() => _dense.AsSpan(0, _count);
 155
 156    /// <summary>
 157    /// Determines whether the <see cref="SwiftPackedSet{T}"/> contains an element that matches the conditions defined b
 158    /// </summary>
 159    /// <param name="match">The predicate that defines the conditions of the element to search for.</param>
 160    /// <returns><c>true</c> if the <see cref="SwiftPackedSet{T}"/> contains one or more elements that match the specifi
 161    public bool Exists(Predicate<T> match)
 3162    {
 3163        SwiftThrowHelper.ThrowIfNull(match, nameof(match));
 164
 10165        for (int i = 0; i < _count; i++)
 4166        {
 4167            if (match(_dense[i]))
 1168                return true;
 3169        }
 170
 1171        return false;
 2172    }
 173
 174    /// <summary>
 175    /// Searches for an element that matches the conditions defined by the specified predicate, and returns the first ma
 176    /// </summary>
 177    /// <param name="match">The predicate that defines the conditions of the element to search for.</param>
 178    /// <returns>The first element that matches the conditions defined by the specified predicate, if found; otherwise, 
 179    public T Find(Predicate<T> match)
 2180    {
 2181        SwiftThrowHelper.ThrowIfNull(match, nameof(match));
 182
 10183        for (int i = 0; i < _count; i++)
 4184        {
 4185            if (match(_dense[i]))
 1186                return _dense[i];
 3187        }
 188
 1189        return default;
 2190    }
 191
 192    public bool Add(T value)
 11096193    {
 11096194        if (_lookup.ContainsKey(value))
 1195            return false;
 196
 11095197        EnsureCapacity(_count + 1);
 198
 11095199        _dense[_count] = value;
 11095200        _lookup.Add(value, _count);
 201
 11095202        _count++;
 11095203        _version++;
 204
 11095205        return true;
 11096206    }
 207
 1208    void ICollection<T>.Add(T item) => Add(item);
 209
 210    public bool Remove(T value)
 5013211    {
 5013212        if (!_lookup.TryGetValue(value, out int index))
 3213            return false;
 214
 5010215        int last = --_count;
 216
 5010217        if (index != last)
 5006218        {
 5006219            T moved = _dense[last];
 220
 5006221            _dense[index] = moved;
 5006222            _lookup[moved] = index;
 5006223        }
 224
 5010225        if (_clearReleasedSlots)
 3226            _dense[last] = default;
 5010227        _lookup.Remove(value);
 228
 5010229        _version++;
 5010230        return true;
 5013231    }
 232
 233    public void Clear()
 7234    {
 8235        if (_count == 0) return;
 236
 6237        if (_clearReleasedSlots)
 1238            Array.Clear(_dense, 0, _count);
 6239        _lookup.Clear();
 240
 6241        _count = 0;
 6242        _version++;
 7243    }
 244
 245    #endregion
 246
 247    #region Capacity
 248
 249    public void EnsureCapacity(int capacity)
 11096250    {
 11096251        int newCapacity = SwiftHashTools.NextPowerOfTwo(capacity);
 11096252        if (newCapacity <= _dense.Length)
 11078253            return;
 254
 18255        var newArray = new T[newCapacity];
 18256        Array.Copy(_dense, newArray, _count);
 257
 18258        _dense = newArray;
 11096259    }
 260
 261    #endregion
 262
 263    #region Enumeration
 264
 15265    public Enumerator GetEnumerator() => new Enumerator(this);
 266
 12267    IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
 1268    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 269
 270    public struct Enumerator : IEnumerator<T>
 271    {
 272        private readonly SwiftPackedSet<T> _set;
 273        private readonly uint _version;
 274        private int _index;
 275
 276        internal Enumerator(SwiftPackedSet<T> set)
 15277        {
 15278            _set = set;
 15279            _version = set._version;
 15280            _index = -1;
 15281            Current = default;
 15282        }
 283
 44284        public T Current { get; private set; }
 285
 2286        object IEnumerator.Current => Current;
 287
 288        public bool MoveNext()
 19289        {
 19290            if (_version != _set._version)
 1291                throw new InvalidOperationException("Collection modified during enumeration");
 292
 18293            int next = _index + 1;
 18294            if (next >= _set._count)
 12295            {
 12296                Current = default;
 12297                return false;
 298            }
 299
 6300            _index = next;
 6301            Current = _set._dense[next];
 6302            return true;
 18303        }
 304
 305        public void Reset()
 2306        {
 2307            if (_version != _set._version)
 1308                throw new InvalidOperationException("Collection modified during enumeration");
 309
 1310            _index = -1;
 1311            Current = default;
 1312        }
 313
 24314        public void Dispose() { }
 315    }
 316
 317    #endregion
 318
 319    #region Clone
 320
 321    public void CloneTo(ICollection<T> output)
 1322    {
 1323        SwiftThrowHelper.ThrowIfNull(output, nameof(output));
 324
 1325        output.Clear();
 326
 6327        for (int i = 0; i < _count; i++)
 2328            output.Add(_dense[i]);
 1329    }
 330
 331    public void CopyTo(T[] array, int arrayIndex)
 3332    {
 3333        SwiftThrowHelper.ThrowIfNull(array, nameof(array));
 4334        if ((uint)arrayIndex > array.Length) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
 3335        if (array.Length - arrayIndex < _count) throw new ArgumentException("Destination array is not long enough.", nam
 336
 1337        Array.Copy(_dense, 0, array, arrayIndex, _count);
 1338    }
 339
 340    #endregion
 341
 342    #region ISet<T> Implementations
 343
 344    public void ExceptWith(IEnumerable<T> other)
 2345    {
 2346        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 347
 2348        if (ReferenceEquals(this, other))
 1349        {
 1350            Clear();
 1351            return;
 352        }
 353
 1354        var otherSet = new SwiftHashSet<T>(other);
 355
 9356        foreach (var item in otherSet)
 3357            Remove(item);
 2358    }
 359
 360    public void IntersectWith(IEnumerable<T> other)
 2361    {
 2362        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 363
 2364        if (ReferenceEquals(this, other))
 1365            return;
 366
 1367        var otherSet = new SwiftHashSet<T>(other);
 368
 10369        for (int i = _count - 1; i >= 0; i--)
 4370        {
 4371            var value = _dense[i];
 4372            if (!otherSet.Contains(value))
 2373                Remove(value);
 4374        }
 2375    }
 376
 377    public bool IsProperSubsetOf(IEnumerable<T> other)
 2378    {
 2379        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 380
 2381        var set = new SwiftHashSet<T>(other);
 382
 2383        if (_count >= set.Count)
 1384            return false;
 385
 8386        for (int i = 0; i < _count; i++)
 3387            if (!set.Contains(_dense[i]))
 0388                return false;
 389
 1390        return true;
 2391    }
 392
 393    public bool IsProperSupersetOf(IEnumerable<T> other)
 3394    {
 3395        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 396
 3397        var set = new SwiftHashSet<T>(other);
 398
 3399        if (_count <= set.Count)
 1400            return false;
 401
 11402        foreach (var item in set)
 3403            if (!Contains(item))
 1404                return false;
 405
 1406        return true;
 3407    }
 408
 409    public bool IsSubsetOf(IEnumerable<T> other)
 3410    {
 3411        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 412
 3413        var set = new SwiftHashSet<T>(other);
 414
 3415        if (_count > set.Count)
 1416            return false;
 417
 14418        for (int i = 0; i < _count; i++)
 6419            if (!set.Contains(_dense[i]))
 1420                return false;
 421
 1422        return true;
 3423    }
 424
 425    public bool IsSupersetOf(IEnumerable<T> other)
 2426    {
 2427        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 428
 15429        foreach (var item in other)
 5430            if (!Contains(item))
 1431                return false;
 432
 1433        return true;
 2434    }
 435
 436    public bool Overlaps(IEnumerable<T> other)
 2437    {
 2438        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 439
 11440        foreach (var item in other)
 3441            if (Contains(item))
 1442                return true;
 443
 1444        return false;
 2445    }
 446
 447    public bool SetEquals(IEnumerable<T> other)
 6448    {
 6449        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 450
 6451        var set = new SwiftHashSet<T>(other);
 452
 6453        if (_count != set.Count)
 1454            return false;
 455
 38456        for (int i = 0; i < _count; i++)
 15457            if (!set.Contains(_dense[i]))
 1458                return false;
 459
 4460        return true;
 6461    }
 462
 463    public void SymmetricExceptWith(IEnumerable<T> other)
 2464    {
 2465        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 466
 2467        if (ReferenceEquals(this, other))
 1468        {
 1469            Clear();
 1470            return;
 471        }
 472
 1473        var set = new SwiftHashSet<T>(other);
 474
 7475        foreach (var item in set)
 2476        {
 2477            if (!Remove(item))
 1478                Add(item);
 2479        }
 2480    }
 481
 482    public void UnionWith(IEnumerable<T> other)
 1483    {
 1484        SwiftThrowHelper.ThrowIfNull(other, nameof(other));
 485
 7486        foreach (var item in other)
 2487            Add(item);
 1488    }
 489
 490    #endregion
 491}