63 lines
1.6 KiB
Zig
63 lines
1.6 KiB
Zig
const std = @import("std");
|
|
|
|
pub fn Int(comptime int: std.builtin.Type.Int) type {
|
|
return @Type(.{.Int = int});
|
|
}
|
|
|
|
pub fn clamp(value: anytype, lower: anytype, upper: anytype) @TypeOf(value, lower, upper) {
|
|
return @max(lower, @min(upper, value));
|
|
}
|
|
|
|
pub fn checked_add(a: anytype, b: anytype) ?@TypeOf(a + b) {
|
|
const result = @addWithOverflow(a, b);
|
|
|
|
return if (result.@"1" == 0) result.@"0" else null;
|
|
}
|
|
|
|
pub fn checked_mul(a: anytype, b: anytype) ?@TypeOf(a * b) {
|
|
const result = @mulWithOverflow(a, b);
|
|
|
|
return if (result.@"1" == 0) result.@"0" else null;
|
|
}
|
|
|
|
pub fn checked_sub(a: anytype, b: anytype) ?@TypeOf(a - b) {
|
|
const result = @subWithOverflow(a, b);
|
|
|
|
return if (result.@"1" == 0) result.@"0" else null;
|
|
}
|
|
|
|
pub fn clamped_cast(comptime dest_int: std.builtin.Type.Int, value: anytype) Int(dest_int) {
|
|
const Value = @TypeOf(value);
|
|
|
|
return switch (@typeInfo(Value)) {
|
|
.Int => |int| switch (int.signedness) {
|
|
.signed => @intCast(clamp(value, min_int(dest_int), max_int(dest_int))),
|
|
.unsigned => @intCast(@min(value, max_int(dest_int))),
|
|
},
|
|
|
|
.Float => @intFromFloat(clamp(value, min_int(dest_int), max_int(dest_int))),
|
|
|
|
else => @compileError("`" ++ @typeName(Value) ++ "` cannot be cast to an int"),
|
|
};
|
|
}
|
|
|
|
pub fn max_int(comptime int: std.builtin.Type.Int) comptime_int {
|
|
const bit_count = int.bits;
|
|
|
|
if (bit_count == 0) return 0;
|
|
|
|
return (1 << (bit_count - @intFromBool(int.signedness == .signed))) - 1;
|
|
}
|
|
|
|
pub fn min_int(comptime int: std.builtin.Type.Int) comptime_int {
|
|
if (int.signedness == .unsigned) {
|
|
return 0;
|
|
}
|
|
|
|
const bit_count = int.bits;
|
|
|
|
if (bit_count == 0) return 0;
|
|
|
|
return -(1 << (bit_count - 1));
|
|
}
|