@@ -1317,9 +1317,9 @@ test "EnumSet non-exhaustive" {
1317
1317
}
1318
1318
1319
1319
pub fn EnumIndexer (comptime E : type ) type {
1320
- // Assumes that the enum fields are sorted in ascending order (optimistic) .
1321
- // Unsorted enums may require the user to manually increase the quota.
1322
- @setEvalBranchQuota (3 * @typeInfo ( E ).@ "enum" .fields . len + eval_branch_quota_cushion );
1320
+ // n log n for `std.mem.sortUnstable` call below .
1321
+ const fields_len = @typeInfo ( E ).@ "enum" .fields . len ;
1322
+ @setEvalBranchQuota (3 * fields_len * std . math . log2 ( @max ( fields_len , 1 )) + eval_branch_quota_cushion );
1323
1323
1324
1324
if (! @typeInfo (E ).@"enum" .is_exhaustive ) {
1325
1325
const BackingInt = @typeInfo (E ).@"enum" .tag_type ;
@@ -1354,10 +1354,6 @@ pub fn EnumIndexer(comptime E: type) type {
1354
1354
};
1355
1355
}
1356
1356
1357
- const const_fields = @typeInfo (E ).@"enum" .fields ;
1358
- var fields = const_fields [0.. const_fields .len ].* ;
1359
- const fields_len = fields .len ;
1360
-
1361
1357
if (fields_len == 0 ) {
1362
1358
return struct {
1363
1359
pub const Key = E ;
@@ -1373,22 +1369,17 @@ pub fn EnumIndexer(comptime E: type) type {
1373
1369
};
1374
1370
}
1375
1371
1376
- const min = fields [0 ].value ;
1377
- const max = fields [fields .len - 1 ].value ;
1378
-
1379
- const SortContext = struct {
1380
- fields : []EnumField ,
1372
+ var fields : [fields_len ]EnumField = @typeInfo (E ).@"enum" .fields [0.. ].* ;
1381
1373
1382
- pub fn lessThan (comptime ctx : @This (), comptime a : usize , comptime b : usize ) bool {
1383
- return ctx .fields [a ].value < ctx .fields [b ].value ;
1374
+ std .mem .sortUnstable (EnumField , & fields , {}, struct {
1375
+ fn lessThan (ctx : void , lhs : EnumField , rhs : EnumField ) bool {
1376
+ ctx ;
1377
+ return lhs .value < rhs .value ;
1384
1378
}
1379
+ }.lessThan );
1385
1380
1386
- pub fn swap (comptime ctx : @This (), comptime a : usize , comptime b : usize ) void {
1387
- return std .mem .swap (EnumField , & ctx .fields [a ], & ctx .fields [b ]);
1388
- }
1389
- };
1390
- std .sort .insertionContext (0 , fields_len , SortContext { .fields = & fields });
1391
-
1381
+ const min = fields [0 ].value ;
1382
+ const max = fields [fields_len - 1 ].value ;
1392
1383
if (max - min == fields .len - 1 ) {
1393
1384
return struct {
1394
1385
pub const Key = E ;
@@ -1538,6 +1529,29 @@ test "EnumIndexer empty" {
1538
1529
try testing .expectEqual (0 , Indexer .count );
1539
1530
}
1540
1531
1532
+ test "EnumIndexer large dense unsorted" {
1533
+ @setEvalBranchQuota (500_000 ); // many `comptimePrint`s
1534
+ // Make an enum with 500 fields with values in *descending* order.
1535
+ const E = @Type (.{ .@"enum" = .{
1536
+ .tag_type = u32 ,
1537
+ .fields = comptime fields : {
1538
+ var fields : [500 ]EnumField = undefined ;
1539
+ for (& fields , 0.. ) | * f , i | f .* = .{
1540
+ .name = std .fmt .comptimePrint ("f{d}" , .{i }),
1541
+ .value = 500 - i ,
1542
+ };
1543
+ break :fields & fields ;
1544
+ },
1545
+ .decls = &.{},
1546
+ .is_exhaustive = true ,
1547
+ } });
1548
+ const Indexer = EnumIndexer (E );
1549
+ try testing .expectEqual (E .f0 , Indexer .keyForIndex (499 ));
1550
+ try testing .expectEqual (E .f499 , Indexer .keyForIndex (0 ));
1551
+ try testing .expectEqual (499 , Indexer .indexOf (.f0 ));
1552
+ try testing .expectEqual (0 , Indexer .indexOf (.f499 ));
1553
+ }
1554
+
1541
1555
test values {
1542
1556
const E = enum {
1543
1557
X ,
0 commit comments