mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
Merge pull request #19258 from castholm/enums-eval-branch-quota
std.enums: Increase eval branch quotas
This commit is contained in:
commit
778ab767b1
@ -5,25 +5,28 @@ 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 {
|
||||
const StructField = std.builtin.Type.StructField;
|
||||
var fields: []const StructField = &[_]StructField{};
|
||||
for (std.meta.fields(E)) |field| {
|
||||
fields = fields ++ &[_]StructField{.{
|
||||
.name = field.name ++ "",
|
||||
@setEvalBranchQuota(@typeInfo(E).Enum.fields.len + eval_branch_quota_cushion);
|
||||
var struct_fields: [@typeInfo(E).Enum.fields.len]std.builtin.Type.StructField = undefined;
|
||||
for (&struct_fields, @typeInfo(E).Enum.fields) |*struct_field, enum_field| {
|
||||
struct_field.* = .{
|
||||
.name = enum_field.name ++ "",
|
||||
.type = Data,
|
||||
.default_value = if (field_default) |d| @as(?*const anyopaque, @ptrCast(&d)) else null,
|
||||
.is_comptime = false,
|
||||
.alignment = if (@sizeOf(Data) > 0) @alignOf(Data) else 0,
|
||||
}};
|
||||
};
|
||||
}
|
||||
return @Type(.{ .Struct = .{
|
||||
.layout = .auto,
|
||||
.fields = fields,
|
||||
.fields = &struct_fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
@ -76,7 +79,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 +261,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 +442,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 +452,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 +475,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 +648,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 +1052,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 +1223,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 +1260,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 +1307,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))));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ pub const simple_cases = [_]SimpleCase{
|
||||
.{ .src_path = "test/standalone/main_return_error/error_u8_non_zero.zig" },
|
||||
.{ .src_path = "test/standalone/noreturn_call/inline.zig" },
|
||||
.{ .src_path = "test/standalone/noreturn_call/as_arg.zig" },
|
||||
.{ .src_path = "test/standalone/std_enums_big_enums.zig" },
|
||||
|
||||
.{
|
||||
.src_path = "test/standalone/issue_9402/main.zig",
|
||||
|
||||
38
test/standalone/std_enums_big_enums.zig
Normal file
38
test/standalone/std_enums_big_enums.zig
Normal file
@ -0,0 +1,38 @@
|
||||
const std = @import("std");
|
||||
|
||||
// big enums should not hit the eval branch quota
|
||||
pub fn main() void {
|
||||
const big = struct {
|
||||
const Big = @Type(@as(std.builtin.Type, .{
|
||||
.Enum = .{
|
||||
.tag_type = u16,
|
||||
.fields = make_fields: {
|
||||
var fields: [1001]std.builtin.Type.EnumField = undefined;
|
||||
for (&fields, 0..) |*field, i| {
|
||||
field.* = .{ .name = std.fmt.comptimePrint("field_{d}", .{i}), .value = i };
|
||||
}
|
||||
fields[1000] = .{ .name = "field_9999", .value = 9999 };
|
||||
break :make_fields &fields;
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
var set = std.enums.EnumSet(big.Big).init(.{});
|
||||
_ = &set;
|
||||
|
||||
var map = std.enums.EnumMap(big.Big, u8).init(undefined);
|
||||
map = std.enums.EnumMap(big.Big, u8).initFullWith(undefined);
|
||||
map = std.enums.EnumMap(big.Big, u8).initFullWithDefault(123, .{});
|
||||
|
||||
var multiset = std.enums.EnumMultiset(big.Big).init(.{});
|
||||
_ = &multiset;
|
||||
|
||||
var bounded_multiset = std.enums.BoundedEnumMultiset(big.Big, u8).init(.{});
|
||||
_ = &bounded_multiset;
|
||||
|
||||
var array = std.enums.EnumArray(big.Big, u8).init(undefined);
|
||||
array = std.enums.EnumArray(big.Big, u8).initDefault(123, .{});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user