composable-allocators 0.1.6

Composable memory allocators for new allocator API.
Documentation
use crate::base::*;
use core::alloc::{self, AllocError, Allocator};
use core::mem::size_of;
use core::ptr::{self, NonNull, null_mut};
use libc::{c_int, free, malloc, posix_memalign, realloc};

#[derive(Debug, Copy, Clone)]
pub struct Posix;

impl const Default for Posix {
    fn default() -> Self { Posix }
}

fn zero(r: c_int) -> Result<(), AllocError> {
    if r == 0 {
        Ok(())
    } else {
        Err(AllocError)
    }
}

fn is_native_align(align: usize) -> bool {
    align <= 2 * size_of::<usize>()
}

unsafe impl NonUnwinding for Posix { }

unsafe impl Allocator for Posix {
    fn allocate(&self, layout: alloc::Layout) -> Result<NonNull<[u8]>, AllocError> {
        let ptr = if layout.size() == 0 {
            unsafe { NonNull::new_unchecked(ptr::invalid_mut(layout.align())) }
        } else if !is_native_align(layout.align()) {
            let mut ptr = null_mut();
            zero(unsafe { posix_memalign(&raw mut ptr, layout.align(), layout.size()) })?;
            unsafe { NonNull::new_unchecked(ptr as *mut u8) }
        } else {
            let ptr = NonNull::new(unsafe { malloc(layout.size()) } as *mut u8).ok_or(AllocError)?;
            if ptr.as_ptr() as usize % layout.align() != 0 { return Err(AllocError); }
            ptr
        };
        Ok(NonNull::slice_from_raw_parts(ptr, layout.size()))
    }

    fn allocate_zeroed(&self, layout: alloc::Layout) -> Result<NonNull<[u8]>, AllocError> {
        let ptr = self.allocate(layout)?;
        unsafe { ptr.as_mut_ptr().write_bytes(0, ptr.len()); }
        Ok(ptr)
    }

    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: alloc::Layout) {
        if layout.size() != 0 {
            free(ptr.as_ptr() as _);
        }
    }

    unsafe fn grow(
        &self,
        ptr: NonNull<u8>,
        old_layout: alloc::Layout,
        new_layout: alloc::Layout
    ) -> Result<NonNull<[u8]>, AllocError> {
        if old_layout.size() != 0 && is_native_align(old_layout.align()) && is_native_align(new_layout.align()) {
            let ptr = NonNull::new(realloc(ptr.as_ptr() as _, new_layout.size()) as *mut u8).ok_or(AllocError)?;
            if ptr.as_ptr() as usize % new_layout.align() != 0 { return Err(AllocError); }
            Ok(NonNull::slice_from_raw_parts(ptr, new_layout.size()))
        } else {
            let new = self.allocate(new_layout)?;
            ptr::copy_nonoverlapping(ptr.as_ptr(), new.as_mut_ptr(), old_layout.size());
            self.deallocate(ptr, old_layout);
            Ok(new)
        }
    }

    unsafe fn grow_zeroed(
        &self,
        ptr: NonNull<u8>,
        old_layout: alloc::Layout,
        new_layout: alloc::Layout
    ) -> Result<NonNull<[u8]>, AllocError> {
        let ptr = self.grow(ptr, old_layout, new_layout)?;
        ptr.as_mut_ptr().map_addr(|x| x + old_layout.size()).write_bytes(0, ptr.len() - old_layout.size());
        Ok(ptr)
    }

    unsafe fn shrink(
        &self,
        ptr: NonNull<u8>,
        old_layout: alloc::Layout,
        new_layout: alloc::Layout
    ) -> Result<NonNull<[u8]>, AllocError> {
        if new_layout.size() != 0 && is_native_align(old_layout.align()) && is_native_align(new_layout.align()) {
            let ptr = NonNull::new(realloc(ptr.as_ptr() as _, new_layout.size()) as *mut u8).ok_or(AllocError)?;
            if ptr.as_ptr() as usize % new_layout.align() != 0 { return Err(AllocError); }
            Ok(NonNull::slice_from_raw_parts(ptr, new_layout.size()))
        } else {
            let new = self.allocate(new_layout)?;
            ptr::copy_nonoverlapping(ptr.as_ptr(), new.as_mut_ptr(), new_layout.size());
            self.deallocate(ptr, old_layout);
            Ok(new)
        }
    }
}