Skip to main content

anathema_store/
stack.rs

1#[derive(Debug, Default, PartialEq, Clone, Copy)]
2enum Entry<T> {
3    Occupied(T),
4    #[default]
5    Empty,
6}
7
8impl<T> Entry<T> {
9    fn to_value_ref(&self) -> Option<&T> {
10        match self {
11            Self::Occupied(val) => Some(val),
12            Self::Empty => None,
13        }
14    }
15
16    fn to_value_mut(&mut self) -> Option<&mut T> {
17        match self {
18            Self::Occupied(val) => Some(val),
19            Self::Empty => None,
20        }
21    }
22
23    fn into_value(self) -> Option<T> {
24        match self {
25            Self::Occupied(val) => Some(val),
26            Self::Empty => None,
27        }
28    }
29}
30
31/// Allocate memory but never free it until the entire `Stack` is dropped.
32/// Items popped from the stack are marked as `Empty` so the memory is reused.
33#[derive(Debug, Default)]
34pub struct Stack<T> {
35    inner: Vec<Entry<T>>,
36    len: usize,
37}
38
39impl<T> Stack<T> {
40    /// Create an empty stack
41    pub const fn empty() -> Self {
42        Self {
43            inner: Vec::new(),
44            len: 0,
45        }
46    }
47
48    /// Get the next index that will be written to
49    pub fn next_index(&self) -> usize {
50        self.len
51    }
52
53    /// Create a stack with an initial capacity.
54    /// This will fill the stack with empty entries
55    pub fn with_capacity(cap: usize) -> Self {
56        let mut inner = Vec::with_capacity(cap);
57        inner.fill_with(|| Entry::Empty);
58        Self { inner, len: 0 }
59    }
60
61    /// Push a value onto the stack
62    pub fn push(&mut self, value: T) {
63        let mut entry = Entry::Occupied(value);
64        if self.len < self.inner.len() {
65            std::mem::swap(&mut entry, &mut self.inner[self.len]);
66        } else {
67            self.inner.push(entry);
68        }
69        self.len += 1;
70    }
71
72    /// Pop a value off the stack
73    pub fn pop(&mut self) -> Option<T> {
74        if self.is_empty() {
75            return None;
76        }
77
78        let mut entry = Entry::Empty;
79        self.len -= 1;
80        std::mem::swap(&mut entry, &mut self.inner[self.len]);
81        let value = entry
82            .into_value()
83            .expect("the length would be zero if there wasn't a value present");
84        Some(value)
85    }
86
87    pub fn get(&self, index: usize) -> Option<&T> {
88        let entry = self.inner.get(index)?;
89        match entry {
90            Entry::Occupied(val) => Some(val),
91            Entry::Empty => None,
92        }
93    }
94
95    /// Swap out a value in the stack at a given location.
96    ///
97    /// # Panics
98    ///
99    /// Panics if the index contains an empty slot
100    #[must_use]
101    pub fn swap(&mut self, index: usize, new_value: T) -> T {
102        let mut entry = Entry::Occupied(new_value);
103        std::mem::swap(&mut self.inner[index], &mut entry);
104        match entry {
105            Entry::Occupied(val) => val,
106            Entry::Empty => panic!("tried to take value from an empty entry"),
107        }
108    }
109
110    /// Create an iterator over the values on the stack
111    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> + '_ {
112        self.inner[..self.len].iter().filter_map(Entry::to_value_ref)
113    }
114
115    /// Create an iterator over the values on the stack
116    pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut T> + '_ {
117        self.inner[..self.len].iter_mut().filter_map(Entry::to_value_mut)
118    }
119
120    /// A draining iterator over the values on the stack.
121    /// ```
122    /// # use anathema_store::stack::Stack;
123    /// let mut stack = Stack::empty();
124    /// stack.push(1);
125    /// stack.push(2);
126    ///
127    /// assert_eq!(stack.drain().next(), Some(2));
128    /// assert!(stack.is_empty());
129    /// ```
130    pub fn drain(&mut self) -> StackDrain<T, impl DoubleEndedIterator<Item = T> + '_> {
131        let len = std::mem::take(&mut self.len);
132        let iter = self.inner[..len]
133            .iter_mut()
134            .rev()
135            .filter_map(|e| match std::mem::take(e) {
136                Entry::Occupied(value) => Some(value),
137                Entry::Empty => unreachable!(),
138            });
139
140        StackDrain { inner: iter, len }
141    }
142
143    /// Clear the values from the stack
144    pub fn clear(&mut self) {
145        self.inner[..self.len].fill_with(|| Entry::Empty);
146        self.len = 0;
147    }
148
149    /// The stack will contains allocated memory even if `is_empty` returns true.k
150    pub fn is_empty(&self) -> bool {
151        self.len == 0
152    }
153
154    pub fn len(&self) -> usize {
155        self.len
156    }
157
158    pub fn reserve(&mut self, len: usize) {
159        if self.len >= len {
160            return;
161        }
162
163        self.inner.resize_with(len, || Entry::Empty);
164    }
165
166    /// Drain all the values into another stack.
167    /// Prefer `Self::drain_copy_into` if `T` is `Copy`.
168    /// It might be marginally faster.
169    pub fn drain_into(&mut self, local: &mut Stack<T>) {
170        if self.is_empty() {
171            return;
172        }
173        local.reserve(self.len);
174        self.drain().rev().for_each(|ent| local.push(ent));
175    }
176}
177
178impl<T: PartialEq> Stack<T> {
179    /// Check if the stack contains a given value
180    pub fn contains(&self, value: &T) -> bool {
181        self.iter().any(|v| v == value)
182    }
183}
184
185impl<T: Copy> Stack<T> {
186    /// Drain the values into another stack.
187    /// This function can be marginally faster than `Self::drain_into` but
188    /// depends on `T` being `Copy`.
189    pub fn drain_copy_into(&mut self, local: &mut Stack<T>) {
190        if self.is_empty() {
191            return;
192        }
193        local.reserve(self.len);
194        local.len = self.len;
195        local.inner[..self.len].copy_from_slice(&self.inner[..self.len]);
196        self.clear();
197    }
198}
199
200impl<T> FromIterator<T> for Stack<T> {
201    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
202        let inner = iter.into_iter().map(|val| Entry::Occupied(val)).collect::<Vec<_>>();
203
204        Self {
205            len: inner.len(),
206            inner,
207        }
208    }
209}
210
211/// A draining iterator over the stack.
212/// Any values that wasn't consumed will be dropped
213/// along with the iterator.
214pub struct StackDrain<T, I>
215where
216    I: DoubleEndedIterator<Item = T>,
217{
218    inner: I,
219    len: usize,
220}
221
222impl<T, I> StackDrain<T, I>
223where
224    I: DoubleEndedIterator<Item = T>,
225{
226    pub fn len(&self) -> usize {
227        self.len
228    }
229}
230
231impl<T, I> Iterator for StackDrain<T, I>
232where
233    I: DoubleEndedIterator<Item = T>,
234{
235    type Item = T;
236
237    fn next(&mut self) -> Option<Self::Item> {
238        self.inner.next()
239    }
240}
241
242impl<T, I> DoubleEndedIterator for StackDrain<T, I>
243where
244    I: DoubleEndedIterator<Item = T>,
245{
246    fn next_back(&mut self) -> Option<Self::Item> {
247        self.inner.next_back()
248    }
249}
250
251impl<T, I> Drop for StackDrain<T, I>
252where
253    I: DoubleEndedIterator<Item = T>,
254{
255    fn drop(&mut self) {
256        self.for_each(|_| {});
257    }
258}
259
260#[cfg(test)]
261mod test {
262    use super::*;
263
264    #[test]
265    fn drain() {
266        let mut stack = Stack::empty();
267        stack.push(1);
268        stack.push(2);
269
270        let mut iter = stack.drain();
271        assert_eq!(2, iter.next().unwrap());
272        drop(iter);
273
274        assert_eq!(stack.inner, vec![Entry::Empty, Entry::Empty]);
275    }
276}