pub(super) mod fft;
#[cfg(all(
target_arch = "aarch64",
target_endian = "little",
target_pointer_width = "64",
any(
target_vendor = "apple",
target_os = "linux",
target_os = "android",
target_os = "windows",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "fuchsia"
),
not(miri)
))]
#[path = "mul/aarch64.rs"]
pub(super) mod kernels;
#[cfg(all(target_arch = "x86_64", not(miri)))]
#[path = "mul/x86_64.rs"]
mod kernels;
#[cfg(not(any(
all(
target_arch = "aarch64",
target_endian = "little",
target_pointer_width = "64",
any(
target_vendor = "apple",
target_os = "linux",
target_os = "android",
target_os = "windows",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "fuchsia"
),
not(miri)
),
all(target_arch = "x86_64", not(miri))
)))]
#[path = "mul/portable.rs"]
mod kernels;
pub(super) mod limbs;
pub(crate) mod basecase {
use super::kernels;
#[inline(always)]
pub(crate) unsafe fn mul(r: *mut u64, x: *const u64, y: *const u64, n: usize) {
unsafe { kernels::mul_basecase(r, x, n, y, n) }
}
#[inline(always)]
pub(crate) unsafe fn sqr(r: *mut u64, x: *const u64, n: usize) {
unsafe { kernels::sqr_basecase(r, x, n) }
}
}
mod toom;
pub(super) use kernels::mul_1_bytes;
use super::add::{SMALL, read, read_small, significant_len, small, write, write_small};
use super::div::limb_of;
use super::prim::{copy_times_limb, times_limb};
use super::{ByteOrder, Number};
use core::mem::{self, MaybeUninit};
use core::ops::{Mul, MulAssign};
use core::ptr;
impl Mul<&Number> for &Number {
type Output = Number;
fn mul(self, rhs: &Number) -> Number {
if small(self, rhs) {
let p = unsafe { small_product(self, rhs) };
return small_number(self.byte_order, p);
}
ref_times_ref(self, rhs)
}
}
impl Mul<&Number> for Number {
type Output = Number;
fn mul(mut self, rhs: &Number) -> Number {
self *= rhs;
self
}
}
impl Mul<Number> for &Number {
type Output = Number;
fn mul(self, mut rhs: Number) -> Number {
if small(self, &rhs) {
let p = unsafe { small_product(self, &rhs) };
let order = self.byte_order;
put_small(&mut rhs.value, order, p);
return Number {
value: rhs.value,
negative: p.negative,
byte_order: order,
};
}
ref_times_value(self, &mut rhs)
}
}
impl Mul<Number> for Number {
type Output = Number;
fn mul(mut self, rhs: Number) -> Number {
self *= rhs;
self
}
}
impl MulAssign<&Number> for Number {
#[inline]
fn mul_assign(&mut self, rhs: &Number) {
if small(self, rhs) {
let p = unsafe { small_product(self, rhs) };
put_small(&mut self.value, self.byte_order, p);
self.negative = p.negative;
return;
}
mul_assign_ref(self, rhs);
}
}
impl MulAssign<Number> for Number {
#[inline]
fn mul_assign(&mut self, mut rhs: Number) {
if small(self, &rhs) {
let p = unsafe { small_product(self, &rhs) };
if self.value.capacity() < p.len && rhs.value.capacity() >= p.len {
mem::swap(&mut self.value, &mut rhs.value);
}
put_small(&mut self.value, self.byte_order, p);
self.negative = p.negative;
return;
}
mul_assign_value(self, &mut rhs);
}
}
#[derive(Clone, Copy)]
struct Small {
limbs: [u64; 4],
len: usize,
negative: bool,
}
#[inline(always)]
unsafe fn small_product(a: &Number, b: &Number) -> Small {
let (x, y) = unsafe {
(
read_small(&a.value, a.byte_order),
read_small(&b.value, b.byte_order),
)
};
let (x0, x1) = (x as u64, (x >> 64) as u64);
let (y0, y1) = (y as u64, (y >> 64) as u64);
let p00 = u128::from(x0) * u128::from(y0);
let p01 = u128::from(x0) * u128::from(y1);
let p10 = u128::from(x1) * u128::from(y0);
let p11 = u128::from(x1) * u128::from(y1);
let c1 = (p00 >> 64) + u128::from(p01 as u64) + u128::from(p10 as u64);
let c2 = (c1 >> 64) + (p01 >> 64) + (p10 >> 64) + u128::from(p11 as u64);
let c3 = (c2 >> 64) + (p11 >> 64);
let limbs = [p00 as u64, c1 as u64, c2 as u64, c3 as u64];
let zeros = if limbs[3] != 0 {
limbs[3].leading_zeros() / 8
} else if limbs[2] != 0 {
8 + limbs[2].leading_zeros() / 8
} else if limbs[1] != 0 {
16 + limbs[1].leading_zeros() / 8
} else {
24 + (limbs[0] | 1).leading_zeros() / 8
};
Small {
limbs,
len: 32 - zeros as usize,
negative: a.negative != b.negative && x != 0 && y != 0,
}
}
#[inline(always)]
unsafe fn write_small_product(dst: *mut u8, order: ByteOrder, p: Small) {
let [l0, l1, l2, l3] = p.limbs;
let len = p.len;
unsafe {
if len <= SMALL {
write_small(dst, order, l0, l1, len);
return;
}
let low = u128::from(l0) | (u128::from(l1) << 64);
let high = u128::from(l2) | (u128::from(l3) << 64);
let k = 8 * (len - 16) as u32;
let top = low.checked_shr(k).unwrap_or(0) | high << (128 - k);
if order == ByteOrder::BigEndian {
write(dst.add(len - 16), low.to_be_bytes());
write(dst, top.to_be_bytes());
} else {
write(dst, low.to_le_bytes());
write(dst.add(len - 16), top.to_le_bytes());
}
}
}
#[inline(always)]
fn put_small(v: &mut Vec<u8>, order: ByteOrder, p: Small) {
if v.capacity() >= p.len {
unsafe {
write_small_product(v.as_mut_ptr(), order, p);
v.set_len(p.len);
}
} else {
replace_small(v, order, p);
}
}
#[cold]
#[inline(never)]
fn replace_small(v: &mut Vec<u8>, order: ByteOrder, p: Small) {
*v = new_small(order, p);
}
#[inline(always)]
fn new_small(order: ByteOrder, p: Small) -> Vec<u8> {
let mut v = Vec::with_capacity(p.len);
unsafe {
write_small_product(v.as_mut_ptr(), order, p);
v.set_len(p.len);
}
v
}
#[inline(never)]
fn small_number(order: ByteOrder, p: Small) -> Number {
Number {
value: new_small(order, p),
negative: p.negative,
byte_order: order,
}
}
pub(super) const WIDE: usize = 32;
#[inline(always)]
fn wide(a: &Number, b: &Number) -> bool {
a.value.len() <= WIDE && b.value.len() <= WIDE
}
#[derive(Clone, Copy)]
pub(super) struct Wide {
pub(super) limbs: [u64; 8],
pub(super) len: usize,
pub(super) negative: bool,
}
#[inline(always)]
pub(super) unsafe fn read_wide(v: &[u8], order: ByteOrder) -> [u64; 4] {
let (p, n) = (v.as_ptr(), v.len());
unsafe {
if n <= SMALL {
let x = read_small(v, order);
return [x as u64, (x >> 64) as u64, 0, 0];
}
let (low, top) = if order == ByteOrder::BigEndian {
(
u128::from_be_bytes(read(p.add(n - 16))),
u128::from_be_bytes(read(p)),
)
} else {
(
u128::from_le_bytes(read(p)),
u128::from_le_bytes(read(p.add(n - 16))),
)
};
let high = top >> (8 * (WIDE - n));
[
low as u64,
(low >> 64) as u64,
high as u64,
(high >> 64) as u64,
]
}
}
#[inline(always)]
unsafe fn wide_product(a: &Number, b: &Number) -> Wide {
let (x, y) = unsafe {
(
read_wide(&a.value, a.byte_order),
read_wide(&b.value, b.byte_order),
)
};
let mut r = [0u64; 8];
for i in 0..4 {
let mut carry = 0u64;
for j in 0..4 {
let t = u128::from(x[i]) * u128::from(y[j]) + u128::from(r[i + j]) + u128::from(carry);
r[i + j] = t as u64;
carry = (t >> 64) as u64;
}
r[i + 4] = carry;
}
let top = r.iter().rposition(|&l| l != 0);
let len = match top {
Some(t) => 8 * t + 8 - r[t].leading_zeros() as usize / 8,
None => 1,
};
let nonzero = |v: [u64; 4]| v.iter().any(|&l| l != 0);
Wide {
limbs: r,
len,
negative: a.negative != b.negative && nonzero(x) && nonzero(y),
}
}
#[inline(always)]
pub(super) unsafe fn write_wide(dst: *mut u8, order: ByteOrder, w: &Wide) {
let (l, len) = (w.limbs, w.len);
unsafe {
if len <= 2 * SMALL {
let p = Small {
limbs: [l[0], l[1], l[2], l[3]],
len,
negative: w.negative,
};
write_small_product(dst, order, p);
return;
}
let k = 8 * (len - 32);
let (q, b) = (k / 64, (k % 64) as u32);
let limb = |i: usize| if i < 8 { l[i] } else { 0 };
let mut t = [0u64; 4];
for (i, v) in t.iter_mut().enumerate() {
*v = if b == 0 {
limb(i + q)
} else {
(limb(i + q) >> b) | (limb(i + q + 1) << (64 - b))
};
}
let u = |a: u64, b: u64| u128::from(a) | (u128::from(b) << 64);
let (l01, l23, t01, t23) = (u(l[0], l[1]), u(l[2], l[3]), u(t[0], t[1]), u(t[2], t[3]));
if order == ByteOrder::BigEndian {
write(dst.add(len - 16), l01.to_be_bytes());
write(dst.add(len - 32), l23.to_be_bytes());
write(dst.add(16), t01.to_be_bytes());
write(dst, t23.to_be_bytes());
} else {
write(dst, l01.to_le_bytes());
write(dst.add(16), l23.to_le_bytes());
write(dst.add(len - 32), t01.to_le_bytes());
write(dst.add(len - 16), t23.to_le_bytes());
}
}
}
#[inline(always)]
pub(super) fn put_wide(v: &mut Vec<u8>, order: ByteOrder, w: &Wide) {
if v.capacity() < w.len {
*v = Vec::with_capacity(w.len);
}
unsafe {
write_wide(v.as_mut_ptr(), order, w);
v.set_len(w.len);
}
}
const WIDEST: usize = 48;
#[inline(always)]
fn widest(a: &Number, b: &Number) -> bool {
a.value.len() <= WIDEST && b.value.len() <= WIDEST
}
#[derive(Clone, Copy)]
struct Widest {
limbs: [u64; 12],
len: usize,
negative: bool,
}
#[inline(always)]
unsafe fn read_widest(v: &[u8], order: ByteOrder) -> [u64; 6] {
let (p, n) = (v.as_ptr(), v.len());
unsafe {
if n <= WIDE {
let [l0, l1, l2, l3] = read_wide(v, order);
return [l0, l1, l2, l3, 0, 0];
}
let (low, middle, top) = if order == ByteOrder::BigEndian {
(
u128::from_be_bytes(read(p.add(n - 16))),
u128::from_be_bytes(read(p.add(n - 32))),
u128::from_be_bytes(read(p)),
)
} else {
(
u128::from_le_bytes(read(p)),
u128::from_le_bytes(read(p.add(16))),
u128::from_le_bytes(read(p.add(n - 16))),
)
};
let high = top >> (8 * (WIDEST - n));
[
low as u64,
(low >> 64) as u64,
middle as u64,
(middle >> 64) as u64,
high as u64,
(high >> 64) as u64,
]
}
}
#[inline(always)]
unsafe fn widest_product(a: &Number, b: &Number) -> Widest {
let (x, y) = unsafe {
(
read_widest(&a.value, a.byte_order),
read_widest(&b.value, b.byte_order),
)
};
let mut r = [0u64; 12];
for i in 0..6 {
let mut carry = 0u64;
for j in 0..6 {
let t = u128::from(x[i]) * u128::from(y[j]) + u128::from(r[i + j]) + u128::from(carry);
r[i + j] = t as u64;
carry = (t >> 64) as u64;
}
r[i + 6] = carry;
}
let top = r.iter().rposition(|&l| l != 0);
let len = match top {
Some(t) => 8 * t + 8 - r[t].leading_zeros() as usize / 8,
None => 1,
};
let nonzero = |v: [u64; 6]| v.iter().any(|&l| l != 0);
Widest {
limbs: r,
len,
negative: a.negative != b.negative && nonzero(x) && nonzero(y),
}
}
#[inline(always)]
unsafe fn write_widest(dst: *mut u8, order: ByteOrder, w: &Widest) {
let (l, len) = (w.limbs, w.len);
unsafe {
if len <= 4 * SMALL {
let mut limbs = [0; 8];
limbs.copy_from_slice(&l[..8]);
let wide = Wide {
limbs,
len,
negative: w.negative,
};
write_wide(dst, order, &wide);
return;
}
let k = 8 * (len - 32);
let (q, b) = (k / 64, (k % 64) as u32);
let limb = |i: usize| if i < 12 { l[i] } else { 0 };
let mut t = [0u64; 4];
for (i, v) in t.iter_mut().enumerate() {
*v = if b == 0 {
limb(i + q)
} else {
(limb(i + q) >> b) | (limb(i + q + 1) << (64 - b))
};
}
let u = |a: u64, b: u64| u128::from(a) | (u128::from(b) << 64);
let low = [u(l[0], l[1]), u(l[2], l[3]), u(l[4], l[5]), u(l[6], l[7])];
let (t01, t23) = (u(t[0], t[1]), u(t[2], t[3]));
if order == ByteOrder::BigEndian {
for (i, v) in low.iter().enumerate() {
write(dst.add(len - 16 * i - 16), v.to_be_bytes());
}
write(dst.add(16), t01.to_be_bytes());
write(dst, t23.to_be_bytes());
} else {
for (i, v) in low.iter().enumerate() {
write(dst.add(16 * i), v.to_le_bytes());
}
write(dst.add(len - 32), t01.to_le_bytes());
write(dst.add(len - 16), t23.to_le_bytes());
}
}
}
#[inline(always)]
fn put_widest(v: &mut Vec<u8>, order: ByteOrder, w: &Widest) {
if v.capacity() < w.len {
*v = Vec::with_capacity(w.len);
}
unsafe {
write_widest(v.as_mut_ptr(), order, w);
v.set_len(w.len);
}
}
#[derive(Clone, Copy)]
pub(super) struct Operand {
pub(super) ptr: *const u8,
pub(super) len: usize,
pub(super) big_endian: bool,
pub(super) significant: usize,
}
impl Operand {
pub(super) fn of(n: &Number) -> Self {
let big_endian = n.byte_order == ByteOrder::BigEndian;
let significant = if big_endian {
significant_len::<true>(&n.value)
} else {
significant_len::<false>(&n.value)
};
Operand {
ptr: n.value.as_ptr(),
len: n.value.len(),
big_endian,
significant,
}
}
}
#[inline(never)]
fn ref_times_ref(a: &Number, b: &Number) -> Number {
let order = a.byte_order;
if wide(a, b) {
let w = unsafe { wide_product(a, b) };
let mut value = Vec::new();
put_wide(&mut value, order, &w);
return Number {
value,
negative: w.negative,
byte_order: order,
};
}
if widest(a, b) {
let w = unsafe { widest_product(a, b) };
let mut value = Vec::new();
put_widest(&mut value, order, &w);
return Number {
value,
negative: w.negative,
byte_order: order,
};
}
let (x, y) = (Operand::of(a), Operand::of(b));
unsafe {
if y.significant <= 8
&& a.byte_order == ByteOrder::LittleEndian
&& let Some(p) = copy_times_limb(a, b.negative, limb_of(y), None)
{
return p;
}
if x.significant <= 8
&& a.byte_order == ByteOrder::LittleEndian
&& b.byte_order == ByteOrder::LittleEndian
&& let Some(p) = copy_times_limb(b, a.negative, limb_of(x), None)
{
return p;
}
}
let negative = a.negative != b.negative;
let square = ptr::eq(a, b);
unsafe {
product(x, y, square, negative, |p| {
let mut v = Vec::with_capacity(p.len);
p.write(v.as_mut_ptr(), order);
v.set_len(p.len);
Number {
value: v,
negative: p.negative,
byte_order: order,
}
})
}
}
#[inline(never)]
fn ref_times_value(a: &Number, b: &mut Number) -> Number {
let order = a.byte_order;
if wide(a, b) {
let w = unsafe { wide_product(a, b) };
put_wide(&mut b.value, order, &w);
return Number {
value: mem::take(&mut b.value),
negative: w.negative,
byte_order: order,
};
}
if widest(a, b) {
let w = unsafe { widest_product(a, b) };
put_widest(&mut b.value, order, &w);
return Number {
value: mem::take(&mut b.value),
negative: w.negative,
byte_order: order,
};
}
let (x, y) = (Operand::of(a), Operand::of(b));
unsafe {
if x.significant <= 8
&& order == ByteOrder::LittleEndian
&& b.byte_order == order
&& times_limb(b, a.negative, limb_of(x), None)
{
return mem::take(b);
}
if y.significant <= 8 && order == ByteOrder::LittleEndian {
let negative = b.negative;
if let Some(p) = copy_times_limb(a, negative, limb_of(y), Some(&mut b.value)) {
return p;
}
}
}
let negative = a.negative != b.negative;
unsafe {
product(x, y, false, negative, |p| {
p.put_in(&mut b.value, order);
Number {
value: mem::take(&mut b.value),
negative: p.negative,
byte_order: order,
}
})
}
}
#[inline(never)]
fn mul_assign_ref(a: &mut Number, b: &Number) {
let order = a.byte_order;
if wide(a, b) {
let w = unsafe { wide_product(a, b) };
put_wide(&mut a.value, order, &w);
a.negative = w.negative;
return;
}
if widest(a, b) {
let w = unsafe { widest_product(a, b) };
put_widest(&mut a.value, order, &w);
a.negative = w.negative;
return;
}
let (x, y) = (Operand::of(a), Operand::of(b));
if y.significant <= 8
&& order == ByteOrder::LittleEndian
&& times_limb(a, b.negative, unsafe { limb_of(y) }, None)
{
return;
}
let negative = a.negative != b.negative;
unsafe {
product(x, y, false, negative, |p| {
p.put_in(&mut a.value, order);
a.negative = p.negative;
});
}
}
#[inline(never)]
fn mul_assign_value(a: &mut Number, b: &mut Number) {
let order = a.byte_order;
if wide(a, b) {
let w = unsafe { wide_product(a, b) };
if a.value.capacity() < w.len && b.value.capacity() >= w.len {
mem::swap(&mut a.value, &mut b.value);
}
put_wide(&mut a.value, order, &w);
a.negative = w.negative;
return;
}
if widest(a, b) {
let w = unsafe { widest_product(a, b) };
if a.value.capacity() < w.len && b.value.capacity() >= w.len {
mem::swap(&mut a.value, &mut b.value);
}
put_widest(&mut a.value, order, &w);
a.negative = w.negative;
return;
}
let (x, y) = (Operand::of(a), Operand::of(b));
if y.significant <= 8 && order == ByteOrder::LittleEndian {
let negative = b.negative;
if times_limb(a, negative, unsafe { limb_of(y) }, Some(&mut b.value)) {
return;
}
}
let negative = a.negative != b.negative;
unsafe {
product(x, y, false, negative, |p| {
if a.value.capacity() < p.len && b.value.capacity() >= p.len {
mem::swap(&mut a.value, &mut b.value);
}
p.put_in(&mut a.value, order);
a.negative = p.negative;
});
}
}
pub(super) struct Product {
pub(super) r: *const u64,
pub(super) len: usize,
pub(super) negative: bool,
}
impl Product {
pub(super) unsafe fn write(&self, dst: *mut u8, order: ByteOrder) {
unsafe {
if self.r.is_null() {
*dst = 0;
} else if self.len < 8 {
write_small(dst, order, *self.r, 0, self.len);
} else if order == ByteOrder::BigEndian {
write_limbs::<true>(dst, self.r, self.len);
} else {
write_limbs::<false>(dst, self.r, self.len);
}
}
}
#[inline(always)]
pub(super) unsafe fn put_in(&self, v: &mut Vec<u8>, order: ByteOrder) {
if v.capacity() < self.len {
*v = Vec::with_capacity(self.len);
}
unsafe {
self.write(v.as_mut_ptr(), order);
v.set_len(self.len);
}
}
}
const MEDIUM_LIMBS: usize = 16;
pub(super) const STACK_LIMBS: usize = 1024;
#[derive(Clone, Copy)]
#[repr(C, align(16))]
struct Pair([MaybeUninit<u64>; 2]);
const PAIR: Pair = Pair([MaybeUninit::uninit(); 2]);
#[inline(always)]
const fn even(n: usize) -> usize {
(n + 1) & !1
}
#[inline(always)]
unsafe fn product<R>(
x: Operand,
y: Operand,
square: bool,
negative: bool,
place: impl FnOnce(&Product) -> R,
) -> R {
let (la, lb) = (x.significant, y.significant);
if la == 0 || lb == 0 {
return place(&Product {
r: ptr::null(),
len: 1,
negative: false,
});
}
let (nx, ny) = (la.div_ceil(8), lb.div_ceil(8));
unsafe {
if nx + ny <= MEDIUM_LIMBS {
let mut s = [PAIR; MEDIUM_LIMBS + 1];
return compute(s.as_mut_ptr().cast(), x, y, square, negative, place);
}
let (long, short) = if nx >= ny { (nx, ny) } else { (ny, nx) };
let itch = if square {
limbs::sqr_itch(nx)
} else {
limbs::mul_itch(long, short)
};
let operands = if square {
even(nx)
} else {
even(nx) + even(ny)
};
let need = operands + even(nx + ny) + itch;
let compute = |s: *mut MaybeUninit<u64>| compute(s.cast(), x, y, square, negative, place);
if need <= STACK_LIMBS {
on_stack(compute)
} else {
on_heap(need, compute)
}
}
}
#[inline(always)]
unsafe fn compute<R>(
s: *mut u64,
x: Operand,
y: Operand,
square: bool,
negative: bool,
place: impl FnOnce(&Product) -> R,
) -> R {
let (la, lb) = (x.significant, y.significant);
let (nx, ny) = (la.div_ceil(8), lb.div_ceil(8));
unsafe {
let (a, b) = (s.add(nx & 1), s.add(even(nx) + (ny & 1)));
to_limbs(x, a);
let operands = if square {
even(nx)
} else {
even(nx) + even(ny)
};
let r = s.add(operands);
let t = r.add(even(nx + ny));
let medium = nx + ny <= MEDIUM_LIMBS;
if square {
if medium {
kernels::sqr_basecase(r, a, nx);
} else {
limbs::sqr(r, a, nx, t);
}
} else {
to_limbs(y, b);
let ((p, np), (q, nq)) = if nx >= ny {
((a, nx), (b, ny))
} else {
((b, ny), (a, nx))
};
if medium {
kernels::mul_basecase(r, p, np, q, nq);
} else {
limbs::mul(r, p, np, q, nq, t);
}
}
let top = la + lb - 1;
let byte = (*r.add(top / 8) >> (8 * (top % 8))) as u8;
let len = if byte == 0 { top } else { top + 1 };
place(&Product { r, len, negative })
}
}
const STACK_PAD: usize = 256;
#[inline(never)]
pub(super) fn on_stack<R>(f: impl FnOnce(*mut MaybeUninit<u64>) -> R) -> R {
let mut s = [PAIR; (STACK_LIMBS + STACK_PAD) / 2];
f(s.as_mut_ptr().cast())
}
#[cold]
#[inline(never)]
pub(super) fn on_heap<R>(need: usize, f: impl FnOnce(*mut MaybeUninit<u64>) -> R) -> R {
let mut s = Vec::<Pair>::with_capacity(need.div_ceil(2));
f(s.as_mut_ptr().cast())
}
#[inline(always)]
pub(super) unsafe fn to_limbs(x: Operand, out: *mut u64) {
let l = x.significant;
let (full, rem) = (l / 8, l % 8);
unsafe {
let shift = 8 * (8 - rem) as u32;
if x.big_endian {
let end = x.ptr.add(x.len);
for i in 0..full {
*out.add(i) = u64::from_be_bytes(read(end.sub(8 * i + 8)));
}
if rem > 0 {
*out.add(full) = if l >= 8 {
u64::from_be_bytes(read(end.sub(l))) >> shift
} else {
read_small(
core::slice::from_raw_parts(end.sub(l), rem),
ByteOrder::BigEndian,
) as u64
};
}
} else {
for i in 0..full {
*out.add(i) = u64::from_le_bytes(read(x.ptr.add(8 * i)));
}
if rem > 0 {
*out.add(full) = if l >= 8 {
u64::from_le_bytes(read(x.ptr.add(l - 8))) >> shift
} else {
read_small(
core::slice::from_raw_parts(x.ptr, rem),
ByteOrder::LittleEndian,
) as u64
};
}
}
}
}
#[inline(always)]
unsafe fn write_limbs<const BE: bool>(dst: *mut u8, r: *const u64, len: usize) {
let (full, rem) = (len / 8, len % 8);
unsafe {
for i in 0..full {
let v = *r.add(i);
if BE {
write(dst.add(len - 8 * i - 8), v.to_be_bytes());
} else {
write(dst.add(8 * i), v.to_le_bytes());
}
}
if rem > 0 {
let k = 8 * rem as u32;
let v = (*r.add(full - 1) >> k) | (*r.add(full) << (64 - k));
if BE {
write(dst, v.to_be_bytes());
} else {
write(dst.add(len - 8), v.to_le_bytes());
}
}
}
}