Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ The System.Collections.Immutable library is built-in as part of the shared frame
<Compile Include="System\Collections\Frozen\ImmutableArrayFactory.cs" />
<Compile Include="System\Collections\Frozen\ItemsFrozenSet.cs" />
<Compile Include="System\Collections\Frozen\KeysAndValuesFrozenDictionary.cs" />
<Compile Include="System\Collections\Frozen\LengthBucketsFrozenDictionary.cs" />
<Compile Include="System\Collections\Frozen\LengthBucketsFrozenSet.cs" />
<Compile Include="System\Collections\Frozen\String\LengthBucketsFrozenDictionary.cs" />
<Compile Include="System\Collections\Frozen\String\LengthBucketsFrozenSet.cs" />
<Compile Include="System\Collections\Frozen\SmallFrozenDictionary.cs" />
<Compile Include="System\Collections\Frozen\SmallFrozenSet.cs" />
<Compile Include="System\Collections\Frozen\ValueTypeDefaultComparerFrozenDictionary.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace System.Collections.Frozen
internal sealed class DefaultFrozenDictionary<TKey, TValue> : KeysAndValuesFrozenDictionary<TKey, TValue>, IDictionary<TKey, TValue>
where TKey : notnull
{
internal DefaultFrozenDictionary(Dictionary<TKey, TValue> source, IEqualityComparer<TKey> comparer) :
base(source, comparer)
internal DefaultFrozenDictionary(Dictionary<TKey, TValue> source, IEqualityComparer<TKey> comparer)
: base(source, comparer)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace System.Collections.Frozen
/// <typeparam name="T">The type of the values in the set.</typeparam>
internal sealed class DefaultFrozenSet<T> : ItemsFrozenSet<T, DefaultFrozenSet<T>.GSW>
{
internal DefaultFrozenSet(HashSet<T> source, IEqualityComparer<T> comparer) :
base(source, comparer)
internal DefaultFrozenSet(HashSet<T> source, IEqualityComparer<T> comparer)
: base(source, comparer)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ static FrozenDictionary<TKey, TValue> PickIntegerDictionary<TInt>(Dictionary<TKe
return (FrozenDictionary<TKey, TValue>)(object)frozenDictionary;
}

var entries = (string[])(object)source.Keys.ToArray();
string[] entries = (string[])(object)source.Keys.ToArray();

KeyAnalyzer.Analyze(entries, ReferenceEquals(stringComparer, StringComparer.OrdinalIgnoreCase), out KeyAnalyzer.AnalysisResults results);
if (results.SubstringHashing)
Expand Down Expand Up @@ -242,9 +242,9 @@ static FrozenDictionary<TKey, TValue> PickIntegerDictionary<TInt>(Dictionary<TKe
}
else
{
frozenDictionary = results.HashCount == 1
? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar<TValue>(stringEntries, entries, stringComparer, results.MinimumLength, results.MaximumLengthDiff, results.HashIndex)
: new OrdinalStringFrozenDictionary_LeftJustifiedSubstring<TValue>(stringEntries, entries, stringComparer, results.MinimumLength, results.MaximumLengthDiff, results.HashIndex, results.HashCount);
frozenDictionary = results.HashCount == 1
? new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar<TValue>(stringEntries, entries, stringComparer, results.MinimumLength, results.MaximumLengthDiff, results.HashIndex)
: new OrdinalStringFrozenDictionary_LeftJustifiedSubstring<TValue>(stringEntries, entries, stringComparer, results.MinimumLength, results.MaximumLengthDiff, results.HashIndex, results.HashCount);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ public void FindMatchingEntries(int hashCode, out int startIndex, out int endInd
/// <remarks>
/// This tries to select a prime number of buckets. Rather than iterating through all possible bucket
/// sizes, starting at the exact number of hash codes and incrementing the bucket count by 1 per trial,
/// this is a trade-off between speed of determining a good number of buckets and maximumal density.
/// this is a trade-off between speed of determining a good number of buckets and maximal density.
/// </remarks>
private static int CalcNumBuckets(int[] hashCodes)
{
const double AcceptableCollisionRate = 0.05; // What is a satifactory rate of hash collisions?
const double AcceptableCollisionRate = 0.05; // What is a satisfactory rate of hash collisions?
const int LargeInputSizeThreshold = 1000; // What is the limit for an input to be considered "small"?
const int MaxSmallBucketTableMultiplier = 16; // How large a bucket table should be allowed for small inputs?
const int MaxLargeBucketTableMultiplier = 3; // How large a bucket table should be allowed for large inputs?
Expand All @@ -125,13 +125,14 @@ private static int CalcNumBuckets(int[] hashCodes)
Debug.Assert(codes.Count != 0);

// In our precomputed primes table, find the index of the smallest prime that's at least as large as our number of
// hash codes. If there are more codes than in our precomputed primes table, which accomodates millions of values,
// hash codes. If there are more codes than in our precomputed primes table, which accommodates millions of values,
// give up and just use the next prime.
int minPrimeIndexInclusive = 0;
while (minPrimeIndexInclusive < HashHelpers.s_primes.Length && codes.Count > HashHelpers.s_primes[minPrimeIndexInclusive])
{
minPrimeIndexInclusive++;
}

if (minPrimeIndexInclusive >= HashHelpers.s_primes.Length)
{
return HashHelpers.GetPrime(codes.Count);
Expand All @@ -143,12 +144,13 @@ private static int CalcNumBuckets(int[] hashCodes)
codes.Count *
(codes.Count >= LargeInputSizeThreshold ? MaxLargeBucketTableMultiplier : MaxSmallBucketTableMultiplier);

// Find the index of the smallest prime that accomodates our max buckets.
// Find the index of the smallest prime that accommodates our max buckets.
int maxPrimeIndexExclusive = minPrimeIndexInclusive;
while (maxPrimeIndexExclusive < HashHelpers.s_primes.Length && maxNumBuckets > HashHelpers.s_primes[maxPrimeIndexExclusive])
{
maxPrimeIndexExclusive++;
}

if (maxPrimeIndexExclusive < HashHelpers.s_primes.Length)
{
Debug.Assert(maxPrimeIndexExclusive != 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// 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 System.Collections.Immutable;
using System.Diagnostics;
Expand Down Expand Up @@ -158,7 +157,7 @@ static FrozenSet<T> PickIntegerSet<TInt>(HashSet<T> values)
else if (typeof(T) == typeof(string))
{
// Null is rare as a value in the set and we don't optimize for it. This enables the ordinal string
// implementation to fast-path out on null inputs rather than having to accomodate null inputs.
// implementation to fast-path out on null inputs rather than having to accommodate null inputs.
if (!uniqueValues.Contains(default!))
{
// If the value is a string and the comparer is known to provide ordinal (case-sensitive or case-insensitive) semantics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;

namespace System.Collections.Frozen
{
/// <summary>Provides a base class for frozen dictionaries that store their keys and values in dedicated arrays.</summary>
public abstract class KeysAndValuesFrozenDictionary<TKey, TValue> : FrozenDictionary<TKey, TValue>, IDictionary<TKey, TValue>
Comment thread
stephentoub marked this conversation as resolved.
internal abstract class KeysAndValuesFrozenDictionary<TKey, TValue> : FrozenDictionary<TKey, TValue>, IDictionary<TKey, TValue>
where TKey : notnull
{
private protected readonly FrozenHashTable _hashTable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ internal sealed class LengthBucketsFrozenDictionary<TValue> : FrozenDictionary<s
private readonly bool _ignoreCase;

private LengthBucketsFrozenDictionary(
string[] keys, TValue[] values, KeyValuePair<string, int>[][] lengthBuckets, int minLength, IEqualityComparer<string> comparer) :
base(comparer)
string[] keys, TValue[] values, KeyValuePair<string, int>[][] lengthBuckets, int minLength, IEqualityComparer<string> comparer)
: base(comparer)
{
Debug.Assert(comparer == EqualityComparer<string>.Default || comparer == StringComparer.Ordinal || comparer == StringComparer.OrdinalIgnoreCase);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal sealed class LengthBucketsFrozenSet : FrozenSetInternalBase<string, Len
{
/// <summary>Allowed ratio between buckets with values and total buckets. Under this ratio, this implementation won't be used due to too much wasted space.</summary>
private const double EmptyLengthsRatio = 0.2;

/// <summary>The maximum number of items allowed per bucket. The larger the value, the longer it can take to search a bucket, which is sequentially examined.</summary>
private const int MaxPerLength = 5;

Expand All @@ -20,8 +21,8 @@ internal sealed class LengthBucketsFrozenSet : FrozenSetInternalBase<string, Len
private readonly string[] _items;
private readonly bool _ignoreCase;

private LengthBucketsFrozenSet(string[] items, KeyValuePair<string, int>[][] lengthBuckets, int minLength, IEqualityComparer<string> comparer) :
base(comparer)
private LengthBucketsFrozenSet(string[] items, KeyValuePair<string, int>[][] lengthBuckets, int minLength, IEqualityComparer<string> comparer)
: base(comparer)
{
Debug.Assert(comparer == EqualityComparer<string>.Default || comparer == StringComparer.Ordinal || comparer == StringComparer.OrdinalIgnoreCase);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace System.Collections.Frozen
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace System.Collections.Frozen
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// 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.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Collections.Frozen
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ internal OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(
private protected override int FindItemIndex(string item) => base.FindItemIndex(item);

private protected override bool Equals(string? x, string? y) => StringComparer.OrdinalIgnoreCase.Equals(x, y);
private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan(s.Length + HashIndex, HashCount));
private protected override int GetHashCode(string s) => Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan(s.Length + HashIndex, HashCount));
}
}