use std::alloc;
use std::intrinsics::abort;
use std::io::{self, Write};
use std::mem;
use std::ptr;
use ll::limb::Limb;
use ll::limb_ptr::LimbsMut;
unsafe fn get_usize_align_layout(size: usize) -> alloc::Layout {
let alignment = mem::align_of::<usize>();
match alloc::Layout::from_size_align(size, alignment) {
Ok(l) => l,
Err(layout_err) => {
let _ = writeln!(
io::stderr(),
"Failed to construct mem layout (size={}, alignment={}): {}",
size,
alignment,
layout_err
);
abort();
}
}
}
pub unsafe fn allocate_bytes(size: usize) -> *mut u8 {
let layout = get_usize_align_layout(size);
let ret = alloc::alloc_zeroed(layout.clone());
if ret.is_null() {
writeln!(
io::stderr(),
"Failed to allocate memory (layout={:?})",
layout,
)
.unwrap();
abort();
};
ptr::write_bytes(ret, 0, size);
ret
}
pub unsafe fn deallocate_bytes(ptr: ptr::NonNull<u8>, size: usize) {
let layout = get_usize_align_layout(size);
alloc::dealloc(ptr.as_ptr(), layout);
}
pub struct TmpAllocator {
mark: *mut Marker,
}
struct Marker {
next: *mut Marker,
size: usize,
}
impl TmpAllocator {
pub fn new() -> TmpAllocator {
TmpAllocator {
mark: ptr::null_mut(),
}
}
pub unsafe fn allocate_bytes(&mut self, size: usize) -> *mut u8 {
let size = size + mem::size_of::<Marker>();
let ptr = allocate_bytes(size);
let mark = ptr as *mut Marker;
(*mark).size = size;
(*mark).next = self.mark;
self.mark = mark;
ptr.offset(mem::size_of::<Marker>() as isize)
}
pub unsafe fn allocate(&mut self, n: usize) -> LimbsMut {
let ptr = self.allocate_bytes(n * mem::size_of::<Limb>()) as *mut Limb;
LimbsMut::new(ptr, 0, n as i32)
}
pub unsafe fn allocate_2(&mut self, n1: usize, n2: usize) -> (LimbsMut, LimbsMut) {
let mut x = self.allocate(n1 + n2);
let mut y = x.offset(n1 as isize);
(
LimbsMut::new(&mut *x, 0, n1 as i32),
LimbsMut::new(&mut *y, 0, n2 as i32),
)
}
}
impl Drop for TmpAllocator {
fn drop(&mut self) {
unsafe {
let mut next;
let mut mark = self.mark;
while let Some(checked_mark) = ptr::NonNull::new(mark) {
next = checked_mark.as_ref().next;
let size = checked_mark.as_ref().size;
deallocate_bytes(checked_mark.cast(), size);
mark = next;
}
}
}
}