Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Remove some boxing from tuples with >= 8 elements (dotnet/coreclr#26584)
Browse files Browse the repository at this point in the history
Take advantage of dotnet/coreclr#14698 to avoid boxing the TRest argument and improve devirtualization.

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
  • Loading branch information
stephentoub authored and MichalStrehovsky committed Sep 15, 2019
1 parent c290c01 commit 87a759f
Showing 1 changed file with 64 additions and 35 deletions.
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

0 comments on commit 87a759f

Please sign in to comment.