eta_algorithms/data_structs/
stack.rs1use std::alloc::{realloc, Layout};
2use std::fmt::Debug;
3use std::ops::{Index, IndexMut};
4use std::ptr;
5
6pub struct Stack<T>
7where
8 T: Copy + Sized,
9{
10 capacity: usize,
11 len: usize,
12 layout: Layout,
13 data: *mut T,
14 top: *mut T,
15 end: *mut T,
16}
17
18impl<T> Stack<T>
19where
20 T: Copy + Sized,
21{
22 #[inline(always)]
23 pub fn capacity(&self) -> usize {
24 self.capacity
25 }
26 #[inline(always)]
27 pub fn len(&self) -> usize {
28 self.len
29 }
30 pub fn new(capacity: usize) -> Self {
31 let layout = Layout::array::<T>(capacity).expect("Failed to create layout");
32 let data = unsafe { std::alloc::alloc(layout) as *mut T };
33 if data.is_null() {
34 panic!("Failed to allocate memory");
35 }
36
37 Stack {
38 capacity,
39 layout,
40 data,
41 len: 0,
42 top: unsafe { data.offset(-1) },
43 end: unsafe { data.add(capacity) },
44 }
45 }
46
47 #[inline(always)]
48 pub fn is_empty(&self) -> bool {
49 self.len == 0
50 }
51
52 pub fn extend(&mut self, new_capacity: usize) {
53 let new_layout = Layout::array::<T>(new_capacity).expect("Failed to create layout");
54 unsafe {
55 self.data = realloc(self.data as *mut u8, new_layout, new_layout.size()) as *mut T;
56 if self.data.is_null() {
57 panic!("Failed to reallocate memory");
58 }
59 self.end = self.data.add(new_capacity);
60 self.top = self.data.offset((self.len as isize) - 1);
61 }
62 self.capacity = new_capacity;
63 self.layout = new_layout;
64 }
65 #[inline(always)]
66 pub fn extend_by(&mut self, additional_capacity: usize) {
67 self.extend(self.capacity + additional_capacity);
68 }
69 #[inline(always)]
70 pub fn top(&self) -> Option<&T> {
71 if self.len == 0 {
72 return None;
73 }
74 unsafe { Some(self.top.as_ref().unwrap()) }
75 }
76 #[inline(always)]
77 pub fn top_mut(&mut self) -> Option<&mut T> {
78 if self.len == 0 {
79 return None;
80 }
81 unsafe { Some(self.top.as_mut().unwrap()) }
82 }
83 #[inline(always)]
84 pub fn push(&mut self, value: T) {
85 let new_top = unsafe { self.top.offset(1) };
86 if new_top == self.end {
87 panic!("Stack over capacity!");
88 }
89
90 self.top = new_top;
91 unsafe { self.top.write(value) };
92 self.len += 1;
93 }
94 #[inline(always)]
95 pub fn pop(&mut self) -> Option<T> {
96 if self.len == 0 {
97 return None;
98 }
99
100 unsafe {
101 let result = Some(ptr::read(self.top));
102 self.top = self.top.offset(-1);
103 self.len -= 1;
104 result
105 }
106 }
107}
108
109impl<T> Debug for Stack<T>
110where
111 T: Copy + Sized + Debug,
112{
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 write!(f, "Stack [len={}, cap={}] [", self.len, self.capacity)?;
115 unsafe {
116 let mut pivot = self.data;
117 let end = self.top.add(1);
118 while pivot != end {
119 let value = pivot.read();
120 write!(f, " {:?}", value)?;
121 pivot = pivot.add(1);
122 }
123 }
124 write!(f, " ]")?;
125 Ok(())
126 }
127}
128
129impl<T> Index<isize> for Stack<T>
130where
131 T: Copy + Sized,
132{
133 type Output = T;
134 #[inline(always)]
135 fn index(&self, index: isize) -> &Self::Output {
136 if index > 0 {
137 panic!("Index out of bounds");
138 }
139
140 if index <= -(self.len as isize) {
141 panic!("Index out of bounds");
142 }
143
144 let indexed_data = unsafe { self.top.offset(index) };
145 unsafe { indexed_data.as_ref().unwrap() }
146 }
147}
148
149impl<T> IndexMut<isize> for Stack<T>
150where
151 T: Copy + Sized,
152{
153 #[inline(always)]
154 fn index_mut(&mut self, index: isize) -> &mut Self::Output {
155 if index > 0 {
156 panic!("Index out of bounds");
157 }
158
159 if index < -(self.len as isize) {
160 panic!("Index out of bounds");
161 }
162
163 let indexed_data = unsafe { self.top.offset(index) };
164 unsafe { indexed_data.as_mut().unwrap() }
165 }
166}
167
168impl<T> Drop for Stack<T>
169where
170 T: Copy + Sized,
171{
172 fn drop(&mut self) {
173 unsafe {
174 std::alloc::dealloc(self.data as *mut u8, self.layout);
175 }
176 }
177}