Skip to main content

osom_lib_alloc/
std_allocator.rs

1//! Holds the implementation of the standard allocator, based on `libc` crate.
2
3use core::{alloc::Layout, ptr::NonNull};
4
5use osom_lib_reprc::macros::reprc;
6
7use super::traits::{AllocationError, Allocator};
8
9/// The standard allocator based on `libc` crate.
10#[derive(Debug, Default, Clone, Copy)]
11#[reprc]
12pub struct StdAllocator;
13
14/// The standard allocator error.
15#[derive(Debug, Clone, Copy)]
16#[reprc]
17pub enum StdAllocationError {
18    /// A generic allocation error. Likely because of out of memory.
19    AllocationError = 0,
20
21    /// The result is misaligned. Likely because the requested alignment is above
22    /// what malloc supports.
23    MisalignedResult = 1,
24}
25
26impl From<StdAllocationError> for AllocationError {
27    fn from(_: StdAllocationError) -> Self {
28        Self
29    }
30}
31
32unsafe impl Allocator for StdAllocator {
33    type SpecificAllocationError = StdAllocationError;
34
35    fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, Self::SpecificAllocationError> {
36        let raw_ptr = raw_aligned_malloc(layout);
37        if raw_ptr.is_null() {
38            return Err(StdAllocationError::AllocationError);
39        }
40
41        if raw_ptr.align_offset(layout.align()) != 0 {
42            raw_aligned_free(raw_ptr.cast(), layout);
43            return Err(StdAllocationError::MisalignedResult);
44        }
45
46        Ok(unsafe { NonNull::new_unchecked(raw_ptr.cast()) })
47    }
48
49    #[inline(always)]
50    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
51        raw_aligned_free(ptr.as_ptr().cast(), layout);
52    }
53
54    unsafe fn resize(
55        &self,
56        ptr: NonNull<u8>,
57        old_layout: Layout,
58        new_layout: Layout,
59    ) -> Result<NonNull<u8>, Self::SpecificAllocationError> {
60        let new_align = new_layout.align();
61        if old_layout.align() == new_align {
62            let raw_ptr = raw_aligned_realloc(ptr.as_ptr().cast(), old_layout, new_layout.size());
63            if raw_ptr.is_null() {
64                return Err(StdAllocationError::AllocationError);
65            }
66
67            if raw_ptr.align_offset(new_align) != 0 {
68                raw_aligned_free(raw_ptr.cast(), new_layout);
69                return Err(StdAllocationError::MisalignedResult);
70            }
71
72            Ok(unsafe { NonNull::new_unchecked(raw_ptr.cast()) })
73        } else {
74            unsafe {
75                let new_ptr = self.allocate(new_layout)?;
76                new_ptr.copy_from_nonoverlapping(ptr, new_layout.size());
77                self.deallocate(ptr, old_layout);
78                Ok(new_ptr)
79            }
80        }
81    }
82}
83
84osom_lib_cfg_ext::cfg_match!(
85    (miri) => {
86        extern crate alloc;
87
88        #[inline(always)]
89        fn raw_aligned_malloc(layout: Layout) -> *mut u8 {
90            unsafe { alloc::alloc::alloc(layout) }
91        }
92
93        #[inline(always)]
94        fn raw_aligned_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
95            unsafe { alloc::alloc::realloc(ptr, old_layout, new_size) }
96        }
97
98        #[inline(always)]
99        fn raw_aligned_free(ptr: *mut u8, layout: Layout) {
100            unsafe { alloc::alloc::dealloc(ptr, layout) }
101        }
102    },
103    (target_os="windows") => {
104        #[inline(always)]
105        fn raw_aligned_malloc(layout: Layout) -> *mut u8 {
106            unsafe { ::libc::aligned_malloc(layout.size(), layout.align()).cast() }
107        }
108
109        #[inline(always)]
110        fn raw_aligned_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
111            unsafe { ::libc::aligned_realloc(ptr.cast(), new_size, old_layout.align()).cast() }
112        }
113
114        #[inline(always)]
115        fn raw_aligned_free(ptr: *mut u8, _layout: Layout) {
116            unsafe { ::libc::aligned_free(ptr.cast()) }
117        }
118    },
119    _ => {
120        #[inline(always)]
121        fn raw_aligned_malloc(layout: Layout) -> *mut u8 {
122            unsafe { ::libc::malloc(layout.size()).cast() }
123        }
124
125        #[inline(always)]
126        fn raw_aligned_realloc(ptr: *mut u8, _old_layout: Layout, new_size: usize) -> *mut u8 {
127            unsafe { ::libc::realloc(ptr.cast(), new_size).cast() }
128        }
129
130        #[inline(always)]
131        fn raw_aligned_free(ptr: *mut u8, _layout: Layout) {
132            unsafe { ::libc::free(ptr.cast()) }
133        }
134    }
135);