Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make internal FrozenHashTable non-generic #81603

Merged
merged 1 commit into from Feb 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -36,29 +36,28 @@ private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultipli
}

/// <summary>Initializes a frozen hash table.</summary>
/// <param name="entries">The set of entries to track from the hash table.</param>
/// <param name="hasher">A delegate that produces a hash code for a given entry.</param>
/// <param name="setter">A delegate that assigns the index to a specific entry.</param>
/// <param name="entriesLength">The number of entries to track from the hash table.</param>
/// <param name="hashAtIndex">A delegate that produces a hash code for a given entry. It's passed the index of the entry and returns that entry's hash code.</param>
/// <param name="storeDestIndexFromSrcIndex">A delegate that assigns the index to a specific entry. It's passed the destination and source indices.</param>
/// <param name="optimizeForReading">true to spend additional effort tuning for subsequent read speed on the table; false to prioritize construction time.</param>
/// <typeparam name="T">The type of elements in the hash table.</typeparam>
/// <remarks>
/// This method will iterate through the incoming entries and will invoke the hasher on each once.
/// It will then determine the optimal number of hash buckets to allocate and will populate the
/// bucket table. In the process of doing so, it calls out to the <paramref name="setter"/> to indicate
/// bucket table. In the process of doing so, it calls out to the <paramref name="storeDestIndexFromSrcIndex"/> to indicate
/// the resulting index for that entry. <see cref="FindMatchingEntries(int, out int, out int)"/>
/// then uses this index to reference individual entries by indexing into <see cref="HashCodes"/>.
/// </remarks>
/// <returns>A frozen hash table.</returns>
public static FrozenHashTable Create<T>(T[] entries, Func<T, int> hasher, Action<int, T> setter, bool optimizeForReading = true)
public static FrozenHashTable Create(int entriesLength, Func<int, int> hashAtIndex, Action<int, int> storeDestIndexFromSrcIndex, bool optimizeForReading = true)
{
Debug.Assert(entries.Length != 0);
Debug.Assert(entriesLength != 0);

// Calculate the hashcodes for every entry.
int[] arrayPoolHashCodes = ArrayPool<int>.Shared.Rent(entries.Length);
Span<int> hashCodes = arrayPoolHashCodes.AsSpan(0, entries.Length);
for (int i = 0; i < entries.Length; i++)
int[] arrayPoolHashCodes = ArrayPool<int>.Shared.Rent(entriesLength);
Span<int> hashCodes = arrayPoolHashCodes.AsSpan(0, entriesLength);
for (int i = 0; i < entriesLength; i++)
{
hashCodes[i] = hasher(entries[i]);
hashCodes[i] = hashAtIndex(i);
}

// Determine how many buckets to use. This might be fewer than the number of entries
Expand Down Expand Up @@ -113,7 +112,7 @@ public static FrozenHashTable Create<T>(T[] entries, Func<T, int> hasher, Action
while (index >= 0)
{
hashtableHashcodes[count] = hashCodes[index];
setter(count, entries[index]);
storeDestIndexFromSrcIndex(count, index);
count++;
bucketCount++;

Expand Down
Expand Up @@ -28,9 +28,9 @@ internal Int32FrozenDictionary(Dictionary<int, TValue> source) : base(EqualityCo
_values = new TValue[entries.Length];

_hashTable = FrozenHashTable.Create(
entries,
pair => pair.Key,
(index, pair) => _values[index] = pair.Value);
entries.Length,
index => entries[index].Key,
(destIndex, srcIndex) => _values[destIndex] = entries[srcIndex].Value);
}

/// <inheritdoc />
Expand Down
@@ -1,9 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace System.Collections.Frozen
{
Expand All @@ -21,10 +21,16 @@ internal Int32FrozenSet(HashSet<int> source) : base(EqualityComparer<int>.Defaul
Debug.Assert(source.Count != 0);
Debug.Assert(ReferenceEquals(source.Comparer, EqualityComparer<int>.Default));

int count = source.Count;
int[] entries = ArrayPool<int>.Shared.Rent(count);
source.CopyTo(entries);

_hashTable = FrozenHashTable.Create(
source.ToArray(),
item => item,
(_, _) => { });
count,
index => entries[index],
delegate { });

ArrayPool<int>.Shared.Return(entries);
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
}

/// <inheritdoc />
Expand Down
Expand Up @@ -23,9 +23,9 @@ protected ItemsFrozenSet(HashSet<T> source, bool optimizeForReading = true) : ba
_items = new T[entries.Length];

_hashTable = FrozenHashTable.Create(
entries,
o => o is null ? 0 : Comparer.GetHashCode(o),
(index, item) => _items[index] = item,
entries.Length,
index => entries[index] is T t ? Comparer.GetHashCode(t) : 0,
(destIndex, srcIndex) => _items[destIndex] = entries[srcIndex],
optimizeForReading);
}

Expand Down
Expand Up @@ -25,12 +25,12 @@ protected KeysAndValuesFrozenDictionary(Dictionary<TKey, TValue> source, bool op
_values = new TValue[entries.Length];

_hashTable = FrozenHashTable.Create(
entries,
pair => Comparer.GetHashCode(pair.Key),
(index, pair) =>
entries.Length,
index => Comparer.GetHashCode(entries[index].Key),
(destIndex, srcIndex) =>
{
_keys[index] = pair.Key;
_values[index] = pair.Value;
_keys[destIndex] = entries[srcIndex].Key;
_values[destIndex] = entries[srcIndex].Value;
},
optimizeForReading);
}
Expand Down
Expand Up @@ -41,12 +41,12 @@ internal abstract class OrdinalStringFrozenDictionary<TValue> : FrozenDictionary
HashCount = hashCount;

_hashTable = FrozenHashTable.Create(
entries,
pair => GetHashCode(pair.Key),
(index, pair) =>
entries.Length,
index => GetHashCode(entries[index].Key),
(destIndex, srcIndex) =>
{
_keys[index] = pair.Key;
_values[index] = pair.Value;
_keys[destIndex] = entries[srcIndex].Key;
_values[destIndex] = entries[srcIndex].Value;
});
}

Expand Down
Expand Up @@ -31,9 +31,9 @@ internal abstract class OrdinalStringFrozenSet : FrozenSetInternalBase<string, O
HashCount = hashCount;

_hashTable = FrozenHashTable.Create(
entries,
GetHashCode,
(index, item) => _items[index] = item);
entries.Length,
index => GetHashCode(entries[index]),
(destIndex, srcIndex) => _items[destIndex] = entries[srcIndex]);
}

private protected int HashIndex { get; }
Expand Down