-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a553ab2
commit 8179b48
Showing
12 changed files
with
1,511 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T>`](alloc::collections::BTreeSet) | ||
|
||
## API Differences | ||
|
||
As with all `bitvec` data structures, this takes two type parameters `<T, O>` | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T = usize, O = Lsb0> | ||
where | ||
T: BitStore, | ||
O: BitOrder, | ||
{ | ||
inner: BitVec<T, O>, | ||
} | ||
|
||
/// Constructors. | ||
impl<T, O> BitSet<T, O> | ||
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<usize>) -> 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<T, O>) -> Self { | ||
Self { inner } | ||
} | ||
} | ||
|
||
/// Converters. | ||
impl<T, O> BitSet<T, O> | ||
where | ||
T: BitStore, | ||
O: BitOrder, | ||
{ | ||
/// Explicitly views the bit-set as a bit-slice. | ||
#[inline] | ||
pub fn as_bitslice(&self) -> &BitSlice<T, O> { | ||
self.inner.as_bitslice() | ||
} | ||
|
||
/// Explicitly views the bit-set as a mutable bit-slice. | ||
#[inline] | ||
pub fn as_mut_bitslice(&mut self) -> &mut BitSlice<T, O> { | ||
self.inner.as_mut_bitslice() | ||
} | ||
|
||
/// Explicitly views the bit-set as a bit-vec. | ||
#[inline] | ||
pub fn as_bitvec(&self) -> &BitVec<T, O> { | ||
&self.inner | ||
} | ||
|
||
/// Explicitly views the bit-set as a mutable bit-vec. | ||
#[inline] | ||
pub fn as_mut_bitvec(&mut self) -> &mut BitVec<T, O> { | ||
&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<Const, T, O> { | ||
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<Mut, T, O> { | ||
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<T, O> { | ||
self.inner.into_boxed_bitslice() | ||
} | ||
|
||
/// Converts a bit-set into a bit-vec. | ||
#[inline] | ||
pub fn into_bitvec(self) -> BitVec<T, O> { | ||
self.inner | ||
} | ||
} | ||
|
||
/// Utilities. | ||
impl<T, O> BitSet<T, O> | ||
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<T, O> { | ||
match self.inner.last_one() { | ||
Some(idx) => &self.inner[.. idx + 1], | ||
None => Default::default(), | ||
} | ||
} | ||
} |
Oops, something went wrong.