| ... | @@ -219,11 +219,59 @@ pub fn negate(x: var) -> %@typeOf(x) { | ... | @@ -219,11 +219,59 @@ pub fn negate(x: var) -> %@typeOf(x) { |
| 219 | } | 219 | } |
| 220 | | 220 | |
| 221 | error Overflow; | 221 | error Overflow; |
| 222 | pub fn shl(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T { | 222 | pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) -> %T { |
| 223 | var answer: T = undefined; | 223 | var answer: T = undefined; |
| 224 | if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer | 224 | if (@shlWithOverflow(T, a, shift_amt, &answer)) error.Overflow else answer |
| 225 | } | 225 | } |
| 226 | | 226 | |
| | 227 | /// Shifts left. Overflowed bits are truncated. |
| | 228 | /// A negative shift amount results in a right shift. |
| | 229 | pub fn shl(comptime T: type, a: T, shift_amt: var) -> T { |
| | 230 | const abs_shift_amt = absCast(shift_amt); |
| | 231 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else Log2Int(T)(abs_shift_amt); |
| | 232 | |
| | 233 | if (@typeOf(shift_amt).is_signed) { |
| | 234 | if (shift_amt >= 0) { |
| | 235 | return a << casted_shift_amt; |
| | 236 | } else { |
| | 237 | return a >> casted_shift_amt; |
| | 238 | } |
| | 239 | } |
| | 240 | |
| | 241 | return a << casted_shift_amt; |
| | 242 | } |
| | 243 | |
| | 244 | test "math.shl" { |
| | 245 | assert(shl(u8, 0b11111111, usize(3)) == 0b11111000); |
| | 246 | assert(shl(u8, 0b11111111, usize(8)) == 0); |
| | 247 | assert(shl(u8, 0b11111111, usize(9)) == 0); |
| | 248 | assert(shl(u8, 0b11111111, isize(-2)) == 0b00111111); |
| | 249 | } |
| | 250 | |
| | 251 | /// Shifts right. Overflowed bits are truncated. |
| | 252 | /// A negative shift amount results in a lefft shift. |
| | 253 | pub fn shr(comptime T: type, a: T, shift_amt: var) -> T { |
| | 254 | const abs_shift_amt = absCast(shift_amt); |
| | 255 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else Log2Int(T)(abs_shift_amt); |
| | 256 | |
| | 257 | if (@typeOf(shift_amt).is_signed) { |
| | 258 | if (shift_amt >= 0) { |
| | 259 | return a >> casted_shift_amt; |
| | 260 | } else { |
| | 261 | return a << casted_shift_amt; |
| | 262 | } |
| | 263 | } |
| | 264 | |
| | 265 | return a >> casted_shift_amt; |
| | 266 | } |
| | 267 | |
| | 268 | test "math.shr" { |
| | 269 | assert(shr(u8, 0b11111111, usize(3)) == 0b00011111); |
| | 270 | assert(shr(u8, 0b11111111, usize(8)) == 0); |
| | 271 | assert(shr(u8, 0b11111111, usize(9)) == 0); |
| | 272 | assert(shr(u8, 0b11111111, isize(-2)) == 0b11111100); |
| | 273 | } |
| | 274 | |
| 227 | pub fn Log2Int(comptime T: type) -> type { | 275 | pub fn Log2Int(comptime T: type) -> type { |
| 228 | @IntType(false, log2(T.bit_count)) | 276 | @IntType(false, log2(T.bit_count)) |
| 229 | } | 277 | } |
| ... | @@ -237,7 +285,7 @@ fn testOverflow() { | ... | @@ -237,7 +285,7 @@ fn testOverflow() { |
| 237 | assert(%%mul(i32, 3, 4) == 12); | 285 | assert(%%mul(i32, 3, 4) == 12); |
| 238 | assert(%%add(i32, 3, 4) == 7); | 286 | assert(%%add(i32, 3, 4) == 7); |
| 239 | assert(%%sub(i32, 3, 4) == -1); | 287 | assert(%%sub(i32, 3, 4) == -1); |
| 240 | assert(%%shl(i32, 0b11, 4) == 0b110000); | 288 | assert(%%shlExact(i32, 0b11, 4) == 0b110000); |
| 241 | } | 289 | } |
| 242 | | 290 | |
| 243 | | 291 | |