#[cfg(all(
target_arch = "aarch64",
target_endian = "little",
target_pointer_width = "64",
target_feature = "neon",
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 = "bits/aarch64.rs"]
mod kernels;
#[cfg(not(all(
target_arch = "aarch64",
target_endian = "little",
target_pointer_width = "64",
target_feature = "neon",
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 = "bits/portable.rs"]
mod kernels;
use super::add::{
SMALL, long, medium, read, read_limbs, read_small, significant_len, small, top_of, write,
write_small,
};
use super::{ByteOrder, Number};
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
use core::{mem, ptr};
const AND: u8 = 0;
const OR: u8 = 1;
const XOR: u8 = 2;
const AND_NOT: u8 = 3;
const NOT_AND: u8 = 4;
#[inline(always)]
fn apply(g: u8, x: u64, y: u64) -> u64 {
match g {
AND => x & y,
OR => x | y,
XOR => x ^ y,
AND_NOT => x & !y,
_ => !x & y,
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
enum Op {
And,
Or,
Xor,
}
#[inline(always)]
fn select(op: Op, nx: bool, ny: bool) -> (u8, bool) {
const TABLE: [[u8; 4]; 3] = [
[AND, AND_NOT, NOT_AND, OR | 0x80],
[OR, NOT_AND | 0x80, AND_NOT | 0x80, AND | 0x80],
[XOR, XOR | 0x80, XOR | 0x80, XOR],
];
let t = TABLE[op as usize][usize::from(nx) * 2 + usize::from(ny)];
(t & 0x7F, t & 0x80 != 0)
}
macro_rules! bitwise {
(
$Op:ident, $op:ident, $Assign:ident, $assign:ident, $kind:expr, $OP:expr, $sym:literal,
$what:literal, $value:literal, $magnitude:literal, $negative:literal, $wide:literal,
$by_b:literal, $in_b:literal, $built_in_b:literal
) => {
impl $Op<&Number> for &Number {
type Output = Number;
#[doc = concat!("Returns `self ", $sym, " rhs`, the bitwise ", $what, " of the numbers in")]
#[doc = concat!("let c = &a ", $sym, " &b;")]
#[doc = concat!("// As for `i32`: `12 ", $sym, " -10` is ", $value, ".")]
#[doc = concat!("assert_eq!(c.value, [", $magnitude, "]);")]
#[doc = concat!("assert_eq!(c.is_negative(), ", $negative, ");")]
fn $op(self, rhs: &Number) -> Number {
if small(self, rhs) {
let s = unsafe { small_result(self, rhs, $kind) };
return small_number(self.byte_order, s);
}
if let Some(n) = plus_new::<{ $OP }>(self, rhs) {
return n;
}
if medium(self, rhs) {
let m = unsafe { medium_result::<{ $OP }>(self, rhs) };
return medium_number(self.byte_order, &m);
}
ref_ref(self, rhs, $kind)
}
}
impl $Op<&Number> for Number {
type Output = Number;
#[doc = concat!("Returns `self ", $sym, " rhs`, in the byte order of `self`, in the shortest")]
#[doc = concat!("form, as `self ", $sym, "= rhs` does.")]
#[doc = concat!("let c = a ", $sym, " &Number::new_from_u8(0xF0, ByteOrder::LittleEndian);")]
#[doc = concat!("assert_eq!(c.value, [", $wide, "]);")]
fn $op(mut self, rhs: &Number) -> Number {
$Assign::$assign(&mut self, rhs);
self
}
}
impl $Op<Number> for &Number {
type Output = Number;
#[doc = concat!("Returns `self ", $sym, " rhs`, in the byte order of `self`, in the shortest")]
#[doc = concat!("let c = &a ", $sym, " b;")]
#[doc = concat!("assert_eq!(c.value, [", $wide, "]);")]
fn $op(self, mut rhs: Number) -> Number {
if small(self, &rhs) {
let s = unsafe { small_result(self, &rhs, $kind) };
let order = self.byte_order;
put_small(&mut rhs.value, order, s);
return Number {
value: rhs.value,
negative: s.negative,
byte_order: order,
};
}
if plus_over::<{ $OP }>(&mut rhs, self) {
return rhs;
}
if medium(self, &rhs) {
let m = unsafe { medium_result::<{ $OP }>(self, &rhs) };
let order = self.byte_order;
put_medium(&mut rhs.value, order, &m);
return Number {
value: rhs.value,
negative: m.negative,
byte_order: order,
};
}
ref_value(self, &mut rhs, $kind)
}
}
impl $Op<Number> for Number {
type Output = Number;
#[doc = concat!("Returns `self ", $sym, " rhs`, in the byte order of `self`, in the shortest")]
#[doc = concat!("form, as `self ", $sym, "= rhs` does.")]
#[doc = concat!("let c = a ", $sym, " b;")]
#[doc = concat!("assert_eq!(c.value, [", $magnitude, "]);")]
#[doc = concat!("assert_eq!(c.is_negative(), ", $negative, ");")]
fn $op(mut self, rhs: Number) -> Number {
$Assign::$assign(&mut self, rhs);
self
}
}
impl $Assign<&Number> for Number {
#[doc = concat!("Sets `self` to `self ", $sym, " rhs`, keeping its byte order, in the shortest form.")]
#[doc = concat!("n ", $sym, "= &Number::new_from_i32(-10, ByteOrder::BigEndian);")]
#[doc = concat!("assert_eq!(n.value, [", $magnitude, "]);")]
#[doc = concat!("assert_eq!(n.is_negative(), ", $negative, ");")]
#[inline]
fn $assign(&mut self, rhs: &Number) {
if small(self, rhs) {
let s = unsafe { small_result(self, rhs, $kind) };
put_small(&mut self.value, self.byte_order, s);
self.negative = s.negative;
return;
}
if plus_over::<{ $OP }>(self, rhs) {
return;
}
if medium(self, rhs) {
let m = unsafe { medium_result::<{ $OP }>(self, rhs) };
put_medium(&mut self.value, self.byte_order, &m);
self.negative = m.negative;
return;
}
assign_ref(self, rhs, $kind);
}
}
impl $Assign<Number> for Number {
#[doc = concat!("Sets `self` to `self ", $sym, " rhs`, keeping its byte order, in the shortest form.")]
#[doc = concat!("n ", $sym, "= b;")]
#[doc = concat!("// `0xFF ", $sym, " 0x01_00` is ", $by_b, ".")]
#[doc = concat!("assert_eq!(n.value, [", $in_b, "]);")]
#[doc = concat!("assert_eq!(n.value.as_ptr() == pointer, ", $built_in_b, ");")]
#[inline]
fn $assign(&mut self, mut rhs: Number) {
if small(self, &rhs) {
let s = unsafe { small_result(self, &rhs, $kind) };
if self.value.capacity() < s.len && rhs.value.capacity() >= s.len {
mem::swap(&mut self.value, &mut rhs.value);
}
put_small(&mut self.value, self.byte_order, s);
self.negative = s.negative;
return;
}
if plus_over::<{ $OP }>(self, &rhs) {
return;
}
if medium(self, &rhs) {
let m = unsafe { medium_result::<{ $OP }>(self, &rhs) };
if self.value.capacity() < m.len && rhs.value.capacity() >= m.len {
mem::swap(&mut self.value, &mut rhs.value);
}
put_medium(&mut self.value, self.byte_order, &m);
self.negative = m.negative;
return;
}
assign_value(self, &mut rhs, $kind);
}
}
};
}
bitwise!(
BitAnd,
bitand,
BitAndAssign,
bitand_assign,
Op::And,
AND,
"&",
"and",
"4",
"4",
"false",
"0",
"0",
"0",
"false"
);
bitwise!(
BitOr,
bitor,
BitOrAssign,
bitor_assign,
Op::Or,
OR,
"|",
"or",
"-2",
"2",
"true",
"0x0F, 0xF0",
"0x01_FF",
"0x01, 0xFF",
"true"
);
bitwise!(
BitXor,
bitxor,
BitXorAssign,
bitxor_assign,
Op::Xor,
XOR,
"^",
"exclusive or",
"-6",
"6",
"true",
"0x0F, 0xF0",
"0x01_FF",
"0x01, 0xFF",
"true"
);
impl Not for Number {
type Output = Number;
#[inline]
fn not(mut self) -> Number {
not_in_place(&mut self);
self
}
}
impl Not for &Number {
type Output = Number;
#[inline]
fn not(self) -> Number {
not_new(self)
}
}
#[derive(Clone, Copy)]
struct Small {
lo: u64,
hi: u64,
len: usize,
negative: bool,
}
#[inline(always)]
fn small_of(m: u128, top: bool, negative: bool) -> Small {
Small {
lo: m as u64,
hi: (m >> 64) as u64,
len: if top {
SMALL + 1
} else {
SMALL - (m | 1).leading_zeros() as usize / 8
},
negative,
}
}
#[inline(always)]
unsafe fn small_result(a: &Number, b: &Number, op: Op) -> Small {
let (x, y) = unsafe {
(
read_small(&a.value, a.byte_order),
read_small(&b.value, b.byte_order),
)
};
let (nx, ny) = (a.negative && x != 0, b.negative && y != 0);
let tx = if nx { x.wrapping_neg() } else { x };
let ty = if ny { y.wrapping_neg() } else { y };
let (r, negative) = match op {
Op::And => (tx & ty, nx & ny),
Op::Or => (tx | ty, nx | ny),
Op::Xor => (tx ^ ty, nx ^ ny),
};
let m = if negative { r.wrapping_neg() } else { r };
small_of(m, negative && r == 0, negative)
}
#[inline(always)]
fn put_small(v: &mut Vec<u8>, order: ByteOrder, s: Small) {
if v.capacity() >= s.len {
unsafe {
write_small(v.as_mut_ptr(), order, s.lo, s.hi, s.len);
v.set_len(s.len);
}
} else {
replace_small(v, order, s);
}
}
#[cold]
#[inline(never)]
fn replace_small(v: &mut Vec<u8>, order: ByteOrder, s: Small) {
*v = new_small(order, s);
}
#[inline(always)]
fn new_small(order: ByteOrder, s: Small) -> Vec<u8> {
let mut v = Vec::with_capacity(s.len);
unsafe {
write_small(v.as_mut_ptr(), order, s.lo, s.hi, s.len);
v.set_len(s.len);
}
v
}
#[inline(never)]
fn small_number(order: ByteOrder, s: Small) -> Number {
Number {
value: new_small(order, s),
negative: s.negative,
byte_order: order,
}
}
#[inline(always)]
fn plus_over<const OP: u8>(a: &mut Number, b: &Number) -> bool {
if a.negative | b.negative || a.byte_order != b.byte_order {
return false;
}
if a.byte_order == ByteOrder::BigEndian {
plus_over_in::<OP, true>(&mut a.value, &b.value)
} else {
plus_over_in::<OP, false>(&mut a.value, &b.value)
}
}
#[inline(never)]
fn plus_over_in<const OP: u8, const BE: bool>(v: &mut Vec<u8>, y: &[u8]) -> bool {
let n = v.len();
let (lx, ly) = (sig_len::<BE>(v), sig_len::<BE>(y));
let (long, short) = (lx.max(ly), lx.min(ly));
let u = if OP == AND { short } else { long };
if short == 0 || v.capacity() < u || (BE && u != n) {
return false;
}
let ye = end::<BE>(y);
let cut = OP == AND || (OP == XOR && lx == ly);
let first = if cut && BE {
unsafe { highest::<BE, BE>(OP, end::<BE>(v), ye, 0, short) }.unwrap_or(1)
} else {
long
};
let base = v.as_mut_ptr();
unsafe {
let dst = if BE { base.add(n) } else { base };
kernels::logic::<OP, false, false>(
at_mut::<BE>(dst, 0, short),
at::<BE>(dst, 0, short),
at::<BE>(ye, 0, short),
short,
);
let len = if cut && BE {
if first < u {
ptr::copy(base.add(u - first), base, first);
}
first
} else if cut {
highest_of::<BE>(dst, u)
} else {
if ly > lx {
let k = long - short;
ptr::copy_nonoverlapping(at::<BE>(ye, short, k), at_mut::<BE>(dst, short, k), k);
}
long
};
v.set_len(len);
}
true
}
#[inline(always)]
unsafe fn highest_of<const BE: bool>(end: *const u8, u: usize) -> usize {
let mut q = u;
unsafe {
while q >= 8 {
let w = load::<BE>(end, q - 8);
if w != 0 {
return q - w.leading_zeros() as usize / 8;
}
q -= 8;
}
while q > 1 && get::<BE>(end, q - 1) == 0 {
q -= 1;
}
q.max(1)
}
}
#[inline(always)]
fn plus_new<const OP: u8>(a: &Number, b: &Number) -> Option<Number> {
if a.negative | b.negative || a.byte_order != b.byte_order {
return None;
}
let value = if a.byte_order == ByteOrder::BigEndian {
plus_new_in::<OP, true>(&a.value, &b.value)?
} else {
plus_new_in::<OP, false>(&a.value, &b.value)?
};
Some(Number {
value,
negative: false,
byte_order: a.byte_order,
})
}
#[inline(never)]
fn plus_new_in<const OP: u8, const BE: bool>(x: &[u8], y: &[u8]) -> Option<Vec<u8>> {
let (lx, ly) = (sig_len::<BE>(x), sig_len::<BE>(y));
let (long, short) = (lx.max(ly), lx.min(ly));
let (xe, ye) = (end::<BE>(x), end::<BE>(y));
let len = if OP == AND || (OP == XOR && lx == ly) {
unsafe { highest::<BE, BE>(OP, xe, ye, 0, short)? }
} else if short > 0 {
long
} else {
return None;
};
let mut v = Vec::<u8>::with_capacity(len);
unsafe {
let base = v.as_mut_ptr();
let dst = if BE { base.add(len) } else { base };
let k = short.min(len);
kernels::logic::<OP, false, false>(
at_mut::<BE>(dst, 0, k),
at::<BE>(xe, 0, k),
at::<BE>(ye, 0, k),
k,
);
if len > short {
let (from, k) = (if lx > ly { xe } else { ye }, len - short);
ptr::copy_nonoverlapping(at::<BE>(from, short, k), at_mut::<BE>(dst, short, k), k);
}
v.set_len(len);
}
Some(v)
}
struct Medium {
limbs: [u64; 9],
len: usize,
long: usize,
top: u64,
negative: bool,
}
#[inline(always)]
unsafe fn medium_result<const OP: u8>(a: &Number, b: &Number) -> Medium {
unsafe {
match a.value.len().max(b.value.len()).div_ceil(8) {
..=3 => medium_of::<OP, 3>(a, b),
4 => medium_of::<OP, 4>(a, b),
5 => medium_of::<OP, 5>(a, b),
6 => medium_of::<OP, 6>(a, b),
7 => medium_of::<OP, 7>(a, b),
_ => medium_of::<OP, 8>(a, b),
}
}
}
#[inline(never)]
unsafe fn medium_of<const OP: u8, const L: usize>(a: &Number, b: &Number) -> Medium {
let (x, y) = unsafe {
(
read_limbs::<L>(&a.value, a.byte_order),
read_limbs::<L>(&b.value, b.byte_order),
)
};
let nonzero = |v: &[u64; 9]| v.iter().take(L).fold(0, |o, &l| o | l) != 0;
let (nx, ny) = (a.negative && nonzero(&x), b.negative && nonzero(&y));
let negative = match OP {
AND => nx & ny,
OR => nx | ny,
_ => nx ^ ny,
};
let (mx, my, mr) = (
0u64.wrapping_sub(u64::from(nx)),
0u64.wrapping_sub(u64::from(ny)),
0u64.wrapping_sub(u64::from(negative)),
);
let (mut cx, mut cy, mut cr) = (nx, ny, negative);
let mut limbs = [0u64; 9];
for i in 0..L {
let (tx, c) = (x[i] ^ mx).overflowing_add(u64::from(cx));
cx = c;
let (ty, c) = (y[i] ^ my).overflowing_add(u64::from(cy));
cy = c;
let r = match OP {
AND => tx & ty,
OR => tx | ty,
_ => tx ^ ty,
};
let (m, c) = (r ^ mr).overflowing_add(u64::from(cr));
cr = c;
limbs[i] = m;
}
limbs[L] = u64::from(cr);
if long::<L>(&limbs) {
let (len, top) = top_of::<L>(&limbs);
return Medium {
limbs,
len,
long: L,
top,
negative,
};
}
let mut t = L;
while t > 0 && limbs[t] == 0 {
t -= 1;
}
Medium {
limbs,
len: 8 * t + 8 - (limbs[t] | 1).leading_zeros() as usize / 8,
long: 0,
top: 0,
negative,
}
}
#[inline(always)]
unsafe fn write_medium(p: *mut u8, order: ByteOrder, m: &Medium) {
let (r, len) = (&m.limbs, m.len);
let be = order == ByteOrder::BigEndian;
unsafe {
if m.long > 0 {
let l = m.long;
let c = (8 * (l - 1)).min(len - 8);
for (i, limb) in r.iter().enumerate().take(l - 1) {
if be {
write(p.add(len - 8 - 8 * i), limb.to_be_bytes());
} else {
write(p.add(8 * i), limb.to_le_bytes());
}
}
if be {
write(p.add(len - 8 - c), r[l - 1].to_be_bytes());
write(p, m.top.to_be_bytes());
} else {
write(p.add(c), r[l - 1].to_le_bytes());
write(p.add(len - 8), m.top.to_le_bytes());
}
return;
}
if len <= SMALL {
write_small(p, order, r[0], r[1], len);
return;
}
let (full, rem) = (len / 8, len % 8);
for (i, limb) in r.iter().enumerate().take(full) {
if be {
write(p.add(len - 8 - 8 * i), limb.to_be_bytes());
} else {
write(p.add(8 * i), limb.to_le_bytes());
}
}
if rem > 0 {
let k = 8 * rem as u32;
let top = (r[full - 1] >> k) | (r[full] << (64 - k));
if be {
write(p, top.to_be_bytes());
} else {
write(p.add(len - 8), top.to_le_bytes());
}
}
}
}
#[inline(always)]
fn put_medium(v: &mut Vec<u8>, order: ByteOrder, m: &Medium) {
if v.capacity() < m.len {
*v = Vec::with_capacity(m.len);
}
unsafe {
write_medium(v.as_mut_ptr(), order, m);
v.set_len(m.len);
}
}
#[inline(never)]
fn medium_number(order: ByteOrder, m: &Medium) -> Number {
let mut value = Vec::new();
put_medium(&mut value, order, m);
Number {
value,
negative: m.negative,
byte_order: order,
}
}
#[inline(never)]
fn ref_ref(a: &Number, b: &Number, op: Op) -> Number {
let plan = plan(a, b, op);
Number {
value: new_result(a, b, &plan),
negative: plan.negative,
byte_order: a.byte_order,
}
}
#[inline(never)]
fn ref_value(a: &Number, b: &mut Number, op: Op) -> Number {
let order = a.byte_order;
if b.byte_order == order
&& let Some(negative) = over(&mut b.value, order, b.negative, a, op)
{
return Number {
value: mem::take(&mut b.value),
negative,
byte_order: order,
};
}
let plan = plan(a, b, op);
let value = if b.value.capacity() >= plan.len {
if b.byte_order != order {
b.value.reverse();
b.byte_order = order;
}
unsafe { in_vector(&mut b.value, order, a, &plan.swapped()) };
mem::take(&mut b.value)
} else {
new_result(a, b, &plan)
};
Number {
value,
negative: plan.negative,
byte_order: order,
}
}
#[inline(never)]
fn assign_ref(a: &mut Number, b: &Number, op: Op) {
if let Some(negative) = over(&mut a.value, a.byte_order, a.negative, b, op) {
a.negative = negative;
return;
}
let plan = plan(a, b, op);
if a.value.capacity() >= plan.len {
unsafe { in_vector(&mut a.value, a.byte_order, b, &plan) };
} else {
a.value = new_result(a, b, &plan);
}
a.negative = plan.negative;
}
#[inline(never)]
fn assign_value(a: &mut Number, b: &mut Number, op: Op) {
let order = a.byte_order;
if let Some(negative) = over(&mut a.value, order, a.negative, b, op) {
a.negative = negative;
return;
}
let plan = plan(a, b, op);
if a.value.capacity() >= plan.len {
unsafe { in_vector(&mut a.value, order, b, &plan) };
} else if b.value.capacity() >= plan.len {
if b.byte_order != order {
b.value.reverse();
b.byte_order = order;
}
unsafe { in_vector(&mut b.value, order, a, &plan.swapped()) };
mem::swap(&mut a.value, &mut b.value);
} else {
a.value = new_result(a, b, &plan);
}
a.negative = plan.negative;
}
#[inline]
fn over(v: &mut Vec<u8>, order: ByteOrder, negative_x: bool, y: &Number, op: Op) -> Option<bool> {
unsafe {
match (
order == ByteOrder::BigEndian,
y.byte_order == ByteOrder::BigEndian,
) {
(true, true) => over_in::<true, true>(v, negative_x, y, op),
(true, false) => over_in::<true, false>(v, negative_x, y, op),
(false, true) => over_in::<false, true>(v, negative_x, y, op),
(false, false) => over_in::<false, false>(v, negative_x, y, op),
}
}
}
#[inline(never)]
unsafe fn over_in<const XBE: bool, const YBE: bool>(
v: &mut Vec<u8>,
negative_x: bool,
y: &Number,
op: Op,
) -> Option<bool> {
let n = v.len();
let lx = sig_len::<XBE>(v);
let ly = sig_len::<YBE>(&y.value);
let (nx, ny) = (negative_x && lx > 0, y.negative && ly > 0);
let (g, negative) = select(op, nx, ny);
let tail = tail_of(g, lx, ly);
let (long, short) = (lx.max(ly), lx.min(ly));
let x = end::<XBE>(v);
let ye = end::<YBE>(&y.value);
let (head, lo) = unsafe {
if nx | ny | negative {
let mut flags = Flags {
x: nx,
y: ny,
carry: negative,
};
let w = flags.next(g, limb::<XBE>(x, lx, 0), limb::<YBE>(ye, ly, 0));
if flags.running() || short < 8 {
return None;
}
(w, 8)
} else {
(0, 0)
}
};
let len = if tail != Tail::Zero {
long
} else {
match unsafe { highest::<XBE, YBE>(g, x, ye, lo, short) } {
Some(len) => len,
None if lo == 0 => return None,
None => 8 - (head | 1).leading_zeros() as usize / 8,
}
};
if v.capacity() < len || (XBE && len != n) {
return None;
}
let base = v.as_mut_ptr();
unsafe {
let dst = if XBE { base.add(n) } else { base };
let x = dst.cast_const();
if lo > 0 {
put_limb::<XBE>(dst, len, 0, head);
}
let bulk = short.min(len);
if bulk > lo {
let k = bulk - lo;
logic::<false>(
g,
XBE != YBE,
at_mut::<XBE>(dst, lo, k),
at::<XBE>(x, lo, k),
at::<YBE>(ye, lo, k),
k,
);
}
if tail == Tail::Y {
let k = long - short;
if XBE != YBE {
kernels::copy_reversed(at_mut::<XBE>(dst, short, k), at::<YBE>(ye, short, k), k);
} else {
ptr::copy_nonoverlapping(at::<YBE>(ye, short, k), at_mut::<XBE>(dst, short, k), k);
}
}
v.set_len(len);
}
Some(negative)
}
#[inline(always)]
fn tail_of(g: u8, lx: usize, ly: usize) -> Tail {
const KEEPS_X: u8 = 1 << OR | 1 << XOR | 1 << AND_NOT;
const KEEPS_Y: u8 = 1 << OR | 1 << XOR | 1 << NOT_AND;
if lx > ly && KEEPS_X >> g & 1 != 0 {
Tail::X
} else if ly > lx && KEEPS_Y >> g & 1 != 0 {
Tail::Y
} else {
Tail::Zero
}
}
#[inline(always)]
fn sig_len<const BE: bool>(v: &[u8]) -> usize {
let n = v.len();
if n > 0 && unsafe { get::<BE>(end::<BE>(v), n - 1) } != 0 {
n
} else {
significant_len::<BE>(v)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Tail {
Zero,
X,
Y,
}
#[derive(Clone, Copy)]
struct Plan {
g: u8,
lx: usize,
ly: usize,
nx: bool,
ny: bool,
negative: bool,
head: usize,
tail: Tail,
len: usize,
}
impl Plan {
#[inline(always)]
fn swapped(&self) -> Plan {
Plan {
g: match self.g {
AND_NOT => NOT_AND,
NOT_AND => AND_NOT,
g => g,
},
lx: self.ly,
ly: self.lx,
nx: self.ny,
ny: self.nx,
tail: match self.tail {
Tail::X => Tail::Y,
Tail::Y => Tail::X,
Tail::Zero => Tail::Zero,
},
..*self
}
}
}
struct Flags {
x: bool,
y: bool,
carry: bool,
}
impl Flags {
#[inline(always)]
fn next(&mut self, g: u8, x: u64, y: u64) -> u64 {
let xm = x.wrapping_sub(u64::from(self.x));
self.x &= x == 0;
let ym = y.wrapping_sub(u64::from(self.y));
self.y &= y == 0;
let m = apply(g, xm, ym);
let r = m.wrapping_add(u64::from(self.carry));
self.carry &= m == u64::MAX;
r
}
#[inline(always)]
fn running(&self) -> bool {
self.x | self.y | self.carry
}
}
#[inline]
fn plan(a: &Number, b: &Number, op: Op) -> Plan {
match (
a.byte_order == ByteOrder::BigEndian,
b.byte_order == ByteOrder::BigEndian,
) {
(true, true) => plan_in::<true, true>(a, b, op),
(true, false) => plan_in::<true, false>(a, b, op),
(false, true) => plan_in::<false, true>(a, b, op),
(false, false) => plan_in::<false, false>(a, b, op),
}
}
#[inline(always)]
fn plan_in<const XBE: bool, const YBE: bool>(a: &Number, b: &Number, op: Op) -> Plan {
let lx = sig_len::<XBE>(&a.value);
let ly = sig_len::<YBE>(&b.value);
let (nx, ny) = (a.negative && lx > 0, b.negative && ly > 0);
let (g, negative) = select(op, nx, ny);
let tail = tail_of(g, lx, ly);
let (xe, ye) = (end::<XBE>(&a.value), end::<YBE>(&b.value));
let (mut head, mut top) = (0, 0);
if nx | ny | negative {
let mut flags = Flags {
x: nx,
y: ny,
carry: negative,
};
loop {
let r = unsafe { flags.next(g, limb::<XBE>(xe, lx, head), limb::<YBE>(ye, ly, head)) };
if r != 0 {
top = 8 * head + 8 - r.leading_zeros() as usize / 8;
}
head += 1;
if !flags.running() {
break;
}
}
}
let (long, short) = (lx.max(ly), lx.min(ly));
let len = if 8 * head >= long {
top.max(1)
} else if tail != Tail::Zero {
long
} else {
unsafe { highest::<XBE, YBE>(g, xe, ye, 8 * head, short) }.unwrap_or(top.max(1))
};
Plan {
g,
lx,
ly,
nx,
ny,
negative,
head,
tail,
len,
}
}
#[inline(always)]
unsafe fn highest<const XBE: bool, const YBE: bool>(
g: u8,
x: *const u8,
y: *const u8,
lo: usize,
hi: usize,
) -> Option<usize> {
let mut q = hi;
unsafe {
while q >= lo + 8 {
let m = apply(g, load::<XBE>(x, q - 8), load::<YBE>(y, q - 8));
if m != 0 {
return Some(q - m.leading_zeros() as usize / 8);
}
q -= 8;
}
while q > lo {
let m = apply(
g,
u64::from(get::<XBE>(x, q - 1)),
u64::from(get::<YBE>(y, q - 1)),
);
if m as u8 != 0 {
return Some(q);
}
q -= 1;
}
}
None
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Place {
New,
Same,
Above,
Below,
}
const HELD: usize = 4;
fn new_result(a: &Number, b: &Number, plan: &Plan) -> Vec<u8> {
let mut v = Vec::<u8>::with_capacity(plan.len);
let p = v.as_mut_ptr();
unsafe {
match (
a.byte_order == ByteOrder::BigEndian,
b.byte_order == ByteOrder::BigEndian,
) {
(true, true) => compute::<true, true>(
p.add(plan.len),
end::<true>(&a.value),
end::<true>(&b.value),
plan,
Place::New,
),
(true, false) => compute::<true, false>(
p.add(plan.len),
end::<true>(&a.value),
end::<false>(&b.value),
plan,
Place::New,
),
(false, true) => compute::<false, true>(
p,
end::<false>(&a.value),
end::<true>(&b.value),
plan,
Place::New,
),
(false, false) => compute::<false, false>(
p,
end::<false>(&a.value),
end::<false>(&b.value),
plan,
Place::New,
),
}
v.set_len(plan.len);
}
v
}
#[inline(always)]
unsafe fn in_vector(v: &mut Vec<u8>, order: ByteOrder, y: &Number, plan: &Plan) {
let (n, len) = (v.len(), plan.len);
let base = v.as_mut_ptr();
unsafe {
if order == ByteOrder::BigEndian {
let place = match len.cmp(&n) {
core::cmp::Ordering::Equal => Place::Same,
core::cmp::Ordering::Greater => Place::Above,
core::cmp::Ordering::Less => Place::Below,
};
let (dst, x) = (base.add(len), base.add(n).cast_const());
if y.byte_order == ByteOrder::BigEndian {
compute::<true, true>(dst, x, end::<true>(&y.value), plan, place);
} else {
compute::<true, false>(dst, x, end::<false>(&y.value), plan, place);
}
} else if y.byte_order == ByteOrder::BigEndian {
compute::<false, true>(base, base, end::<true>(&y.value), plan, Place::Same);
} else {
compute::<false, false>(base, base, end::<false>(&y.value), plan, Place::Same);
}
v.set_len(len);
}
}
#[inline(never)]
unsafe fn compute<const XBE: bool, const YBE: bool>(
dst: *mut u8,
x: *const u8,
y: *const u8,
plan: &Plan,
place: Place,
) {
let mixed = XBE != YBE;
let len = plan.len;
let short = plan.lx.min(plan.ly);
let lo = 8 * plan.head;
let held = plan.head.min(len.div_ceil(8));
let bulk = short.min(len);
let rest = short.max(lo);
unsafe {
match place {
Place::Below if held > HELD => {
let m = plan.lx.min(len);
ptr::copy(x.sub(m), dst.sub(m), m);
let moved = Plan { lx: m, ..*plan };
compute::<XBE, YBE>(dst, dst, y, &moved, Place::Same);
}
Place::Below => {
let mut limbs = [0u64; HELD];
let mut flags = Flags {
x: plan.nx,
y: plan.ny,
carry: plan.negative,
};
for (i, w) in limbs.iter_mut().enumerate().take(held) {
*w = flags.next(
plan.g,
limb::<XBE>(x, plan.lx, i),
limb::<YBE>(y, plan.ly, i),
);
}
tail::<XBE, YBE>(dst, x, y, plan, rest, place);
if bulk > lo {
let n = bulk - lo;
logic::<false>(
plan.g,
mixed,
at_mut::<XBE>(dst, lo, n),
at::<XBE>(x, lo, n),
at::<YBE>(y, lo, n),
n,
);
}
for (i, &w) in limbs.iter().enumerate().take(held) {
put_limb::<XBE>(dst, len, i, w);
}
}
_ => {
let mut flags = Flags {
x: plan.nx,
y: plan.ny,
carry: plan.negative,
};
for i in 0..held {
let w = flags.next(
plan.g,
limb::<XBE>(x, plan.lx, i),
limb::<YBE>(y, plan.ly, i),
);
put_limb::<XBE>(dst, len, i, w);
}
if bulk > lo {
let n = bulk - lo;
let (d, xs, ys) = (
at_mut::<XBE>(dst, lo, n),
at::<XBE>(x, lo, n),
at::<YBE>(y, lo, n),
);
if place == Place::Above {
logic::<true>(plan.g, mixed, d, xs, ys, n);
} else {
logic::<false>(plan.g, mixed, d, xs, ys, n);
}
}
tail::<XBE, YBE>(dst, x, y, plan, rest, place);
}
}
}
}
#[inline(always)]
unsafe fn tail<const XBE: bool, const YBE: bool>(
dst: *mut u8,
x: *const u8,
y: *const u8,
plan: &Plan,
rest: usize,
place: Place,
) {
let len = plan.len;
if len <= rest {
return;
}
let n = len - rest;
unsafe {
match plan.tail {
Tail::X if place != Place::Same => {
ptr::copy(at::<XBE>(x, rest, n), at_mut::<XBE>(dst, rest, n), n);
}
Tail::Y if XBE != YBE => {
kernels::copy_reversed(at_mut::<XBE>(dst, rest, n), at::<YBE>(y, rest, n), n);
}
Tail::Y => {
ptr::copy_nonoverlapping(at::<YBE>(y, rest, n), at_mut::<XBE>(dst, rest, n), n);
}
Tail::Zero => {
ptr::write_bytes(at_mut::<XBE>(dst, rest, n), 0, n);
}
Tail::X => {}
}
}
}
type Kernel = unsafe fn(*mut u8, *const u8, *const u8, usize);
const KERNELS: [[[Kernel; 5]; 2]; 2] = [
[
[
kernels::logic::<AND, false, false>,
kernels::logic::<OR, false, false>,
kernels::logic::<XOR, false, false>,
kernels::logic::<AND_NOT, false, false>,
kernels::logic::<NOT_AND, false, false>,
],
[
kernels::logic::<AND, true, false>,
kernels::logic::<OR, true, false>,
kernels::logic::<XOR, true, false>,
kernels::logic::<AND_NOT, true, false>,
kernels::logic::<NOT_AND, true, false>,
],
],
[
[
kernels::logic::<AND, false, true>,
kernels::logic::<OR, false, true>,
kernels::logic::<XOR, false, true>,
kernels::logic::<AND_NOT, false, true>,
kernels::logic::<NOT_AND, false, true>,
],
[
kernels::logic::<AND, true, true>,
kernels::logic::<OR, true, true>,
kernels::logic::<XOR, true, true>,
kernels::logic::<AND_NOT, true, true>,
kernels::logic::<NOT_AND, true, true>,
],
],
];
#[inline(always)]
unsafe fn logic<const DOWN: bool>(
g: u8,
mixed: bool,
dst: *mut u8,
x: *const u8,
y: *const u8,
n: usize,
) {
unsafe { KERNELS[usize::from(DOWN)][usize::from(mixed)][usize::from(g)](dst, x, y, n) }
}
#[inline(never)]
fn not_new(a: &Number) -> Number {
let order = a.byte_order;
if a.value.len() <= SMALL {
let s = unsafe { small_not(a) };
return small_number(order, s);
}
let (value, negative) = if order == ByteOrder::BigEndian {
not_copy::<true>(a)
} else {
not_copy::<false>(a)
};
Number {
value,
negative,
byte_order: order,
}
}
#[inline(always)]
unsafe fn small_not(a: &Number) -> Small {
let x = unsafe { read_small(&a.value, a.byte_order) };
if a.negative && x != 0 {
small_of(x - 1, false, false)
} else {
let (m, carry) = x.overflowing_add(1);
small_of(m, carry, true)
}
}
fn not_copy<const BE: bool>(a: &Number) -> (Vec<u8>, bool) {
let l = sig_len::<BE>(&a.value);
let src = end::<BE>(&a.value);
let negative = !(a.negative && l > 0);
if l > 8 {
let w = unsafe { load::<BE>(src, 0) };
let (low, out) = if negative {
w.overflowing_add(1)
} else {
w.overflowing_sub(1)
};
if !out {
let mut v = Vec::<u8>::with_capacity(l);
unsafe {
let base = v.as_mut_ptr();
ptr::copy_nonoverlapping(at::<BE>(src, 0, l), base, l);
store::<BE>(if BE { base.add(l) } else { base }, 0, low);
v.set_len(l);
}
return (v, negative);
}
}
let (r, len) = unsafe { run::<BE>(src, l, negative) };
let mut v = Vec::<u8>::with_capacity(len);
let base = v.as_mut_ptr();
let dst = if BE {
unsafe { base.add(len) }
} else {
base
};
unsafe {
step::<BE>(dst, src, l, r, len, negative, false);
v.set_len(len);
}
(v, negative)
}
#[inline(never)]
fn not_in_place(a: &mut Number) {
if a.value.len() <= SMALL {
let s = unsafe { small_not(a) };
put_small(&mut a.value, a.byte_order, s);
a.negative = s.negative;
return;
}
if a.byte_order == ByteOrder::BigEndian {
not_in::<true>(a);
} else {
not_in::<false>(a);
}
}
fn not_in<const BE: bool>(a: &mut Number) {
let n = a.value.len();
let l = sig_len::<BE>(&a.value);
let negative = !(a.negative && l > 0);
if l > 8 && (!BE || l == n) {
let base = a.value.as_mut_ptr();
let e = if BE {
unsafe { base.add(n) }
} else {
base
};
let w = unsafe { load::<BE>(e, 0) };
let (low, out) = if negative {
w.overflowing_add(1)
} else {
w.overflowing_sub(1)
};
if !out {
unsafe {
store::<BE>(e, 0, low);
a.value.set_len(l);
}
a.negative = negative;
return;
}
}
let (r, len) = unsafe { run::<BE>(end::<BE>(&a.value), l, negative) };
if a.value.capacity() < len {
let (value, negative) = not_copy::<BE>(a);
a.value = value;
a.negative = negative;
return;
}
a.negative = negative;
let base = a.value.as_mut_ptr();
unsafe {
if BE {
if len == l && n > l {
ptr::copy(base.add(n - l), base, l);
}
let in_place = len == l;
step::<true>(
base.add(len),
base.add(l).cast_const(),
l,
r,
len,
negative,
in_place,
);
} else {
step::<false>(base, base.cast_const(), l, r, len, negative, true);
}
a.value.set_len(len);
}
}
#[inline(always)]
unsafe fn run<const BE: bool>(src: *const u8, l: usize, plus: bool) -> (usize, usize) {
let pass = if plus { u64::MAX } else { 0 };
let mut r = 0;
unsafe {
while r + 8 <= l && load::<BE>(src, r) == pass {
r += 8;
}
while r < l && get::<BE>(src, r) == pass as u8 {
r += 1;
}
let len = if plus {
if r == l { l + 1 } else { l }
} else if r + 1 == l && get::<BE>(src, r) == 1 {
(l - 1).max(1)
} else {
l
};
(r, len)
}
}
#[inline(always)]
unsafe fn step<const BE: bool>(
dst: *mut u8,
src: *const u8,
l: usize,
r: usize,
len: usize,
plus: bool,
in_place: bool,
) {
let fill = if plus { 0 } else { 0xFF };
unsafe {
if len != l {
ptr::write_bytes(at_mut::<BE>(dst, 0, len), fill, len);
if plus {
set::<BE>(dst, len - 1, 1);
}
return;
}
ptr::write_bytes(at_mut::<BE>(dst, 0, r), fill, r);
let byte = get::<BE>(src, r);
set::<BE>(dst, r, if plus { byte + 1 } else { byte - 1 });
if !in_place && l > r + 1 {
let n = l - r - 1;
ptr::copy_nonoverlapping(at::<BE>(src, r + 1, n), at_mut::<BE>(dst, r + 1, n), n);
}
}
}
impl Number {
pub fn bits(&self) -> u64 {
let (l, top) = if self.byte_order == ByteOrder::BigEndian {
top_byte::<true>(&self.value)
} else {
top_byte::<false>(&self.value)
};
if l == 0 {
0
} else {
8 * (l as u64 - 1) + u64::from(8 - top.leading_zeros())
}
}
pub fn count_ones(&self) -> u64 {
let v = &self.value;
if v.len() <= SMALL {
return u64::from(unsafe { read_small(v, ByteOrder::LittleEndian) }.count_ones());
}
unsafe { kernels::count_ones(v.as_ptr(), v.len()) }
}
pub fn trailing_zeros(&self) -> Option<u64> {
unsafe {
if self.byte_order == ByteOrder::BigEndian {
lowest::<true>(&self.value)
} else {
lowest::<false>(&self.value)
}
}
}
pub fn bit(&self, i: u64) -> bool {
if self.byte_order == ByteOrder::BigEndian {
bit_of::<true>(self, i)
} else {
bit_of::<false>(self, i)
}
}
#[track_caller]
pub fn set_bit(&mut self, i: u64, value: bool) {
if self.byte_order == ByteOrder::BigEndian {
set_bit_in::<true>(self, i, value);
} else {
set_bit_in::<false>(self, i, value);
}
}
}
#[inline(always)]
fn top_byte<const BE: bool>(v: &[u8]) -> (usize, u8) {
let l = significant_len::<BE>(v);
if l == 0 {
return (0, 0);
}
(l, unsafe { get::<BE>(end::<BE>(v), l - 1) })
}
#[inline(always)]
unsafe fn lowest<const BE: bool>(v: &[u8]) -> Option<u64> {
let (e, n) = (end::<BE>(v), v.len());
let mut p = 0;
unsafe {
while p + 8 <= n {
let w = load::<BE>(e, p);
if w != 0 {
return Some(8 * p as u64 + u64::from(w.trailing_zeros()));
}
p += 8;
}
while p < n {
let b = get::<BE>(e, p);
if b != 0 {
return Some(8 * p as u64 + u64::from(b.trailing_zeros()));
}
p += 1;
}
}
None
}
#[inline(always)]
unsafe fn any_below<const BE: bool>(e: *const u8, q: usize) -> bool {
let mut p = q;
unsafe {
while p >= 8 {
if load::<BE>(e, p - 8) != 0 {
return true;
}
p -= 8;
}
while p > 0 {
if get::<BE>(e, p - 1) != 0 {
return true;
}
p -= 1;
}
}
false
}
#[inline(always)]
unsafe fn bit_and_below<const BE: bool>(e: *const u8, q: usize, k: u32) -> (bool, bool) {
unsafe {
let (word, s) = if q >= 7 {
(load::<BE>(e, q - 7), 56 + k)
} else {
(limb::<BE>(e, q + 1, 0), 8 * q as u32 + k)
};
let own = (word >> s) & 1 == 1;
let below = word & ((1 << s) - 1) != 0 || (q > 7 && any_below::<BE>(e, q - 7));
(own, below)
}
}
#[inline(always)]
fn bit_of<const BE: bool>(a: &Number, i: u64) -> bool {
let (e, n) = (end::<BE>(&a.value), a.value.len());
let (q, k) = (i / 8, (i % 8) as u32);
if q >= n as u64 {
return a.negative && significant_len::<BE>(&a.value) > 0;
}
let q = q as usize;
unsafe {
if !a.negative {
return (get::<BE>(e, q) >> k) & 1 == 1;
}
let (own, below) = bit_and_below::<BE>(e, q, k);
own ^ below
}
}
#[track_caller]
fn set_bit_in<const BE: bool>(a: &mut Number, i: u64, value: bool) {
let l = sig_len::<BE>(&a.value);
if l != a.value.len() || l == 0 {
trim::<BE>(&mut a.value, l);
if l == 0 {
a.negative = false;
}
}
if !a.negative {
if value {
set_magnitude_bit::<BE>(&mut a.value, i);
} else {
clear_magnitude_bit::<BE>(&mut a.value, i);
}
return;
}
let (e, n) = (end::<BE>(&a.value), a.value.len());
let (q, k) = (i / 8, (i % 8) as u32);
let (below, own) = if q >= n as u64 {
(true, false)
} else {
let (own, below) = unsafe { bit_and_below::<BE>(e, q as usize, k) };
(below, own)
};
match (below, own, value) {
(true, _, true) => clear_magnitude_bit::<BE>(&mut a.value, i),
(true, _, false) => set_magnitude_bit::<BE>(&mut a.value, i),
(false, true, false) => add_power::<BE>(&mut a.value, i),
(false, false, true) => subtract_power::<BE>(&mut a.value, i),
_ => {}
}
}
fn trim<const BE: bool>(v: &mut Vec<u8>, l: usize) {
let keep = l.max(1);
if v.len() > keep {
if BE {
v.drain(..v.len() - keep);
} else {
v.truncate(keep);
}
} else if v.is_empty() {
v.push(0);
}
}
#[track_caller]
fn grow<const BE: bool>(v: &mut Vec<u8>, len: usize) {
let (n, more) = (v.len(), len - v.len());
if v.try_reserve(more).is_err() {
too_long(len);
}
unsafe {
let p = v.as_mut_ptr();
if BE {
ptr::copy(p, p.add(more), n);
ptr::write_bytes(p, 0, more);
} else {
ptr::write_bytes(p.add(n), 0, more);
}
v.set_len(len);
}
}
#[cold]
#[inline(never)]
#[track_caller]
fn too_long(len: usize) -> ! {
panic!("a number of {len} bytes cannot be allocated")
}
#[cold]
#[inline(never)]
#[track_caller]
fn too_far(i: u64) -> ! {
panic!("a number with bit {i} set cannot be allocated")
}
#[track_caller]
fn set_magnitude_bit<const BE: bool>(v: &mut Vec<u8>, i: u64) {
let n = v.len();
let q = i / 8;
if q >= n as u64 {
let Some(len) = usize::try_from(q).ok().and_then(|q| q.checked_add(1)) else {
too_far(i)
};
grow::<BE>(v, len);
}
let n = v.len();
unsafe {
let e = v.as_mut_ptr().add(if BE { n } else { 0 });
let q = q as usize;
set::<BE>(e, q, get::<BE>(e, q) | (1 << (i % 8)));
}
}
fn clear_magnitude_bit<const BE: bool>(v: &mut Vec<u8>, i: u64) {
let n = v.len();
let q = i / 8;
if q >= n as u64 {
return;
}
let q = q as usize;
let byte = unsafe {
let e = v.as_mut_ptr().add(if BE { n } else { 0 });
let byte = get::<BE>(e, q) & !(1 << (i % 8));
set::<BE>(e, q, byte);
byte
};
if byte == 0 && q + 1 == n {
let l = significant_len::<BE>(v);
trim::<BE>(v, l);
}
}
#[track_caller]
fn add_power<const BE: bool>(v: &mut Vec<u8>, t: u64) {
let n = v.len();
let mut q = (t / 8) as usize;
unsafe {
let e = v.as_mut_ptr().add(if BE { n } else { 0 });
let (byte, carry) = get::<BE>(e, q).overflowing_add(1 << (t % 8));
set::<BE>(e, q, byte);
if !carry {
return;
}
q += 1;
while q < n && get::<BE>(e, q) == 0xFF {
set::<BE>(e, q, 0);
q += 1;
}
if q < n {
set::<BE>(e, q, get::<BE>(e, q) + 1);
return;
}
}
grow::<BE>(v, n + 1);
unsafe {
let e = v.as_mut_ptr().add(if BE { n + 1 } else { 0 });
set::<BE>(e, n, 1);
}
}
fn subtract_power<const BE: bool>(v: &mut Vec<u8>, i: u64) {
let n = v.len();
let mut q = (i / 8) as usize;
unsafe {
let e = v.as_mut_ptr().add(if BE { n } else { 0 });
let (byte, borrow) = get::<BE>(e, q).overflowing_sub(1 << (i % 8));
set::<BE>(e, q, byte);
if borrow {
q += 1;
while get::<BE>(e, q) == 0 {
set::<BE>(e, q, 0xFF);
q += 1;
}
set::<BE>(e, q, get::<BE>(e, q) - 1);
}
}
if q + 1 == n {
let l = significant_len::<BE>(v);
trim::<BE>(v, l);
}
}
#[inline(always)]
fn end<const BE: bool>(v: &[u8]) -> *const u8 {
if BE { v.as_ptr_range().end } else { v.as_ptr() }
}
#[inline(always)]
unsafe fn at<const BE: bool>(end: *const u8, p: usize, n: usize) -> *const u8 {
unsafe { if BE { end.sub(p + n) } else { end.add(p) } }
}
#[inline(always)]
unsafe fn at_mut<const BE: bool>(end: *mut u8, p: usize, n: usize) -> *mut u8 {
unsafe { if BE { end.sub(p + n) } else { end.add(p) } }
}
#[inline(always)]
unsafe fn get<const BE: bool>(end: *const u8, p: usize) -> u8 {
unsafe { *at::<BE>(end, p, 1) }
}
#[inline(always)]
unsafe fn set<const BE: bool>(end: *mut u8, p: usize, v: u8) {
unsafe { *at_mut::<BE>(end, p, 1) = v };
}
#[inline(always)]
unsafe fn load<const BE: bool>(end: *const u8, p: usize) -> u64 {
unsafe {
let bytes = read(at::<BE>(end, p, 8));
if BE {
u64::from_be_bytes(bytes)
} else {
u64::from_le_bytes(bytes)
}
}
}
#[inline(always)]
unsafe fn store<const BE: bool>(end: *mut u8, p: usize, v: u64) {
unsafe {
let bytes = if BE { v.to_be_bytes() } else { v.to_le_bytes() };
write(at_mut::<BE>(end, p, 8), bytes);
}
}
#[inline(always)]
unsafe fn limb<const BE: bool>(end: *const u8, l: usize, i: usize) -> u64 {
let p = 8 * i;
unsafe {
if p + 8 <= l {
load::<BE>(end, p)
} else if p >= l {
0
} else if l >= 8 {
load::<BE>(end, l - 8) >> (8 * (p + 8 - l))
} else {
let order = if BE {
ByteOrder::BigEndian
} else {
ByteOrder::LittleEndian
};
read_small(&*ptr::slice_from_raw_parts(at::<BE>(end, 0, l), l), order) as u64
}
}
}
#[inline(always)]
unsafe fn put_limb<const BE: bool>(end: *mut u8, len: usize, i: usize, v: u64) {
let p = 8 * i;
unsafe {
if p + 8 <= len {
store::<BE>(end, p, v);
} else {
let n = len - p;
let order = if BE {
ByteOrder::BigEndian
} else {
ByteOrder::LittleEndian
};
write_small(at_mut::<BE>(end, p, n), order, v, 0, n);
}
}
}