use core::cmp;
use core::fmt;
use core::mem;
use core::usize;
use core::ptr::{self, NonNull};
use ::NonNullCast;
pub enum Opaque {}
impl Opaque {
pub fn null() -> *const Self {
0 as _
}
pub fn null_mut() -> *mut Self {
0 as _
}
}
#[derive(Debug)]
pub struct Excess(pub NonNull<Opaque>, pub usize);
fn size_align<T>() -> (usize, usize) {
(mem::size_of::<T>(), mem::align_of::<T>())
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Layout {
size: usize,
align: usize,
}
impl Layout {
#[inline]
pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
if !align.is_power_of_two() {
return Err(LayoutErr { private: () });
}
if size > usize::MAX - (align - 1) {
return Err(LayoutErr { private: () });
}
unsafe {
Ok(Layout::from_size_align_unchecked(size, align))
}
}
#[inline]
pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
Layout { size: size, align: align }
}
#[inline]
pub fn size(&self) -> usize { self.size }
#[inline]
pub fn align(&self) -> usize { self.align }
pub fn new<T>() -> Self {
let (size, align) = size_align::<T>();
debug_assert!(Layout::from_size_align(size, align).is_ok());
unsafe {
Layout::from_size_align_unchecked(size, align)
}
}
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
debug_assert!(Layout::from_size_align(size, align).is_ok());
unsafe {
Layout::from_size_align_unchecked(size, align)
}
}
#[inline]
pub fn align_to(&self, align: usize) -> Self {
Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap()
}
#[inline]
pub fn padding_needed_for(&self, align: usize) -> usize {
let len = self.size();
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
return len_rounded_up.wrapping_sub(len);
}
#[inline]
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
let padded_size = self.size.checked_add(self.padding_needed_for(self.align))
.ok_or(LayoutErr { private: () })?;
let alloc_size = padded_size.checked_mul(n)
.ok_or(LayoutErr { private: () })?;
Ok((Layout::from_size_align(alloc_size, self.align)?, padded_size))
}
pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
let new_align = cmp::max(self.align, next.align);
let realigned = Layout::from_size_align(self.size, new_align)?;
let pad = realigned.padding_needed_for(next.align);
let offset = self.size.checked_add(pad)
.ok_or(LayoutErr { private: () })?;
let new_size = offset.checked_add(next.size)
.ok_or(LayoutErr { private: () })?;
let layout = Layout::from_size_align(new_size, new_align)?;
Ok((layout, offset))
}
pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
Layout::from_size_align(size, self.align)
}
pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
let new_size = self.size().checked_add(next.size())
.ok_or(LayoutErr { private: () })?;
let layout = Layout::from_size_align(new_size, self.align)?;
Ok((layout, self.size()))
}
pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
Layout::new::<T>()
.repeat(n)
.map(|(k, offs)| {
debug_assert!(offs == mem::size_of::<T>());
k
})
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutErr {
private: ()
}
impl fmt::Display for LayoutErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("invalid parameters to Layout::from_size_align")
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;
impl fmt::Display for AllocErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("memory allocation failed")
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CannotReallocInPlace;
impl CannotReallocInPlace {
pub fn description(&self) -> &str {
"cannot reallocate allocator's memory in place"
}
}
impl fmt::Display for CannotReallocInPlace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum CollectionAllocErr {
CapacityOverflow,
AllocErr,
}
impl From<AllocErr> for CollectionAllocErr {
#[inline]
fn from(AllocErr: AllocErr) -> Self {
CollectionAllocErr::AllocErr
}
}
pub unsafe trait GlobalAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque;
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout);
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
let size = layout.size();
let ptr = self.alloc(layout);
if !ptr.is_null() {
ptr::write_bytes(ptr as *mut u8, 0, size);
}
ptr
}
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
let new_ptr = self.alloc(new_layout);
if !new_ptr.is_null() {
ptr::copy_nonoverlapping(
ptr as *const u8,
new_ptr as *mut u8,
cmp::min(layout.size(), new_size),
);
self.dealloc(ptr, layout);
}
new_ptr
}
fn oom(&self) -> ! {
loop {}
}
}
pub unsafe trait Alloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr>;
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout);
fn oom(&mut self) -> ! {
loop {}
}
#[inline]
fn usable_size(&self, layout: &Layout) -> (usize, usize) {
(layout.size(), layout.size())
}
unsafe fn realloc(&mut self,
ptr: NonNull<Opaque>,
layout: Layout,
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
let old_size = layout.size();
if new_size >= old_size {
if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_size) {
return Ok(ptr);
}
} else if new_size < old_size {
if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_size) {
return Ok(ptr);
}
}
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
let result = self.alloc(new_layout);
if let Ok(new_ptr) = result {
ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8,
new_ptr.as_ptr() as *mut u8,
cmp::min(old_size, new_size));
self.dealloc(ptr, layout);
}
result
}
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
let size = layout.size();
let p = self.alloc(layout);
if let Ok(p) = p {
ptr::write_bytes(p.as_ptr() as *mut u8, 0, size);
}
p
}
unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
let usable_size = self.usable_size(&layout);
self.alloc(layout).map(|p| Excess(p, usable_size.1))
}
unsafe fn realloc_excess(&mut self,
ptr: NonNull<Opaque>,
layout: Layout,
new_size: usize) -> Result<Excess, AllocErr> {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
let usable_size = self.usable_size(&new_layout);
self.realloc(ptr, layout, new_size)
.map(|p| Excess(p, usable_size.1))
}
unsafe fn grow_in_place(&mut self,
ptr: NonNull<Opaque>,
layout: Layout,
new_size: usize) -> Result<(), CannotReallocInPlace> {
let _ = ptr; debug_assert!(new_size >= layout.size);
let (_l, u) = self.usable_size(&layout);
if new_size <= u {
return Ok(());
} else {
return Err(CannotReallocInPlace);
}
}
unsafe fn shrink_in_place(&mut self,
ptr: NonNull<Opaque>,
layout: Layout,
new_size: usize) -> Result<(), CannotReallocInPlace> {
let _ = ptr; debug_assert!(new_size <= layout.size);
let (l, _u) = self.usable_size(&layout);
if l <= new_size {
return Ok(());
} else {
return Err(CannotReallocInPlace);
}
}
fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
where Self: Sized
{
let k = Layout::new::<T>();
if k.size() > 0 {
unsafe { self.alloc(k).map(|p| p.cast_()) }
} else {
Err(AllocErr)
}
}
unsafe fn dealloc_one<T>(&mut self, ptr: NonNull<T>)
where Self: Sized
{
let k = Layout::new::<T>();
if k.size() > 0 {
self.dealloc(ptr.as_opaque_(), k);
}
}
fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
where Self: Sized
{
match Layout::array::<T>(n) {
Ok(ref layout) if layout.size() > 0 => {
unsafe {
self.alloc(layout.clone()).map(|p| p.cast_())
}
}
_ => Err(AllocErr),
}
}
unsafe fn realloc_array<T>(&mut self,
ptr: NonNull<T>,
n_old: usize,
n_new: usize) -> Result<NonNull<T>, AllocErr>
where Self: Sized
{
match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) {
(Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
debug_assert!(k_old.align() == k_new.align());
self.realloc(ptr.as_opaque_(), k_old.clone(), k_new.size()).map(NonNull::cast_)
}
_ => {
Err(AllocErr)
}
}
}
unsafe fn dealloc_array<T>(&mut self, ptr: NonNull<T>, n: usize) -> Result<(), AllocErr>
where Self: Sized
{
match Layout::array::<T>(n) {
Ok(ref k) if k.size() > 0 => {
Ok(self.dealloc(ptr.as_opaque_(), k.clone()))
}
_ => {
Err(AllocErr)
}
}
}
}