Commit 0a931393c0
Changed files (1)
lib
std
lib/std/enums.zig
@@ -5,14 +5,18 @@ const assert = std.debug.assert;
const testing = std.testing;
const EnumField = std.builtin.Type.EnumField;
+/// Increment this value when adding APIs that add single backwards branches.
+const eval_branch_quota_cushion = 5;
+
/// Returns a struct with a field matching each unique named enum element.
/// If the enum is extern and has multiple names for the same value, only
/// the first name is used. Each field is of type Data and has the provided
/// default, which may be undefined.
pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type {
+ @setEvalBranchQuota(@typeInfo(E).Enum.fields.len + eval_branch_quota_cushion);
const StructField = std.builtin.Type.StructField;
var fields: []const StructField = &[_]StructField{};
- for (std.meta.fields(E)) |field| {
+ for (@typeInfo(E).Enum.fields) |field| {
fields = fields ++ &[_]StructField{.{
.name = field.name ++ "",
.type = Data,
@@ -76,7 +80,7 @@ test tagName {
pub fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int {
var max_value: comptime_int = -1;
const max_usize: comptime_int = ~@as(usize, 0);
- const fields = std.meta.fields(E);
+ const fields = @typeInfo(E).Enum.fields;
for (fields) |f| {
if (f.value < 0) {
@compileError("Cannot create a direct enum array for " ++ @typeName(E) ++ ", field ." ++ f.name ++ " has a negative value.");
@@ -258,6 +262,7 @@ pub fn EnumSet(comptime E: type) type {
/// Initializes the set using a struct of bools
pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self {
+ @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len);
var result: Self = .{};
inline for (0..Self.len) |i| {
const key = comptime Indexer.keyForIndex(i);
@@ -438,6 +443,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type {
/// Initializes the map using a sparse struct of optionals
pub fn init(init_values: EnumFieldStruct(E, ?Value, null)) Self {
+ @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len);
var result: Self = .{};
inline for (0..Self.len) |i| {
const key = comptime Indexer.keyForIndex(i);
@@ -447,6 +453,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type {
result.values[i] = v.*;
}
}
+ return result;
}
/// Initializes a full mapping with all keys set to value.
@@ -469,6 +476,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type {
/// Initializes a full mapping with a provided default.
/// Consider using EnumArray instead if the map will remain full.
pub fn initFullWithDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self {
+ @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len);
var result: Self = .{
.bits = Self.BitSet.initFull(),
.values = undefined,
@@ -641,6 +649,7 @@ pub fn BoundedEnumMultiset(comptime E: type, comptime CountSize: type) type {
/// Initializes the multiset using a struct of counts.
pub fn init(init_counts: EnumFieldStruct(E, CountSize, 0)) Self {
+ @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len);
var self = initWithCount(0);
inline for (@typeInfo(E).Enum.fields) |field| {
const c = @field(init_counts, field.name);
@@ -1044,6 +1053,7 @@ pub fn EnumArray(comptime E: type, comptime V: type) type {
/// Initializes values in the enum array, with the specified default.
pub fn initDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self {
+ @setEvalBranchQuota(2 * @typeInfo(E).Enum.fields.len);
var result: Self = .{ .values = undefined };
inline for (0..Self.len) |i| {
const key = comptime Indexer.keyForIndex(i);
@@ -1214,6 +1224,10 @@ test "EnumSet const iterator" {
}
pub fn EnumIndexer(comptime E: type) type {
+ // Assumes that the enum fields are sorted in ascending order (optimistic).
+ // Unsorted enums may require the user to manually increase the quota.
+ @setEvalBranchQuota(3 * @typeInfo(E).Enum.fields.len + eval_branch_quota_cushion);
+
if (!@typeInfo(E).Enum.is_exhaustive) {
const BackingInt = @typeInfo(E).Enum.tag_type;
if (@bitSizeOf(BackingInt) > @bitSizeOf(usize))
@@ -1247,7 +1261,7 @@ pub fn EnumIndexer(comptime E: type) type {
};
}
- const const_fields = std.meta.fields(E);
+ const const_fields = @typeInfo(E).Enum.fields;
var fields = const_fields[0..const_fields.len].*;
const fields_len = fields.len;
@@ -1294,7 +1308,7 @@ pub fn EnumIndexer(comptime E: type) type {
// gives up some safety to avoid artificially limiting
// the range of signed enum values to max_isize.
const enum_value = if (min < 0) @as(isize, @bitCast(i)) +% min else i + min;
- return @as(E, @enumFromInt(@as(std.meta.Tag(E), @intCast(enum_value))));
+ return @as(E, @enumFromInt(@as(@typeInfo(E).Enum.tag_type, @intCast(enum_value))));
}
};
}
@@ -1440,3 +1454,45 @@ test values {
};
try testing.expectEqualSlices(E, &.{ .X, .Y, .Z }, values(E));
}
+
+test "big enums should not hit the eval branch quota" {
+ const big = struct {
+ const Big = @Type(@as(std.builtin.Type, .{
+ .Enum = .{
+ .tag_type = u16,
+ .fields = make_fields: {
+ var fields: []const std.builtin.Type.EnumField = &.{};
+ for (0..1999) |i| {
+ fields = fields ++ &[_]std.builtin.Type.EnumField{.{
+ .name = std.fmt.comptimePrint("field_{d}", .{i}),
+ .value = i,
+ }};
+ }
+ fields = fields ++ &[_]std.builtin.Type.EnumField{.{
+ .name = "field_9999",
+ .value = 9999,
+ }};
+ break :make_fields fields;
+ },
+ .decls = &.{},
+ .is_exhaustive = true,
+ },
+ }));
+ };
+
+ var set = EnumSet(big.Big).init(.{});
+ _ = &set;
+
+ var map = EnumMap(big.Big, u8).init(undefined);
+ map = EnumMap(big.Big, u8).initFullWith(undefined);
+ map = EnumMap(big.Big, u8).initFullWithDefault(123, .{});
+
+ var multiset = EnumMultiset(big.Big).init(.{});
+ _ = &multiset;
+
+ var bounded_multiset = BoundedEnumMultiset(big.Big, u8).init(.{});
+ _ = &bounded_multiset;
+
+ var array = EnumArray(big.Big, u8).init(undefined);
+ array = EnumArray(big.Big, u8).initDefault(123, .{});
+}