Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 3f678ae

Browse files
authored
Remove some boxing from tuples with >= 8 elements (#26584)
Take advantage of #14698 to avoid boxing the TRest argument and improve devirtualization.
1 parent c707157 commit 3f678ae

File tree

1 file changed

+64
-35
lines changed

1 file changed

+64
-35
lines changed

src/System.Private.CoreLib/shared/System/ValueTuple.cs

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,8 +2018,8 @@ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
20182018
/// <returns>A 32-bit signed integer hash code.</returns>
20192019
public override int GetHashCode()
20202020
{
2021-
// We want to have a limited hash in this case. We'll use the last 8 elements of the tuple
2022-
if (!(Rest is IValueTupleInternal rest))
2021+
// We want to have a limited hash in this case. We'll use the first 7 elements of the tuple
2022+
if (!(Rest is IValueTupleInternal))
20232023
{
20242024
return HashCode.Combine(Item1?.GetHashCode() ?? 0,
20252025
Item2?.GetHashCode() ?? 0,
@@ -2030,46 +2030,50 @@ public override int GetHashCode()
20302030
Item7?.GetHashCode() ?? 0);
20312031
}
20322032

2033-
int size = rest.Length;
2034-
if (size >= 8) { return rest.GetHashCode(); }
2033+
int size = ((IValueTupleInternal)Rest).Length;
2034+
int restHashCode = Rest.GetHashCode();
2035+
if (size >= 8)
2036+
{
2037+
return restHashCode;
2038+
}
20352039

2036-
// In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest
2040+
// 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
20372041
int k = 8 - size;
20382042
switch (k)
20392043
{
20402044
case 1:
20412045
return HashCode.Combine(Item7?.GetHashCode() ?? 0,
2042-
rest.GetHashCode());
2046+
restHashCode);
20432047
case 2:
20442048
return HashCode.Combine(Item6?.GetHashCode() ?? 0,
20452049
Item7?.GetHashCode() ?? 0,
2046-
rest.GetHashCode());
2050+
restHashCode);
20472051
case 3:
20482052
return HashCode.Combine(Item5?.GetHashCode() ?? 0,
20492053
Item6?.GetHashCode() ?? 0,
20502054
Item7?.GetHashCode() ?? 0,
2051-
rest.GetHashCode());
2055+
restHashCode);
20522056
case 4:
20532057
return HashCode.Combine(Item4?.GetHashCode() ?? 0,
20542058
Item5?.GetHashCode() ?? 0,
20552059
Item6?.GetHashCode() ?? 0,
20562060
Item7?.GetHashCode() ?? 0,
2057-
rest.GetHashCode());
2061+
restHashCode);
20582062
case 5:
20592063
return HashCode.Combine(Item3?.GetHashCode() ?? 0,
20602064
Item4?.GetHashCode() ?? 0,
20612065
Item5?.GetHashCode() ?? 0,
20622066
Item6?.GetHashCode() ?? 0,
20632067
Item7?.GetHashCode() ?? 0,
2064-
rest.GetHashCode());
2068+
restHashCode);
20652069
case 6:
20662070
return HashCode.Combine(Item2?.GetHashCode() ?? 0,
20672071
Item3?.GetHashCode() ?? 0,
20682072
Item4?.GetHashCode() ?? 0,
20692073
Item5?.GetHashCode() ?? 0,
20702074
Item6?.GetHashCode() ?? 0,
20712075
Item7?.GetHashCode() ?? 0,
2072-
rest.GetHashCode());
2076+
restHashCode);
20732077
case 7:
20742078
case 8:
20752079
return HashCode.Combine(Item1?.GetHashCode() ?? 0,
@@ -2079,7 +2083,7 @@ public override int GetHashCode()
20792083
Item5?.GetHashCode() ?? 0,
20802084
Item6?.GetHashCode() ?? 0,
20812085
Item7?.GetHashCode() ?? 0,
2082-
rest.GetHashCode());
2086+
restHashCode);
20832087
}
20842088

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

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

21042108
int size = rest.Length;
2105-
if (size >= 8) { return rest.GetHashCode(comparer); }
2109+
int restHashCode = rest.GetHashCode(comparer);
2110+
if (size >= 8)
2111+
{
2112+
return restHashCode;
2113+
}
21062114

21072115
// In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest
21082116
int k = 8 - size;
21092117
switch (k)
21102118
{
21112119
case 1:
2112-
return HashCode.Combine(comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
2120+
return HashCode.Combine(comparer.GetHashCode(Item7!),
2121+
restHashCode);
21132122
case 2:
2114-
return HashCode.Combine(comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
2123+
return HashCode.Combine(comparer.GetHashCode(Item6!),
2124+
comparer.GetHashCode(Item7!),
2125+
restHashCode);
21152126
case 3:
2116-
return HashCode.Combine(comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!),
2117-
rest.GetHashCode(comparer));
2127+
return HashCode.Combine(comparer.GetHashCode(Item5!),
2128+
comparer.GetHashCode(Item6!),
2129+
comparer.GetHashCode(Item7!),
2130+
restHashCode);
21182131
case 4:
2119-
return HashCode.Combine(comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!),
2120-
comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
2132+
return HashCode.Combine(comparer.GetHashCode(Item4!),
2133+
comparer.GetHashCode(Item5!),
2134+
comparer.GetHashCode(Item6!),
2135+
comparer.GetHashCode(Item7!),
2136+
restHashCode);
21212137
case 5:
2122-
return HashCode.Combine(comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!),
2123-
comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
2138+
return HashCode.Combine(comparer.GetHashCode(Item3!),
2139+
comparer.GetHashCode(Item4!),
2140+
comparer.GetHashCode(Item5!),
2141+
comparer.GetHashCode(Item6!),
2142+
comparer.GetHashCode(Item7!),
2143+
restHashCode);
21242144
case 6:
2125-
return HashCode.Combine(comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!),
2126-
comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!),
2127-
rest.GetHashCode(comparer));
2145+
return HashCode.Combine(comparer.GetHashCode(Item2!),
2146+
comparer.GetHashCode(Item3!),
2147+
comparer.GetHashCode(Item4!),
2148+
comparer.GetHashCode(Item5!),
2149+
comparer.GetHashCode(Item6!),
2150+
comparer.GetHashCode(Item7!),
2151+
restHashCode);
21282152
case 7:
21292153
case 8:
2130-
return HashCode.Combine(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!),
2131-
comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!),
2132-
comparer.GetHashCode(Item7!), rest.GetHashCode(comparer));
2154+
return HashCode.Combine(comparer.GetHashCode(Item1!),
2155+
comparer.GetHashCode(Item2!),
2156+
comparer.GetHashCode(Item3!),
2157+
comparer.GetHashCode(Item4!),
2158+
comparer.GetHashCode(Item5!),
2159+
comparer.GetHashCode(Item6!),
2160+
comparer.GetHashCode(Item7!),
2161+
restHashCode);
21332162
}
21342163

21352164
Debug.Fail("Missed all cases for computing ValueTuple hash code");
@@ -2151,19 +2180,19 @@ int IValueTupleInternal.GetHashCode(IEqualityComparer comparer)
21512180
/// </remarks>
21522181
public override string ToString()
21532182
{
2154-
if (Rest is IValueTupleInternal rest)
2183+
if (Rest is IValueTupleInternal)
21552184
{
2156-
return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + rest.ToStringEnd();
2185+
return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + ((IValueTupleInternal)Rest).ToStringEnd();
21572186
}
21582187

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

21622191
string IValueTupleInternal.ToStringEnd()
21632192
{
2164-
if (Rest is IValueTupleInternal rest)
2193+
if (Rest is IValueTupleInternal)
21652194
{
2166-
return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + rest.ToStringEnd();
2195+
return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + ((IValueTupleInternal)Rest).ToStringEnd();
21672196
}
21682197

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

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

2202-
if (Rest is IValueTupleInternal rest)
2231+
if (Rest is IValueTupleInternal)
22032232
{
2204-
return rest[index - 7];
2233+
return ((IValueTupleInternal)Rest)[index - 7];
22052234
}
22062235

22072236

0 commit comments

Comments
 (0)