zig-dimal/src/Dimensions.zig
2026-04-22 22:08:05 +02:00

135 lines
3.7 KiB
Zig

const std = @import("std");
pub const ArgOpts = struct {
L: comptime_int = 0,
M: comptime_int = 0,
T: comptime_int = 0,
I: comptime_int = 0,
Tp: comptime_int = 0,
N: comptime_int = 0,
J: comptime_int = 0,
};
pub const Dimension = enum {
/// Length
L,
/// Mass
M,
/// Time
T,
/// Electric Current
I,
/// Temperature
Tp,
/// Amount of Substance
N,
/// Luminous Intensity
J,
pub fn unit(self: @This()) []const u8 {
return switch (self) {
.L => "m",
.M => "g",
.T => "s",
.I => "A",
.Tp => "K",
.N => "mol",
.J => "cd",
};
}
};
// --------- Dimensions struct ---------
/// Holds the exponent of each SI base dimension for a given quantity (e.g. velocity = L¹T⁻¹).
/// All values are `comptime_int` — no runtime storage.
const Self = @This();
data: std.EnumArray(Dimension, comptime_int),
/// Create a `Dimensions` from a struct literal, e.g. `.{ .L = 1, .T = -1 }`.
/// Unspecified dimensions default to 0.
pub fn init(comptime init_val: ArgOpts) Self {
var s = Self{ .data = std.EnumArray(Dimension, comptime_int).initFill(0) };
inline for (std.meta.fields(@TypeOf(init_val))) |f|
s.data.set(@field(Dimension, f.name), @field(init_val, f.name));
return s;
}
pub fn initFill(comptime val: comptime_int) Self {
return .{ .data = std.EnumArray(Dimension, comptime_int).initFill(val) };
}
pub fn get(comptime self: Self, comptime key: Dimension) comptime_int {
return self.data.get(key);
}
pub fn set(comptime self: *Self, comptime key: Dimension, comptime val: i8) void {
self.data.set(key, val);
}
pub fn argsOpt(self: Self) ArgOpts {
var args: ArgOpts = undefined;
inline for (std.enums.values(Dimension)) |d|
@field(args, @tagName(d)) = self.get(d);
return args;
}
/// Add exponents component-wise. Used internally by `mulBy`.
pub fn add(comptime a: Self, comptime b: Self) Self {
var result = Self.initFill(0);
inline for (std.enums.values(Dimension)) |d|
result.set(d, a.get(d) + b.get(d));
return result;
}
/// Subtract exponents component-wise. Used internally by `divBy`.
pub fn sub(comptime a: Self, comptime b: Self) Self {
var result = Self.initFill(0);
inline for (std.enums.values(Dimension)) |d|
result.set(d, a.get(d) - b.get(d));
return result;
}
/// Multiply exponents by a scalar integer. Used internally by `pow` in Scalar.
pub fn scale(comptime a: Self, comptime exp: comptime_int) Self {
var result = Self.initFill(0);
inline for (std.enums.values(Dimension)) |d|
result.set(d, a.get(d) * exp);
return result;
}
pub fn div(comptime a: Self, comptime exp: comptime_int) Self {
var result = Self.initFill(0);
inline for (std.enums.values(Dimension)) |d|
result.set(d, a.get(d) / exp);
return result;
}
/// Returns true if every dimension exponent is equal. Used to enforce type compatibility in `add`, `sub`, `to`.
pub fn eql(comptime a: Self, comptime b: Self) bool {
inline for (std.enums.values(Dimension)) |d|
if (a.get(d) != b.get(d)) return false;
return true;
}
pub fn isSquare(comptime a: Self) bool {
inline for (std.enums.values(Dimension)) |d|
if (a.get(d) % 2 != 0) return false;
return true;
}
pub fn str(comptime a: Self) []const u8 {
var out: []const u8 = "";
const dims = std.enums.values(Dimension);
inline for (dims) |d| {
const val = a.get(d);
if (val != 0) {
out = out ++ @tagName(d) ++ std.fmt.comptimePrint("{d}", .{val});
}
}
return if (out.len == 0) "Dimensionless" else out;
}