diff --git a/doc/set.md b/doc/set.md new file mode 100644 index 00000000..1d7fd02d --- /dev/null +++ b/doc/set.md @@ -0,0 +1,12 @@ +# Automatically-Managed Index Set + +This module defines the [`BitSet`] collection as a useful wrapper over a +[`BitVec`]. + +A `BitVec` is a very efficient way of storing a set of [`usize`] values since +the various set operations can be easily represented using bit operations. +However, a `BitVec` is less ergonomic than a `BitSet` because of the need to +resize when inserting elements larger than any already in the set. + +[`BitSet`]: crate::set::BitSet +[`BitVec`]: crate::vec::BitVec diff --git a/doc/set/BitSet.md b/doc/set/BitSet.md new file mode 100644 index 00000000..a4039f06 --- /dev/null +++ b/doc/set/BitSet.md @@ -0,0 +1,70 @@ +# Packed-Bits Set + +This is a data structure that consists of an automatically managed [`BitVec`] +which stores a set of `usize` values as `true` bits in the `BitVec`. + +The main benefit of this structure is the automatic handling of the memory +backing the [`BitVec`], which must be resized to account for the sizes of data +inside it. If you know the bounds of your data ahead of time, you may prefer to +use a regular [`BitVec`] or even a [`BitArray`] instead, the latter of which +will be allocated on the stack instead of the heap. + +## Documentation Practices + +`BitSet` attempts to replicate the API of the standard-library `BTreeSet` type, +including inherent methods, trait implementations, and relationships with the +[`BitSet`] analogue. + +Items that are either direct ports, or renamed variants, of standard-library +APIs will have a `## Original` section that links to their standard-library +documentation. Items that map to standard-library APIs but have a different API +signature will also have an `## API Differences` section that describes what +the difference is, why it exists, and how to transform your code to fit it. For +example: + +## Original + +[`BTreeSet`](alloc::collections::BTreeSet) + +## API Differences + +As with all `bitvec` data structures, this takes two type parameters `` +that govern the bit-vector’s storage representation in the underlying memory, +and does *not* take a type parameter to govern what data type it stores (always +`usize`) + +### Accessing the internal [`BitVec`] + +Since `BitSet` is merely an API over the internal `BitVec`, you can freely +take ownership of the internal buffer or borrow the buffer as a `BitSlice`. + +However, since would be inconsistent with the set-style API, these require +dedicated methods instead of simple deref: + +```rust +use bitvec::prelude::*; +use bitvec::set::BitSet; + +fn mutate_bitvec(vec: &mut BitVec) { + // … +} + +fn read_bitslice(bits: &BitSlice) { + // … +} + +let mut bs: BitSet = BitSet::new(); +bs.insert(10); +bs.insert(20); +bs.insert(30); +read_bitslice(bs.as_bitslice()); +mutate_bitvec(bs.as_mut_bitvec()); +``` + +Since a `BitSet` requires no additional invariants over `BitVec`, any mutations +to the internal vec are allowed without restrictions. For more details on the +safety guarantees of [`BitVec`], see its specific documentation. + +[`BitArray`]: crate::array::BitArray +[`BitSet`]: crate::set::BitSet +[`BitVec`]: crate::vec::BitVec diff --git a/doc/set/iter.md b/doc/set/iter.md new file mode 100644 index 00000000..2a7ecea7 --- /dev/null +++ b/doc/set/iter.md @@ -0,0 +1,14 @@ +# Bit-Set Iteration + +This module provides iteration protocols for `BitSet`, including: + +- extension of existing bit-sets with new data +- collection of data into new bit-sets +- iteration over the contents of a bit-sets + +`BitSet` implements `Extend` and `FromIterator` for sources of `usize`. + +Since the implementation is the same for sets, the [`IterOnes`] iterator from +the `slice` module is used for the set iterator instead of a wrapper. + +[`IterOnes`]: crate::slice::IterOnes diff --git a/doc/set/iter/Range.md b/doc/set/iter/Range.md new file mode 100644 index 00000000..305d2bec --- /dev/null +++ b/doc/set/iter/Range.md @@ -0,0 +1,33 @@ +# Bit-Set Range Iteration + +This view iterates over the elements in a bit-set within a given range. It is +created by the [`BitSet::range`] method. + +## Original + +[`btree_map::Range`](alloc::collections::btree_map::Range) + +## API Differences + +Since the `usize` are not physically stored in the set, this yields `usize` +values instead of references. + +## Examples + +```rust +use bitvec::prelude::*; +use bitvec::set::BitSet; + +let mut bs: BitSet = BitSet::new(); +bs.insert(1); +bs.insert(2); +bs.insert(3); +bs.insert(4); +for val in bs.range(2..6) { + # #[cfg(feature = "std")] { + println!("{val}"); + # } +} +``` + +[`BitSet::range`]: crate::set::BitSet::range diff --git a/rustfmt-stable.toml b/rustfmt-stable.toml index 509ac5fd..a0f52ccc 100644 --- a/rustfmt-stable.toml +++ b/rustfmt-stable.toml @@ -13,7 +13,7 @@ # attr_fn_like_width = 70 # Leave implicit # chain_width = 60 # Leave implicit edition = "2018" -fn_args_layout = "Tall" +fn_params_layout = "Tall" # fn_call_width = 60 # Leave implicit force_explicit_abi = true hard_tabs = true diff --git a/rustfmt.toml b/rustfmt.toml index 5d210ea7..0d34beb4 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -14,7 +14,7 @@ # attr_fn_like_width = 70 # Leave implicit # chain_width = 60 # Leave implicit edition = "2018" -fn_args_layout = "Tall" +fn_params_layout = "Tall" # fn_call_width = 60 # Leave implicit force_explicit_abi = true hard_tabs = true @@ -69,7 +69,7 @@ normalize_comments = false normalize_doc_attributes = false overflow_delimited_expr = true reorder_impl_items = true -required_version = "1.5.1" +required_version = "1.6.0" skip_children = false space_after_colon = true space_before_colon = false diff --git a/src/lib.rs b/src/lib.rs index 462ec46c..5d09ddbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ pub mod mem; pub mod order; pub mod ptr; mod serdes; +pub mod set; pub mod slice; pub mod store; pub mod vec; diff --git a/src/set.rs b/src/set.rs new file mode 100644 index 00000000..fd8b2813 --- /dev/null +++ b/src/set.rs @@ -0,0 +1,188 @@ +#![doc = include_str!("../doc/set.md")] +#![cfg(feature = "alloc")] + +#[cfg(not(feature = "std"))] +use alloc::vec; +use core::ops; + +use wyz::comu::{ + Const, + Mut, +}; + +use crate::{ + boxed::BitBox, + order::{ + BitOrder, + Lsb0, + }, + ptr::BitPtr, + slice::BitSlice, + store::BitStore, + vec::BitVec, +}; + +mod api; +mod iter; +mod traits; + +pub use iter::Range; + +#[repr(transparent)] +#[doc = include_str!("../doc/set/BitSet.md")] +pub struct BitSet +where + T: BitStore, + O: BitOrder, +{ + inner: BitVec, +} + +/// Constructors. +impl BitSet +where + T: BitStore, + O: BitOrder, +{ + /// An empty bit-set with no backing allocation. + pub const EMPTY: Self = Self { + inner: BitVec::EMPTY, + }; + + /// Creates a new bit-set for a range of indices. + #[inline] + pub fn from_range(range: ops::Range) -> Self { + let mut inner = BitVec::with_capacity(range.end); + unsafe { + inner.set_len(range.end); + inner[.. range.start].fill(false); + inner[range.start ..].fill(true); + } + Self { inner } + } + + /// Constructs a new bit-set from an existing bit-vec. + #[inline] + pub fn from_bitvec(inner: BitVec) -> Self { + Self { inner } + } +} + +/// Converters. +impl BitSet +where + T: BitStore, + O: BitOrder, +{ + /// Explicitly views the bit-set as a bit-slice. + #[inline] + pub fn as_bitslice(&self) -> &BitSlice { + self.inner.as_bitslice() + } + + /// Explicitly views the bit-set as a mutable bit-slice. + #[inline] + pub fn as_mut_bitslice(&mut self) -> &mut BitSlice { + self.inner.as_mut_bitslice() + } + + /// Explicitly views the bit-set as a bit-vec. + #[inline] + pub fn as_bitvec(&self) -> &BitVec { + &self.inner + } + + /// Explicitly views the bit-set as a mutable bit-vec. + #[inline] + pub fn as_mut_bitvec(&mut self) -> &mut BitVec { + &mut self.inner + } + + /// Views the bit-set as a slice of its underlying memory elements. + #[inline] + pub fn as_raw_slice(&self) -> &[T] { + self.inner.as_raw_slice() + } + + /// Views the bit-set as a mutable slice of its underlying memory + /// elements. + #[inline] + pub fn as_raw_mut_slice(&mut self) -> &mut [T] { + self.inner.as_raw_mut_slice() + } + + /// Creates an unsafe shared bit-pointer to the start of the buffer. + /// + /// ## Original + /// + /// [`Vec::as_ptr`](alloc::vec::Vec::as_ptr) + /// + /// ## Safety + /// + /// You must initialize the contents of the underlying buffer before + /// accessing memory through this pointer. See the `BitPtr` documentation + /// for more details. + #[inline] + pub fn as_bitptr(&self) -> BitPtr { + self.inner.as_bitptr() + } + + /// Creates an unsafe writable bit-pointer to the start of the buffer. + /// + /// ## Original + /// + /// [`Vec::as_mut_ptr`](alloc::vec::Vec::as_mut_ptr) + /// + /// ## Safety + /// + /// You must initialize the contents of the underlying buffer before + /// accessing memory through this pointer. See the `BitPtr` documentation + /// for more details. + #[inline] + pub fn as_mut_bitptr(&mut self) -> BitPtr { + self.inner.as_mut_bitptr() + } + + /// Converts a bit-set into a boxed bit-slice. + /// + /// This may cause a reällocation to drop any excess capacity. + /// + /// ## Original + /// + /// [`Vec::into_boxed_slice`](alloc::vec::Vec::into_boxed_slice) + #[inline] + pub fn into_boxed_bitslice(self) -> BitBox { + self.inner.into_boxed_bitslice() + } + + /// Converts a bit-set into a bit-vec. + #[inline] + pub fn into_bitvec(self) -> BitVec { + self.inner + } +} + +/// Utilities. +impl BitSet +where + T: BitStore, + O: BitOrder, +{ + /// Shrinks the inner vector to the minimum size, without changing capacity. + #[inline] + fn shrink_inner(&mut self) { + match self.inner.last_one() { + Some(idx) => self.inner.truncate(idx + 1), + None => self.inner.clear(), + } + } + + /// Immutable shrink as a bitslice. + #[inline] + fn shrunken(&self) -> &BitSlice { + match self.inner.last_one() { + Some(idx) => &self.inner[.. idx + 1], + None => Default::default(), + } + } +} diff --git a/src/set/api.rs b/src/set/api.rs new file mode 100644 index 00000000..90eade08 --- /dev/null +++ b/src/set/api.rs @@ -0,0 +1,786 @@ +//! Port of the `BTreeSet` inherent API. + +use core::ops::{self,}; + +use super::{ + BitSet, + Range, +}; +use crate::{ + order::BitOrder, + slice::IterOnes, + store::BitStore, + vec::BitVec, +}; + +/// Port of the `BTreeSet` inherent API. +impl BitSet +where + T: BitStore, + O: BitOrder, +{ + /// Constructs a new, empty, bit-set. + /// + /// Does not allocate anything on its own. + /// + /// ## Original + /// + /// [`BTreeSet::new`](alloc::collections::BTreeSet::new) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let bs = BitSet::::new(); + /// assert!(bs.is_empty()); + /// ``` + #[inline] + pub fn new() -> Self { + Self::EMPTY + } + + /// Constructs a double-ended iterator over a sub-range of elements in the + /// set. + /// + /// ## Panics + /// + /// Panics if range `start > end`. + /// + /// ## Original + /// + /// [`BTreeSet::range`](alloc::collections::BTreeSet::range) + /// + /// ## API Differences + /// + /// Since bit-sets can only contain `usize`, the API has been restricted to + /// only accept standard ranges (like `1..10`) instead of all possible range + /// types. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// set.insert(3); + /// set.insert(5); + /// set.insert(8); + /// for elem in set.range(4..9) { + /// println!("{elem}"); + /// } + /// assert_eq!(Some(5), set.range(4..9).next()); + /// ``` + #[inline] + pub fn range(&self, range: ops::Range) -> Range<'_, T, O> { + let start = range.start; + let end = range.end; + assert!( + start <= end, + "range start ({}) less than range end ({})", + start, + end + ); + Range::new( + if end < self.inner.len() { + &self.inner[start .. end] + } + else { + &self.inner[start ..] + }, + start, + ) + } + + /* + /// Visits the elements representing the difference, i.e., + /// the elements that are in `self` but not in `other`, + /// in ascending order. + /// + /// ## Original + /// + /// [`BTreeSet::difference`](alloc::collections::BTreeSet::difference) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut a: BitSet = BitSet::new(); + /// a.insert(1); + /// a.insert(2); + /// + /// let mut b: BitSet = BitSet::new(); + /// b.insert(2); + /// b.insert(3); + /// + /// let diff: Vec<_> = a.difference(&b).cloned().collect(); + /// assert_eq!(diff, [1]); + /// ``` + #[inline] + pub fn difference<'a>(&'a self, other: &'a BitSet) -> Difference<'_, T, O> { + todo!() + } + + /// Visits the elements representing the symmetric difference, + /// i.e., the elements that are in `self` or in other but not in both, in ascending order. + /// + /// ## Original + /// + /// [`BTreeSet::symmetric_difference`](alloc::collections::BTreeSet::symmetric_difference) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut a: BitSet = BitSet::new(); + /// a.insert(1); + /// a.insert(2); + /// + /// let mut b: BitSet = BitSet::new(); + /// b.insert(2); + /// b.insert(3); + /// + /// let diff: Vec<_> = a.symmetric_difference(&b).cloned().collect(); + /// assert_eq!(diff, [1, 3]); + /// ``` + #[inline] + pub fn symmetric_difference<'a>(&'a self, other: &'a BitSet) -> SymmetricDifference<'_, T, O> { + todo!() + } + + /// Visits the elements representing the intersection, + /// i.e., the elements that are in both `self` and `other`, in ascending order. + /// + /// ## Original + /// + /// [`BTreeSet::intersection`](alloc::collections::BTreeSet::intersection) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut a: BitSet = BitSet::new(); + /// a.insert(1); + /// a.insert(2); + /// + /// let mut b: BitSet = BitSet::new(); + /// b.insert(2); + /// b.insert(3); + /// + /// let diff: Vec<_> = a.intersection(&b).cloned().collect(); + /// assert_eq!(diff, [2]); + /// ``` + #[inline] + pub fn intersection<'a>(&'a self, other: &'a BitSet) -> Intersection<'_, T, O> { + todo!() + } + + /// Visits the elements representing the union, + /// i.e., all the elements in both `self` or `other`, without duplicates, in ascending order. + /// + /// ## Original + /// + /// [`BTreeSet::union`](alloc::collections::BTreeSet::union) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut a: BitSet = BitSet::new(); + /// a.insert(1); + /// a.insert(2); + /// + /// let mut b: BitSet = BitSet::new(); + /// b.insert(2); + /// b.insert(3); + /// + /// let diff: Vec<_> = a.union(&b).cloned().collect(); + /// assert_eq!(diff, [1, 2, 3]); + /// ``` + #[inline] + pub fn union<'a>(&'a self, other: &'a BitSet) -> Union<'_, T, O> { + todo!() + } + */ + + /// Clears the set, removing all elements. + /// + /// ## Original + /// + /// [`BTreeSet::clear`](alloc::collections::BTreeSet::clear) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// set.insert(1); + /// set.clear(); + /// assert!(set.is_empty()); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } + + /// Returns `true` if the set contains the given element. + /// + /// ## Original + /// + /// [`BTreeSet::contains`](alloc::collections::BTreeSet::contains) + /// + /// ## API Differences + /// + /// Since bit-sets can only contain `usize`, the argument has been adjusted + /// to accept a `usize` value instead of a reference to be easier to use. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// set.insert(1); + /// set.insert(2); + /// set.insert(3); + /// assert!(set.contains(1)); + /// assert!(!set.contains(4)); + /// ``` + #[inline] + pub fn contains(&self, value: usize) -> bool { + if value >= self.inner.len() { + false + } + else { + self.inner[value] + } + } + + /* + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// ## Original + /// + /// [`BTreeSet::is_disjoint`](alloc::collections::BTreeSet::is_disjoint) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut a: BitSet = BitSet::new(); + /// a.insert(1); + /// a.insert(2); + /// a.insert(3); + /// + /// let mut b: BitSet = BitSet::new(); + /// assert!(a.is_disjoint(&b)); + /// b.insert(4); + /// assert!(a.is_disjoint(&b)); + /// b.insert(1); + /// assert!(!a.is_disjoint(&b)); + /// ``` + #[inline] + pub fn is_disjoint(&self, other: &BitSet) -> bool { + self.intersection(other).next().is_none() + } + + /// Returns `true` if the set is a subset of another, i.e., + /// `other` contains at least all the elements in `self`. + /// + /// ## Original + /// + /// [`BTreeSet::is_subset`](alloc::collections::BTreeSet::is_subset) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut sup: BitSet = BitSet::new(); + /// sup.insert(1); + /// sup.insert(2); + /// sup.insert(3); + /// + /// let mut set: BitSet = BitSet::new(); + /// assert!(set.is_subset(&sup)); + /// set.insert(2); + /// assert!(set.is_subset(&sup)); + /// set.insert(4); + /// assert!(!set.is_subset(&sup)); + /// ``` + #[inline] + pub fn is_subset(&self, other: &BitSet) -> bool { + todo!() + } + + /// Returns `true` if the set is a superset of another, i.e., + /// `self` contains at least all the elements in `other`. + /// + /// ## Original + /// + /// [`BTreeSet::is_superset`](alloc::collections::BTreeSet::is_superset) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut sub: BitSet = BitSet::new(); + /// sub.insert(1); + /// sub.insert(2); + /// sub.insert(3); + /// + /// let mut set: BitSet = BitSet::new(); + /// assert!(!set.is_superset(&sub)); + /// set.insert(0); + /// set.insert(1); + /// assert!(!set.is_superset(&sub)); + /// set.insert(2); + /// assert!(set.is_superset(&sub)); + /// ``` + #[inline] + pub fn is_superset(&self, other: &BitSet) -> bool { + todo!() + } + */ + + /// Returns the first element in the set, if any. + /// This element is always the minimum of all elements in the set. + /// + /// ## Original + /// + /// [`BTreeSet::first`](alloc::collections::BTreeSet::first) + /// + /// ## API Differences + /// + /// Since bit-sets store their elements as bits instead of values, the + /// element is returned by-value instead. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// assert_eq!(set.first(), None); + /// set.insert(1); + /// assert_eq!(set.first(), Some(1)); + /// set.insert(2); + /// assert_eq!(set.first(), Some(1)); + /// ``` + #[inline] + pub fn first(&self) -> Option { + self.inner.first_one() + } + + /// Returns the last element in the set, if any. + /// This element is always the maximum of all elements in the set. + /// + /// ## Original + /// + /// [`BTreeSet::last`](alloc::collections::BTreeSet::last) + /// + /// ## API Differences + /// + /// Since bit-sets store their elements as bits instead of values, the + /// element is returned by-value instead. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// assert_eq!(set.last(), None); + /// set.insert(1); + /// assert_eq!(set.last(), Some(1)); + /// set.insert(2); + /// assert_eq!(set.last(), Some(2)); + /// ``` + #[inline] + pub fn last(&self) -> Option { + self.inner.last_one() + } + + /// Removes the first element from the set and returns it, if any. + /// The first element is always the minimum element in the set. + /// + /// ## Original + /// + /// [`BTreeSet::pop_first`](alloc::collections::BTreeSet::pop_first) + /// + /// ## API Differences + /// + /// Since bit-sets store their elements as bits instead of values, the + /// element is returned by-value instead. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// set.insert(1); + /// while let Some(n) = set.pop_first() { + /// assert_eq!(n, 1); + /// } + /// assert!(set.is_empty()); + /// ``` + #[inline] + pub fn pop_first(&mut self) -> Option { + let first = self.first()?; + self.remove(first); + Some(first) + } + + /// Removes the last element from the set and returns it, if any. + /// The last element is always the maximum element in the set. + /// + /// ## Original + /// + /// [`BTreeSet::pop_last`](alloc::collections::BTreeSet::pop_last) + /// + /// ## API Differences + /// + /// Since bit-sets store their elements as bits instead of values, the + /// element is returned by-value instead. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// set.insert(1); + /// while let Some(n) = set.pop_last() { + /// assert_eq!(n, 1); + /// } + /// assert!(set.is_empty()); + /// ``` + #[inline] + pub fn pop_last(&mut self) -> Option { + let last = self.last()?; + self.remove(last); + Some(last) + } + + /// Adds a value to the set. + /// + /// Returns whether the value was newly inserted. That is: + /// + /// * If the set did not previously contain the value, `true` is returned. + /// * If the set already contained the value, `false` is returned. + /// + /// ## API Differences + /// + /// Since bit-sets can only contain `usize`, the argument has been adjusted + /// to accept a `usize` value instead of a reference to be easier to use. + /// + /// ## Original + /// + /// [`BTreeSet::insert`](alloc::collections::BTreeSet::insert) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// + /// assert!(set.insert(2)); + /// assert!(!set.insert(2)); + /// assert_eq!(set.len(), 1); + /// ``` + #[inline] + pub fn insert(&mut self, value: usize) -> bool { + let old_len = self.inner.len(); + if value >= old_len { + self.inner.resize(value + 1, false); + self.inner.set(value, true); + true + } + else { + !self.inner.replace(value, true) + } + } + + /// If the set contains the value, removes it from the set. + /// Returns whether such an element was present. + /// + /// ## Original + /// + /// [`BTreeSet::remove`](alloc::collections::BTreeSet::remove) + /// + /// ## API Differences + /// + /// Since bit-sets can only contain `usize`, the argument has been adjusted + /// to accept a `usize` value instead of a reference to be easier to use. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// + /// set.insert(2); + /// assert!(set.remove(2)); + /// assert!(!set.remove(2)); + /// ``` + #[inline] + pub fn remove(&mut self, value: usize) -> bool { + let old_len = self.inner.len(); + if value >= old_len { + false + } + else { + let ret = self.inner.replace(value, false); + + // NOTE: it's unclear how this affects performance and if we should + // do this automatically, or require it manually only + self.shrink_inner(); + + ret + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(e)` returns + /// `false`. The elements are visited in ascending order. + /// + /// ## Original + /// + /// [`BTreeSet::retain`](alloc::collections::BTreeSet::retain) + /// + /// ## API Differences + /// + /// Since bit-sets can only contain `usize`, the function argument has been + /// adjusted to accept `usize` values instead of references to be easier to + /// use. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// set.insert(1); + /// set.insert(2); + /// set.insert(3); + /// set.insert(4); + /// set.insert(5); + /// set.insert(6); + /// // Keep only the even numbers. + /// set.retain(|k| k % 2 == 0); + /// assert!(set.iter().eq([2, 4, 6].into_iter())); + /// ``` + #[inline] + pub fn retain(&mut self, mut f: F) + where F: FnMut(usize) -> bool { + self.inner + .iter_mut() + .enumerate() + .for_each(|(idx, mut bit)| { + if *bit && !f(idx) { + bit.set(false); + } + }); + } + + /// Moves all elements from `other` into `self`, leaving `other` empty. + /// + /// ## Original + /// + /// [`BTreeSet::append`](alloc::collections::BTreeSet::append) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut a: BitSet = BitSet::new(); + /// a.insert(1); + /// a.insert(2); + /// a.insert(3); + /// + /// let mut b: BitSet = BitSet::new(); + /// b.insert(3); + /// b.insert(4); + /// b.insert(5); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 5); + /// assert_eq!(b.len(), 0); + /// + /// assert!(a.contains(1)); + /// assert!(a.contains(2)); + /// assert!(a.contains(3)); + /// assert!(a.contains(4)); + /// assert!(a.contains(5)); + /// ``` + #[inline] + pub fn append(&mut self, other: &mut BitSet) { + other.shrink_inner(); + let and_len = Ord::min(self.inner.len(), other.inner.len()); + self.inner[.. and_len] |= &other.inner[.. and_len]; + self.inner.extend_from_bitslice(&other.inner[and_len ..]); + other.inner.clear(); + } + + /// Splits the collection into two at the value. + /// Returns a new collection with all elements greater than or equal to the + /// value. + /// + /// ## Original + /// + /// [`BTreeSet::split_off`](alloc::collections::BTreeSet::split_off) + /// + /// ## API Differences + /// + /// Since bit-sets can only contain `usize`, the argument has been adjusted + /// to accept a `usize` value instead of a reference to be easier to use. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut a: BitSet = BitSet::new(); + /// a.insert(1); + /// a.insert(2); + /// a.insert(3); + /// a.insert(17); + /// a.insert(41); + /// + /// let mut b = a.split_off(3); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 3); + /// + /// assert!(a.contains(1)); + /// assert!(a.contains(2)); + /// assert!(b.contains(3)); + /// assert!(b.contains(17)); + /// assert!(b.contains(41)); + /// ``` + #[inline] + pub fn split_off(&mut self, value: usize) -> BitSet { + let len = self.inner.len(); + if value > len { + self.shrink_inner(); + return BitSet::new(); + } + + let mut other = >::with_capacity(len); + unsafe { + other.set_len(len); + other[.. value].fill(false); + other[value ..].copy_from_bitslice(&self.inner[value ..]); + } + self.inner.truncate(value); + self.shrink_inner(); + BitSet { inner: other } + } + + /// Gets an iterator that visits the elements in the bit-set in ascending + /// order. + /// + /// ## Original + /// + /// [`BTreeSet::iter`](alloc::collections::BTreeSet::iter) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// set.insert(3); + /// set.insert(1); + /// set.insert(2); + /// + /// let mut set_iter = set.iter(); + /// assert_eq!(set_iter.next(), Some(1)); + /// assert_eq!(set_iter.next(), Some(2)); + /// assert_eq!(set_iter.next(), Some(3)); + /// assert_eq!(set_iter.next(), None); + /// ``` + #[inline] + pub fn iter(&self) -> IterOnes<'_, T, O> { + self.inner.iter_ones() + } + + /// Returns the number of elements in the set. + /// + /// ## Original + /// + /// [`BTreeSet::len`](alloc::collections::BTreeSet::len) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// assert_eq!(set.len(), 0); + /// set.insert(1); + /// assert_eq!(set.len(), 1); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.inner.count_ones() + } + + /// Returns `true` if the set contains no elements. + /// + /// ## Original + /// + /// [`BTreeSet::is_empty`](alloc::collections::BTreeSet::is_empty) + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::set::BitSet; + /// + /// let mut set: BitSet = BitSet::new(); + /// assert!(set.is_empty()); + /// set.insert(1); + /// assert!(!set.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.inner.not_any() + } +} diff --git a/src/set/iter.rs b/src/set/iter.rs new file mode 100644 index 00000000..72e9300d --- /dev/null +++ b/src/set/iter.rs @@ -0,0 +1,163 @@ +#![doc = include_str!("../../doc/set/iter.md")] + +use core::iter::{ + FromIterator, + FusedIterator, +}; + +use super::BitSet; +use crate::{ + order::BitOrder, + slice::{ + BitSlice, + IterOnes, + }, + store::BitStore, +}; + +impl Extend for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn extend(&mut self, iter: I) + where I: IntoIterator { + iter.into_iter().for_each(|val| { + self.insert(val); + }); + } +} + +#[cfg(not(tarpaulin_include))] +impl<'a, T, O> Extend<&'a usize> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn extend(&mut self, iter: I) + where I: IntoIterator { + self.extend(iter.into_iter().copied()); + } +} + +#[cfg(not(tarpaulin_include))] +impl FromIterator for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn from_iter(iter: I) -> Self + where I: IntoIterator { + let mut set = Self::new(); + set.extend(iter.into_iter()); + set + } +} + +#[cfg(not(tarpaulin_include))] +impl<'a, T, O> FromIterator<&'a usize> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn from_iter(iter: I) -> Self + where I: IntoIterator { + iter.into_iter().copied().collect::() + } +} + +/* +impl IntoIterator for BitSet +where + T: BitStore, + O: BitOrder, +{ + type IntoIter = ???; + type Item = usize; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.inner.into_boxed_bitslice().???() + } +} +*/ + +#[cfg(not(tarpaulin_include))] +impl<'a, T, O> IntoIterator for &'a BitSet +where + O: BitOrder, + T: 'a + BitStore, +{ + type IntoIter = IterOnes<'a, T, O>; + type Item = usize; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +#[doc = include_str!("../../doc/set/iter/Range.md")] +pub struct Range<'a, T, O> +where + T: BitStore, + O: BitOrder, +{ + /// Inner [`IterOnes`] iterator. + inner: IterOnes<'a, T, O>, +} +impl<'a, T, O> Range<'a, T, O> +where + T: BitStore, + O: BitOrder, +{ + pub(super) fn new(slice: &'a BitSlice, offset: usize) -> Self { + Self { + inner: IterOnes::new(slice, offset), + } + } +} +impl<'a, T, O> Iterator for Range<'a, T, O> +where + T: BitStore, + O: BitOrder, +{ + type Item = usize; + + easy_iter!(); + + #[inline] + fn next(&mut self) -> Option { + self.inner.next() + } +} +impl<'a, T, O> DoubleEndedIterator for Range<'a, T, O> +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.inner.next_back() + } +} +impl ExactSizeIterator for Range<'_, T, O> +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Range<'_, T, O> +where + T: BitStore, + O: BitOrder, +{ +} diff --git a/src/set/traits.rs b/src/set/traits.rs new file mode 100644 index 00000000..cb192718 --- /dev/null +++ b/src/set/traits.rs @@ -0,0 +1,237 @@ +//! General trait implementations for bit-sets. + +use core::{ + cmp, + fmt::{ + self, + Debug, + Formatter, + }, + hash::Hasher, + marker::Unpin, +}; + +use super::BitSet; +use crate::{ + order::BitOrder, + slice::BitSlice, + store::BitStore, + vec::BitVec, +}; + +#[cfg(not(tarpaulin_include))] +impl Clone for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} + +impl Eq for BitSet +where + T: BitStore, + O: BitOrder, +{ +} + +#[cfg(not(tarpaulin_include))] +impl Ord for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.iter().cmp(other.iter()) + } +} + +#[cfg(not(tarpaulin_include))] +impl PartialEq> for BitSet +where + T1: BitStore, + T2: BitStore, + O1: BitOrder, + O2: BitOrder, +{ + #[inline] + fn eq(&self, other: &BitSet) -> bool { + self.shrunken() == other.shrunken() + } +} + +#[cfg(not(tarpaulin_include))] +impl PartialOrd> for BitSet +where + T1: BitStore, + T2: BitStore, + O1: BitOrder, + O2: BitOrder, +{ + #[inline] + fn partial_cmp(&self, other: &BitSet) -> Option { + Some(self.iter().cmp(other.iter())) + } +} + +#[cfg(not(tarpaulin_include))] +impl AsRef> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn as_ref(&self) -> &BitSlice { + self.as_bitslice() + } +} + +#[cfg(not(tarpaulin_include))] +impl AsMut> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn as_mut(&mut self) -> &mut BitSlice { + self.as_mut_bitslice() + } +} + +#[cfg(not(tarpaulin_include))] +impl AsRef> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn as_ref(&self) -> &BitVec { + self.as_bitvec() + } +} + +#[cfg(not(tarpaulin_include))] +impl AsMut> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn as_mut(&mut self) -> &mut BitVec { + self.as_mut_bitvec() + } +} + +#[cfg(not(tarpaulin_include))] +impl AsRef> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn as_ref(&self) -> &Self { + self + } +} + +#[cfg(not(tarpaulin_include))] +impl AsMut> for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn as_mut(&mut self) -> &mut Self { + self + } +} + +#[cfg(not(tarpaulin_include))] +impl Default for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl Debug for BitSet +where + T: BitStore, + O: BitOrder, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + fmt.debug_set().entries(self.iter()).finish() + } +} + +unsafe impl Send for BitSet +where + T: BitStore, + O: BitOrder, +{ +} + +unsafe impl Sync for BitSet +where + T: BitStore, + O: BitOrder, +{ +} + +impl Unpin for BitSet +where + T: BitStore, + O: BitOrder, +{ +} + +/* +impl BitAnd<&BitSet> for &BitSet +where + T: BitStore, + O: BitOrder, +{ + type Output = BitSet; + + #[inline] + fn bitand(self, rhs: &BitSet) -> BitSet { + BitSet::from_iter(self.intersection(rhs)) + } +} + +impl BitOr<&BitSet> for &BitSet +where + T: BitStore, + O: BitOrder, +{ + type Output = BitSet; + + #[inline] + fn bitor(self, rhs: &BitSet) -> BitSet { + BitSet::from_iter(self.union(rhs)) + } +} +impl BitXor<&BitSet> for &BitSet +where + T: BitStore, + O: BitOrder, +{ + type Output = BitSet; + + #[inline] + fn bitxor(self, rhs: &BitSet) -> BitSet { + BitSet::from_iter(self.symmetric_difference(rhs)) + } +} +*/ diff --git a/src/slice.rs b/src/slice.rs index f73efc49..0c67869d 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -1144,7 +1144,7 @@ where /// ``` #[inline] pub fn iter_ones(&self) -> IterOnes { - IterOnes::new(self) + IterOnes::new(self, 0) } /// Enumerates the index of each bit in a bit-slice cleared to `0`. @@ -1183,7 +1183,7 @@ where /// ``` #[inline] pub fn iter_zeros(&self) -> IterZeros { - IterZeros::new(self) + IterZeros::new(self, 0) } /// Finds the index of the first bit in the bit-slice set to `1`. diff --git a/src/slice/api.rs b/src/slice/api.rs index 6ac0de00..f5a6e631 100644 --- a/src/slice/api.rs +++ b/src/slice/api.rs @@ -2593,7 +2593,7 @@ where fn index(self, bits: &'a BitSlice) -> Self::Immut { match self.get(bits) { Some(b) => b, - None => panic!("index {} out of bounds: {}", self, bits.len()) + None => panic!("index {} out of bounds: {}", self, bits.len()), } } diff --git a/src/slice/iter.rs b/src/slice/iter.rs index a9b974bf..2a04b74d 100644 --- a/src/slice/iter.rs +++ b/src/slice/iter.rs @@ -2123,10 +2123,10 @@ where { #[inline] #[allow(missing_docs, clippy::missing_docs_in_private_items)] - pub(super) fn new(slice: &'a BitSlice) -> Self { + pub(crate) fn new(slice: &'a BitSlice, offset: usize) -> Self { Self { inner: slice, - front: 0, + front: offset, } } } @@ -2254,10 +2254,10 @@ where O: BitOrder, { #[allow(missing_docs, clippy::missing_docs_in_private_items)] - pub(super) fn new(slice: &'a BitSlice) -> Self { + pub(crate) fn new(slice: &'a BitSlice, offset: usize) -> Self { Self { inner: slice, - front: 0, + front: offset, } } }