bufferring/masking/
mod.rs

1//! A ring buffer for power-of-two capacities.
2
3use core::fmt::{self, Debug, Display};
4use core::num::Wrapping;
5
6use crate::{storage::Slot, RingBuffer, Storage};
7
8pub mod prop;
9
10mod tests;
11
12/// A ring buffer for power-of-two capacities.
13///
14/// When the capacity is a power of two, wrapping out-of-bound indices into the
15/// valid range simply requires a binary AND operation (known as masking); it is
16/// much faster than a general remainder computation.  This type requires that
17/// the capacity be a power of two (which is a fairly common use case), and uses
18/// masking liberally to simplify internal control logic.
19pub struct MaskingBuffer<S: Storage + ?Sized> {
20    /// The current offset.
21    ///
22    /// This points to the first initialized item in the data buffer (if any).
23    /// It should be interpreted modulo the buffer capacity.
24    cur: Wrapping<usize>,
25
26    /// The number of initialized items.
27    ///
28    /// If this is equal to the buffer capacity, then the buffer is full; adding
29    /// a new item will drop the oldest item to make space.
30    ///
31    /// This value, plus the current offset, indicates where the next-added item
32    /// will be placed in the data buffer.
33    len: usize,
34
35    /// The underlying data buffer.
36    ///
37    /// This stores the actual items, and is a generic parameter so that they
38    /// can be stored at an arbitrary location (e.g. on the stack or heap).
39    data: S,
40}
41
42// TODO: Provide emplacement for non-Sized storages.
43
44impl<S: Storage> MaskingBuffer<S> {
45    /// Create a new [`MaskingBuffer`].
46    ///
47    /// If the given storage's capacity is not a power of two, [`Err`] will be
48    /// returned.
49    pub fn new(storage: S) -> Result<Self, Error> {
50        if storage.cap().is_power_of_two() {
51            // SAFETY: We have verified that the capacity is valid.
52            Ok(unsafe { Self::new_unchecked(storage) })
53        } else {
54            Err(Error::NotPowerOfTwo)
55        }
56    }
57
58    /// Create a new [`MaskingBuffer`], assuming that the given capacity is a
59    /// power of two.
60    ///
61    /// If this is called with a capacity that is not a power of two, undefined
62    /// behaviour will occur.
63    pub unsafe fn new_unchecked(storage: S) -> Self {
64        Self { cur: Wrapping(0), len: 0, data: storage }
65    }
66}
67
68impl<S: Storage + ?Sized> MaskingBuffer<S> {
69    /// Mask the given offset by the capacity.
70    fn mask(&self, off: Wrapping<usize>) -> usize {
71        off.0 & (self.cap() - 1)
72    }
73}
74
75impl<S: Storage + ?Sized> RingBuffer for MaskingBuffer<S> {
76    type Item = S::Item;
77
78    fn cap(&self) -> usize {
79        self.data.cap()
80    }
81
82    fn len(&self) -> usize {
83        self.len
84    }
85
86    fn get(&self, off: usize) -> Option<&Self::Item> {
87        if off >= self.len { return None; }
88        // SAFETY:
89        // - 'mask()' always returns a valid index into the buffer.
90        // - 'off' is in range, so it refers to an initialized element.
91        let off = self.mask(self.cur + Wrapping(off));
92        Some(unsafe { self.data.get().get_unchecked(off).get_ref() })
93    }
94
95    fn get_mut(&mut self, off: usize) -> Option<&mut Self::Item> {
96        if off >= self.len { return None; }
97        // SAFETY:
98        // - 'mask()' always returns a valid index into the buffer.
99        // - 'off' is in range, so it refers to an initialized element.
100        let off = self.mask(self.cur + Wrapping(off));
101        Some(unsafe { self.data.get_mut().get_unchecked_mut(off).get_mut() })
102    }
103
104    unsafe fn get_disjoint_mut(&self, off: usize) -> &mut Self::Item {
105        // SAFETY:
106        // - 'mask()' always returns a valid index into the buffer.
107        // - The caller guarantees that 'off' is in range.
108        // - The caller guarantees that this item is not already in use.
109        let off = self.mask(self.cur + Wrapping(off));
110        unsafe { self.data.get().get_unchecked(off).get_int_mut() }
111    }
112
113    fn enqueue(&mut self, item: Self::Item) -> Option<Self::Item> {
114        let is_full = self.is_full();
115        // SAFETY:
116        // - 'mask()' always returns a valid index into the buffer.
117        let off = self.mask(self.cur + Wrapping(self.len));
118        let ptr = unsafe { self.data.get_mut().get_unchecked_mut(off) };
119
120        let res = is_full.then(|| {
121            // SAFETY:
122            // - The buffer is full, so the slot is initialized.
123            self.len -= 1;
124            self.cur += 1;
125            unsafe { ptr.take() }
126        });
127
128        *ptr = Slot::new(item);
129
130        self.len += 1;
131
132        res
133    }
134
135    fn dequeue(&mut self) -> Option<Self::Item> {
136        if self.is_empty() { return None; }
137
138        // SAFETY:
139        // - 'mask()' always returns a valid index into the buffer.
140        // - The buffer is not empty, so this (first) slot must be initialized.
141        let off = self.mask(self.cur);
142        let item = unsafe { self.data.get_mut().get_unchecked_mut(off).take() };
143
144        self.cur += 1;
145        self.len -= 1;
146        Some(item)
147    }
148
149    fn skip_one(&mut self) {
150        if self.is_empty() { return; }
151
152        // SAFETY:
153        // - 'mask()' always returns a valid index into the buffer.
154        // - The buffer is not empty, so this (first) slot must be initialized.
155        let off = self.mask(self.cur + Wrapping(self.len));
156        unsafe { self.data.get_mut().get_unchecked_mut(off).drop_in_place(); }
157
158        self.cur += 1;
159        self.len -= 1;
160    }
161}
162
163impl<T: Clone, S: Storage<Item = T> + Clone> Clone for MaskingBuffer<S> {
164    fn clone(&self) -> Self {
165        // SAFETY: A `MaskingBuffer` with the same storage already exists.
166        let mut res = unsafe { Self::new_unchecked(self.data.clone()) };
167        for item in self.iter() {
168            res.enqueue(item.clone());
169        }
170        res
171    }
172}
173
174impl<S: Storage> Debug for MaskingBuffer<S>
175where S: Debug, S::Item: Debug {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        struct Items<'a, S: Storage>(&'a MaskingBuffer<S>);
178
179        impl<'a, S: Storage> Debug for Items<'a, S>
180        where S::Item: Debug {
181            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182                f.debug_list().entries(self.0.iter()).finish()
183            }
184        }
185
186        f.debug_struct("MaskingBuffer")
187            .field("cur", &self.cur)
188            .field("len", &self.len)
189            .field("data", &self.data)
190            .field("items", &Items(self))
191            .finish()
192    }
193}
194
195/// Errors for [`MaskingBuffer`].
196#[derive(Clone, PartialEq, Eq, Debug)]
197pub enum Error {
198    /// An attempt was made to create a [`MaskingBuffer`] with a capacity that
199    /// is not a power of two.
200    NotPowerOfTwo,
201}
202
203impl Display for Error {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        match self {
206            Self::NotPowerOfTwo => write!(f,
207                "An attempt was made to create a `MaskingBuffer` with a \
208                capacity that is not a power of two"),
209        }
210    }
211}