mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
std: lessThan and greaterThan between signed and unsigned
It is a deviation from C, but I think we should consider making this the behavior of the operators. See #2133
This commit is contained in:
parent
2c7a2aefbf
commit
143603b39f
100
lib/std/math.zig
100
lib/std/math.zig
@ -943,3 +943,103 @@ test "math.mulWide" {
|
||||
testing.expect(mulWide(i8, 5, -5) == -25);
|
||||
testing.expect(mulWide(u8, 100, 100) == 10000);
|
||||
}
|
||||
|
||||
// not to be confused with std.mem.Compare
|
||||
pub const CompareOperator = enum {
|
||||
lessThan,
|
||||
lessThanOrEqual,
|
||||
equal,
|
||||
greaterThan,
|
||||
greaterThanOrEqual,
|
||||
};
|
||||
|
||||
pub fn compare(a: var, comptime op: CompareOperator, b: var) bool {
|
||||
const A = @typeOf(a);
|
||||
const B = @typeOf(b);
|
||||
if (@typeId(@typeOf(a)) != .Int or @typeId(@typeOf(b)) != .Int) @compileError("only integers supported");
|
||||
if (A.is_signed == B.is_signed) {
|
||||
return switch (op) {
|
||||
.lessThan => a < b,
|
||||
.lessThanOrEqual => a <= b,
|
||||
.equal => a == b,
|
||||
.greaterThan => a > b,
|
||||
.greaterThanOrEqual => a >= b,
|
||||
};
|
||||
}
|
||||
const Signed = if (A.is_signed) A else B;
|
||||
const Unsigned = if (B.is_signed) A else B;
|
||||
const signedMoreBits = Signed.bit_count > Unsigned.bit_count;
|
||||
const bits = if (signedMoreBits) Signed.bit_count else Unsigned.bit_count;
|
||||
if (signedMoreBits) {
|
||||
const T = @IntType(true, bits);
|
||||
if (A.is_signed) {
|
||||
return switch (op) {
|
||||
.lessThan => a < @intCast(T, b),
|
||||
.lessThanOrEqual => a <= @intCast(T, b),
|
||||
.equal => a == @intCast(T, b),
|
||||
.greaterThan => a > @intCast(T, b),
|
||||
.greaterThanOrEqual => a >= @intCast(T, b),
|
||||
};
|
||||
} else {
|
||||
return switch (op) {
|
||||
.lessThan => @intCast(T, a) < b,
|
||||
.lessThanOrEqual => @intCast(T, a) <= b,
|
||||
.equal => @intCast(T, a) == b,
|
||||
.greaterThan => @intCast(T, a) > b,
|
||||
.greaterThanOrEqual => @intCast(T, a) >= b,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (A.is_signed) {
|
||||
const U = @IntType(false, A.bit_count);
|
||||
const T = @IntType(false, A.bit_count - 1);
|
||||
switch (op) {
|
||||
.lessThan => if (a < 0 or maxInt(A) < b) return true,
|
||||
.lessThanOrEqual => if (a <= 0 or maxInt(A) <= b) return true,
|
||||
.equal => if (A.bit_count <= B.bit_count and a < 0) return false,
|
||||
else => {},
|
||||
}
|
||||
return switch (op) {
|
||||
.lessThan => @truncate(T, @bitCast(U, a)) < b,
|
||||
.lessThanOrEqual => @truncate(T, @bitCast(U, a)) <= b,
|
||||
.equal => @truncate(T, @bitCast(U, a)) == b,
|
||||
.greaterThan => @truncate(T, @bitCast(U, a)) > b,
|
||||
.greaterThanOrEqual => @truncate(T, @bitCast(U, a)) >= b,
|
||||
};
|
||||
} else {
|
||||
const U = @IntType(false, B.bit_count);
|
||||
const T = @IntType(false, B.bit_count - 1);
|
||||
switch (op) {
|
||||
.greaterThan => if (0 > b or a > maxInt(B)) return true,
|
||||
.greaterThanOrEqual => if (0 >= b or a >= maxInt(B)) return true,
|
||||
.equal => if (A.bit_count >= B.bit_count and 0 > b) return false,
|
||||
else => {},
|
||||
}
|
||||
return switch (op) {
|
||||
.lessThan => a < @truncate(T, @bitCast(U, b)),
|
||||
.lessThanOrEqual => a <= @truncate(T, @bitCast(U, b)),
|
||||
.equal => a == @truncate(T, @bitCast(U, b)),
|
||||
.greaterThan => a > @truncate(T, @bitCast(U, b)),
|
||||
.greaterThanOrEqual => a >= @truncate(T, @bitCast(U, b)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
test "math.lessThan, et al < <= > >= between signed and unsigned" {
|
||||
testing.expect(compare(i8(-1), .lessThan, u8(255)));
|
||||
testing.expect(!compare(i8(-1), .greaterThanOrEqual, u8(255)));
|
||||
testing.expect(compare(u8(255), .greaterThan, i8(-1)));
|
||||
testing.expect(!compare(u8(255), .lessThanOrEqual, i8(-1)));
|
||||
testing.expect(compare(i8(-1), .lessThan, u9(255)));
|
||||
testing.expect(!compare(i8(-1), .greaterThanOrEqual, u9(255)));
|
||||
testing.expect(compare(u9(255), .greaterThan, i8(-1)));
|
||||
testing.expect(!compare(u9(255), .lessThanOrEqual, i8(-1)));
|
||||
testing.expect(compare(i9(-1), .lessThan, u8(255)));
|
||||
testing.expect(!compare(i9(-1), .greaterThanOrEqual, u8(255)));
|
||||
testing.expect(compare(u8(255), .greaterThan, i9(-1)));
|
||||
testing.expect(!compare(u8(255), .lessThanOrEqual, i9(-1)));
|
||||
testing.expect(compare(u8(1), .lessThan, u8(2)));
|
||||
testing.expect(@bitCast(u8, i8(-1)) == u8(255));
|
||||
testing.expect(!compare(u8(255), .equal, i8(-1)));
|
||||
testing.expect(compare(u8(1), .equal, u8(1)));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user