2023-05-23 02:08:34 +02:00
|
|
|
const std = @import("std");
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Errors that may occur during checked integer arithmetic operations.
|
|
|
|
///
|
2023-04-19 01:25:35 +02:00
|
|
|
pub const CheckedArithmeticError = error {
|
|
|
|
IntOverflow,
|
|
|
|
};
|
|
|
|
|
2023-05-28 03:19:46 +02:00
|
|
|
///
|
|
|
|
/// Returns the float type described by `float`.
|
|
|
|
///
|
|
|
|
pub fn Float(comptime float: std.builtin.Type.Float) type {
|
|
|
|
return @Type(.{.Float = float});
|
2023-04-19 01:25:35 +02:00
|
|
|
}
|
|
|
|
|
2023-05-28 03:19:46 +02:00
|
|
|
///
|
|
|
|
/// Returns the integer type described by `int`.
|
|
|
|
///
|
|
|
|
pub fn Int(comptime int: std.builtin.Type.Int) type {
|
|
|
|
return @Type(.{.Int = int});
|
2023-04-19 01:25:35 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// Two-dimensional vector type.
|
|
|
|
///
|
2023-04-29 00:20:46 +02:00
|
|
|
pub const Vector2 = extern struct {
|
2023-04-19 01:25:35 +02:00
|
|
|
x: f32,
|
|
|
|
y: f32,
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// A [Vector2] with a value of `0` assigned to all of the components.
|
|
|
|
///
|
2023-04-19 01:25:35 +02:00
|
|
|
pub const zero = Vector2{.x = 0, .y = 0};
|
|
|
|
};
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// Attempts to perform a checked addition between `a` and `b`, returning the result or [CheckedArithmeticError] if the
|
|
|
|
/// operation tried to invoke safety-checked behavior.
|
|
|
|
///
|
|
|
|
/// `checked_add` can be seen as an alternative to the language-native addition operator (+) that exposes the safety-
|
|
|
|
/// checked behavior in the form of an error type that may be caught or tried on.
|
|
|
|
///
|
2023-04-19 01:25:35 +02:00
|
|
|
pub fn checked_add(a: anytype, b: anytype) CheckedArithmeticError!@TypeOf(a + b) {
|
|
|
|
const result = @addWithOverflow(a, b);
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
if (result.@"1" != 0) {
|
|
|
|
return error.IntOverflow;
|
|
|
|
}
|
2023-04-19 01:25:35 +02:00
|
|
|
|
|
|
|
return result.@"0";
|
|
|
|
}
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
2023-05-28 03:19:46 +02:00
|
|
|
/// Attempts to perform a checked integer cast to the type expressed by `int` on `value`, returning the result or
|
|
|
|
/// [CheckedArithmeticError] if the operation tried to invoke safety-checked behavior.
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// `checked_cast` can be seen as an alternative to the language-native `@intCast` builtin that exposes the safety-
|
|
|
|
/// checked behavior in the form of an error type that may be caught or tried on.
|
|
|
|
///
|
2023-05-28 03:19:46 +02:00
|
|
|
pub fn checked_cast(comptime int: std.builtin.Type.Int, value: anytype) CheckedArithmeticError!Int(int) {
|
|
|
|
if ((value < min_int(int)) or (value > max_int(int))) {
|
2023-05-23 02:08:34 +02:00
|
|
|
return error.IntOverflow;
|
|
|
|
}
|
|
|
|
|
2023-05-28 03:19:46 +02:00
|
|
|
return @intCast(Int(int), value);
|
2023-05-23 02:08:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Attempts to perform a checked multiplication between `a` and `b`, returning the result or [CheckedArithmeticError]
|
|
|
|
/// if the operation tried to invoke safety-checked behavior.
|
|
|
|
///
|
|
|
|
/// `checked_mul` can be seen as an alternative to the language-native multiplication operator (*) that exposes the
|
|
|
|
/// safety-checked behavior in the form of an error type that may be caught or tried on.
|
|
|
|
///
|
2023-04-19 01:25:35 +02:00
|
|
|
pub fn checked_mul(a: anytype, b: anytype) CheckedArithmeticError!@TypeOf(a * b) {
|
|
|
|
const result = @mulWithOverflow(a, b);
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
if (result.@"1" != 0) {
|
|
|
|
return error.IntOverflow;
|
|
|
|
}
|
2023-04-19 01:25:35 +02:00
|
|
|
|
|
|
|
return result.@"0";
|
|
|
|
}
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// Attempts to perform a checked subtraction between `a` and `b`, returning the result or [CheckedArithmeticError] if
|
|
|
|
/// the operation tried to invoke safety-checked behavior.
|
|
|
|
///
|
|
|
|
/// `checked_sub` can be seen as an alternative to the language-native subtraction operator (-) that exposes the safety-
|
|
|
|
/// checked behavior in the form of an error type that may be caught or tried on.
|
|
|
|
///
|
2023-04-19 01:25:35 +02:00
|
|
|
pub fn checked_sub(a: anytype, b: anytype) CheckedArithmeticError!@TypeOf(a - b) {
|
|
|
|
const result = @subWithOverflow(a, b);
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
if (result.@"1" != 0) {
|
|
|
|
return error.IntOverflow;
|
|
|
|
}
|
2023-04-19 01:25:35 +02:00
|
|
|
|
|
|
|
return result.@"0";
|
|
|
|
}
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// Returns `value` clamped between the inclusive bounds of `lower` and `upper`.
|
|
|
|
///
|
|
|
|
pub fn clamp(value: anytype, lower: anytype, upper: anytype) @TypeOf(value, lower, upper) {
|
|
|
|
return max(lower, min(upper, value));
|
2023-04-19 01:25:35 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// Returns `true` if `value` is clamped within the inclusive bounds of `lower` and `upper`.
|
|
|
|
///
|
|
|
|
pub fn is_clamped(value: anytype, lower: anytype, upper: anytype) bool {
|
|
|
|
return (value >= lower) and (value <= upper);
|
2023-04-19 01:25:35 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// Returns the maximum value between `a` and `b`.
|
|
|
|
///
|
|
|
|
pub fn max(a: anytype, b: anytype) @TypeOf(a, b) {
|
|
|
|
return @max(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Returns the maximum value that the integer described by `int` may express.
|
|
|
|
///
|
|
|
|
pub fn max_int(comptime int: std.builtin.Type.Int) comptime_int {
|
|
|
|
const bit_count = int.bits;
|
2023-04-19 01:25:35 +02:00
|
|
|
|
|
|
|
if (bit_count == 0) return 0;
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
return (1 << (bit_count - @boolToInt(int.signedness == .signed))) - 1;
|
2023-04-19 01:25:35 +02:00
|
|
|
}
|
|
|
|
|
2023-05-23 02:08:34 +02:00
|
|
|
///
|
|
|
|
/// Returns the minimum value between `a` and `b`.
|
|
|
|
///
|
|
|
|
pub fn min(a: anytype, b: anytype) @TypeOf(a, b) {
|
|
|
|
return @min(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Returns the minimum value that the integer described by `int` may express.
|
|
|
|
///
|
|
|
|
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));
|
2023-04-19 01:25:35 +02:00
|
|
|
}
|
2023-05-24 01:22:12 +02:00
|
|
|
|
|
|
|
///
|
|
|
|
/// Returns `value` wrapped around the inclusive bounds of `lower` and `upper`.
|
|
|
|
///
|
|
|
|
pub fn wrap(value: anytype, lower: anytype, upper: anytype) @TypeOf(value, lower, upper) {
|
|
|
|
const range = upper - lower;
|
|
|
|
|
|
|
|
return if (range == 0) lower else lower + @mod((@mod((value - lower), range) + range), range);
|
|
|
|
}
|