File: Contracts\SHash_1.cs
Web Access
Project: src\src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using Microsoft.Diagnostics.DataContractReader.Data;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal readonly partial struct SHash_1 : ISHash
{
    internal readonly Target _target;
    public SHash_1(Target target)
    {
        _target = target;
    }

    private class SHash<TKey, TEntry> : ISHash<TKey, TEntry> where TEntry : IData<TEntry>
    {
        public TargetPointer Table { get; set; }
        public uint TableSize { get; set; }
        public uint EntrySize { get; set; }
        public List<TEntry>? Entries { get; set; }
        public ITraits<TKey, TEntry>? Traits { get; set; }
    }

    ISHash<TKey, TEntry> ISHash.CreateSHash<TKey, TEntry>(Target target, TargetPointer address, Target.TypeInfo type, ITraits<TKey, TEntry> traits)
    {
        TargetPointer table = target.ReadPointer(address + (ulong)type.Fields[nameof(SHash<TKey, TEntry>.Table)].Offset);
        uint tableSize = target.Read<uint>(address + (ulong)type.Fields[nameof(SHash<TKey, TEntry>.TableSize)].Offset);
        uint entrySize = type.Size ?? 0;
        List<TEntry> entries = [];
        for (int i = 0; i < tableSize; i++)
        {
            TargetPointer entryAddress = table + (ulong)(i * entrySize);
            TEntry entry = target.ProcessedData.GetOrAdd<TEntry>(entryAddress);
            entries.Add(entry);
        }
        return new SHash<TKey, TEntry>
        {
            Table = table,
            TableSize = tableSize,
            EntrySize = entrySize,
            Traits = traits,
            Entries = entries
        };
    }
    TEntry ISHash.LookupSHash<TKey, TEntry>(ISHash<TKey, TEntry> hashTable, TKey key)
    {
        SHash<TKey, TEntry> shashTable = (SHash<TKey, TEntry>)hashTable;
        if (shashTable.TableSize == 0)
            return shashTable.Traits!.Null();

        uint hash = shashTable.Traits!.Hash(key);
        uint index = hash % shashTable.TableSize;
        uint increment = 0;
        while (true)
        {
            TEntry current = shashTable.Entries![(int)index];
            if (shashTable.Traits.IsNull(current))
                return shashTable.Traits.Null();
            // we don't support the removal of entries
            if (!shashTable.Traits.IsDeleted(current) && shashTable.Traits.Equals(key, shashTable.Traits.GetKey(current)))
                return current;

            if (increment == 0)
                increment = (hash % (shashTable.TableSize - 1)) + 1;

            index += increment;
            if (index >= shashTable.TableSize)
                index -= shashTable.TableSize;
        }
    }
}