use std::{alloc::Layout, hint::unreachable_unchecked, ptr::NonNull};
pub use super::bumpalo_alloc::AllocErr;
pub trait Pointer {
fn addr(self) -> usize;
}
impl<T: ?Sized> Pointer for *const T {
#[inline]
fn addr(self) -> usize {
self.addr()
}
}
impl<T: ?Sized> Pointer for *mut T {
#[inline]
fn addr(self) -> usize {
self.addr()
}
}
impl<T: ?Sized> Pointer for NonNull<T> {
#[inline]
fn addr(self) -> usize {
self.addr().get()
}
}
#[inline(always)]
pub fn is_pointer_aligned_to<P: Pointer>(ptr: P, align: usize) -> bool {
debug_assert!(align.is_power_of_two());
(ptr.addr() & (align - 1)) == 0
}
#[inline]
pub const fn round_up_to(n: usize, divisor: usize) -> Option<usize> {
debug_assert!(divisor.is_power_of_two());
match n.checked_add(divisor - 1) {
Some(x) => Some(x & !(divisor - 1)),
None => None,
}
}
#[inline]
pub unsafe fn round_up_to_unchecked(n: usize, divisor: usize) -> usize {
if let Some(x) = round_up_to(n, divisor) {
x
} else {
debug_assert!(false, "round_up_to_unchecked failed");
unsafe { unreachable_unchecked() }
}
}
#[inline]
pub fn round_down_to(n: usize, divisor: usize) -> usize {
debug_assert!(divisor.is_power_of_two());
n & !(divisor - 1)
}
#[inline]
pub fn round_mut_ptr_down_to(ptr: *mut u8, divisor: usize) -> *mut u8 {
debug_assert!(divisor.is_power_of_two());
ptr.wrapping_sub(ptr.addr() & (divisor - 1))
}
#[inline]
pub unsafe fn round_nonnull_ptr_up_to_unchecked(ptr: NonNull<u8>, divisor: usize) -> NonNull<u8> {
debug_assert!(divisor.is_power_of_two());
unsafe {
let addr = ptr.addr().get();
let aligned = round_up_to_unchecked(addr, divisor);
let delta = aligned - addr;
ptr.add(delta)
}
}
#[inline]
pub fn layout_from_size_align(size: usize, align: usize) -> Result<Layout, AllocErr> {
Layout::from_size_align(size, align).map_err(|_| AllocErr)
}
#[inline(never)]
#[cold]
pub fn oom() -> ! {
panic!("out of memory")
}