Skip to main content

ts_array256/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3#![forbid(unsafe_code)]
4
5extern crate alloc;
6#[cfg(test)]
7extern crate std;
8
9use core::fmt::{self, Debug};
10
11use ts_bitset::Bitset256;
12
13mod storage;
14pub use storage::*;
15
16/// A sparse array of 256 elements.
17///
18/// Indexed by [`Bitset256`] and backed by a configurable [`ArrayStorage`],
19/// which is a contiguous chunk of memory holding up to 256 values.
20#[derive(Clone, PartialEq, Eq, Hash)]
21pub struct Array256<S> {
22    bitset: Bitset256,
23    storage: S,
24}
25
26impl<S> Debug for Array256<S>
27where
28    S: ArrayStorage + AsRef<[S::T]>,
29    S::T: Debug,
30{
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        f.debug_map()
33            .entries(self.bitset.bits().zip(self.storage.iter()))
34            .finish()
35    }
36}
37
38impl<S> Default for Array256<S>
39where
40    S: Default,
41{
42    #[inline]
43    fn default() -> Self {
44        Self {
45            bitset: Bitset256::EMPTY,
46            storage: Default::default(),
47        }
48    }
49}
50
51impl<S> Array256<S>
52where
53    S: ConstEmptyArrayStorage,
54{
55    /// The empty array.
56    pub const EMPTY: Self = Self {
57        bitset: Bitset256::EMPTY,
58        storage: S::EMPTY,
59    };
60}
61
62impl<S> Array256<S>
63where
64    S: ArrayStorage,
65{
66    /// Check if the specified index is occupied.
67    pub fn test(&self, index: u8) -> bool {
68        self.bitset.test(index as usize)
69    }
70
71    /// Check whether this array's occupancy intersects with the given bitset.
72    pub fn intersects(&self, other: &Bitset256) -> bool {
73        self.bitset.intersects(other)
74    }
75
76    /// Check whether this array's occupancy intersects with the given bitset, and if so,
77    /// the highest set bit of that intersection.
78    pub fn intersection_top(&self, other: &Bitset256) -> Option<u8> {
79        self.bitset.intersection_top(other).map(|x| x as u8)
80    }
81
82    /// Return whether this array has no elements.
83    pub const fn is_empty(&self) -> bool {
84        self.bitset.is_empty()
85    }
86
87    // PERF(npry): delegate to `storage` because it doesn't need to count bits in the
88    // bitset, just returns the inner Vec::len (a usize). This gets computed a lot -- saw a
89    // substantial impact in benchmarks.
90    /// Get the number of items in this array.
91    pub fn len(&self) -> usize
92    where
93        S: AsRef<[S::T]>,
94    {
95        self.storage.len()
96    }
97
98    /// Get a reference to the element at the specified index, if there is one.
99    pub fn get(&self, index: u8) -> Option<&S::T>
100    where
101        S: AsRef<[S::T]>,
102    {
103        if self.test(index) {
104            Some(&self.storage.as_ref()[self.storage_index(index)])
105        } else {
106            None
107        }
108    }
109
110    /// Get a mutable reference to the element at the specified index, if there
111    /// is one.
112    pub fn get_mut(&mut self, index: u8) -> Option<&mut S::T>
113    where
114        S: AsMut<[S::T]>,
115    {
116        if self.test(index) {
117            let storage_index = self.storage_index(index);
118            Some(&mut self.storage.as_mut()[storage_index])
119        } else {
120            None
121        }
122    }
123
124    /// Insert an item at the specified index. Returns the previous occupant if
125    /// there was one.
126    pub fn insert(&mut self, index: u8, element: S::T) -> Option<S::T>
127    where
128        S: AsMut<[S::T]>,
129    {
130        if self.test(index) {
131            let storage_idx = self.storage_index(index);
132
133            return Some(core::mem::replace(
134                &mut self.storage.as_mut()[storage_idx],
135                element,
136            ));
137        }
138
139        // order matters: set the value in bitset first so that storage_index is valid
140        self.bitset.set(index as _);
141        self.storage.insert(self.storage_index(index), element);
142
143        None
144    }
145
146    /// Remove an item by index.
147    pub fn remove(&mut self, index: u8) -> Option<S::T>
148    where
149        S: AsRef<[S::T]>,
150    {
151        if self.storage.len() == 0 || !self.test(index) {
152            return None;
153        }
154
155        // order matters: get the storage_index before we remove the item from the
156        // bitset
157        let storage_idx = self.storage_index(index);
158        let value = self.storage.remove(storage_idx);
159
160        self.bitset.clear(index as _);
161
162        Some(value)
163    }
164
165    /// Clear the array.
166    pub fn clear(&mut self) {
167        self.bitset = Bitset256::EMPTY;
168        self.storage.clear();
169    }
170
171    /// Get a reference to the internal [`Bitset256`] which stores the occupied
172    /// storage indices.
173    #[inline]
174    pub const fn bitset(&self) -> &Bitset256 {
175        &self.bitset
176    }
177
178    /// Calculate the index at which item `idx` is stored in the internal `Vec`.
179    ///
180    /// Assumes that the bitset has _already_ been populated with the item at
181    /// `idx`, may panic otherwise.
182    #[inline]
183    const fn storage_index(&self, idx: u8) -> usize {
184        self.bitset.rank256(idx as _) - 1
185    }
186
187    /// Iterate over all occupied entries in the array.
188    #[inline]
189    pub fn iter(&self) -> impl Iterator<Item = (u8, &S::T)>
190    where
191        S: AsRef<[S::T]>,
192    {
193        self.bitset.bits().map(|x| x as u8).zip(self.storage.iter())
194    }
195
196    /// Iterate over occupied entries in the array starting after index `n`.
197    #[inline]
198    pub fn iter_after(&self, n: u8) -> impl Iterator<Item = (u8, &S::T)>
199    where
200        S: AsRef<[S::T]>,
201    {
202        self.bitset.bits_after(n).map(|idx| {
203            (
204                idx as u8,
205                &self.storage.as_ref()[self.storage_index(idx as _)],
206            )
207        })
208    }
209
210    /// Iterate over mutable references to all occupied entries in the array.
211    #[inline]
212    pub fn iter_mut(&mut self) -> impl Iterator<Item = (u8, &mut S::T)>
213    where
214        S: AsMut<[S::T]>,
215    {
216        self.bitset
217            .bits()
218            .map(|x| x as u8)
219            .zip(self.storage.iter_mut())
220    }
221
222    /// Provide a [`Debug`] instance for this value when `T` is not necessarily
223    /// `Debug`.
224    #[inline]
225    pub fn custom_storage_fmt<'slf, 'f, U>(
226        &'slf self,
227        f: &'f dyn Fn(&'slf S::T) -> U,
228    ) -> impl Debug + 'slf
229    where
230        'f: 'slf,
231        U: Debug + 'slf,
232        S: AsRef<[S::T]>,
233    {
234        struct CustomFmt<'slf, 'f, S, U>
235        where
236            S: ArrayStorage,
237        {
238            ary: &'slf Array256<S>,
239            f: &'f dyn Fn(&'slf S::T) -> U,
240        }
241
242        impl<'slf, 'f, S, U> Debug for CustomFmt<'slf, 'f, S, U>
243        where
244            'f: 'slf,
245            S: ArrayStorage + AsRef<[S::T]>,
246            U: Debug + 'slf,
247        {
248            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249                f.debug_map()
250                    .entries(
251                        self.ary
252                            .bitset
253                            .bits()
254                            .zip(self.ary.storage.iter().map(self.f)),
255                    )
256                    .finish()
257            }
258        }
259
260        CustomFmt { ary: self, f }
261    }
262
263    /// Clone self with a custom function supporting clone of &T.
264    #[inline]
265    pub fn clone_with(&self, f: &dyn Fn(&S::T) -> S::T) -> Self
266    where
267        S: FromIterator<S::T>,
268        S: AsRef<[S::T]>,
269    {
270        Self {
271            bitset: self.bitset,
272            storage: self.storage.iter().map(f).collect(),
273        }
274    }
275}
276
277impl<S> core::ops::Index<u8> for Array256<S>
278where
279    S: ArrayStorage + AsRef<[S::T]>,
280{
281    type Output = S::T;
282
283    #[inline]
284    fn index(&self, index: u8) -> &Self::Output {
285        self.get(index).unwrap()
286    }
287}
288
289impl<S> core::ops::IndexMut<u8> for Array256<S>
290where
291    S: ArrayStorage + AsRef<[S::T]> + AsMut<[S::T]>,
292{
293    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
294        self.get_mut(index).unwrap()
295    }
296}
297
298impl<S> FromIterator<(u8, S::T)> for Array256<S>
299where
300    S: ConstEmptyArrayStorage + AsMut<[S::T]>,
301{
302    #[inline]
303    fn from_iter<I>(iter: I) -> Self
304    where
305        I: IntoIterator<Item = (u8, S::T)>,
306    {
307        let mut ary = Array256::<S>::EMPTY;
308
309        for (addr, item) in iter {
310            ary.insert(addr, item);
311        }
312
313        ary
314    }
315}
316
317#[cfg(test)]
318mod test {
319    use super::*;
320
321    type VecArray<T> = Array256<alloc::vec::Vec<T>>;
322
323    lazy_static::lazy_static! {
324        static ref IDX_FILLED: VecArray<u8> = {
325            let mut ary = VecArray::EMPTY;
326
327            for i in 0u8..=255 {
328                assert_eq!(None, ary.insert(i, i));
329            }
330
331            ary
332        };
333    }
334
335    #[test]
336    fn new_array() {
337        let ary = VecArray::<()>::default();
338
339        assert_eq!(ary.len(), 0);
340        assert!(ary.is_empty());
341    }
342
343    #[test]
344    fn len() {
345        let mut ary = IDX_FILLED.clone();
346        assert_eq!(256, ary.len());
347
348        assert_eq!(Some(255), ary.insert(255, 255));
349        assert_eq!(256, ary.len());
350
351        for i in 0u8..128 {
352            assert_eq!(Some(i), ary.remove(i));
353        }
354
355        assert_eq!(128, ary.len());
356    }
357
358    proptest::proptest! {
359        #[test]
360        fn get_remove(i: u8) {
361            let mut ary = IDX_FILLED.clone();
362            proptest::prop_assert_eq!(Some(&i), ary.get(i));
363            proptest::prop_assert_eq!(Some(i), ary.remove(i));
364            proptest::prop_assert_eq!(None, ary.get(i));
365        }
366
367        #[test]
368        fn remove_empty(i: u8) {
369            let mut ary = VecArray::<u8>::EMPTY;
370            proptest::prop_assert_eq!(None, ary.remove(i));
371        }
372    }
373}