Skip to content

Commit 65c3a5b

Browse files
committed
[STJ] Only compute PopCount once when topologically sorting Enums
1 parent 2fe0457 commit 65c3a5b

File tree

1 file changed

+22
-23
lines changed
  • src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value

1 file changed

+22
-23
lines changed

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -676,44 +676,43 @@ private static EnumFieldInfo[] TopologicalSortEnumFields(EnumFieldInfo[] enumFie
676676
return enumFields;
677677
}
678678

679-
var indices = new int[enumFields.Length];
679+
var indices = new long[enumFields.Length];
680680
for (int i = 0; i < enumFields.Length; i++)
681681
{
682-
indices[i] = i;
682+
// we want values with more bits set to come first so negate the pop count
683+
int popCount = -PopCount(enumFields[i].Key);
684+
// pack into a long with the pop count in the high bits and the index in the low bits
685+
// this allows us to sort by pop count and then by index in case of ties
686+
indices[i] = ((long)popCount << 32) | (uint)i;
683687
}
684688

685-
Array.Sort(indices, (i, j) => GetComparisonKey(i).CompareTo(GetComparisonKey(j)));
689+
indices.AsSpan().Sort();
686690

687691
var sortedFields = new EnumFieldInfo[enumFields.Length];
688692
for (int i = 0; i < indices.Length; i++)
689693
{
690-
sortedFields[i] = enumFields[indices[i]];
694+
// extract the index from the long, which is the low bits
695+
// the high bits are the pop count, which we don't need anymore
696+
int index = (int)(uint)indices[i];
697+
sortedFields[i] = enumFields[index];
691698
}
692699

693700
return sortedFields;
701+
}
694702

695-
(int PopCount, int Index) GetComparisonKey(int i)
696-
{
697-
// Sort by descending pop count of the enum value.
698-
// Since Array.Sort isn't a stable algorithm
699-
// append the current index to the comparison key.
700-
return (-PopCount(enumFields[i].Key), i);
701-
}
702-
703-
static int PopCount(ulong value)
704-
{
703+
private static int PopCount(ulong value)
704+
{
705705
#if NET
706-
return (int)ulong.PopCount(value);
706+
return (int)ulong.PopCount(value);
707707
#else
708-
int count = 0;
709-
while (value != 0)
710-
{
711-
value &= value - 1;
712-
count++;
713-
}
714-
return count;
715-
#endif
708+
int count = 0;
709+
while (value != 0)
710+
{
711+
value &= value - 1;
712+
count++;
716713
}
714+
return count;
715+
#endif
717716
}
718717

719718
private enum EnumFieldNameKind

0 commit comments

Comments
 (0)