Skip to content

Commit aa2cb6f

Browse files
committed
Make OptimizedSwitch.cs hashing deterministic.
[nightly ignore]
1 parent add4e5a commit aa2cb6f

File tree

4 files changed

+129
-61
lines changed

4 files changed

+129
-61
lines changed

src/Compilers/Lua/Portable/Generated/Loretta.Generators.SyntaxFactsGenerator/Loretta.Generators.SyntaxFactsGenerator.SyntaxFactsGenerator/SyntaxFacts.g.cs

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -167,23 +167,23 @@ public static Option<SyntaxKind> GetBinaryExpression(SyntaxKind kind) =>
167167
/// </summary>
168168
public static SyntaxKind GetKeywordKind(String text)
169169
{
170-
int __branch__216C9C4E = -1;
170+
int __branch__C36C95CA = -1;
171171
switch (text.Length)
172172
{
173173
case 2:
174174
switch (System.Runtime.InteropServices.MemoryMarshal.Read<int>(System.Runtime.InteropServices.MemoryMarshal.Cast<char, byte>(text.AsSpan(0, 2))))
175175
{
176176
case /* "do" = */ 0x006f0064:
177-
__branch__216C9C4E = 3;
177+
__branch__C36C95CA = 3;
178178
break;
179179
case /* "if" = */ 0x00660069:
180-
__branch__216C9C4E = 12;
180+
__branch__C36C95CA = 12;
181181
break;
182182
case /* "in" = */ 0x006e0069:
183-
__branch__216C9C4E = 13;
183+
__branch__C36C95CA = 13;
184184
break;
185185
case /* "or" = */ 0x0072006f:
186-
__branch__216C9C4E = 17;
186+
__branch__C36C95CA = 17;
187187
break;
188188
}
189189
break;
@@ -192,43 +192,43 @@ public static SyntaxKind GetKeywordKind(String text)
192192
{
193193
// and
194194
case /* "an" = */ 0x006e0061 when string.Equals(text, "and", StringComparison.Ordinal):
195-
__branch__216C9C4E = 0;
195+
__branch__C36C95CA = 0;
196196
break;
197197
// end
198198
case /* "en" = */ 0x006e0065 when string.Equals(text, "end", StringComparison.Ordinal):
199-
__branch__216C9C4E = 6;
199+
__branch__C36C95CA = 6;
200200
break;
201201
// for
202202
case /* "fo" = */ 0x006f0066 when string.Equals(text, "for", StringComparison.Ordinal):
203-
__branch__216C9C4E = 9;
203+
__branch__C36C95CA = 9;
204204
break;
205205
// nil
206206
case /* "ni" = */ 0x0069006e when string.Equals(text, "nil", StringComparison.Ordinal):
207-
__branch__216C9C4E = 15;
207+
__branch__C36C95CA = 15;
208208
break;
209209
// not
210210
case /* "no" = */ 0x006f006e when string.Equals(text, "not", StringComparison.Ordinal):
211-
__branch__216C9C4E = 16;
211+
__branch__C36C95CA = 16;
212212
break;
213213
}
214214
break;
215215
case 4:
216216
switch (System.Runtime.InteropServices.MemoryMarshal.Read<long>(System.Runtime.InteropServices.MemoryMarshal.Cast<char, byte>(text.AsSpan(0, 4))))
217217
{
218218
case /* "else" = */ 0x00650073006c0065:
219-
__branch__216C9C4E = 5;
219+
__branch__C36C95CA = 5;
220220
break;
221221
case /* "goto" = */ 0x006f0074006f0067:
222-
__branch__216C9C4E = 11;
222+
__branch__C36C95CA = 11;
223223
break;
224224
case /* "then" = */ 0x006e006500680074:
225-
__branch__216C9C4E = 20;
225+
__branch__C36C95CA = 20;
226226
break;
227227
case /* "true" = */ 0x0065007500720074:
228-
__branch__216C9C4E = 21;
228+
__branch__C36C95CA = 21;
229229
break;
230230
case /* "type" = */ 0x0065007000790074:
231-
__branch__216C9C4E = 22;
231+
__branch__C36C95CA = 22;
232232
break;
233233
}
234234
break;
@@ -237,23 +237,23 @@ public static SyntaxKind GetKeywordKind(String text)
237237
{
238238
// break
239239
case /* "b" = */ 'b' when string.Equals(text, "break", StringComparison.Ordinal):
240-
__branch__216C9C4E = 1;
240+
__branch__C36C95CA = 1;
241241
break;
242242
// false
243243
case /* "f" = */ 'f' when string.Equals(text, "false", StringComparison.Ordinal):
244-
__branch__216C9C4E = 8;
244+
__branch__C36C95CA = 8;
245245
break;
246246
// local
247247
case /* "l" = */ 'l' when string.Equals(text, "local", StringComparison.Ordinal):
248-
__branch__216C9C4E = 14;
248+
__branch__C36C95CA = 14;
249249
break;
250250
// until
251251
case /* "u" = */ 'u' when string.Equals(text, "until", StringComparison.Ordinal):
252-
__branch__216C9C4E = 24;
252+
__branch__C36C95CA = 24;
253253
break;
254254
// while
255255
case /* "w" = */ 'w' when string.Equals(text, "while", StringComparison.Ordinal):
256-
__branch__216C9C4E = 25;
256+
__branch__C36C95CA = 25;
257257
break;
258258
}
259259
break;
@@ -262,23 +262,23 @@ public static SyntaxKind GetKeywordKind(String text)
262262
{
263263
// elseif
264264
case /* "ls" = */ 0x0073006c when string.Equals(text, "elseif", StringComparison.Ordinal):
265-
__branch__216C9C4E = 4;
265+
__branch__C36C95CA = 4;
266266
break;
267267
// export
268268
case /* "xp" = */ 0x00700078 when string.Equals(text, "export", StringComparison.Ordinal):
269-
__branch__216C9C4E = 7;
269+
__branch__C36C95CA = 7;
270270
break;
271271
// repeat
272272
case /* "ep" = */ 0x00700065 when string.Equals(text, "repeat", StringComparison.Ordinal):
273-
__branch__216C9C4E = 18;
273+
__branch__C36C95CA = 18;
274274
break;
275275
// return
276276
case /* "et" = */ 0x00740065 when string.Equals(text, "return", StringComparison.Ordinal):
277-
__branch__216C9C4E = 19;
277+
__branch__C36C95CA = 19;
278278
break;
279279
// typeof
280280
case /* "yp" = */ 0x00700079 when string.Equals(text, "typeof", StringComparison.Ordinal):
281-
__branch__216C9C4E = 23;
281+
__branch__C36C95CA = 23;
282282
break;
283283
}
284284
break;
@@ -287,17 +287,17 @@ public static SyntaxKind GetKeywordKind(String text)
287287
{
288288
// continue
289289
case /* "c" = */ 'c' when string.Equals(text, "continue", StringComparison.Ordinal):
290-
__branch__216C9C4E = 2;
290+
__branch__C36C95CA = 2;
291291
break;
292292
// function
293293
case /* "f" = */ 'f' when string.Equals(text, "function", StringComparison.Ordinal):
294-
__branch__216C9C4E = 10;
294+
__branch__C36C95CA = 10;
295295
break;
296296
}
297297
break;
298298
}
299299

300-
switch (__branch__216C9C4E)
300+
switch (__branch__C36C95CA)
301301
{
302302
case 0:
303303
{
@@ -496,23 +496,23 @@ public static SyntaxKind GetKeywordKind(String text)
496496
/// </summary>
497497
public static SyntaxKind GetKeywordKind(ReadOnlySpan<char> span)
498498
{
499-
int __branch__216C9C4E = -1;
499+
int __branch__C36C95CA = -1;
500500
switch (span.Length)
501501
{
502502
case 2:
503503
switch (System.Runtime.InteropServices.MemoryMarshal.Read<int>(System.Runtime.InteropServices.MemoryMarshal.Cast<char, byte>(span.Slice(0, 2))))
504504
{
505505
case /* "do" = */ 0x006f0064:
506-
__branch__216C9C4E = 3;
506+
__branch__C36C95CA = 3;
507507
break;
508508
case /* "if" = */ 0x00660069:
509-
__branch__216C9C4E = 12;
509+
__branch__C36C95CA = 12;
510510
break;
511511
case /* "in" = */ 0x006e0069:
512-
__branch__216C9C4E = 13;
512+
__branch__C36C95CA = 13;
513513
break;
514514
case /* "or" = */ 0x0072006f:
515-
__branch__216C9C4E = 17;
515+
__branch__C36C95CA = 17;
516516
break;
517517
}
518518
break;
@@ -521,43 +521,43 @@ public static SyntaxKind GetKeywordKind(ReadOnlySpan<char> span)
521521
{
522522
// and
523523
case /* "an" = */ 0x006e0061 when span.Equals("and".AsSpan(), StringComparison.Ordinal):
524-
__branch__216C9C4E = 0;
524+
__branch__C36C95CA = 0;
525525
break;
526526
// end
527527
case /* "en" = */ 0x006e0065 when span.Equals("end".AsSpan(), StringComparison.Ordinal):
528-
__branch__216C9C4E = 6;
528+
__branch__C36C95CA = 6;
529529
break;
530530
// for
531531
case /* "fo" = */ 0x006f0066 when span.Equals("for".AsSpan(), StringComparison.Ordinal):
532-
__branch__216C9C4E = 9;
532+
__branch__C36C95CA = 9;
533533
break;
534534
// nil
535535
case /* "ni" = */ 0x0069006e when span.Equals("nil".AsSpan(), StringComparison.Ordinal):
536-
__branch__216C9C4E = 15;
536+
__branch__C36C95CA = 15;
537537
break;
538538
// not
539539
case /* "no" = */ 0x006f006e when span.Equals("not".AsSpan(), StringComparison.Ordinal):
540-
__branch__216C9C4E = 16;
540+
__branch__C36C95CA = 16;
541541
break;
542542
}
543543
break;
544544
case 4:
545545
switch (System.Runtime.InteropServices.MemoryMarshal.Read<long>(System.Runtime.InteropServices.MemoryMarshal.Cast<char, byte>(span.Slice(0, 4))))
546546
{
547547
case /* "else" = */ 0x00650073006c0065:
548-
__branch__216C9C4E = 5;
548+
__branch__C36C95CA = 5;
549549
break;
550550
case /* "goto" = */ 0x006f0074006f0067:
551-
__branch__216C9C4E = 11;
551+
__branch__C36C95CA = 11;
552552
break;
553553
case /* "then" = */ 0x006e006500680074:
554-
__branch__216C9C4E = 20;
554+
__branch__C36C95CA = 20;
555555
break;
556556
case /* "true" = */ 0x0065007500720074:
557-
__branch__216C9C4E = 21;
557+
__branch__C36C95CA = 21;
558558
break;
559559
case /* "type" = */ 0x0065007000790074:
560-
__branch__216C9C4E = 22;
560+
__branch__C36C95CA = 22;
561561
break;
562562
}
563563
break;
@@ -566,23 +566,23 @@ public static SyntaxKind GetKeywordKind(ReadOnlySpan<char> span)
566566
{
567567
// break
568568
case /* "b" = */ 'b' when span.Equals("break".AsSpan(), StringComparison.Ordinal):
569-
__branch__216C9C4E = 1;
569+
__branch__C36C95CA = 1;
570570
break;
571571
// false
572572
case /* "f" = */ 'f' when span.Equals("false".AsSpan(), StringComparison.Ordinal):
573-
__branch__216C9C4E = 8;
573+
__branch__C36C95CA = 8;
574574
break;
575575
// local
576576
case /* "l" = */ 'l' when span.Equals("local".AsSpan(), StringComparison.Ordinal):
577-
__branch__216C9C4E = 14;
577+
__branch__C36C95CA = 14;
578578
break;
579579
// until
580580
case /* "u" = */ 'u' when span.Equals("until".AsSpan(), StringComparison.Ordinal):
581-
__branch__216C9C4E = 24;
581+
__branch__C36C95CA = 24;
582582
break;
583583
// while
584584
case /* "w" = */ 'w' when span.Equals("while".AsSpan(), StringComparison.Ordinal):
585-
__branch__216C9C4E = 25;
585+
__branch__C36C95CA = 25;
586586
break;
587587
}
588588
break;
@@ -591,23 +591,23 @@ public static SyntaxKind GetKeywordKind(ReadOnlySpan<char> span)
591591
{
592592
// elseif
593593
case /* "ls" = */ 0x0073006c when span.Equals("elseif".AsSpan(), StringComparison.Ordinal):
594-
__branch__216C9C4E = 4;
594+
__branch__C36C95CA = 4;
595595
break;
596596
// export
597597
case /* "xp" = */ 0x00700078 when span.Equals("export".AsSpan(), StringComparison.Ordinal):
598-
__branch__216C9C4E = 7;
598+
__branch__C36C95CA = 7;
599599
break;
600600
// repeat
601601
case /* "ep" = */ 0x00700065 when span.Equals("repeat".AsSpan(), StringComparison.Ordinal):
602-
__branch__216C9C4E = 18;
602+
__branch__C36C95CA = 18;
603603
break;
604604
// return
605605
case /* "et" = */ 0x00740065 when span.Equals("return".AsSpan(), StringComparison.Ordinal):
606-
__branch__216C9C4E = 19;
606+
__branch__C36C95CA = 19;
607607
break;
608608
// typeof
609609
case /* "yp" = */ 0x00700079 when span.Equals("typeof".AsSpan(), StringComparison.Ordinal):
610-
__branch__216C9C4E = 23;
610+
__branch__C36C95CA = 23;
611611
break;
612612
}
613613
break;
@@ -616,17 +616,17 @@ public static SyntaxKind GetKeywordKind(ReadOnlySpan<char> span)
616616
{
617617
// continue
618618
case /* "c" = */ 'c' when span.Equals("continue".AsSpan(), StringComparison.Ordinal):
619-
__branch__216C9C4E = 2;
619+
__branch__C36C95CA = 2;
620620
break;
621621
// function
622622
case /* "f" = */ 'f' when span.Equals("function".AsSpan(), StringComparison.Ordinal):
623-
__branch__216C9C4E = 10;
623+
__branch__C36C95CA = 10;
624624
break;
625625
}
626626
break;
627627
}
628628

629-
switch (__branch__216C9C4E)
629+
switch (__branch__C36C95CA)
630630
{
631631
case 0:
632632
{

src/Tools/Generators/Shared/Hash.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
namespace Loretta.Generators
2+
{
3+
internal static class Hash
4+
{
5+
/// <summary>
6+
/// This is how VB Anonymous Types combine hash values for fields.
7+
/// </summary>
8+
internal static int Combine(int newKey, int currentKey) => unchecked((currentKey * (int) 0xA5555529) + newKey);
9+
10+
internal static int Combine(bool newKeyPart, int currentKey) => Combine(currentKey, newKeyPart ? 1 : 0);
11+
12+
/// <summary>
13+
/// This is how VB Anonymous Types combine hash values for fields.
14+
/// PERF: Do not use with enum types because that involves multiple
15+
/// unnecessary boxing operations. Unfortunately, we can't constrain
16+
/// T to "non-enum", so we'll use a more restrictive constraint.
17+
/// </summary>
18+
internal static int Combine<T>(T newKeyPart, int currentKey) where T : class?
19+
{
20+
var hash = unchecked(currentKey * (int) 0xA5555529);
21+
22+
if (newKeyPart != null) return unchecked(hash + newKeyPart.GetHashCode());
23+
24+
return hash;
25+
}
26+
27+
internal static int CombineValues<T>(IEnumerable<T>? values, int maxItemsToHash = int.MaxValue)
28+
=> values is null
29+
? 0
30+
: values.Take(maxItemsToHash).Where(static x => x is not null).Aggregate(
31+
0,
32+
static (current, value) => Combine(value!.GetHashCode(), current));
33+
34+
internal static int CombineValues<T>(T[]? values, int maxItemsToHash = int.MaxValue)
35+
{
36+
if (values == null) return 0;
37+
38+
var maxSize = Math.Min(maxItemsToHash, values.Length);
39+
var hashCode = 0;
40+
41+
for (var i = 0; i < maxSize; i++)
42+
{
43+
var value = values[i];
44+
45+
// Should end up with a constrained virtual call to object.GetHashCode (i.e. avoid boxing where possible).
46+
if (value is not null) hashCode = Combine(value.GetHashCode(), hashCode);
47+
}
48+
49+
return hashCode;
50+
}
51+
52+
internal static int CombineValues<T>(ImmutableArray<T> values, int maxItemsToHash = int.MaxValue)
53+
=> values.IsDefaultOrEmpty
54+
? 0
55+
: values.Take(maxItemsToHash).Where(static x => x is not null).Aggregate(
56+
0,
57+
static (current, value) => Combine(value!.GetHashCode(), current));
58+
59+
internal static int CombineValues(
60+
IEnumerable<string?>? values,
61+
StringComparer stringComparer,
62+
int maxItemsToHash = int.MaxValue)
63+
=> values == null
64+
? 0
65+
: values.Take(maxItemsToHash).OfType<string>().Aggregate(
66+
0,
67+
(current, value) => Combine(stringComparer.GetHashCode(value), current));
68+
}
69+
}

0 commit comments

Comments
 (0)