Doing x << y (where x: usize and y: u32) panics on debug builds if y is larger than the word size. I want the normal C behavior: this results in all 0s. However, it doesn't look like any of the usize methods support this. The best I can come up with is:
let res = {
let (res, overflow) = x.overflowing_shl(y);
if overflow { 0 } else { res }
};
This will probably be decently fast in practice, but it's pretty ugly (and probably not as fast as a single shift). Is there anything else I can do?
The C behavior is undefined (section 6.5.7 of the C99 standard, still there in C11), in part because common processors can't decide what to do in this case (I believe x86 does the shift modulo-wordsize, where ARMv7 has the behavior you describe until the RHS crosses 255, and I think AArch64 changed this).
So you're going to be paying some runtime cost on most machines to get what you want. The code @birkenfeld suggests is clean, and if you want to avoid boilerplating it, put it in a new Trait and impl it for usize.
Most languages I've seen that define it (such as .Net) take the shift amount modulo the size of the number, since that's what x86 does. (Which is fast, if not useful...)
Hmm. I feel like I've definitely written code that assumes that the overflowing shift is valid (and results in 0), but it's possible that I just wrote code that used that assumption to justify its correctness in edge cases that, in practice, I never tested it with.
I know this thread is quite old, but instead of opening a new one I thought I just use this...
I'm also facing the issue: attempt to shift left with overflow any use of this value will cause an error.
As my "shift assignment" is part of a const fn this approach: x.checked_shl(y).unwrap_or(0) is not working. Is there any option to solve this inside a const fn?