bittle

github crates.io docs.rs build status

Zero-cost bitsets over native Rust types.

The name bittle comes from bit and little. Small bitsets!


Usage

Add bittle as a dependency in your Cargo.toml:


toml [dependencies] bittle = "0.4.2"


Guide

A bit is always identified by a [u32] by its index, and the exact location for primitive numbers is that the least significant bit corresponds to the lowest index, and the most significant bit is the highest ([see issue #2]). This is called "shift left indexing" and doesn't correspond with what literals look like when reading them left-to-right:

text 0b0010_0010u8 ^ ^- index 1 '------ index 5

It gets a bit more confusing when considering arrays, since each element in the array defines a span of bits which does increase left-to-right:

text 0 --------- 8 8 -------- 15 [0b0010_0010u8, 0b1000_0000u8] ^ ^ ^- index 15 | '--------- index 1 '-------------- index 5

Note: shift right indexing is available experimentally under the --cfg bittle_shr flag for benchmarking.


To interact with these bits we define the [Bits], [BitsMut], and [BitsOwned] traits. These traits are implemented for primitive types such as u32, [u32; 4], or &[u32]:

```rust use bittle::Bits;

let array: [u32; 4] = [0, 1, 2, 3]; assert!(array.iter_ones().eq([32, 65, 96, 97]));

let n = 0b00000000000000000000000000010001u32; assert!(n.iterones().eq([0, 4]));

let arrayofarrays: [[u8; 4]; 2] = [[16, 0, 0, 0], [0, 0, 1, 0]]; assert!(arrayofarrays.iter_ones().eq([4, 48]));

let mut vec: Vec = vec![0, 1, 2, 3]; assert!(vec.iter_ones().eq([32, 65, 96, 97])); ```


We also provide the [set!] macro, which is a zero-cost convenience method for constructing primitive forms of bit sets:

```rust use bittle::Bits;

let array: [u32; 4] = bittle::set![32, 65, 96, 97]; assert!(array.iter_ones().eq([32, 65, 96, 97]));

let n: u32 = bittle::set![0, 4]; assert!(n.iter_ones().eq([0, 4]));

let arrayofarrays: [[u8; 4]; 2] = bittle::set![4, 48]; assert!(arrayofarrays.iter_ones().eq([4, 48])); ```


Since a vector is not a primitive bit set, it could instead make use of [BitsMut] directly:

```rust use bittle::{Bits, BitsMut};

let mut vec: Vec = vec![0u32; 4]; vec.setbit(32); vec.setbit(65); vec.setbit(96); vec.setbit(97); assert!(vec.iterones().eq([32, 65, 96, 97])); asserteq!(vec, [0, 1, 2, 3]); ```


Due to how broadly these traits are implemented, we also try to avoid using names which are commonly used in other APIs, instead opt for bit-specific terminology such as:

```rust use bittle::{Bits, BitsMut};

let mut set = [0u16; 2];

set.setbit(15); assert!(set.testbit(15));

set.unionassign(&bittle::set![31, 7]); assert!(set.testbit(31) && set.test_bit(7));

set.clearbit(31); assert!(!set.testbit(31));

set.clearbits(); assert!(set.allzeros()); ```


Some other interesting operations, such as [Bits::join_ones] are available, allowing bitsets to act like masks over other iterators:

```rust use bittle::{Bits, BitsMut};

let elements = vec![10, 48, 101]; let mut m = 0u128;

m.setbit(0); assert!(m.joinones(&elements).eq([&10])); m.setbit(2); assert!(m.joinones(&elements).eq([&10, &101])); ```