< Summary

Information
Class: SwiftCollections.Query.QueryKeyIndexMap<T>
Assembly: SwiftCollections
File(s): /home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Query/Shared/QueryKeyIndexMap.cs
Line coverage
100%
Covered lines: 49
Uncovered lines: 0
Coverable lines: 49
Total lines: 133
Line coverage: 100%
Branch coverage
92%
Covered branches: 26
Total branches: 28
Branch coverage: 92.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)75%44100%
Insert(...)100%22100%
Find(...)100%44100%
Remove(...)100%44100%
ResizeAndRehash(...)100%66100%
Clear()100%22100%
GetStartBucket(...)100%11100%
NormalizeBucketCapacity(...)100%22100%
RehashBucketCluster(...)75%44100%

File(s)

/home/runner/work/SwiftCollections/SwiftCollections/src/SwiftCollections/Query/Shared/QueryKeyIndexMap.cs

#LineLine coverage
 1//=======================================================================
 2// QueryKeyIndexMap.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 SwiftCollections.Utility;
 9using System;
 10using System.Collections.Generic;
 11using System.Runtime.CompilerServices;
 12
 13namespace SwiftCollections.Query;
 14
 15internal sealed class QueryKeyIndexMap<TKey> where TKey : notnull
 16{
 17    private readonly IEqualityComparer<TKey> _comparer;
 18    private int[] _buckets;
 19    private int _bucketMask;
 20
 10621    public QueryKeyIndexMap(int capacity, IEqualityComparer<TKey>? comparer = null)
 22    {
 10623        _comparer = comparer ?? SwiftHashTools.GetDeterministicEqualityComparer<TKey>();
 10624        capacity = NormalizeBucketCapacity(capacity);
 10625        _buckets = new int[capacity].Populate(() => -1);
 10626        _bucketMask = capacity - 1;
 10627    }
 28
 29    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 30    public void Insert(TKey key, int index)
 31    {
 3198132        int bucketIndex = GetStartBucket(key);
 33
 3249734        while (_buckets[bucketIndex] != -1)
 51635            bucketIndex = (bucketIndex + 1) & _bucketMask;
 36
 3198137        _buckets[bucketIndex] = index;
 3198138    }
 39
 40    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 41    public int Find(TKey key, Func<int, TKey, bool> isMatch)
 42    {
 33443        int bucketIndex = GetStartBucket(key);
 44
 36545        while (_buckets[bucketIndex] != -1)
 46        {
 20447            int candidate = _buckets[bucketIndex];
 20448            if (isMatch(candidate, key))
 17349                return candidate;
 50
 3151            bucketIndex = (bucketIndex + 1) & _bucketMask;
 52        }
 53
 16154        return -1;
 55    }
 56
 57    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 58    public bool Remove(
 59        TKey key,
 60        Func<int, TKey, bool> isMatch,
 61        Func<int, bool> canRehash,
 62        Func<int, TKey> getKey)
 63    {
 14064        int bucketIndex = GetStartBucket(key);
 65
 14266        while (_buckets[bucketIndex] != -1)
 67        {
 14168            int candidate = _buckets[bucketIndex];
 14169            if (isMatch(candidate, key))
 70            {
 13971                _buckets[bucketIndex] = -1;
 13972                RehashBucketCluster((bucketIndex + 1) & _bucketMask, canRehash, getKey);
 13973                return true;
 74            }
 75
 276            bucketIndex = (bucketIndex + 1) & _bucketMask;
 77        }
 78
 179        return false;
 80    }
 81
 82    public void ResizeAndRehash(int capacity, int entryCount, Func<int, bool> shouldRehash, Func<int, TKey> getKey)
 83    {
 3984        capacity = NormalizeBucketCapacity(capacity);
 3985        _buckets = new int[capacity].Populate(() => -1);
 3986        _bucketMask = capacity - 1;
 87
 7046888        for (int i = 0; i < entryCount; i++)
 89        {
 3519590            if (!shouldRehash(i))
 91                continue;
 92
 1764193            Insert(getKey(i), i);
 94        }
 3995    }
 96
 97    public void Clear()
 98    {
 69299        for (int i = 0; i < _buckets.Length; i++)
 340100            _buckets[i] = -1;
 6101    }
 102
 103    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 104    private int GetStartBucket(TKey key)
 105    {
 32455106        int hash = _comparer.GetHashCode(key) & 0x7FFFFFFF;
 32455107        return hash & _bucketMask;
 108    }
 109
 110    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 111    private static int NormalizeBucketCapacity(int capacity)
 112    {
 145113        capacity = SwiftHashTools.NextPowerOfTwo(capacity);
 145114        return capacity <= 1 ? 2 : capacity * 2;
 115    }
 116
 117    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 118    private void RehashBucketCluster(int startIndex, Func<int, bool> canRehash, Func<int, TKey> getKey)
 119    {
 139120        int bucketIndex = startIndex;
 121
 1091122        while (_buckets[bucketIndex] != -1)
 123        {
 952124            int candidate = _buckets[bucketIndex];
 952125            _buckets[bucketIndex] = -1;
 126
 952127            if (canRehash(candidate))
 952128                Insert(getKey(candidate), candidate);
 129
 952130            bucketIndex = (bucketIndex + 1) & _bucketMask;
 131        }
 139132    }
 133}