cursed_collections/
lazy_array.rs1use ::alloc::alloc;
2use core::{mem, ptr, slice};
3
4#[derive(Debug)]
28pub struct LazyArray<T> {
29 buffer: *mut Option<T>,
30 capacity: usize,
31 layout: alloc::Layout,
32}
33
34impl<T> LazyArray<T> {
35 pub fn new(capacity: usize) -> Self {
36 unsafe {
37 let layout = alloc::Layout::array::<Option<T>>(capacity).expect("size overflow");
38 let buffer = alloc::alloc(layout);
39 {
40 let slice =
41 slice::from_raw_parts_mut(buffer as *mut mem::MaybeUninit<Option<T>>, capacity);
42 for i in slice {
43 *i = mem::MaybeUninit::new(None);
44 }
45 }
46 Self {
47 buffer: buffer as *mut Option<T>,
48 capacity,
49 layout,
50 }
51 }
52 }
53
54 fn entry(&self, index: usize) -> *mut Option<T> {
55 unsafe {
56 assert!(index < self.capacity);
57 self.buffer.add(index)
58 }
59 }
60
61 pub fn get_or_insert(&self, index: usize, t: T) -> &T {
62 unsafe {
63 let entry = self.entry(index);
66 match *entry {
67 None => {
68 ptr::write(entry, Some(t));
69 (*entry).as_ref().unwrap_unchecked()
70 }
71 Some(ref v) => v,
72 }
73 }
74 }
75
76 pub fn get(&self, index: usize) -> Option<&T> {
77 assert!(index < self.capacity);
78 unsafe { (*self.buffer.add(index)).as_ref() }
79 }
80}
81
82impl<T> Drop for LazyArray<T> {
83 fn drop(&mut self) {
84 unsafe {
85 alloc::dealloc(self.buffer as *mut u8, self.layout);
86 }
87 }
88}
89
90impl<T> Default for LazyArray<T> {
91 fn default() -> Self {
92 Self::new(0)
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::LazyArray;
99
100 #[test]
101 fn it_works() {
102 let lazy_array = LazyArray::<i32>::new(10);
103 for i in 0..10 {
104 assert_eq!(lazy_array.get(i), None)
105 }
106
107 assert_eq!(lazy_array.get_or_insert(7, 112233), &112233);
108
109 for i in 0..10 {
110 assert_eq!(lazy_array.get(i), if i == 7 { Some(&112233) } else { None })
111 }
112 }
113
114 #[test]
115 fn cannot_insert_twice() {
116 let lazy_array = LazyArray::<i32>::new(10);
117 assert_eq!(lazy_array.get_or_insert(7, 112233), &112233);
118 assert_eq!(lazy_array.get_or_insert(7, 445566), &112233);
119 }
120
121 #[test]
122 #[should_panic]
123 fn cannot_put_out_of_bounds() {
124 let lazy_array = LazyArray::<i32>::new(10);
125 lazy_array.get_or_insert(10, 112233);
126 }
127}