1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use crate::{internal, Base, RawMem};
use std::mem::size_of;
use std::{
    alloc::{self, Layout, LayoutError},
    io,
    ptr::{self, NonNull},
};

pub struct GlobalMem<T>(Base<T>);

impl<T: Default> GlobalMem<T> {
    pub fn new() -> Self {
        Self(Base::new(NonNull::slice_from_raw_parts(
            NonNull::dangling(),
            0,
        )))
    }

    fn layout_impl(capacity: usize) -> io::Result<Layout> {
        Layout::array::<T>(capacity).map_err(io::Error::other)
    }

    unsafe fn on_reserved_impl(&mut self, new_capacity: usize) -> io::Result<&mut [T]> {
        let old_capacity = self.0.allocated();
        let ptr = if self.0.ptr.as_non_null_ptr() == NonNull::dangling() {
            let layout = Self::layout_impl(new_capacity)?;
            let ptr = alloc::alloc_zeroed(layout);
            NonNull::slice_from_raw_parts(NonNull::new_unchecked(ptr), layout.size())
        } else {
            let new_capacity = new_capacity * size_of::<T>();
            let ptr = internal::align_from(self.0.ptr);
            let layout = Self::layout_impl(old_capacity)?;
            let new = alloc::realloc(ptr.as_mut_ptr(), layout, new_capacity);
            NonNull::slice_from_raw_parts(NonNull::new_unchecked(new), new_capacity)
        };

        self.0.ptr = internal::guaranteed_align_to(ptr);
        for i in old_capacity..new_capacity {
            self.0.ptr.as_mut_ptr().add(i).write(T::default());
        }
        Ok(self.0.ptr.as_mut())
    }
}

impl<T: Default> Default for GlobalMem<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T: Default> RawMem<T> for GlobalMem<T> {
    fn alloc(&mut self, capacity: usize) -> io::Result<&mut [T]> {
        unsafe { self.on_reserved_impl(capacity) }
    }

    fn allocated(&self) -> usize {
        self.0.allocated()
    }

    fn occupy(&mut self, capacity: usize) -> io::Result<()> {
        self.0.occupy(capacity)
    }

    fn occupied(&self) -> usize {
        self.0.occupied
    }
}

impl<T> Drop for GlobalMem<T> {
    fn drop(&mut self) {
        // SAFETY: ptr is valid slice
        // SAFETY: items is friendly to drop
        unsafe {
            let slice = self.0.ptr.as_mut();
            for item in slice {
                ptr::drop_in_place(item);
            }
        }

        let _: Result<_, LayoutError> = try {
            let ptr = self.0.ptr;
            let layout = Layout::array::<T>(ptr.len())?;
            // SAFETY: ptr is valid slice
            unsafe {
                let ptr = ptr.as_non_null_ptr().cast();
                alloc::dealloc(ptr.as_ptr(), layout);
            }
        };
    }
}