Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
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
99 changes: 64 additions & 35 deletions src/System.Private.CoreLib/shared/System/ValueTuple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2018,8 +2018,8 @@ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
/// <returns>A 32-bit signed integer hash code.</returns>
public override int GetHashCode()
{
// We want to have a limited hash in this case. We'll use the last 8 elements of the tuple
if (!(Rest is IValueTupleInternal rest))
// We want to have a limited hash in this case. We'll use the first 7 elements of the tuple
if (!(Rest is IValueTupleInternal))
{
return HashCode.Combine(Item1?.GetHashCode() ?? 0,
Item2?.GetHashCode() ?? 0,
Expand All @@ -2030,46 +2030,50 @@ public override int GetHashCode()
Item7?.GetHashCode() ?? 0);
}

int size = rest.Length;
if (size >= 8) { return rest.GetHashCode(); }
int size = ((IValueTupleInternal)Rest).Length;
int restHashCode = Rest.GetHashCode();
if (size >= 8)
{
return restHashCode;
}

// In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest
// In this case, the rest member has less than 8 elements so we need to combine some of our elements with the elements in rest
int k = 8 - size;
switch (k)
{
case 1:
return HashCode.Combine(Item7?.GetHashCode() ?? 0,
rest.GetHashCode());
restHashCode);
case 2:
return HashCode.Combine(Item6?.GetHashCode() ?? 0,
Item7?.GetHashCode() ?? 0,
rest.GetHashCode());
restHashCode);
case 3:
return HashCode.Combine(Item5?.GetHashCode() ?? 0,
Item6?.GetHashCode() ?? 0,
Item7?.GetHashCode() ?? 0,
rest.GetHashCode());
restHashCode);
case 4:
return HashCode.Combine(Item4?.GetHashCode() ?? 0,
Item5?.GetHashCode() ?? 0,
Item6?.GetHashCode() ?? 0,
Item7?.GetHashCode() ?? 0,
rest.GetHashCode());
restHashCode);
case 5:
return HashCode.Combine(Item3?.GetHashCode() ?? 0,
Item4?.GetHashCode() ?? 0,
Item5?.GetHashCode() ?? 0,
Item6?.GetHashCode() ?? 0,
Item7?.GetHashCode() ?? 0,
rest.GetHashCode());
restHashCode);
case 6:
return HashCode.Combine(Item2?.GetHashCode() ?? 0,
Item3?.GetHashCode() ?? 0,
Item4?.GetHashCode() ?? 0,
Item5?.GetHashCode() ?? 0,
Item6?.GetHashCode() ?? 0,
Item7?.GetHashCode() ?? 0,
rest.GetHashCode());
restHashCode);
case 7:
case 8:
return HashCode.Combine(Item1?.GetHashCode() ?? 0,
Expand All @@ -2079,7 +2083,7 @@ public override int GetHashCode()
Item5?.GetHashCode() ?? 0,
Item6?.GetHashCode() ?? 0,
Item7?.GetHashCode() ?? 0,
rest.GetHashCode());
restHashCode);
}

Debug.Fail("Missed all cases for computing ValueTuple hash code");
Expand All @@ -2093,7 +2097,7 @@ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)

private int GetHashCodeCore(IEqualityComparer comparer)
{
// We want to have a limited hash in this case. We'll use the last 8 elements of the tuple
// We want to have a limited hash in this case. We'll use the first 7 elements of the tuple
if (!(Rest is IValueTupleInternal rest))
{
return HashCode.Combine(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!),
Expand All @@ -2102,34 +2106,59 @@ private int GetHashCodeCore(IEqualityComparer comparer)
}

int size = rest.Length;
if (size >= 8) { return rest.GetHashCode(comparer); }
int restHashCode = rest.GetHashCode(comparer);
if (size >= 8)
{
return restHashCode;
}

// In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest
int k = 8 - size;
switch (k)
{
case 1:
return HashCode.Combine(comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
return HashCode.Combine(comparer.GetHashCode(Item7!),
restHashCode);
case 2:
return HashCode.Combine(comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
return HashCode.Combine(comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!),
restHashCode);
case 3:
return HashCode.Combine(comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!),
rest.GetHashCode(comparer));
return HashCode.Combine(comparer.GetHashCode(Item5!),
comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!),
restHashCode);
case 4:
return HashCode.Combine(comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
return HashCode.Combine(comparer.GetHashCode(Item4!),
comparer.GetHashCode(Item5!),
comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!),
restHashCode);
case 5:
return HashCode.Combine(comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!),
comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
return HashCode.Combine(comparer.GetHashCode(Item3!),
comparer.GetHashCode(Item4!),
comparer.GetHashCode(Item5!),
comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!),
restHashCode);
case 6:
return HashCode.Combine(comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!),
comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!),
rest.GetHashCode(comparer));
return HashCode.Combine(comparer.GetHashCode(Item2!),
comparer.GetHashCode(Item3!),
comparer.GetHashCode(Item4!),
comparer.GetHashCode(Item5!),
comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!),
restHashCode);
case 7:
case 8:
return HashCode.Combine(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!),
comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
return HashCode.Combine(comparer.GetHashCode(Item1!),
comparer.GetHashCode(Item2!),
comparer.GetHashCode(Item3!),
comparer.GetHashCode(Item4!),
comparer.GetHashCode(Item5!),
comparer.GetHashCode(Item6!),
comparer.GetHashCode(Item7!),
restHashCode);
}

Debug.Fail("Missed all cases for computing ValueTuple hash code");
Expand All @@ -2151,19 +2180,19 @@ int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
/// </remarks>
public override string ToString()
{
if (Rest is IValueTupleInternal rest)
if (Rest is IValueTupleInternal)
{
return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + rest.ToStringEnd();
return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + ((IValueTupleInternal)Rest).ToStringEnd();
}

return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")";
}

string IValueTupleInternal.ToStringEnd()
{
if (Rest is IValueTupleInternal rest)
if (Rest is IValueTupleInternal)
{
return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + rest.ToStringEnd();
return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + ((IValueTupleInternal)Rest).ToStringEnd();
}

return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")";
Expand All @@ -2172,7 +2201,7 @@ string IValueTupleInternal.ToStringEnd()
/// <summary>
/// The number of positions in this data structure.
/// </summary>
int ITuple.Length => Rest is IValueTupleInternal rest ? 7 + rest.Length : 8;
int ITuple.Length => Rest is IValueTupleInternal ? 7 + ((IValueTupleInternal)Rest).Length : 8;

/// <summary>
/// Get the element at position <param name="index"/>.
Expand All @@ -2199,9 +2228,9 @@ string IValueTupleInternal.ToStringEnd()
return Item7;
}

if (Rest is IValueTupleInternal rest)
if (Rest is IValueTupleInternal)
{
return rest[index - 7];
return ((IValueTupleInternal)Rest)[index - 7];
}


Expand Down