Performs r = a >> shift and returns the amount of limbs affected
if a and r overlaps, then r.ptr <= a.ptr is asserted r must have the capacity to store a >> shift
See tests below for examples of behaviour
fn llshr(r: []Limb, a: []const Limb, shift: usize) usize
fn llshr(r: []Limb, a: []const Limb, shift: usize) usize {
if (slicesOverlap(a, r))
std.debug.assert(@intFromPtr(r.ptr) <= @intFromPtr(a.ptr));
if (a.len == 0) return 0;
if (shift == 0) {
std.debug.assert(r.len >= a.len);
if (a.ptr != r.ptr) @memmove(r[0..a.len], a);
return a.len;
}
if (shift >= limb_bits) {
if (shift / limb_bits >= a.len) {
r[0] = 0;
return 1;
}
return llshr(r, a[shift / limb_bits ..], shift % limb_bits);
}
// shift is guaranteed to be < limb_bits
const bit_shift: Log2Limb = @truncate(shift);
const opposite_bit_shift: Log2Limb = @truncate(limb_bits - bit_shift);
// special case, where there is a risk to set r to 0
if (a.len == 1) {
r[0] = a[0] >> bit_shift;
return 1;
}
if (a.len == 0) {
r[0] = 0;
return 1;
}
// if the most significant limb becomes 0 after the shift
const shrink = a[a.len - 1] >> bit_shift == 0;
std.debug.assert(r.len >= a.len - @intFromBool(shrink));
var i: usize = 0;
while (i < a.len - 1) : (i += 1) {
r[i] = (a[i] >> bit_shift) | (a[i + 1] << opposite_bit_shift);
}
if (!shrink)
r[i] = a[i] >> bit_shift;
return a.len - @intFromBool(shrink);
}