heap_vec/
lib.rs

1#[cfg(test)]
2mod tests {
3    use crate::HeapVec;
4    #[test]
5    fn size_ok() {
6        use std::mem::size_of;
7        assert_eq!(size_of::<*mut u8>(), size_of::<HeapVec<u8>>());
8    }
9
10    #[test]
11    fn insert_test() {
12        let mut hv: crate::HeapVec<u8> = crate::HeapVec::new();
13        assert_eq!(hv.len(), 0);
14        hv.push(0);
15        assert_eq!(hv.len(), 1);
16
17        hv.push(1);
18        assert_eq!(hv.len(), 2);
19
20        let hvc = hv.clone();
21
22
23        assert_eq!(hv[0], 0);
24        assert_eq!(hv[1], 1);
25
26        assert_eq!(hv.pop(), Some(1));
27        assert_eq!(hv.len(), 1);
28        assert_eq!(hv.pop(), Some(0));
29        assert_eq!(hv.len(), 0);
30        assert_eq!(hv.pop(), None);
31        
32        assert_eq!(hvc[..], [0, 1]);
33    }
34
35    #[test]
36    #[should_panic(expected = "droppanic.drop()")]
37    fn test_drop_panic() {
38        // This test should only panic once, and not double panic,
39        // which would mean a double drop
40        struct DropPanic {
41            test: u8
42        };
43        // TODO: make DropPanic a zero-sized type.
44
45        impl Drop for DropPanic {
46            fn drop(&mut self) {
47                panic!("droppanic.drop()");
48
49            }
50        }
51
52        let mut v = HeapVec::new();
53        v.push(DropPanic{test: 0});
54    } 
55}
56
57use std::marker::PhantomData;
58use std::mem;
59
60struct Unique<T> {
61    ptr: *const T,              // *const for variance
62    _marker: PhantomData<T>,    // For the drop checker
63}
64
65// Deriving Send and Sync is safe because we are the Unique owners
66// of this data. It's like Unique<T> is "just" T.
67unsafe impl<T: Send> Send for Unique<T> {}
68unsafe impl<T: Sync> Sync for Unique<T> {}
69
70impl<T> Unique<T> {
71    pub fn new(ptr: *mut T) -> Self {
72        Unique { ptr: ptr, _marker: PhantomData }
73    }
74
75    pub fn as_ptr(&self) -> *mut T {
76        self.ptr as *mut T
77    }
78    
79    pub fn is_null(&self) -> bool {
80        self.ptr as usize == 0
81    }
82}
83
84use std::alloc;
85
86pub struct HeapVec<T> {
87    ptr: Unique<T>,
88}
89
90impl<T> HeapVec<T> {
91    pub fn new() -> Self {
92        assert!(std::mem::size_of::<T>() != 0, "We're not ready to handle types with size 0!");
93        Self { ptr: Unique::new(0 as *mut T)}
94    }
95
96    pub fn raw_ptr(&self) -> *const T {
97        (self.ptr.as_ptr() as usize + Self::get_offset()) as *mut T
98    }
99
100    const fn get_offset() -> usize {
101        // Round up sizeof(usize) * 2 to a multiple of alignof(T)
102        // * 2 is because there is both len and cap
103        // The division is (a + b - 1) / b which is ceiling integer division.
104        ((mem::size_of::<usize>()*2 + mem::align_of::<T>() - 1) / mem::align_of::<T>()) * mem::align_of::<T>()
105    }
106
107    fn get_offset_of(&self, index: usize) -> *mut T {
108        (self.ptr.as_ptr() as usize + Self::get_offset() + mem::size_of::<T>() * index) as *mut T
109    }
110
111    fn capacity(&self) -> usize {
112        if self.ptr.is_null() {
113            0
114        } else {
115            unsafe {
116                *(self.ptr.as_ptr() as *const usize)
117            }
118        }
119    }
120    
121    pub fn len(&self) -> usize {
122        if self.ptr.is_null() {
123            0
124        } else {
125            unsafe {
126                *((self.ptr.as_ptr() as usize + mem::size_of::<usize>()) as *const usize)
127            }
128        }
129    }
130
131    fn get_cap_mut(&mut self) -> &mut usize {
132        unsafe {
133            &mut*(self.ptr.as_ptr() as *mut usize)
134        }
135    }
136    
137    fn get_len_mut(&mut self) -> &mut usize {
138        unsafe {
139            &mut *((self.ptr.as_ptr() as usize + mem::size_of::<usize>()) as *mut usize)
140        }
141    }
142
143    fn grow(&mut self) {
144        unsafe {
145            let cap_size = Self::get_offset();
146            let elem_size = mem::size_of::<T>();
147            let align = std::cmp::max(mem::align_of::<T>(), mem::align_of::<usize>());
148
149
150            if self.ptr.is_null() {
151                let new_num_bytes = cap_size + elem_size;
152
153                let ptr = alloc::alloc(alloc::Layout::from_size_align(new_num_bytes, align).expect("Couldn't create layout!"));
154
155                if ptr.is_null() {
156                    panic!("Allocation failed!");
157                }
158
159                self.ptr = Unique::new(ptr as *mut T);
160                *self.get_cap_mut() = 1;
161
162            } else {
163                let old_cap = self.capacity();
164                let new_cap = old_cap * 2;
165                let old_num_bytes = cap_size + old_cap*elem_size;
166                let new_num_bytes = cap_size + 2*old_cap*elem_size;
167
168                let ptr = alloc::realloc(self.ptr.as_ptr() as *mut u8,
169                        alloc::Layout::from_size_align(old_num_bytes, align).expect("Couldn't create layout!"),
170                        new_num_bytes
171                );
172
173                self.ptr = Unique::new(ptr as *mut T);
174                *self.get_cap_mut() = new_cap;
175            };
176        }
177    }
178
179    pub fn push(&mut self, elem: T) {
180        if self.len() == self.capacity() {
181            self.grow();
182        }
183
184        unsafe {
185            std::ptr::write(self.get_offset_of(self.len()), elem);
186        }
187
188        *self.get_len_mut() += 1;
189    }
190
191    pub fn pop(&mut self) -> Option<T> {
192        if self.len() == 0 {
193            None
194        } else {
195            *self.get_len_mut() -= 1;
196            unsafe {
197                Some(std::ptr::read(self.get_offset_of(self.len())))
198            }
199        }
200    }
201
202    pub fn insert(&mut self, index: usize, elem: T) {
203        assert!(index <= self.len(), "index out of bounds");
204        if self.capacity() == self.len() { self.grow(); }
205
206        unsafe {
207            if index < self.len() {
208                // ptr::copy(src, dest, len): "copy from source to dest len elems"
209                std::ptr::copy(self.get_offset_of(index),
210                        self.get_offset_of(index + 1),
211                        self.len() - index);
212            }
213            std::ptr::write(self.get_offset_of(index), elem);
214        }
215        *self.get_len_mut() += 1;
216    }
217
218    pub fn remove(&mut self, index: usize) -> T {
219        // Note: `<` because it's *not* valid to remove after everything
220        assert!(index < self.len(), "index out of bounds");
221        unsafe {
222            *self.get_len_mut() -= 1;
223            let result = std::ptr::read(self.get_offset_of(index));
224            std::ptr::copy(self.get_offset_of(index + 1),
225                    self.get_offset_of(index),
226                    self.len() - index);
227            result
228        }
229    }
230}
231
232impl<T> Drop for HeapVec<T> {
233    fn drop(&mut self) {
234        if !self.ptr.is_null() {
235            while let Some(_) = self.pop() { }
236
237            let align = std::cmp::max(mem::align_of::<T>(), mem::align_of::<usize>());
238            let elem_size = mem::size_of::<T>();
239            let cap_size = Self::get_offset();
240            let num_bytes = cap_size + elem_size * self.capacity();
241            unsafe {
242                alloc::dealloc(self.ptr.as_ptr() as *mut _, alloc::Layout::from_size_align(num_bytes, align).expect("Couldn't create layout!"));
243            }
244        }
245    }
246}
247
248use std::ops::Deref;
249impl<T> Deref for HeapVec<T> {
250    type Target = [T];
251    fn deref(&self) -> &[T] {
252        unsafe {
253            std::slice::from_raw_parts(self.get_offset_of(0), self.len())
254        }
255    }
256}
257use std::ops::DerefMut;
258impl<T> DerefMut for HeapVec<T> {
259    fn deref_mut(&mut self) -> &mut [T] {
260        unsafe {
261            std::slice::from_raw_parts_mut(self.get_offset_of(0), self.len())
262        }
263    }
264}
265
266impl<T: Clone> Clone for HeapVec<T> {
267    fn clone(&self) -> Self {
268        unsafe {
269            let cap_size = Self::get_offset();
270            let elem_size = mem::size_of::<T>();
271            let align = std::cmp::max(mem::align_of::<T>(), mem::align_of::<usize>());
272            let num_bytes = cap_size + elem_size * self.capacity();
273
274            let ptr = alloc::alloc(alloc::Layout::from_size_align(num_bytes, align).expect("Couldn't create layout!"));
275
276            if ptr.is_null() {
277                panic!("Allocation failed!");
278            } 
279
280            let mut new_hv = Self{ptr: Unique::new(ptr as *mut T)};
281            *new_hv.get_cap_mut() = self.capacity();
282            for v in self.iter() {
283                new_hv.push(v.clone());
284            }
285            new_hv
286        }
287    }
288}
289
290
291// TODO: implement IntoIter
292// TODO: implement Drain
293// TODO: support types with size 0