< 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
 11924    public QueryKeyIndexMap(
 11925        int capacity,
 11926        Func<int, TKey, bool> isMatch,
 11927        Func<int, bool> canRehash,
 11928        Func<int, TKey> getKey)
 29    {
 11930        _comparer = SwiftHashTools.GetDeterministicEqualityComparer<TKey>();
 11931        _isMatch = isMatch;
 11932        _canRehash = canRehash;
 11933        _getKey = getKey;
 11934        capacity = NormalizeBucketCapacity(capacity);
 11935        _buckets = new int[capacity].Populate(() => -1);
 11936        _bucketMask = capacity - 1;
 11937    }
 38
 39    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 40    public void Insert(TKey key, int index)
 41    {
 3615742        int bucketIndex = GetStartBucket(key);
 43
 3640544        while (_buckets[bucketIndex] != -1)
 24845            bucketIndex = (bucketIndex + 1) & _bucketMask;
 46
 3615747        _buckets[bucketIndex] = index;
 3615748    }
 49
 50    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 51    public int Find(TKey key)
 52    {
 35153        int bucketIndex = GetStartBucket(key);
 54
 38255        while (_buckets[bucketIndex] != -1)
 56        {
 20857            int candidate = _buckets[bucketIndex];
 20858            if (_isMatch(candidate, key))
 17759                return candidate;
 60
 3161            bucketIndex = (bucketIndex + 1) & _bucketMask;
 62        }
 63
 17464        return -1;
 65    }
 66
 67    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 68    public bool Remove(TKey key)
 69    {
 27170        int bucketIndex = GetStartBucket(key);
 71
 27372        while (_buckets[bucketIndex] != -1)
 73        {
 27274            int candidate = _buckets[bucketIndex];
 27275            if (_isMatch(candidate, key))
 76            {
 27077                _buckets[bucketIndex] = -1;
 27078                RehashBucketCluster((bucketIndex + 1) & _bucketMask);
 27079                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    {
 4090        capacity = NormalizeBucketCapacity(capacity);
 4091        _buckets = new int[capacity].Populate(() => -1);
 4092        _bucketMask = capacity - 1;
 93
 7047694        for (int i = 0; i < entryCount; i++)
 95        {
 3519896            if (!_canRehash(i))
 97                continue;
 98
 1764399            Insert(_getKey(i), i);
 100        }
 40101    }
 102
 103    public void Clear()
 104    {
 692105        for (int i = 0; i < _buckets.Length; i++)
 340106            _buckets[i] = -1;
 6107    }
 108
 109    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 110    private int GetStartBucket(TKey key)
 111    {
 36779112        int hash = _comparer.GetHashCode(key) & 0x7FFFFFFF;
 36779113        return hash & _bucketMask;
 114    }
 115
 116    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 117    private static int NormalizeBucketCapacity(int capacity)
 118    {
 159119        capacity = SwiftHashTools.NextPowerOfTwo(capacity);
 159120        return capacity <= 1 ? 2 : capacity * 2;
 121    }
 122
 123    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 124    private void RehashBucketCluster(int startIndex)
 125    {
 270126        int bucketIndex = startIndex;
 127
 5254128        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        }
 270137    }
 138}