diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-12-16 10:17:43 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-12-16 11:09:10 -0500 |
| commit | 9468d6381997dedaf3330f0c6e1b4290a9af1345 (patch) | |
| tree | 89b91f227cca342d895d1f8475da28fc71867e74 /lib/std/math.zig | |
| parent | 143603b39faa55f42fffa36d859b380bf1b13984 (diff) | |
| download | zig-9468d6381997dedaf3330f0c6e1b4290a9af1345.tar.gz zig-9468d6381997dedaf3330f0c6e1b4290a9af1345.zip | |
allow comparison of any numeric types
Diffstat (limited to 'lib/std/math.zig')
| -rw-r--r-- | lib/std/math.zig | 141 |
1 files changed, 48 insertions, 93 deletions
diff --git a/lib/std/math.zig b/lib/std/math.zig index 2f3ee07ce8..a12bf5f4e9 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -944,102 +944,57 @@ test "math.mulWide" { testing.expect(mulWide(u8, 100, 100) == 10000); } -// not to be confused with std.mem.Compare +/// Not to be confused with `std.mem.Compare`. pub const CompareOperator = enum { - lessThan, - lessThanOrEqual, - equal, - greaterThan, - greaterThanOrEqual, + /// Less than (`<`) + lt, + + /// Less than or equal (`<=`) + lte, + + /// Equal (`==`) + eq, + + /// Greater than or equal (`>=`) + gte, + + /// Greater than (`>`) + gt, + + /// Not equal (`!=`) + neq, }; -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)), - }; - } +/// This function does the same thing as comparison operators, however the +/// operator is a runtime-known enum value. Works on any operands that +/// support comparison operators. +pub fn compare(a: var, op: CompareOperator, b: var) bool { + return switch (op) { + .lt => a < b, + .lte => a <= b, + .eq => a == b, + .neq => a != b, + .gt => a > b, + .gte => a >= 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))); +test "math.lt, et al < <= > >= between signed and unsigned" { + testing.expect(compare(@as(i8, -1), .lt, @as(u8, 255))); + testing.expect(compare(@as(i8, 2), .gt, @as(u8, 1))); + testing.expect(!compare(@as(i8, -1), .gte, @as(u8, 255))); + testing.expect(compare(@as(u8, 255), .gt, @as(i8, -1))); + testing.expect(!compare(@as(u8, 255), .lte, @as(i8, -1))); + testing.expect(compare(@as(i8, -1), .lt, @as(u9, 255))); + testing.expect(!compare(@as(i8, -1), .gte, @as(u9, 255))); + testing.expect(compare(@as(u9, 255), .gt, @as(i8, -1))); + testing.expect(!compare(@as(u9, 255), .lte, @as(i8, -1))); + testing.expect(compare(@as(i9, -1), .lt, @as(u8, 255))); + testing.expect(!compare(@as(i9, -1), .gte, @as(u8, 255))); + testing.expect(compare(@as(u8, 255), .gt, @as(i9, -1))); + testing.expect(!compare(@as(u8, 255), .lte, @as(i9, -1))); + testing.expect(compare(@as(u8, 1), .lt, @as(u8, 2))); + testing.expect(@bitCast(u8, @as(i8, -1)) == @as(u8, 255)); + testing.expect(!compare(@as(u8, 255), .eq, @as(i8, -1))); + testing.expect(compare(@as(u8, 1), .eq, @as(u8, 1))); } |
