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