123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- #![cfg(feature = "experimental_array_set")]
- // This was contributed by user `dhardy`! Big thanks.
- use super::{take, Array};
- use core::{
- borrow::Borrow,
- fmt,
- mem::swap,
- ops::{AddAssign, SubAssign},
- };
- /// Error resulting from attempting to insert into a full array
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
- pub struct InsertError;
- // TODO(when std): impl std::error::Error for InsertError {}
- impl fmt::Display for InsertError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "ArraySet: insertion failed")
- }
- }
- /// An array-backed set
- ///
- /// This set supports `O(n)` operations and has a fixed size, thus may fail to
- /// insert items. The potential advantage is a *really* small size.
- ///
- /// The set is backed by an array of type `A` and indexed by type `L`.
- /// The item type must support `Default`.
- /// Due to restrictions, `L` may be only `u8` or `u16`.
- #[derive(Clone, Debug, Default)]
- pub struct ArraySet<A: Array, L> {
- arr: A,
- len: L,
- }
- impl<A: Array + Default, L: From<u8>> ArraySet<A, L> {
- /// Constructs a new, empty, set
- #[inline]
- pub fn new() -> Self {
- ArraySet { arr: Default::default(), len: 0.into() }
- }
- }
- impl<A: Array, L: Copy + Into<usize>> ArraySet<A, L> {
- /// Constructs a new set from given inputs
- ///
- /// Panics if `len> arr.len()`.
- #[inline]
- pub fn from(arr: A, len: L) -> Self {
- if len.into() > A::CAPACITY {
- panic!("ArraySet::from(array, len): len > array.len()");
- }
- ArraySet { arr, len }
- }
- }
- impl<A: Array, L> ArraySet<A, L>
- where
- L: Copy + PartialEq + From<u8> + Into<usize>,
- {
- /// Returns the fixed capacity of the set
- #[inline]
- pub fn capacity(&self) -> usize {
- A::CAPACITY
- }
- /// Returns the number of elements in the set
- #[inline]
- pub fn len(&self) -> usize {
- self.len.into()
- }
- /// Returns true when the set contains no elements
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.len == 0.into()
- }
- /// Removes all elements
- #[inline]
- pub fn clear(&mut self) {
- self.len = 0.into();
- }
- /// Iterate over all contents
- #[inline]
- pub fn iter(&self) -> Iter<A::Item> {
- Iter { a: self.arr.as_slice(), i: 0 }
- }
- }
- impl<A: Array, L> ArraySet<A, L>
- where
- L: Copy + PartialOrd + AddAssign + SubAssign + From<u8> + Into<usize>,
- {
- /// Check whether the set contains `elt`
- #[inline]
- pub fn contains<Q: Eq + ?Sized>(&self, elt: &Q) -> bool
- where
- A::Item: Borrow<Q>,
- {
- self.get(elt).is_some()
- }
- /// Get a reference to a contained item matching `elt`
- pub fn get<Q: Eq + ?Sized>(&self, elt: &Q) -> Option<&A::Item>
- where
- A::Item: Borrow<Q>,
- {
- let len: usize = self.len.into();
- let arr = self.arr.as_slice();
- for i in 0..len {
- if arr[i].borrow() == elt {
- return Some(&arr[i]);
- }
- }
- None
- }
- /// Remove an item matching `elt`, if any
- pub fn remove<Q: Eq + ?Sized>(&mut self, elt: &Q) -> Option<A::Item>
- where
- A::Item: Borrow<Q>,
- {
- let len: usize = self.len.into();
- let arr = self.arr.as_slice_mut();
- for i in 0..len {
- if arr[i].borrow() == elt {
- let l1 = len - 1;
- if i < l1 {
- arr.swap(i, l1);
- }
- self.len -= L::from(1);
- return Some(take(&mut arr[l1]));
- }
- }
- None
- }
- /// Remove any items for which `f(item) == false`
- pub fn retain<F>(&mut self, mut f: F)
- where
- F: FnMut(&A::Item) -> bool,
- {
- let mut len = self.len;
- let arr = self.arr.as_slice_mut();
- let mut i = 0;
- while i < len.into() {
- if !f(&arr[i]) {
- len -= L::from(1);
- if i < len.into() {
- arr.swap(i, len.into());
- }
- } else {
- i += 1;
- }
- }
- self.len = len;
- }
- }
- impl<A: Array, L> ArraySet<A, L>
- where
- A::Item: Eq,
- L: Copy + PartialOrd + AddAssign + SubAssign + From<u8> + Into<usize>,
- {
- /// Insert an item
- ///
- /// Due to the fixed size of the backing array, insertion may fail.
- #[inline]
- pub fn insert(&mut self, elt: A::Item) -> Result<bool, InsertError> {
- if self.contains(&elt) {
- return Ok(false);
- }
- let len = self.len.into();
- let arr = self.arr.as_slice_mut();
- if len >= arr.len() {
- return Err(InsertError);
- }
- arr[len] = elt;
- self.len += L::from(1);
- Ok(true)
- }
- /* Hits borrow checker
- pub fn get_or_insert(&mut self, elt: A::Item) -> Result<&A::Item, InsertError> {
- if let Some(r) = self.get(&elt) {
- return Ok(r);
- }
- self.insert(elt)?;
- let len: usize = self.len.into();
- Ok(&self.arr.as_slice()[len - 1])
- }
- */
- /// Replace an item matching `elt` with `elt`, or insert `elt`
- ///
- /// Returns the replaced item, if any. Fails when there is no matching item
- /// and the backing array is full, preventing insertion.
- pub fn replace(
- &mut self,
- mut elt: A::Item,
- ) -> Result<Option<A::Item>, InsertError> {
- let len: usize = self.len.into();
- let arr = self.arr.as_slice_mut();
- for i in 0..len {
- if arr[i] == elt {
- swap(&mut arr[i], &mut elt);
- return Ok(Some(elt));
- }
- }
- if len >= arr.len() {
- return Err(InsertError);
- }
- arr[len] = elt;
- self.len += L::from(1);
- Ok(None)
- }
- }
- /// Type returned by [`ArraySet::iter`]
- pub struct Iter<'a, T> {
- a: &'a [T],
- i: usize,
- }
- impl<'a, T> ExactSizeIterator for Iter<'a, T> {
- #[inline]
- fn len(&self) -> usize {
- self.a.len() - self.i
- }
- }
- impl<'a, T> Iterator for Iter<'a, T> {
- type Item = &'a T;
- #[inline]
- fn next(&mut self) -> Option<Self::Item> {
- if self.i < self.a.len() {
- let i = self.i;
- self.i += 1;
- Some(&self.a[i])
- } else {
- None
- }
- }
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let len = self.len();
- (len, Some(len))
- }
- }
- #[cfg(test)]
- mod test {
- use super::*;
- use core::mem::size_of;
- #[test]
- fn test_size() {
- assert_eq!(size_of::<ArraySet<[i8; 7], u8>>(), 8);
- }
- #[test]
- fn test() {
- let mut set: ArraySet<[i8; 7], u8> = ArraySet::new();
- assert_eq!(set.capacity(), 7);
- assert_eq!(set.insert(1), Ok(true));
- assert_eq!(set.insert(5), Ok(true));
- assert_eq!(set.insert(6), Ok(true));
- assert_eq!(set.len(), 3);
- assert_eq!(set.insert(5), Ok(false));
- assert_eq!(set.len(), 3);
- assert_eq!(set.replace(1), Ok(Some(1)));
- assert_eq!(set.replace(2), Ok(None));
- assert_eq!(set.len(), 4);
- assert_eq!(set.insert(3), Ok(true));
- assert_eq!(set.insert(4), Ok(true));
- assert_eq!(set.insert(7), Ok(true));
- assert_eq!(set.insert(8), Err(InsertError));
- assert_eq!(set.len(), 7);
- assert_eq!(set.replace(9), Err(InsertError));
- assert_eq!(set.remove(&3), Some(3));
- assert_eq!(set.len(), 6);
- set.retain(|x| *x == 3 || *x == 6);
- assert_eq!(set.len(), 1);
- assert!(!set.contains(&3));
- assert!(set.contains(&6));
- }
- }
|