heap_ap/
lib.rs

1#![allow(unused)]
2#![cfg_attr(feature = "allocator-api", feature(allocator_api))]
3#![cfg_attr(feature = "allocator-api", feature(alloc_layout_extra))]
4#![cfg_attr(feature = "allocator-api", feature(slice_ptr_get))]
5
6extern crate cheap as _;
7extern crate libc;
8extern crate std;
9
10use std::{
11    alloc::GlobalAlloc,
12    alloc::Layout,
13    ptr::NonNull,
14    hint,
15    marker::PhantomPinned
16};
17#[cfg(feature = "allocator-api")]
18use std::alloc::{Allocator, AllocError};
19
20use libc::{size_t, c_void};
21
22extern "C" {
23    fn allocate(size: size_t, align: size_t) -> *mut c_void;
24    fn allocate_zeroed(size: size_t, align: size_t) -> *mut c_void;
25    fn reallocate(ptr: *mut c_void, size: size_t, align: size_t, new_size: size_t) -> *mut c_void;
26    fn deallocate(ptr: *mut c_void, size: size_t, align: size_t);
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
30#[repr(transparent)]
31pub struct Heap {
32    _pinned: PhantomPinned,
33}
34
35impl Heap {
36    pub const fn new() -> Heap {
37        Heap {
38            _pinned: PhantomPinned,
39        }
40    }
41}
42
43unsafe impl Send for Heap {}
44unsafe impl Sync for Heap {}
45
46unsafe impl GlobalAlloc for Heap {
47    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
48        let size = layout.size() as size_t;
49        let align = layout.align() as size_t;
50        allocate(size, align) as *mut u8
51    }
52    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
53        let size = layout.size() as size_t;
54        let align = layout.align() as size_t;
55        deallocate(ptr as *mut c_void, size, align)
56    }
57    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
58        let size = layout.size() as size_t;
59        let align = layout.align() as size_t;
60        reallocate(ptr as *mut c_void, size, align, new_size as size_t) as *mut u8
61    }
62    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
63        let size = layout.size() as size_t;
64        let align = layout.align() as size_t;
65        allocate_zeroed(size, align) as *mut u8
66    }
67}
68
69#[cfg(feature = "allocator-api")]
70
71impl Heap {
72    #[inline]
73    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
74        match layout.size() {
75            0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
76            size => unsafe {
77                let raw = if zeroed {
78                    self.alloc_zeroed(layout)
79                } else {
80                    self.alloc(layout)
81                };
82                let ptr = NonNull::new(raw).ok_or(AllocError)?;
83                Ok(NonNull::slice_from_raw_parts(ptr, size))
84            },
85        }
86    }
87    #[inline]
88    unsafe fn grow_impl(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
89        debug_assert!(new_layout.size() >= old_layout.size(), "new_layout.size() must be greater then or equal to old_layout.size()");
90        match old_layout.size() {
91            0 => self.alloc_impl(new_layout, zeroed),
92            old_size if old_layout.align() == new_layout.align() => unsafe {
93                let new_size = new_layout.size();
94                hint::assert_unchecked(new_size >= old_layout.size());
95                let raw = self.realloc(ptr.as_ptr(), old_layout, new_size);
96                let ptr = NonNull::new(raw).ok_or(AllocError)?;
97                if zeroed {
98                    raw.add(old_size).write_bytes(0, new_size - old_size);
99                }
100                Ok(NonNull::slice_from_raw_parts(ptr, new_size))
101            },
102            old_size => unsafe {
103                let new = self.alloc_impl(new_layout, zeroed)?;
104                std::ptr::copy_nonoverlapping(ptr.as_ptr(), new.as_mut_ptr(), old_size);
105                self.deallocate(ptr, old_layout);
106                Ok(new)
107            },
108        }
109    }
110}
111
112#[cfg(feature = "allocator-api")]
113unsafe impl Allocator for Heap {
114    #[inline]
115    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
116        self.alloc_impl(layout, false)
117    }
118    #[inline]
119    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
120        self.alloc_impl(layout, true)
121    }
122    #[inline]
123    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
124        if layout.size() != 0 {
125            unsafe {
126                self.dealloc(ptr.as_ptr(), layout)
127            }
128        }
129    }
130    #[inline]
131    unsafe fn grow(
132            &self,
133            ptr: NonNull<u8>,
134            old_layout: Layout,
135            new_layout: Layout,
136        ) -> Result<NonNull<[u8]>, AllocError> {
137        unsafe {
138            self.grow_impl(ptr, old_layout, new_layout, false)
139        }
140    }
141    #[inline]
142    unsafe fn grow_zeroed(
143            &self,
144            ptr: NonNull<u8>,
145            old_layout: Layout,
146            new_layout: Layout,
147        ) -> Result<NonNull<[u8]>, AllocError> {
148        unsafe {
149            self.grow_impl(ptr, old_layout, new_layout, true)
150        }
151    }
152    #[inline]
153    unsafe fn shrink(
154            &self,
155            ptr: NonNull<u8>,
156            old_layout: Layout,
157            new_layout: Layout,
158        ) -> Result<NonNull<[u8]>, AllocError> {
159        debug_assert!(new_layout.size() <= old_layout.size(), "new_layout.size() must be smaller then or equal to old_layout.size()");
160
161        match new_layout.size() {
162            0 => unsafe {
163                self.deallocate(ptr, old_layout);
164                Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
165            },
166            new_size if old_layout.align() == new_layout.align() => unsafe {
167                hint::assert_unchecked(new_size <= old_layout.size());
168                let raw = self.realloc(ptr.as_ptr(), old_layout, new_size);
169                let ptr = NonNull::new(raw).ok_or(AllocError)?;
170                Ok(NonNull::slice_from_raw_parts(ptr, new_size)) 
171            },
172            new_size => unsafe {
173                let new = self.allocate(new_layout)?;
174                std::ptr::copy_nonoverlapping(ptr.as_ptr(), new.as_mut_ptr(), new_size);
175                self.deallocate(ptr, old_layout);
176                Ok(new)
177            },
178        }
179    }
180}
181
182#[cfg(feature = "allocator-api")]
183pub type Vec<T> = std::vec::Vec<T, Heap>;
184#[cfg(feature = "allocator-api")]
185pub type Box<T> = std::boxed::Box<T, Heap>;
186
187