Heap without using dyn Drop
This commit is contained in:
parent
8693aae913
commit
5de72012bf
@ -1,45 +1,21 @@
|
|||||||
use crate::errors::throw_from_windows_err_code;
|
use crate::errors::throw_from_windows_err_code;
|
||||||
use std::mem::{offset_of, uninitialized};
|
use std::ffi::c_void;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::ptr;
|
use std::ptr::NonNull;
|
||||||
use std::ptr::{NonNull, null_mut};
|
|
||||||
use windows::Win32::Foundation::{GetLastError, HANDLE};
|
use windows::Win32::Foundation::{GetLastError, HANDLE};
|
||||||
use windows::Win32::System::Memory::{HEAP_FLAGS, HEAP_NO_SERIALIZE, HeapAlloc, HeapCreate};
|
use windows::Win32::System::Memory::{
|
||||||
|
HeapAlloc, HeapCreate, HeapFree, HEAP_FLAGS, HEAP_NO_SERIALIZE,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) struct Allocator {
|
pub(crate) struct Allocator {
|
||||||
win_heap: HANDLE,
|
win_heap: HANDLE,
|
||||||
last: Option<NonNull<dyn Cell>>,
|
last: Option<NonNull<Header>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Cell {
|
struct Header {
|
||||||
fn get_prev(&self) -> Option<NonNull<dyn Cell>>;
|
prev: Option<NonNull<Header>>,
|
||||||
fn set_prev(&mut self, p: Option<NonNull<dyn Cell>>);
|
next: Option<NonNull<Header>>,
|
||||||
fn get_next(&self) -> Option<NonNull<dyn Cell>>;
|
destructor: unsafe fn(NonNull<c_void>),
|
||||||
fn set_next(&mut self, p: Option<NonNull<dyn Cell>>);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CellImpl<T> {
|
|
||||||
prev: Option<NonNull<dyn Cell>>,
|
|
||||||
next: Option<NonNull<dyn Cell>>,
|
|
||||||
value: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Cell for CellImpl<T> {
|
|
||||||
fn get_prev(&self) -> Option<NonNull<dyn Cell>> {
|
|
||||||
return self.prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_prev(&mut self, p: Option<NonNull<dyn Cell>>) {
|
|
||||||
self.prev = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_next(&self) -> Option<NonNull<dyn Cell>> {
|
|
||||||
return self.next;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_next(&mut self, p: Option<NonNull<dyn Cell>>) {
|
|
||||||
self.next = p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator {
|
impl Allocator {
|
||||||
@ -57,39 +33,78 @@ impl Allocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn alloc<'s, T: Drop + 'static>(
|
const fn _calc_offset<T>() -> usize {
|
||||||
|
match size_of::<Header>() % align_of::<T>() == 0 {
|
||||||
|
true => return size_of::<Header>(),
|
||||||
|
false => {
|
||||||
|
return size_of::<Header>()
|
||||||
|
+ (align_of::<T>() - size_of::<Header>() % align_of::<T>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn alloc<'s, T>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
init: impl FnOnce(Pin<&mut T>),
|
init: impl FnOnce(&mut Pin<&mut T>),
|
||||||
) -> Pin<&'s mut T> {
|
) -> Pin<&'s mut T> {
|
||||||
let mut p = NonNull::new(
|
let mut h = NonNull::new(
|
||||||
HeapAlloc(
|
HeapAlloc(
|
||||||
self.win_heap,
|
self.win_heap,
|
||||||
HEAP_FLAGS::default(),
|
HEAP_FLAGS::default(),
|
||||||
size_of::<CellImpl<T>>(),
|
Self::_calc_offset::<T>() + size_of::<T>(),
|
||||||
)
|
)
|
||||||
.cast::<CellImpl<T>>(),
|
.cast::<Header>(),
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|| throw_from_windows_err_code(GetLastError()));
|
.unwrap_or_else(|| throw_from_windows_err_code(GetLastError()));
|
||||||
|
|
||||||
if let Some(mut last) = self.last {
|
if let Some(mut last) = self.last {
|
||||||
last.as_mut().set_next(Some(p));
|
last.as_mut().next = Some(h);
|
||||||
}
|
}
|
||||||
p.as_mut().prev = self.last;
|
h.as_mut().prev = self.last;
|
||||||
p.as_mut().next = None;
|
h.as_mut().next = None;
|
||||||
self.last = Some(p);
|
h.as_mut().destructor = Self::_destructor::<T>;
|
||||||
|
self.last = Some(h);
|
||||||
|
|
||||||
init(Pin::new_unchecked(&mut p.as_mut().value));
|
let mut p = Pin::new_unchecked(
|
||||||
|
&mut *(h
|
||||||
|
.as_ptr()
|
||||||
|
.map_addr(|a| a + Self::_calc_offset::<T>())
|
||||||
|
.cast::<T>()),
|
||||||
|
);
|
||||||
|
|
||||||
return Pin::new_unchecked(&mut p.as_mut().value);
|
init(&mut p);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn _destructor<T>(obj: NonNull<c_void>) {
|
||||||
|
drop(obj.cast::<T>().read())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn free<T: Drop>(&mut self, p: Pin<&mut T>) {
|
pub unsafe fn free<T: Drop>(&mut self, p: Pin<&mut T>) {
|
||||||
let p = Pin::into_inner_unchecked(p);
|
let p = NonNull::from_mut(Pin::into_inner_unchecked(p));
|
||||||
let c = NonNull::new_unchecked(
|
let h = NonNull::new_unchecked(
|
||||||
NonNull::new_unchecked(p)
|
p.as_ptr()
|
||||||
.as_ptr()
|
.map_addr(|a| a - Self::_calc_offset::<T>())
|
||||||
.map_addr(|a| a - offset_of!(CellImpl<T>, value))
|
.cast::<Header>(),
|
||||||
.cast::<CellImpl<T>>(),
|
)
|
||||||
);
|
.as_mut();
|
||||||
|
|
||||||
|
h.next.map(|mut n| n.as_mut().prev = h.prev);
|
||||||
|
h.prev.map(|mut n| n.as_mut().next = h.next);
|
||||||
|
if self.last == Some(NonNull::from_mut(h)) {
|
||||||
|
self.last = h.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
(h.destructor)(p.cast::<c_void>());
|
||||||
|
|
||||||
|
match HeapFree(
|
||||||
|
self.win_heap,
|
||||||
|
HEAP_FLAGS::default(),
|
||||||
|
Some((h as *mut Header).cast()),
|
||||||
|
) {
|
||||||
|
Ok(_) => return,
|
||||||
|
Err(err) => throw_from_windows_err_code(err.code())
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user