Heap without using dyn Drop

This commit is contained in:
Andrew Golovashevich 2026-03-03 22:49:55 +03:00
parent 8693aae913
commit 5de72012bf

View File

@ -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())
};
} }
} }