pub inline fn baselineWeights(T: type) []const Weight {
return comptime switch (@typeInfo(T)) {
.bool, .int, .float => i: {
// Reject types that don't have a fixed bitsize (esp. usize)
// since they are not gauraunteed to fit in a u64 across targets.
if (std.mem.findScalar(type, &.{
isize, usize,
c_char, c_longdouble,
c_short, c_ushort,
c_int, c_uint,
c_long, c_ulong,
c_longlong, c_ulonglong,
}, T) != null) {
@compileError("type does not have a fixed bitsize: " ++ @typeName(T));
}
break :i &.{.rangeAtMost(Backing(T), 0, (1 << @bitSizeOf(T)) - 1, 1)};
},
.@"struct" => |s| if (s.backing_integer) |B|
baselineWeights(B)
else
@compileError("non-packed structs cannot be weighted"),
.@"union" => |u| if (u.layout == .@"packed")
baselineWeights(Backing(T))
else
@compileError("non-packed unions cannot be weighted"),
.@"enum" => |e| if (e.mode == .nonexhaustive)
baselineWeights(e.tag_type)
else if (e.field_names.len == 0)
// Cannot be included in below branch due to `log2_int_ceil`
@compileError("exhaustive zero-field enums cannot be weighted")
else e: {
@setEvalBranchQuota(@intCast(4 * e.field_names.len *
std.math.log2_int_ceil(usize, e.field_names.len)));
var sorted_fields = blk: {
var fields: [e.field_names.len]EnumField = undefined;
for (e.field_names, e.field_values, &fields) |f_name, f_value, *field| {
field.* = .{
.name = f_name,
.value = f_value,
};
}
break :blk fields;
};
std.mem.sortUnstable(EnumField, &sorted_fields, {}, enumFieldLessThan);
var weights: []const Weight = &.{};
var seq_first: u64 = sorted_fields[0].value;
for (sorted_fields[0 .. sorted_fields.len - 1], sorted_fields[1..]) |prev, field| {
if (field.value != prev.value + 1) {
weights = weights ++ .{Weight.rangeAtMost(u64, seq_first, prev.value, 1)};
seq_first = field.value;
}
}
weights = weights ++ .{Weight.rangeAtMost(
u64,
seq_first,
sorted_fields[sorted_fields.len - 1].value,
1,
)};
break :e weights;
},
else => @compileError("unexpected type: " ++ @typeName(T)),
};
}