holodeque/
meta.rs

1use core::{num::NonZeroUsize, ops::Range};
2
3use crate::DequeEnd;
4
5/// Metadata tracking the layout of the deque's backing array.
6#[derive(Copy, Clone, Debug)]
7pub enum MetaLayout {
8    /// The deque is empty.
9    Empty,
10
11    /// The first item of the deque occurs before the last item of the deque in
12    /// the backing array.
13    Linear {
14        /// The index of the first item of the deque.
15        first: usize,
16
17        /// The number of items in the deque.
18        len: NonZeroUsize,
19    },
20
21    /// The first item of the deque occurs after the last item of the deque in
22    /// the backing array.
23    Wrapped {
24        /// The length of the wrapped portion of the deque.
25        ///
26        /// The wrapped portion begins at index 0 in the backing array.
27        wrap_len: NonZeroUsize,
28
29        /// The length of the unused portion of the backing array.
30        gap_len: usize,
31    },
32}
33
34/// A trait for deque layout metadata.
35pub trait Meta: Clone + Sized {
36    /// Returns the capacity of the deque.
37    fn capacity(&self) -> usize;
38
39    /// Returns the layout of the deque's backing store.
40    fn layout(&self) -> MetaLayout;
41
42    /// Sets the layout of the deque's backing store.
43    fn set_layout(&mut self, layout: MetaLayout);
44
45    /// Returns the number of elements in the deque.
46    fn len(&self) -> usize {
47        match self.layout() {
48            MetaLayout::Empty => 0,
49            MetaLayout::Linear { len, .. } => {
50                debug_assert!(len.get() <= self.capacity());
51                len.get()
52            }
53            MetaLayout::Wrapped { gap_len, .. } => {
54                let len = self.capacity() - gap_len;
55                debug_assert!(len <= self.capacity());
56                len
57            }
58        }
59    }
60
61    fn as_ranges(&self) -> (Range<usize>, Range<usize>) {
62        match self.layout() {
63            MetaLayout::Empty => (0..0, 0..0),
64            MetaLayout::Linear { first, len } => (first..first + len.get(), 0..0),
65            MetaLayout::Wrapped { wrap_len, gap_len } => {
66                let start = wrap_len.get() + gap_len;
67                (start..self.len(), 0..wrap_len.get())
68            }
69        }
70    }
71
72    /// Removes all indices from the deque, returning an iterator over the
73    /// removed indices.
74    fn clear(&mut self) -> MetaDrain<Self> {
75        let drain = MetaDrain {
76            meta: self.clone(),
77            remaining: self.len(),
78            end: DequeEnd::Front,
79        };
80
81        self.set_layout(MetaLayout::Empty);
82
83        drain
84    }
85
86    /// Returns the index of the first element of the deque.
87    ///
88    /// If the deque is empty, `None` is returned.
89    fn front(&self) -> Option<usize> {
90        match self.layout() {
91            MetaLayout::Empty => None,
92            MetaLayout::Linear { first, .. } => {
93                debug_assert!(first < self.capacity());
94                Some(first)
95            }
96            MetaLayout::Wrapped { wrap_len, gap_len } => {
97                let first = wrap_len.get() + gap_len;
98                debug_assert!(first < self.capacity());
99                Some(first)
100            }
101        }
102    }
103
104    /// Returns the index of the last element of the deque.
105    ///
106    /// If the deque is empty, `None` is returned.
107    fn back(&self) -> Option<usize> {
108        match self.layout() {
109            MetaLayout::Empty => None,
110            MetaLayout::Linear { first, len } => {
111                let last = first + len.get() - 1;
112                debug_assert!(last < self.capacity());
113                Some(last)
114            }
115            MetaLayout::Wrapped { wrap_len, .. } => {
116                let last = wrap_len.get() - 1;
117                debug_assert!(last < self.capacity());
118                Some(last)
119            }
120        }
121    }
122
123    /// Reserves an index at the front of the deque.
124    fn reserve_front(&mut self) -> Option<usize> {
125        if self.capacity() == 0 {
126            return None;
127        }
128
129        match self.layout() {
130            MetaLayout::Empty => {
131                self.set_layout(MetaLayout::Linear {
132                    first: self.capacity() - 1,
133                    len: NonZeroUsize::new(1).unwrap(),
134                });
135
136                Some(self.capacity() - 1)
137            }
138
139            MetaLayout::Linear { len, .. } if len.get() == self.capacity() => None,
140
141            MetaLayout::Linear { first: 0, len } => {
142                self.set_layout(MetaLayout::Wrapped {
143                    wrap_len: NonZeroUsize::new(1).unwrap(),
144                    gap_len: self.capacity() - (len.get() + 1),
145                });
146
147                Some(self.capacity() - 1)
148            }
149
150            MetaLayout::Linear { first, len } => {
151                let new_first = first - 1;
152
153                self.set_layout(MetaLayout::Linear {
154                    first: new_first,
155                    len: NonZeroUsize::new(len.get() + 1).unwrap(),
156                });
157
158                Some(new_first)
159            }
160
161            // If gap has zero len, the deque is full.
162            MetaLayout::Wrapped { gap_len: 0, .. } => None,
163
164            MetaLayout::Wrapped { wrap_len, gap_len } => {
165                let new_gap_len = gap_len - 1;
166
167                self.set_layout(MetaLayout::Wrapped {
168                    wrap_len,
169                    gap_len: new_gap_len,
170                });
171
172                Some(wrap_len.get() + new_gap_len)
173            }
174        }
175    }
176
177    /// Reserves an index at the back of the deque.
178    fn reserve_back(&mut self) -> Option<usize> {
179        if self.capacity() == 0 {
180            return None;
181        }
182
183        match self.layout() {
184            MetaLayout::Empty => {
185                self.set_layout(MetaLayout::Linear {
186                    first: 0,
187                    len: NonZeroUsize::new(1).unwrap(),
188                });
189
190                Some(0)
191            }
192
193            MetaLayout::Linear { len, .. } if len.get() == self.capacity() => None,
194
195            MetaLayout::Linear { first, len } if first + len.get() == self.capacity() => {
196                self.set_layout(MetaLayout::Wrapped {
197                    wrap_len: NonZeroUsize::new(1).unwrap(),
198                    gap_len: self.capacity() - (len.get() + 1),
199                });
200
201                Some(0)
202            }
203
204            MetaLayout::Linear { first, len } => {
205                let reserved = first + len.get();
206
207                self.set_layout(MetaLayout::Linear {
208                    first,
209                    len: NonZeroUsize::new(len.get() + 1).unwrap(),
210                });
211
212                Some(reserved)
213            }
214
215            MetaLayout::Wrapped { gap_len: 0, .. } => None,
216
217            MetaLayout::Wrapped { wrap_len, gap_len } => {
218                let reserved = wrap_len.get();
219
220                self.set_layout(MetaLayout::Wrapped {
221                    wrap_len: NonZeroUsize::new(wrap_len.get() + 1).unwrap(),
222                    gap_len: gap_len - 1,
223                });
224
225                Some(reserved)
226            }
227        }
228    }
229
230    /// Frees an index at the front of the deque.
231    fn free_front(&mut self) -> Option<usize> {
232        if self.capacity() == 0 {
233            return None;
234        }
235
236        match self.layout() {
237            MetaLayout::Empty => None,
238
239            MetaLayout::Linear { first, len } => {
240                let freed = first;
241
242                let new_layout = match NonZeroUsize::new(len.get() - 1) {
243                    Some(new_len) => MetaLayout::Linear {
244                        first: first + 1,
245                        len: new_len,
246                    },
247
248                    None => MetaLayout::Empty,
249                };
250
251                self.set_layout(new_layout);
252
253                Some(freed)
254            }
255
256            MetaLayout::Wrapped { wrap_len, gap_len } => {
257                let freed = wrap_len.get() + gap_len;
258
259                let new_layout = if freed == self.capacity() - 1 {
260                    MetaLayout::Linear {
261                        first: 0,
262                        len: wrap_len,
263                    }
264                } else {
265                    MetaLayout::Wrapped {
266                        wrap_len,
267                        gap_len: gap_len + 1,
268                    }
269                };
270
271                self.set_layout(new_layout);
272
273                Some(freed)
274            }
275        }
276    }
277
278    /// Drains `n` indices from the front of the deque.
279    fn drain_front(&mut self, n: usize) -> Option<MetaDrain<Self>> {
280        // This checks that n <= len.
281        let drain = MetaDrain::front(self.clone(), n)?;
282
283        match self.layout() {
284            // n must be zero, so this is a no-op.
285            MetaLayout::Empty => (),
286
287            MetaLayout::Linear { first, len } => match NonZeroUsize::new(len.get() - n) {
288                Some(new_len) => {
289                    self.set_layout(MetaLayout::Linear {
290                        first: first + n,
291                        len: new_len,
292                    });
293                }
294
295                None => {
296                    self.set_layout(MetaLayout::Empty);
297                }
298            },
299
300            MetaLayout::Wrapped { wrap_len, gap_len } => {
301                let front_len = self.capacity() - (wrap_len.get() + gap_len);
302
303                if n >= front_len {
304                    let first = n - front_len;
305
306                    match NonZeroUsize::new(wrap_len.get() - first) {
307                        Some(new_len) => {
308                            self.set_layout(MetaLayout::Linear {
309                                first,
310                                len: new_len,
311                            });
312                        }
313
314                        None => self.set_layout(MetaLayout::Empty),
315                    }
316                } else {
317                    self.set_layout(MetaLayout::Wrapped {
318                        wrap_len,
319                        gap_len: gap_len + n,
320                    });
321                }
322            }
323        }
324
325        Some(drain)
326    }
327
328    /// Frees an index at the back of the deque.
329    fn free_back(&mut self) -> Option<usize> {
330        if self.capacity() == 0 {
331            return None;
332        }
333
334        match self.layout() {
335            MetaLayout::Empty => None,
336
337            MetaLayout::Linear { first, len } => {
338                let freed = first + len.get() - 1;
339
340                let new_layout = match NonZeroUsize::new(len.get() - 1) {
341                    Some(new_len) => MetaLayout::Linear {
342                        first,
343                        len: new_len,
344                    },
345                    None => MetaLayout::Empty,
346                };
347
348                self.set_layout(new_layout);
349
350                Some(freed)
351            }
352
353            MetaLayout::Wrapped { wrap_len, gap_len } => {
354                let (freed, new_layout) = match NonZeroUsize::new(wrap_len.get() - 1) {
355                    Some(new_wrap_len) => (
356                        new_wrap_len.get(),
357                        MetaLayout::Wrapped {
358                            wrap_len: new_wrap_len,
359                            gap_len: gap_len + 1,
360                        },
361                    ),
362
363                    None => (
364                        0,
365                        MetaLayout::Linear {
366                            first: gap_len + 1,
367                            len: NonZeroUsize::new(self.capacity() - (gap_len + 1)).unwrap(),
368                        },
369                    ),
370                };
371
372                self.set_layout(new_layout);
373
374                Some(freed)
375            }
376        }
377    }
378
379    /// Drains `n` indices from the back of the deque.
380    fn drain_back(&mut self, n: usize) -> Option<MetaDrain<Self>> {
381        let drain = MetaDrain::back(self.clone(), n)?;
382
383        match self.layout() {
384            MetaLayout::Empty => (),
385
386            MetaLayout::Linear { first, len } => match NonZeroUsize::new(len.get() - n) {
387                Some(new_len) => {
388                    self.set_layout(MetaLayout::Linear {
389                        first,
390                        len: new_len,
391                    });
392                }
393
394                None => self.set_layout(MetaLayout::Empty),
395            },
396
397            MetaLayout::Wrapped { wrap_len, gap_len } => {
398                if n >= wrap_len.get() {
399                    let total_len = self.capacity() - gap_len;
400
401                    let new_layout = match NonZeroUsize::new(total_len - n) {
402                        Some(new_len) => MetaLayout::Linear {
403                            first: wrap_len.get() + gap_len,
404                            len: new_len,
405                        },
406                        None => MetaLayout::Empty,
407                    };
408
409                    self.set_layout(new_layout);
410                } else {
411                    self.set_layout(MetaLayout::Wrapped {
412                        wrap_len: NonZeroUsize::new(wrap_len.get() - n).unwrap(),
413                        gap_len: gap_len + n,
414                    });
415                }
416            }
417        }
418
419        Some(drain)
420    }
421}
422
423pub struct MetaDrain<M>
424where
425    M: Meta,
426{
427    meta: M,
428    remaining: usize,
429    end: DequeEnd,
430}
431
432impl<M> MetaDrain<M>
433where
434    M: Meta,
435{
436    /// Creates an iterator that drains `n` indices from the front of the deque.
437    ///
438    /// If `n` exceeds the number of items in the deque, `None` is returned.
439    pub fn front(meta: M, n: usize) -> Option<MetaDrain<M>> {
440        if n > meta.len() {
441            None
442        } else {
443            Some(MetaDrain {
444                meta,
445                remaining: n,
446                end: DequeEnd::Front,
447            })
448        }
449    }
450
451    /// Creates an iterator that drains `n` indices from the back of the deque.
452    ///
453    /// If `n` exceeds the number of items in the deque, `None` is returned.
454    pub fn back(meta: M, n: usize) -> Option<MetaDrain<M>> {
455        if n > meta.len() {
456            None
457        } else {
458            Some(MetaDrain {
459                meta,
460                remaining: n,
461                end: DequeEnd::Back,
462            })
463        }
464    }
465}
466
467impl<M> Iterator for MetaDrain<M>
468where
469    M: Meta,
470{
471    type Item = usize;
472
473    fn next(&mut self) -> Option<Self::Item> {
474        if self.remaining > 0 {
475            self.remaining -= 1;
476
477            let index = match self.end {
478                DequeEnd::Front => self.meta.free_front().unwrap(),
479                DequeEnd::Back => self.meta.free_back().unwrap(),
480            };
481
482            Some(index)
483        } else {
484            None
485        }
486    }
487
488    fn size_hint(&self) -> (usize, Option<usize>) {
489        (self.remaining, Some(self.remaining))
490    }
491}