Skip to main content

gc_alloc/
vec.rs

1use std::{ffi::c_void, ptr::NonNull};
2
3use crate::{GcToken, gc};
4
5pub fn from_fn<T>(
6    _token: &impl GcToken,
7    len: usize,
8    mut f: impl FnMut(usize) -> T,
9) -> &'static mut [T] {
10    let vec = VecInner::<T>::new(len);
11    for i in 0..len {
12        unsafe { vec.as_ptr().add(i).write(f(i)) };
13    }
14    vec.set_len(len);
15
16    register_finalizer(vec.as_ptr());
17
18    unsafe { std::slice::from_raw_parts_mut(vec.as_ptr(), len) }
19}
20
21pub fn repeat<T: Clone>(token: &impl GcToken, val: T, len: usize) -> &'static mut [T] {
22    from_fn(token, len, |_| val.clone())
23}
24
25pub fn from_iter<T, I: IntoIterator<Item = T>>(_token: &impl GcToken, iter: I) -> &'static mut [T] {
26    let iter = iter.into_iter();
27    let (lower, _) = iter.size_hint();
28
29    let mut cap = lower.max(1);
30    let mut vec = VecInner::<T>::new(cap);
31    let mut len = 0;
32    for item in iter {
33        if len == cap {
34            cap = cap.checked_mul(2).expect("Capacity overflow");
35            let new_vec = VecInner::<T>::new(cap);
36            unsafe { std::ptr::copy_nonoverlapping(vec.as_ptr(), new_vec.as_ptr(), len) };
37            vec = new_vec;
38        }
39        unsafe { vec.as_ptr().add(len).write(item) };
40        len += 1;
41    }
42    vec.set_len(len);
43
44    register_finalizer(vec.as_ptr());
45
46    unsafe { std::slice::from_raw_parts_mut(vec.as_ptr(), len) }
47}
48
49fn register_finalizer<T>(ptr: *mut T) {
50    if std::mem::needs_drop::<T>() {
51        extern "C" fn finalizer<T>(obj: *mut c_void, _: *mut c_void) {
52            let vec = VecInner(unsafe { NonNull::new_unchecked(obj as *mut T) });
53            let len = vec.num_to_drop();
54            for i in 0..len {
55                unsafe { std::ptr::drop_in_place(vec.as_ptr().add(i)) };
56            }
57        }
58
59        unsafe {
60            gc::GC_register_finalizer(
61                ptr as *mut std::ffi::c_void,
62                Some(finalizer::<T>),
63                std::ptr::null_mut(),
64                std::ptr::null_mut(),
65                std::ptr::null_mut(),
66            );
67        }
68    }
69}
70
71struct VecInner<T>(NonNull<T>);
72
73impl<T> VecInner<T> {
74    fn new(cap: usize) -> Self {
75        if std::mem::needs_drop::<T>() {
76            let padding = usize::max(std::mem::size_of::<usize>(), std::mem::size_of::<T>());
77            let alignment = usize::max(std::mem::align_of::<usize>(), std::mem::align_of::<T>());
78
79            let ptr = unsafe {
80                gc::GC_memalign(
81                    std::mem::size_of::<T>().strict_mul(cap).strict_add(padding),
82                    alignment,
83                ) as *mut T
84            };
85            let ptr = unsafe {
86                NonNull::new(ptr)
87                    .expect("Allocation failed")
88                    .byte_add(padding)
89            };
90            VecInner(ptr)
91        } else {
92            let ptr = unsafe {
93                gc::GC_memalign(
94                    std::mem::size_of::<T>().strict_mul(cap),
95                    std::mem::align_of::<T>(),
96                ) as *mut T
97            };
98            let ptr = NonNull::new(ptr).expect("Allocation failed");
99            VecInner(ptr)
100        }
101    }
102
103    fn as_ptr(&self) -> *mut T {
104        self.0.as_ptr()
105    }
106
107    fn num_to_drop(&self) -> usize {
108        if std::mem::needs_drop::<T>() {
109            let p_len =
110                unsafe { self.0.as_ptr().byte_sub(std::mem::size_of::<usize>()) as *const usize };
111            unsafe { p_len.read() }
112        } else {
113            0
114        }
115    }
116
117    fn set_len(&self, len: usize) {
118        if std::mem::needs_drop::<T>() {
119            let p_len =
120                unsafe { self.0.as_ptr().byte_sub(std::mem::size_of::<usize>()) as *mut usize };
121            unsafe { p_len.write(len) };
122        }
123    }
124}