< 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: 55
Uncovered lines: 0
Coverable lines: 55
Total lines: 138
Line coverage: 100%
Branch coverage
100%
Covered branches: 24
Total branches: 24
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

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

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 System;
 9using System.Collections.Generic;
 10using System.Runtime.CompilerServices;
 11using SwiftCollections.Utility;
 12
 13namespace SwiftCollections.Query;
 14
 15internal sealed class QueryKeyIndexMap<TKey> where TKey : notnull
 16{
 17    private readonly IEqualityComparer<TKey> _comparer;
 18    private readonly Func<int, TKey, bool> _isMatch;
 19    private readonly Func<int, bool> _canRehash;
 20    private readonly Func<int, TKey> _getKey;
 21    private int[] _buckets;
 22    private int _bucketMask;
 23
 9124    public QueryKeyIndexMap(
 9125        int capacity,
 9126        Func<int, TKey, bool> isMatch,
 9127        Func<int, bool> canRehash,
 9128        Func<int, TKey> getKey)
 29    {
 9130        _comparer = SwiftHashTools.GetDeterministicEqualityComparer<TKey>();
 9131        _isMatch = isMatch;
 9132        _canRehash = canRehash;
 9133        _getKey = getKey;
 9134        capacity = NormalizeBucketCapacity(capacity);
 9135        _buckets = new int[capacity].Populate(() => -1);
 9136        _bucketMask = capacity - 1;
 9137    }
 38
 39    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 40    public void Insert(TKey key, int index)
 41    {
 3610742        int bucketIndex = GetStartBucket(key);
 43
 3636644        while (_buckets[bucketIndex] != -1)
 25945            bucketIndex = (bucketIndex + 1) & _bucketMask;
 46
 3610747        _buckets[bucketIndex] = index;
 3610748    }
 49
 50    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 51    public int Find(TKey key)
 52    {
 31453        int bucketIndex = GetStartBucket(key);
 54
 34255        while (_buckets[bucketIndex] != -1)
 56        {
 20057            int candidate = _buckets[bucketIndex];
 20058            if (_isMatch(candidate, key))
 17259                return candidate;
 60
 2861            bucketIndex = (bucketIndex + 1) & _bucketMask;
 62        }
 63
 14264        return -1;
 65    }
 66
 67    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 68    public bool Remove(TKey key)
 69    {
 26970        int bucketIndex = GetStartBucket(key);
 71
 27172        while (_buckets[bucketIndex] != -1)
 73        {
 27074            int candidate = _buckets[bucketIndex];
 27075            if (_isMatch(candidate, key))
 76            {
 26877                _buckets[bucketIndex] = -1;
 26878                RehashBucketCluster((bucketIndex + 1) & _bucketMask);
 26879                return true;
 80            }
 81
 282            bucketIndex = (bucketIndex + 1) & _bucketMask;
 83        }
 84
 185        return false;
 86    }
 87
 88    public void ResizeAndRehash(int capacity, int entryCount)
 89    {
 3790        capacity = NormalizeBucketCapacity(capacity);
 3791        _buckets = new int[capacity].Populate(() => -1);
 3792        _bucketMask = capacity - 1;
 93
 7044894        for (int i = 0; i < entryCount; i++)
 95        {
 3518796            if (!_canRehash(i))
 97                continue;
 98
 1763399            Insert(_getKey(i), i);
 100        }
 37101    }
 102
 103    public void Clear()
 104    {
 674105        for (int i = 0; i < _buckets.Length; i++)
 332106            _buckets[i] = -1;
 5107    }
 108
 109    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 110    private int GetStartBucket(TKey key)
 111    {
 36690112        int hash = _comparer.GetHashCode(key) & 0x7FFFFFFF;
 36690113        return hash & _bucketMask;
 114    }
 115
 116    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 117    private static int NormalizeBucketCapacity(int capacity)
 118    {
 128119        capacity = SwiftHashTools.NextPowerOfTwo(capacity);
 128120        return capacity <= 1 ? 2 : capacity * 2;
 121    }
 122
 123    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 124    private void RehashBucketCluster(int startIndex)
 125    {
 268126        int bucketIndex = startIndex;
 127
 5252128        while (_buckets[bucketIndex] != -1)
 129        {
 4984130            int candidate = _buckets[bucketIndex];
 4984131            _buckets[bucketIndex] = -1;
 132
 4984133            Insert(_getKey(candidate), candidate);
 134
 4984135            bucketIndex = (bucketIndex + 1) & _bucketMask;
 136        }
 268137    }
 138}