#[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 = "shift/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 = "shift/portable.rs"]
mod kernels;
use super::add::{SMALL, read, read_small, significant_len, write, write_small};
use super::{ByteOrder, Number};
use core::hint::select_unpredictable;
use core::ops::{Shl, ShlAssign, Shr, ShrAssign};
use core::ptr;
use std::alloc::{Layout, alloc};
impl Shl<usize> for Number {
type Output = Number;
#[inline]
fn shl(mut self, rhs: usize) -> Number {
self <<= rhs;
self
}
}
impl Shl<usize> for &Number {
type Output = Number;
#[inline]
fn shl(self, rhs: usize) -> Number {
if short_shl(self, rhs) {
let s = unsafe { small_shl(self, rhs) };
return small_number(self.byte_order, s);
}
shl_ref(self, rhs)
}
}
impl ShlAssign<usize> for Number {
#[inline]
fn shl_assign(&mut self, rhs: usize) {
if short_shl(self, rhs) {
let s = unsafe { small_shl(self, rhs) };
self.negative = s.negative;
put_small(&mut self.value, self.byte_order, s);
return;
}
shl_assign_long(self, rhs);
}
}
impl Shr<usize> for Number {
type Output = Number;
#[inline]
fn shr(mut self, rhs: usize) -> Number {
self >>= rhs;
self
}
}
impl Shr<usize> for &Number {
type Output = Number;
#[inline]
fn shr(self, rhs: usize) -> Number {
if self.value.len() <= SMALL {
let s = unsafe { small_shr(self, rhs) };
return small_number(self.byte_order, s);
}
shr_ref(self, rhs)
}
}
impl ShrAssign<usize> for Number {
#[inline]
fn shr_assign(&mut self, rhs: usize) {
if self.value.len() <= SMALL {
let s = unsafe { small_shr(self, rhs) };
self.negative = s.negative;
put_small(&mut self.value, self.byte_order, s);
return;
}
shr_assign_long(self, rhs);
}
}
const SMALL_SHIFT: usize = 128;
#[inline(always)]
fn short_shl(a: &Number, k: usize) -> bool {
a.value.len() <= SMALL && k < SMALL_SHIFT
}
#[derive(Clone, Copy)]
struct Small {
lo: u128,
hi: u128,
len: usize,
negative: bool,
}
#[inline(always)]
unsafe fn small_shl(a: &Number, k: usize) -> Small {
let x = unsafe { read_small(&a.value, a.byte_order) };
let (x0, x1) = (x as u64, (x >> 64) as u64);
let up = |y: u64, s: usize| (y >> 1) >> (63 - s);
let (l0, l1, h0, h1) = if k < 64 {
(x0 << k, x1 << k | up(x0, k), up(x1, k), 0)
} else {
let k = k - 64;
(0, x0 << k, x1 << k | up(x0, k), up(x1, k))
};
let bits = 128 - x.leading_zeros() as usize;
Small {
lo: u128::from(l0) | u128::from(l1) << 64,
hi: u128::from(h0) | u128::from(h1) << 64,
len: if x == 0 { 1 } else { (bits + k).div_ceil(8) },
negative: a.negative && x != 0,
}
}
#[inline(always)]
unsafe fn small_shr(a: &Number, k: usize) -> Small {
let x = unsafe { read_small(&a.value, a.byte_order) };
let negative = a.negative && x != 0;
let (quotient, rest) = if k < 128 {
(x >> k, x & ((1 << k) - 1))
} else {
(0, x)
};
let magnitude = quotient + u128::from(negative && rest != 0);
Small {
lo: magnitude,
hi: 0,
len: SMALL - (magnitude | 1).leading_zeros() as usize / 8,
negative,
}
}
#[inline(always)]
unsafe fn write_small_result(dst: *mut u8, order: ByteOrder, s: Small) {
let len = s.len;
unsafe {
if len <= SMALL {
write_small(dst, order, s.lo as u64, (s.lo >> 64) as u64, len);
return;
}
let (h0, h1) = (s.hi as u64, (s.hi >> 64) as u64);
if order == ByteOrder::BigEndian {
write(dst.add(len - 16), s.lo.to_be_bytes());
write_small(dst, order, h0, h1, len - SMALL);
} else {
write(dst, s.lo.to_le_bytes());
write_small(dst.add(SMALL), order, h0, h1, len - SMALL);
}
}
}
#[inline(always)]
fn put_small(v: &mut Vec<u8>, order: ByteOrder, s: Small) {
if v.capacity() >= s.len {
unsafe {
write_small_result(v.as_mut_ptr(), order, s);
v.set_len(s.len);
}
} else {
replace_small(v, order, s.lo, s.hi, s.len);
}
}
#[cold]
#[inline(never)]
fn replace_small(v: &mut Vec<u8>, order: ByteOrder, lo: u128, hi: u128, len: usize) {
let s = Small {
lo,
hi,
len,
negative: false,
};
*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_result(v.as_mut_ptr(), order, s);
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(never)]
fn shl_ref(a: &Number, k: usize) -> Number {
let value = match a.byte_order {
ByteOrder::BigEndian => shl_new::<true>(&a.value, k),
ByteOrder::LittleEndian => shl_new::<false>(&a.value, k),
};
let zero = matches!(value.as_slice(), [0]);
Number {
value,
negative: a.negative && !zero,
byte_order: a.byte_order,
}
}
#[inline(never)]
fn shl_assign_long(a: &mut Number, k: usize) {
match a.byte_order {
ByteOrder::BigEndian => shl_in::<true>(a, k),
ByteOrder::LittleEndian => shl_in::<false>(a, k),
}
}
#[inline(never)]
fn shr_ref(a: &Number, k: usize) -> Number {
if k / 8 >= a.value.len() {
let negative = shifted_away(a);
return Number {
value: vec![u8::from(negative)],
negative,
byte_order: a.byte_order,
};
}
let (value, negative) = match a.byte_order {
ByteOrder::BigEndian => shr_new::<true>(&a.value, a.negative, k),
ByteOrder::LittleEndian => shr_new::<false>(&a.value, a.negative, k),
};
Number {
value,
negative,
byte_order: a.byte_order,
}
}
#[inline(never)]
fn shr_assign_long(a: &mut Number, k: usize) {
if k / 8 >= a.value.len() {
a.negative = shifted_away(a);
unsafe {
*a.value.as_mut_ptr() = u8::from(a.negative);
a.value.set_len(1);
}
return;
}
a.negative = match a.byte_order {
ByteOrder::BigEndian => shr_in::<true>(&mut a.value, a.negative, k),
ByteOrder::LittleEndian => shr_in::<false>(&mut a.value, a.negative, k),
};
}
#[inline(always)]
fn shifted_away(a: &Number) -> bool {
a.negative && a.value.iter().any(|&b| b != 0)
}
#[cold]
#[inline(never)]
fn set_zero(v: &mut Vec<u8>) {
if v.capacity() == 0 {
*v = vec![0];
} else {
v.clear();
v.push(0);
}
}
#[derive(Clone, Copy)]
struct Left {
l: usize,
q: usize,
r: u32,
len: usize,
}
impl Left {
#[inline(always)]
fn plan(l: usize, top: u8, k: usize) -> Left {
let (q, r) = (k / 8, (k % 8) as u32);
let extra = (u32::from(top) << r) >> 8 != 0;
Left {
l,
q,
r,
len: l + q + usize::from(extra),
}
}
}
#[inline(always)]
fn top_of<const BE: bool>(v: &[u8]) -> (usize, u8) {
let most = if BE { v.first() } else { v.last() };
match most {
Some(&top) if top != 0 => (v.len(), top),
_ => {
let l = significant_len::<BE>(v);
let top = if l == 0 {
0
} else {
unsafe { get::<BE>(end::<BE>(v), l - 1) }
};
(l, top)
}
}
}
#[inline(always)]
fn shl_new<const BE: bool>(v: &[u8], k: usize) -> Vec<u8> {
let (l, top) = top_of::<BE>(v);
if l == 0 {
return vec![0];
}
unsafe { shl_from::<BE>(end::<BE>(v), Left::plan(l, top, k)) }
}
#[inline(never)]
unsafe fn shl_from<const BE: bool>(src: *const u8, plan: Left) -> Vec<u8> {
let mut out = allocate(plan.len);
let dst = out.as_mut_ptr();
unsafe {
shl_into::<BE>(if BE { dst.add(plan.len) } else { dst }, src, plan);
out.set_len(plan.len);
}
out
}
#[inline(always)]
fn shl_in<const BE: bool>(a: &mut Number, k: usize) {
if a.value.len() <= MEDIUM && k < 64 {
return unsafe { medium_shl::<BE>(a, k) };
}
let v = &mut a.value;
let (l, top) = top_of::<BE>(v);
if l == 0 {
a.negative = false;
return set_zero(v);
}
let (len, capacity) = (v.len(), v.capacity());
let plan = Left::plan(l, top, k);
if capacity < plan.len {
return shl_grow::<BE>(v, plan.l, plan.q, plan.r, plan.len);
}
let p = v.as_mut_ptr();
unsafe {
let src: *const u8 = if BE { p.add(len) } else { p };
let dst = if BE { p.add(plan.len) } else { p };
v.set_len(plan.len);
if plan.r == 0 {
return shl_bytes::<BE>(dst, src, plan.l, plan.q);
}
shl_bits_into::<BE>(dst, src, plan);
}
}
const MEDIUM: usize = 32;
#[inline(always)]
unsafe fn medium_shl<const BE: bool>(a: &mut Number, k: usize) {
let v = &mut a.value;
let (p, n) = (v.as_ptr(), v.len());
let (lo, hi) = unsafe {
let above = core::slice::from_raw_parts(if BE { p } else { p.add(16) }, n - 16);
if BE {
(
u128::from_be_bytes(read(p.add(n - 16))),
read_small(above, ByteOrder::BigEndian),
)
} else {
(
u128::from_le_bytes(read(p)),
read_small(above, ByteOrder::LittleEndian),
)
}
};
let bits = if hi != 0 {
256 - hi.leading_zeros()
} else {
128 - lo.leading_zeros()
} as usize;
if bits == 0 {
a.negative = false;
return set_zero(v);
}
let len = (bits + k).div_ceil(8);
let (x0, x1, x2, x3) = (lo as u64, (lo >> 64) as u64, hi as u64, (hi >> 64) as u64);
let up = |y: u64| (y >> 1) >> (63 - k);
let y = [
x0 << k,
x1 << k | up(x0),
x2 << k | up(x1),
x3 << k | up(x2),
up(x3),
];
if v.capacity() < len {
return medium_grow::<BE>(v, y[0], y[1], y[2], y[3], y[4], len);
}
unsafe {
v.set_len(len);
write_medium::<BE>(v.as_mut_ptr(), y, len);
}
}
#[cold]
#[inline(never)]
fn medium_grow<const BE: bool>(
v: &mut Vec<u8>,
y0: u64,
y1: u64,
y2: u64,
y3: u64,
y4: u64,
len: usize,
) {
let y = [y0, y1, y2, y3, y4];
let mut out = allocate(len);
unsafe {
write_medium::<BE>(out.as_mut_ptr(), y, len);
out.set_len(len);
}
*v = out;
}
#[inline(always)]
unsafe fn write_medium<const BE: bool>(dst: *mut u8, y: [u64; 5], len: usize) {
let order = order::<BE>();
let pair = |l: u64, h: u64| u128::from(l) | u128::from(h) << 64;
unsafe {
if len <= SMALL {
return write_small(dst, order, y[0], y[1], len);
}
let low = pair(y[0], y[1]);
if BE {
write(dst.add(len - 16), low.to_be_bytes());
} else {
write(dst, low.to_le_bytes());
}
let rest = len - SMALL;
if rest <= SMALL {
let at = if BE { dst } else { dst.add(SMALL) };
return write_small(at, order, y[2], y[3], rest);
}
let middle = pair(y[2], y[3]);
if BE {
write(dst.add(len - 32), middle.to_be_bytes());
write_small(dst, order, y[4], 0, len - 32);
} else {
write(dst.add(SMALL), middle.to_le_bytes());
write_small(dst.add(32), order, y[4], 0, len - 32);
}
}
}
#[cold]
#[inline(never)]
fn shl_grow<const BE: bool>(v: &mut Vec<u8>, l: usize, q: usize, r: u32, len: usize) {
let src: *const u8 = end::<BE>(v);
*v = unsafe { shl_from::<BE>(src, Left { l, q, r, len }) };
}
#[inline(never)]
unsafe fn shl_bytes<const BE: bool>(dst: *mut u8, src: *const u8, l: usize, q: usize) {
unsafe {
shl_into::<BE>(
dst,
src,
Left {
l,
q,
r: 0,
len: l + q,
},
)
}
}
#[inline(always)]
unsafe fn shl_into<const BE: bool>(dst: *mut u8, src: *const u8, plan: Left) {
let Left { l, q, r, .. } = plan;
unsafe {
if r == 0 {
let (from, to) = (at::<BE>(src, 0, l), at_mut::<BE>(dst, q, l));
if !ptr::eq(from, to) {
move_bytes(to, from, l);
}
zero::<BE>(dst, q);
} else {
shl_bits_into::<BE>(dst, src, plan);
}
}
}
#[inline(always)]
unsafe fn shl_bits_into<const BE: bool>(dst: *mut u8, src: *const u8, plan: Left) {
let Left { l, q, r, len } = plan;
unsafe {
if l < SMALL {
let x = read_small(slice::<BE>(src, 0, l), order::<BE>()) << r;
let n = len - q;
write_small(
at_mut::<BE>(dst, q, n),
order::<BE>(),
x as u64,
(x >> 64) as u64,
n,
);
} else {
let (top, below) = (get::<BE>(src, l - 1), get::<BE>(src, l - 2));
let high = (top << r) | (below >> (8 - r));
let out = top >> (8 - r);
kernels::shl_bits::<BE>(dst, src, l, q, r);
let extra = out != 0;
set::<BE>(
dst,
q + l - 1 + usize::from(extra),
select_unpredictable(extra, out, high),
);
}
zero::<BE>(dst, q);
}
}
#[derive(Clone, Copy)]
struct Right {
l: usize,
q: usize,
r: u32,
len: usize,
round: bool,
}
impl Right {
#[inline(always)]
unsafe fn plan<const BE: bool>(
src: *const u8,
l: usize,
top: u8,
k: usize,
negative: bool,
) -> Right {
let (q, r) = (k / 8, (k % 8) as u32);
unsafe {
Right {
l,
q,
r,
len: l - q - usize::from(top >> r == 0),
round: negative && shifted_out::<BE>(src, l, q, r),
}
}
}
}
#[inline(always)]
fn short_right(l: usize, k: usize) -> bool {
l.saturating_sub(k / 8) <= SMALL
}
#[inline(always)]
unsafe fn short_quotient<const BE: bool>(
src: *const u8,
l: usize,
k: usize,
negative: bool,
) -> Small {
let (q, r) = (k / 8, (k % 8) as u32);
let negative = negative && l != 0;
let (x, round) = unsafe {
if q < l {
let x = read_small(slice::<BE>(src, q, l - q), order::<BE>());
(x, negative && shifted_out::<BE>(src, l, q, r))
} else {
(0, negative)
}
};
let (magnitude, carry) = (x >> r).overflowing_add(u128::from(round));
Small {
lo: magnitude,
hi: u128::from(carry),
len: if carry {
SMALL + 1
} else {
SMALL - (magnitude | 1).leading_zeros() as usize / 8
},
negative,
}
}
#[inline(always)]
fn shr_new<const BE: bool>(v: &[u8], negative: bool, k: usize) -> (Vec<u8>, bool) {
let (l, top) = top_of::<BE>(v);
let src = end::<BE>(v);
unsafe {
if short_right(l, k) {
let s = short_quotient::<BE>(src, l, k, negative);
return (new_small(order::<BE>(), s), s.negative);
}
let plan = Right::plan::<BE>(src, l, top, k, negative);
let carry = negative && all_ones::<BE>(src, plan) && plan.round;
let len = plan.len + usize::from(carry);
let mut out = Vec::<u8>::with_capacity(len);
let dst = out.as_mut_ptr();
let dst = if BE { dst.add(len) } else { dst };
if carry {
ptr::write_bytes(at_mut::<BE>(dst, 0, len), 0, len);
set::<BE>(dst, plan.len, 1);
} else {
shr_into::<BE>(dst, src, plan);
if negative {
round_up::<BE>(dst, plan.len, quotient_low::<BE>(src, plan), plan.round);
}
}
out.set_len(len);
(out, negative)
}
}
#[inline(always)]
fn shr_in<const BE: bool>(v: &mut Vec<u8>, negative: bool, k: usize) -> bool {
let (l, top) = top_of::<BE>(v);
let len = v.len();
let p = v.as_mut_ptr();
unsafe {
let src: *const u8 = if BE { p.add(len) } else { p };
if short_right(l, k) {
let s = short_quotient::<BE>(src, l, k, negative);
put_small(v, order::<BE>(), s);
return s.negative;
}
let plan = Right::plan::<BE>(src, l, top, k, negative);
let src = if BE && len != l {
ptr::copy(p.add(len - l), p, l);
p.add(l)
} else {
src
};
let dst = if BE { p.add(plan.len) } else { p };
let low = if negative {
quotient_low::<BE>(src, plan)
} else {
0
};
shr_into::<BE>(dst, src, plan);
let mut n = plan.len;
if negative && round_up::<BE>(dst, n, low, plan.round) {
n += 1;
if BE {
*p.add(n - 1) = 0;
*p = 1;
} else {
*p.add(n - 1) = 1;
}
}
v.set_len(n);
}
negative && l != 0
}
#[inline(always)]
unsafe fn shr_into<const BE: bool>(dst: *mut u8, src: *const u8, plan: Right) {
let Right { l, q, r, len, .. } = plan;
unsafe {
if r == 0 {
let (from, to) = (at::<BE>(src, q, len), at_mut::<BE>(dst, 0, len));
if !ptr::eq(from, to) {
move_bytes(to, from, len);
}
} else {
let top = get::<BE>(src, l - 1);
let above = top & 0u8.wrapping_sub(u8::from(q + len < l));
kernels::shr_bits::<BE>(dst, src, l, q, r, len, above);
}
}
}
#[inline(always)]
unsafe fn shifted_out<const BE: bool>(src: *const u8, l: usize, q: usize, r: u32) -> bool {
let mut p = 0;
unsafe {
while q - p >= 8 {
if load::<BE>(src, p) != 0 {
return true;
}
p += 8;
}
if l - p >= 8 {
let bits = 8 * (q - p) as u32 + r;
return load::<BE>(src, p) & ((1 << bits) - 1) != 0;
}
while p < q {
if get::<BE>(src, p) != 0 {
return true;
}
p += 1;
}
get::<BE>(src, q) & ((1 << r) - 1) != 0
}
}
unsafe fn all_ones<const BE: bool>(src: *const u8, plan: Right) -> bool {
let Right { l, q, r, len, .. } = plan;
let byte = |p: usize| unsafe {
let above = if q + p + 1 < l {
get::<BE>(src, q + p + 1)
} else {
0
};
((u16::from(get::<BE>(src, q + p)) | (u16::from(above) << 8)) >> r) as u8
};
let mut p = 0;
unsafe {
while p + 8 <= len && q + p + 8 < l {
let above = u64::from(get::<BE>(src, q + p + 8));
let v = (load::<BE>(src, q + p) >> r) | ((above << 1) << (63 - r));
if v != u64::MAX {
return false;
}
p += 8;
}
}
(p..len).all(|p| byte(p) == 0xFF)
}
#[inline(always)]
unsafe fn quotient_low<const BE: bool>(src: *const u8, plan: Right) -> u64 {
let Right { q, r, .. } = plan;
unsafe {
let above = u64::from(get::<BE>(src, q + 8));
(load::<BE>(src, q) >> r) | ((above << 1) << (63 - r))
}
}
#[inline(always)]
unsafe fn round_up<const BE: bool>(dst: *mut u8, n: usize, low: u64, round: bool) -> bool {
let (sum, carry) = low.overflowing_add(u64::from(round));
unsafe {
store::<BE>(dst, 0, sum);
carry && increment::<BE>(dst, 8, n)
}
}
#[cold]
#[inline(never)]
unsafe fn increment<const BE: bool>(dst: *mut u8, mut p: usize, n: usize) -> bool {
unsafe {
while n - p >= 8 {
let v = load::<BE>(dst, p).wrapping_add(1);
store::<BE>(dst, p, v);
if v != 0 {
return false;
}
p += 8;
}
while p < n {
let v = get::<BE>(dst, p).wrapping_add(1);
set::<BE>(dst, p, v);
if v != 0 {
return false;
}
p += 1;
}
}
true
}
fn allocate(len: usize) -> Vec<u8> {
let Ok(layout) = Layout::array::<u8>(len) else {
too_long(len)
};
let p = unsafe { alloc(layout) };
if p.is_null() {
too_long(len);
}
unsafe { Vec::from_raw_parts(p, 0, len) }
}
#[cold]
#[inline(never)]
fn too_long(len: usize) -> ! {
panic!("a shifted number of {len} bytes cannot be allocated")
}
#[inline(always)]
unsafe fn zero<const BE: bool>(dst: *mut u8, q: usize) {
unsafe { zero_bytes(at_mut::<BE>(dst, 0, q), q) };
}
#[inline(always)]
unsafe fn zero_bytes(dst: *mut u8, n: usize) {
unsafe {
if n == 0 {
} else if n > 64 {
ptr::write_bytes(dst, 0, n);
} else if n >= 16 {
write(dst, [0u8; 16]);
write(dst.add(n - 16), [0u8; 16]);
if n > 32 {
write(dst.add(16), [0u8; 16]);
write(dst.add(n - 32), [0u8; 16]);
}
} else if n >= 8 {
write(dst, [0u8; 8]);
write(dst.add(n - 8), [0u8; 8]);
} else if n >= 4 {
write(dst, [0u8; 4]);
write(dst.add(n - 4), [0u8; 4]);
} else {
*dst = 0;
*dst.add(n / 2) = 0;
*dst.add(n - 1) = 0;
}
}
}
#[inline(always)]
unsafe fn move_bytes(dst: *mut u8, src: *const u8, n: usize) {
unsafe {
if n > 64 {
ptr::copy(src, dst, n);
} else if n > 32 {
let a: [u8; 16] = read(src);
let b: [u8; 16] = read(src.add(16));
let c: [u8; 16] = read(src.add(n - 32));
let d: [u8; 16] = read(src.add(n - 16));
write(dst, a);
write(dst.add(16), b);
write(dst.add(n - 32), c);
write(dst.add(n - 16), d);
} else if n >= 16 {
let a: [u8; 16] = read(src);
let b: [u8; 16] = read(src.add(n - 16));
write(dst, a);
write(dst.add(n - 16), b);
} else if n >= 8 {
let a: [u8; 8] = read(src);
let b: [u8; 8] = read(src.add(n - 8));
write(dst, a);
write(dst.add(n - 8), b);
} else if n >= 4 {
let a: [u8; 4] = read(src);
let b: [u8; 4] = read(src.add(n - 4));
write(dst, a);
write(dst.add(n - 4), b);
} else if n > 0 {
let (a, b, c) = (*src, *src.add(n / 2), *src.add(n - 1));
*dst = a;
*dst.add(n / 2) = b;
*dst.add(n - 1) = c;
}
}
}
#[inline(always)]
fn order<const BE: bool>() -> ByteOrder {
if BE {
ByteOrder::BigEndian
} else {
ByteOrder::LittleEndian
}
}
#[inline(always)]
unsafe fn slice<'a, const BE: bool>(end: *const u8, p: usize, n: usize) -> &'a [u8] {
unsafe { &*ptr::slice_from_raw_parts(at::<BE>(end, p, n), n) }
}
#[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);
}
}