| ... | @@ -5,25 +5,28 @@ const assert = std.debug.assert; | ... | @@ -5,25 +5,28 @@ const assert = std.debug.assert; |
| 5 | const testing = std.testing; | 5 | const testing = std.testing; |
| 6 | const EnumField = std.builtin.Type.EnumField; | 6 | const EnumField = std.builtin.Type.EnumField; |
| 7 | | 7 | |
| | 8 | /// Increment this value when adding APIs that add single backwards branches. |
| | 9 | const eval_branch_quota_cushion = 5; |
| | 10 | |
| 8 | /// Returns a struct with a field matching each unique named enum element. | 11 | /// Returns a struct with a field matching each unique named enum element. |
| 9 | /// If the enum is extern and has multiple names for the same value, only | 12 | /// If the enum is extern and has multiple names for the same value, only |
| 10 | /// the first name is used. Each field is of type Data and has the provided | 13 | /// the first name is used. Each field is of type Data and has the provided |
| 11 | /// default, which may be undefined. | 14 | /// default, which may be undefined. |
| 12 | pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { | 15 | pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type { |
| 13 | const StructField = std.builtin.Type.StructField; | 16 | @setEvalBranchQuota(@typeInfo(E).Enum.fields.len + eval_branch_quota_cushion); |
| 14 | var fields: []const StructField = &[_]StructField{}; | 17 | var struct_fields: [@typeInfo(E).Enum.fields.len]std.builtin.Type.StructField = undefined; |
| 15 | for (std.meta.fields(E)) |field| { | 18 | for (&struct_fields, @typeInfo(E).Enum.fields) |*struct_field, enum_field| { |
| 16 | fields = fields ++ &[_]StructField{.{ | 19 | struct_field.* = .{ |
| 17 | .name = field.name ++ "", | 20 | .name = enum_field.name ++ "", |
| 18 | .type = Data, | 21 | .type = Data, |
| 19 | .default_value = if (field_default) |d| @as(?*const anyopaque, @ptrCast(&d)) else null, | 22 | .default_value = if (field_default) |d| @as(?*const anyopaque, @ptrCast(&d)) else null, |
| 20 | .is_comptime = false, | 23 | .is_comptime = false, |
| 21 | .alignment = if (@sizeOf(Data) > 0) @alignOf(Data) else 0, | 24 | .alignment = if (@sizeOf(Data) > 0) @alignOf(Data) else 0, |
| 22 | }}; | 25 | }; |
| 23 | } | 26 | } |
| 24 | return @Type(.{ .Struct = .{ | 27 | return @Type(.{ .Struct = .{ |
| 25 | .layout = .auto, | 28 | .layout = .auto, |
| 26 | .fields = fields, | 29 | .fields = &struct_fields, |
| 27 | .decls = &.{}, | 30 | .decls = &.{}, |
| 28 | .is_tuple = false, | 31 | .is_tuple = false, |
| 29 | } }); | 32 | } }); |
| ... | @@ -76,7 +79,7 @@ test tagName { | ... | @@ -76,7 +79,7 @@ test tagName { |
| 76 | pub fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { | 79 | pub fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { |
| 77 | var max_value: comptime_int = -1; | 80 | var max_value: comptime_int = -1; |
| 78 | const max_usize: comptime_int = ~@as(usize, 0); | 81 | const max_usize: comptime_int = ~@as(usize, 0); |
| 79 | const fields = std.meta.fields(E); | 82 | const fields = @typeInfo(E).Enum.fields; |
| 80 | for (fields) |f| { | 83 | for (fields) |f| { |
| 81 | if (f.value < 0) { | 84 | if (f.value < 0) { |
| 82 | @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value."); | 85 | @compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value."); |
| ... | @@ -258,6 +261,7 @@ pub fn EnumSet(comptime E: type) type { | ... | @@ -258,6 +261,7 @@ pub fn EnumSet(comptime E: type) type { |
| 258 | | 261 | |
| 259 | /// Initializes the set using a struct of bools | 262 | /// Initializes the set using a struct of bools |
| 260 | pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self { | 263 | pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self { |
| | 264 | @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len); |
| 261 | var result: Self = .{}; | 265 | var result: Self = .{}; |
| 262 | inline for (0..Self.len) |i| { | 266 | inline for (0..Self.len) |i| { |
| 263 | const key = comptime Indexer.keyForIndex(i); | 267 | const key = comptime Indexer.keyForIndex(i); |
| ... | @@ -438,6 +442,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { | ... | @@ -438,6 +442,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { |
| 438 | | 442 | |
| 439 | /// Initializes the map using a sparse struct of optionals | 443 | /// Initializes the map using a sparse struct of optionals |
| 440 | pub fn init(init_values: EnumFieldStruct(E, ?Value, null)) Self { | 444 | pub fn init(init_values: EnumFieldStruct(E, ?Value, null)) Self { |
| | 445 | @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len); |
| 441 | var result: Self = .{}; | 446 | var result: Self = .{}; |
| 442 | inline for (0..Self.len) |i| { | 447 | inline for (0..Self.len) |i| { |
| 443 | const key = comptime Indexer.keyForIndex(i); | 448 | const key = comptime Indexer.keyForIndex(i); |
| ... | @@ -447,6 +452,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { | ... | @@ -447,6 +452,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { |
| 447 | result.values[i] = v.*; | 452 | result.values[i] = v.*; |
| 448 | } | 453 | } |
| 449 | } | 454 | } |
| | 455 | return result; |
| 450 | } | 456 | } |
| 451 | | 457 | |
| 452 | /// Initializes a full mapping with all keys set to value. | 458 | /// Initializes a full mapping with all keys set to value. |
| ... | @@ -469,6 +475,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { | ... | @@ -469,6 +475,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type { |
| 469 | /// Initializes a full mapping with a provided default. | 475 | /// Initializes a full mapping with a provided default. |
| 470 | /// Consider using EnumArray instead if the map will remain full. | 476 | /// Consider using EnumArray instead if the map will remain full. |
| 471 | pub fn initFullWithDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self { | 477 | pub fn initFullWithDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self { |
| | 478 | @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len); |
| 472 | var result: Self = .{ | 479 | var result: Self = .{ |
| 473 | .bits = Self.BitSet.initFull(), | 480 | .bits = Self.BitSet.initFull(), |
| 474 | .values = undefined, | 481 | .values = undefined, |
| ... | @@ -641,6 +648,7 @@ pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type { | ... | @@ -641,6 +648,7 @@ pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type { |
| 641 | | 648 | |
| 642 | /// Initializes the multiset using a struct of counts. | 649 | /// Initializes the multiset using a struct of counts. |
| 643 | pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self { | 650 | pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self { |
| | 651 | @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len); |
| 644 | var self = initWithCount(0); | 652 | var self = initWithCount(0); |
| 645 | inline for (@typeInfo(E).Enum.fields) |field| { | 653 | inline for (@typeInfo(E).Enum.fields) |field| { |
| 646 | const c = @field(init_counts, field.name); | 654 | const c = @field(init_counts, field.name); |
| ... | @@ -1044,6 +1052,7 @@ pub fn EnumArray(comptime E: type, comptime V: type) type { | ... | @@ -1044,6 +1052,7 @@ pub fn EnumArray(comptime E: type, comptime V: type) type { |
| 1044 | | 1052 | |
| 1045 | /// Initializes values in the enum array, with the specified default. | 1053 | /// Initializes values in the enum array, with the specified default. |
| 1046 | pub fn initDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self { | 1054 | pub fn initDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self { |
| | 1055 | @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len); |
| 1047 | var result: Self = .{ .values = undefined }; | 1056 | var result: Self = .{ .values = undefined }; |
| 1048 | inline for (0..Self.len) |i| { | 1057 | inline for (0..Self.len) |i| { |
| 1049 | const key = comptime Indexer.keyForIndex(i); | 1058 | const key = comptime Indexer.keyForIndex(i); |
| ... | @@ -1214,6 +1223,10 @@ test "EnumSet const iterator" { | ... | @@ -1214,6 +1223,10 @@ test "EnumSet const iterator" { |
| 1214 | } | 1223 | } |
| 1215 | | 1224 | |
| 1216 | pub fn EnumIndexer(comptime E: type) type { | 1225 | pub fn EnumIndexer(comptime E: type) type { |
| | 1226 | // Assumes that the enum fields are sorted in ascending order (optimistic). |
| | 1227 | // Unsorted enums may require the user to manually increase the quota. |
| | 1228 | @setEvalBranchQuota(3 * @typeInfo(E).Enum.fields.len + eval_branch_quota_cushion); |
| | 1229 | |
| 1217 | if (!@typeInfo(E).Enum.is_exhaustive) { | 1230 | if (!@typeInfo(E).Enum.is_exhaustive) { |
| 1218 | const BackingInt = @typeInfo(E).Enum.tag_type; | 1231 | const BackingInt = @typeInfo(E).Enum.tag_type; |
| 1219 | if (@bitSizeOf(BackingInt) > @bitSizeOf(usize)) | 1232 | if (@bitSizeOf(BackingInt) > @bitSizeOf(usize)) |
| ... | @@ -1247,7 +1260,7 @@ pub fn EnumIndexer(comptime E: type) type { | ... | @@ -1247,7 +1260,7 @@ pub fn EnumIndexer(comptime E: type) type { |
| 1247 | }; | 1260 | }; |
| 1248 | } | 1261 | } |
| 1249 | | 1262 | |
| 1250 | const const_fields = std.meta.fields(E); | 1263 | const const_fields = @typeInfo(E).Enum.fields; |
| 1251 | var fields = const_fields[0..const_fields.len].*; | 1264 | var fields = const_fields[0..const_fields.len].*; |
| 1252 | const fields_len = fields.len; | 1265 | const fields_len = fields.len; |
| 1253 | | 1266 | |
| ... | @@ -1294,7 +1307,7 @@ pub fn EnumIndexer(comptime E: type) type { | ... | @@ -1294,7 +1307,7 @@ pub fn EnumIndexer(comptime E: type) type { |
| 1294 | // gives up some safety to avoid artificially limiting | 1307 | // gives up some safety to avoid artificially limiting |
| 1295 | // the range of signed enum values to max_isize. | 1308 | // the range of signed enum values to max_isize. |
| 1296 | const enum_value = if (min < 0) @as(isize, @bitCast(i)) +% min else i + min; | 1309 | const enum_value = if (min < 0) @as(isize, @bitCast(i)) +% min else i + min; |
| 1297 | return @as(E, @enumFromInt(@as(std.meta.Tag(E), @intCast(enum_value)))); | 1310 | return @as(E, @enumFromInt(@as(@typeInfo(E).Enum.tag_type, @intCast(enum_value)))); |
| 1298 | } | 1311 | } |
| 1299 | }; | 1312 | }; |
| 1300 | } | 1313 | } |