| ... | @@ -943,3 +943,103 @@ test "math.mulWide" { | ... | @@ -943,3 +943,103 @@ test "math.mulWide" { |
| 943 | testing.expect(mulWide(i8, 5, -5) == -25); | 943 | testing.expect(mulWide(i8, 5, -5) == -25); |
| 944 | testing.expect(mulWide(u8, 100, 100) == 10000); | 944 | testing.expect(mulWide(u8, 100, 100) == 10000); |
| 945 | } | 945 | } |
| | 946 | |
| | 947 | // not to be confused with std.mem.Compare |
| | 948 | pub const CompareOperator = enum { |
| | 949 | lessThan, |
| | 950 | lessThanOrEqual, |
| | 951 | equal, |
| | 952 | greaterThan, |
| | 953 | greaterThanOrEqual, |
| | 954 | }; |
| | 955 | |
| | 956 | pub fn compare(a: var, comptime op: CompareOperator, b: var) bool { |
| | 957 | const A = @typeOf(a); |
| | 958 | const B = @typeOf(b); |
| | 959 | if (@typeId(@typeOf(a)) != .Int or @typeId(@typeOf(b)) != .Int) @compileError("only integers supported"); |
| | 960 | if (A.is_signed == B.is_signed) { |
| | 961 | return switch (op) { |
| | 962 | .lessThan => a < b, |
| | 963 | .lessThanOrEqual => a <= b, |
| | 964 | .equal => a == b, |
| | 965 | .greaterThan => a > b, |
| | 966 | .greaterThanOrEqual => a >= b, |
| | 967 | }; |
| | 968 | } |
| | 969 | const Signed = if (A.is_signed) A else B; |
| | 970 | const Unsigned = if (B.is_signed) A else B; |
| | 971 | const signedMoreBits = Signed.bit_count > Unsigned.bit_count; |
| | 972 | const bits = if (signedMoreBits) Signed.bit_count else Unsigned.bit_count; |
| | 973 | if (signedMoreBits) { |
| | 974 | const T = @IntType(true, bits); |
| | 975 | if (A.is_signed) { |
| | 976 | return switch (op) { |
| | 977 | .lessThan => a < @intCast(T, b), |
| | 978 | .lessThanOrEqual => a <= @intCast(T, b), |
| | 979 | .equal => a == @intCast(T, b), |
| | 980 | .greaterThan => a > @intCast(T, b), |
| | 981 | .greaterThanOrEqual => a >= @intCast(T, b), |
| | 982 | }; |
| | 983 | } else { |
| | 984 | return switch (op) { |
| | 985 | .lessThan => @intCast(T, a) < b, |
| | 986 | .lessThanOrEqual => @intCast(T, a) <= b, |
| | 987 | .equal => @intCast(T, a) == b, |
| | 988 | .greaterThan => @intCast(T, a) > b, |
| | 989 | .greaterThanOrEqual => @intCast(T, a) >= b, |
| | 990 | }; |
| | 991 | } |
| | 992 | } |
| | 993 | if (A.is_signed) { |
| | 994 | const U = @IntType(false, A.bit_count); |
| | 995 | const T = @IntType(false, A.bit_count - 1); |
| | 996 | switch (op) { |
| | 997 | .lessThan => if (a < 0 or maxInt(A) < b) return true, |
| | 998 | .lessThanOrEqual => if (a <= 0 or maxInt(A) <= b) return true, |
| | 999 | .equal => if (A.bit_count <= B.bit_count and a < 0) return false, |
| | 1000 | else => {}, |
| | 1001 | } |
| | 1002 | return switch (op) { |
| | 1003 | .lessThan => @truncate(T, @bitCast(U, a)) < b, |
| | 1004 | .lessThanOrEqual => @truncate(T, @bitCast(U, a)) <= b, |
| | 1005 | .equal => @truncate(T, @bitCast(U, a)) == b, |
| | 1006 | .greaterThan => @truncate(T, @bitCast(U, a)) > b, |
| | 1007 | .greaterThanOrEqual => @truncate(T, @bitCast(U, a)) >= b, |
| | 1008 | }; |
| | 1009 | } else { |
| | 1010 | const U = @IntType(false, B.bit_count); |
| | 1011 | const T = @IntType(false, B.bit_count - 1); |
| | 1012 | switch (op) { |
| | 1013 | .greaterThan => if (0 > b or a > maxInt(B)) return true, |
| | 1014 | .greaterThanOrEqual => if (0 >= b or a >= maxInt(B)) return true, |
| | 1015 | .equal => if (A.bit_count >= B.bit_count and 0 > b) return false, |
| | 1016 | else => {}, |
| | 1017 | } |
| | 1018 | return switch (op) { |
| | 1019 | .lessThan => a < @truncate(T, @bitCast(U, b)), |
| | 1020 | .lessThanOrEqual => a <= @truncate(T, @bitCast(U, b)), |
| | 1021 | .equal => a == @truncate(T, @bitCast(U, b)), |
| | 1022 | .greaterThan => a > @truncate(T, @bitCast(U, b)), |
| | 1023 | .greaterThanOrEqual => a >= @truncate(T, @bitCast(U, b)), |
| | 1024 | }; |
| | 1025 | } |
| | 1026 | } |
| | 1027 | |
| | 1028 | test "math.lessThan, et al < <= > >= between signed and unsigned" { |
| | 1029 | testing.expect(compare(i8(-1), .lessThan, u8(255))); |
| | 1030 | testing.expect(!compare(i8(-1), .greaterThanOrEqual, u8(255))); |
| | 1031 | testing.expect(compare(u8(255), .greaterThan, i8(-1))); |
| | 1032 | testing.expect(!compare(u8(255), .lessThanOrEqual, i8(-1))); |
| | 1033 | testing.expect(compare(i8(-1), .lessThan, u9(255))); |
| | 1034 | testing.expect(!compare(i8(-1), .greaterThanOrEqual, u9(255))); |
| | 1035 | testing.expect(compare(u9(255), .greaterThan, i8(-1))); |
| | 1036 | testing.expect(!compare(u9(255), .lessThanOrEqual, i8(-1))); |
| | 1037 | testing.expect(compare(i9(-1), .lessThan, u8(255))); |
| | 1038 | testing.expect(!compare(i9(-1), .greaterThanOrEqual, u8(255))); |
| | 1039 | testing.expect(compare(u8(255), .greaterThan, i9(-1))); |
| | 1040 | testing.expect(!compare(u8(255), .lessThanOrEqual, i9(-1))); |
| | 1041 | testing.expect(compare(u8(1), .lessThan, u8(2))); |
| | 1042 | testing.expect(@bitCast(u8, i8(-1)) == u8(255)); |
| | 1043 | testing.expect(!compare(u8(255), .equal, i8(-1))); |
| | 1044 | testing.expect(compare(u8(1), .equal, u8(1))); |
| | 1045 | } |