-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add BitSet #235
Open
clarfonthey
wants to merge
2
commits into
ferrilab:main
Choose a base branch
from
clarfonthey:bitset
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Add BitSet #235
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev
Previous commit
Add BitSet
- Loading branch information
commit 8179b48b76f8edb5455fca0d246464c2c5784ff6
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This felt like the best analogue for
BitVec::repeat
to me. Since only allowingRangeFrom
seemed weird, I decided to accept a properRange
instead.