├── .github ├── Cargo.toml.wasm_ci └── workflows │ └── rust.yml ├── .gitignore ├── benches ├── Cargo.toml └── benches │ └── benches.rs ├── Cargo.toml ├── LICENSE-MIT ├── src ├── range.rs ├── block │ ├── default.rs │ ├── wasm.rs │ ├── avx2.rs │ ├── avx.rs │ ├── sse2.rs │ └── mod.rs ├── serde_impl.rs └── lib.rs ├── README.md ├── LICENSE-APACHE └── tests └── tests.rs /.github/Cargo.toml.wasm_ci: -------------------------------------------------------------------------------- 1 | wasm-bindgen-test = "0.3" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | Cargo.lock 4 | .vscode -------------------------------------------------------------------------------- /benches/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "benches" 3 | version = "0.1.0" 4 | edition = "2021" 5 | description = "Benchmarks for FixedBitset" 6 | publish = false 7 | license = "MIT OR Apache-2.0" 8 | 9 | [dev-dependencies] 10 | fixedbitset = { path = ".." } 11 | criterion = { version = "0.4", features = ["html_reports"] } 12 | 13 | [[bench]] 14 | name = "benches" 15 | harness = false -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fixedbitset" 3 | version = "0.5.7" 4 | authors = ["bluss"] 5 | license = "MIT OR Apache-2.0" 6 | readme = "README.md" 7 | rust-version = "1.56" 8 | edition = "2021" 9 | 10 | description = "FixedBitSet is a simple bitset collection" 11 | documentation = "https://docs.rs/fixedbitset/" 12 | repository = "https://github.com/petgraph/fixedbitset" 13 | 14 | keywords = ["container", "data-structure", "bitvec", "bitset", "no_std"] 15 | categories = ["data-structures"] 16 | 17 | [features] 18 | std = [] 19 | default = ["std"] 20 | 21 | [package.metadata.release] 22 | no-dev-version = true 23 | tag-name = "{{version}}" 24 | 25 | [dependencies] 26 | serde = { version = "1.0", optional = true } 27 | 28 | [dev-dependencies] 29 | serde_json = "1.0" 30 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2017 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /src/range.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Range, RangeFrom, RangeFull, RangeTo}; 2 | 3 | // Taken from https://github.com/bluss/odds/blob/master/src/range.rs. 4 | 5 | /// **IndexRange** is implemented by Rust's built-in range types, produced 6 | /// by range syntax like `..`, `a..`, `..b` or `c..d`. 7 | pub trait IndexRange { 8 | #[inline] 9 | /// Start index (inclusive) 10 | fn start(&self) -> Option { 11 | None 12 | } 13 | #[inline] 14 | /// End index (exclusive) 15 | fn end(&self) -> Option { 16 | None 17 | } 18 | } 19 | 20 | impl IndexRange for RangeFull {} 21 | 22 | impl IndexRange for RangeFrom { 23 | #[inline] 24 | fn start(&self) -> Option { 25 | Some(self.start) 26 | } 27 | } 28 | 29 | impl IndexRange for RangeTo { 30 | #[inline] 31 | fn end(&self) -> Option { 32 | Some(self.end) 33 | } 34 | } 35 | 36 | impl IndexRange for Range { 37 | #[inline] 38 | fn start(&self) -> Option { 39 | Some(self.start) 40 | } 41 | #[inline] 42 | fn end(&self) -> Option { 43 | Some(self.end) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/block/default.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; 2 | 3 | #[derive(Copy, Clone, PartialEq, Debug)] 4 | #[repr(transparent)] 5 | pub struct Block(pub(super) usize); 6 | 7 | impl Block { 8 | #[inline] 9 | pub const fn is_empty(self) -> bool { 10 | self.0 == Self::NONE.0 11 | } 12 | 13 | #[inline] 14 | pub fn andnot(self, other: Self) -> Self { 15 | Self(!other.0 & self.0) 16 | } 17 | } 18 | 19 | impl Not for Block { 20 | type Output = Block; 21 | #[inline] 22 | fn not(self) -> Self::Output { 23 | Self(self.0.not()) 24 | } 25 | } 26 | 27 | impl BitAnd for Block { 28 | type Output = Block; 29 | #[inline] 30 | fn bitand(self, other: Self) -> Self::Output { 31 | Self(self.0.bitand(other.0)) 32 | } 33 | } 34 | 35 | impl BitAndAssign for Block { 36 | #[inline] 37 | fn bitand_assign(&mut self, other: Self) { 38 | self.0.bitand_assign(other.0); 39 | } 40 | } 41 | 42 | impl BitOr for Block { 43 | type Output = Block; 44 | #[inline] 45 | fn bitor(self, other: Self) -> Self::Output { 46 | Self(self.0.bitor(other.0)) 47 | } 48 | } 49 | 50 | impl BitOrAssign for Block { 51 | #[inline] 52 | fn bitor_assign(&mut self, other: Self) { 53 | self.0.bitor_assign(other.0) 54 | } 55 | } 56 | 57 | impl BitXor for Block { 58 | type Output = Block; 59 | #[inline] 60 | fn bitxor(self, other: Self) -> Self::Output { 61 | Self(self.0.bitxor(other.0)) 62 | } 63 | } 64 | 65 | impl BitXorAssign for Block { 66 | #[inline] 67 | fn bitxor_assign(&mut self, other: Self) { 68 | self.0.bitxor_assign(other.0) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/block/wasm.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | arch::wasm32::*, 3 | ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}, 4 | }; 5 | 6 | #[derive(Copy, Clone, Debug)] 7 | #[repr(transparent)] 8 | pub struct Block(pub(super) v128); 9 | 10 | impl Block { 11 | #[inline] 12 | pub fn is_empty(self) -> bool { 13 | !v128_any_true(self.0) 14 | } 15 | 16 | #[inline] 17 | pub fn andnot(self, other: Self) -> Self { 18 | Self(v128_andnot(self.0, other.0)) 19 | } 20 | } 21 | 22 | impl Not for Block { 23 | type Output = Block; 24 | #[inline] 25 | fn not(self) -> Self::Output { 26 | Self(v128_xor(self.0, Self::ALL.0)) 27 | } 28 | } 29 | 30 | impl BitAnd for Block { 31 | type Output = Block; 32 | #[inline] 33 | fn bitand(self, other: Self) -> Self::Output { 34 | Self(v128_and(self.0, other.0)) 35 | } 36 | } 37 | 38 | impl BitAndAssign for Block { 39 | #[inline] 40 | fn bitand_assign(&mut self, other: Self) { 41 | self.0 = v128_and(self.0, other.0); 42 | } 43 | } 44 | 45 | impl BitOr for Block { 46 | type Output = Block; 47 | #[inline] 48 | fn bitor(self, other: Self) -> Self::Output { 49 | Self(v128_or(self.0, other.0)) 50 | } 51 | } 52 | 53 | impl BitOrAssign for Block { 54 | #[inline] 55 | fn bitor_assign(&mut self, other: Self) { 56 | self.0 = v128_or(self.0, other.0); 57 | } 58 | } 59 | 60 | impl BitXor for Block { 61 | type Output = Block; 62 | #[inline] 63 | fn bitxor(self, other: Self) -> Self::Output { 64 | Self(v128_xor(self.0, other.0)) 65 | } 66 | } 67 | 68 | impl BitXorAssign for Block { 69 | #[inline] 70 | fn bitxor_assign(&mut self, other: Self) { 71 | self.0 = v128_xor(self.0, other.0) 72 | } 73 | } 74 | 75 | impl PartialEq for Block { 76 | #[inline] 77 | fn eq(&self, other: &Self) -> bool { 78 | !v128_any_true(v128_xor(self.0, other.0)) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/block/avx2.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "x86")] 2 | use core::arch::x86::*; 3 | #[cfg(target_arch = "x86_64")] 4 | use core::arch::x86_64::*; 5 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; 6 | 7 | #[derive(Copy, Clone, Debug)] 8 | #[repr(transparent)] 9 | pub struct Block(pub(super) __m256i); 10 | 11 | impl Block { 12 | #[inline] 13 | pub fn is_empty(self) -> bool { 14 | unsafe { _mm256_testz_si256(self.0, self.0) == 1 } 15 | } 16 | 17 | #[inline] 18 | pub fn andnot(self, other: Self) -> Self { 19 | Self(unsafe { _mm256_andnot_si256(other.0, self.0) }) 20 | } 21 | } 22 | 23 | impl Not for Block { 24 | type Output = Block; 25 | #[inline] 26 | fn not(self) -> Self::Output { 27 | unsafe { Self(_mm256_xor_si256(self.0, Self::ALL.0)) } 28 | } 29 | } 30 | 31 | impl BitAnd for Block { 32 | type Output = Block; 33 | #[inline] 34 | fn bitand(self, other: Self) -> Self::Output { 35 | unsafe { Self(_mm256_and_si256(self.0, other.0)) } 36 | } 37 | } 38 | 39 | impl BitAndAssign for Block { 40 | #[inline] 41 | fn bitand_assign(&mut self, other: Self) { 42 | unsafe { 43 | self.0 = _mm256_and_si256(self.0, other.0); 44 | } 45 | } 46 | } 47 | 48 | impl BitOr for Block { 49 | type Output = Block; 50 | #[inline] 51 | fn bitor(self, other: Self) -> Self::Output { 52 | unsafe { Self(_mm256_or_si256(self.0, other.0)) } 53 | } 54 | } 55 | 56 | impl BitOrAssign for Block { 57 | #[inline] 58 | fn bitor_assign(&mut self, other: Self) { 59 | unsafe { 60 | self.0 = _mm256_or_si256(self.0, other.0); 61 | } 62 | } 63 | } 64 | 65 | impl BitXor for Block { 66 | type Output = Block; 67 | #[inline] 68 | fn bitxor(self, other: Self) -> Self::Output { 69 | unsafe { Self(_mm256_xor_si256(self.0, other.0)) } 70 | } 71 | } 72 | 73 | impl BitXorAssign for Block { 74 | #[inline] 75 | fn bitxor_assign(&mut self, other: Self) { 76 | unsafe { self.0 = _mm256_xor_si256(self.0, other.0) } 77 | } 78 | } 79 | 80 | impl PartialEq for Block { 81 | #[inline] 82 | fn eq(&self, other: &Self) -> bool { 83 | unsafe { 84 | let neq = _mm256_xor_si256(self.0, other.0); 85 | _mm256_testz_si256(neq, neq) == 1 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/block/avx.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "x86")] 2 | use core::arch::x86::*; 3 | #[cfg(target_arch = "x86_64")] 4 | use core::arch::x86_64::*; 5 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; 6 | 7 | #[derive(Copy, Clone, Debug)] 8 | #[repr(transparent)] 9 | pub struct Block(pub(super) __m256d); 10 | 11 | impl Block { 12 | #[inline] 13 | pub fn is_empty(self) -> bool { 14 | unsafe { 15 | let value = _mm256_castpd_si256(self.0); 16 | _mm256_testz_si256(value, value) == 1 17 | } 18 | } 19 | 20 | #[inline] 21 | pub fn andnot(self, other: Self) -> Self { 22 | unsafe { Self(_mm256_andnot_pd(other.0, self.0)) } 23 | } 24 | } 25 | 26 | impl Not for Block { 27 | type Output = Block; 28 | #[inline] 29 | fn not(self) -> Self::Output { 30 | unsafe { Self(_mm256_xor_pd(self.0, Self::ALL.0)) } 31 | } 32 | } 33 | 34 | impl BitAnd for Block { 35 | type Output = Block; 36 | #[inline] 37 | fn bitand(self, other: Self) -> Self::Output { 38 | unsafe { Self(_mm256_and_pd(self.0, other.0)) } 39 | } 40 | } 41 | 42 | impl BitAndAssign for Block { 43 | #[inline] 44 | fn bitand_assign(&mut self, other: Self) { 45 | unsafe { 46 | self.0 = _mm256_and_pd(self.0, other.0); 47 | } 48 | } 49 | } 50 | 51 | impl BitOr for Block { 52 | type Output = Block; 53 | #[inline] 54 | fn bitor(self, other: Self) -> Self::Output { 55 | unsafe { Self(_mm256_or_pd(self.0, other.0)) } 56 | } 57 | } 58 | 59 | impl BitOrAssign for Block { 60 | #[inline] 61 | fn bitor_assign(&mut self, other: Self) { 62 | unsafe { 63 | self.0 = _mm256_or_pd(self.0, other.0); 64 | } 65 | } 66 | } 67 | 68 | impl BitXor for Block { 69 | type Output = Block; 70 | #[inline] 71 | fn bitxor(self, other: Self) -> Self::Output { 72 | unsafe { Self(_mm256_xor_pd(self.0, other.0)) } 73 | } 74 | } 75 | 76 | impl BitXorAssign for Block { 77 | #[inline] 78 | fn bitxor_assign(&mut self, other: Self) { 79 | unsafe { self.0 = _mm256_xor_pd(self.0, other.0) } 80 | } 81 | } 82 | 83 | impl PartialEq for Block { 84 | #[inline] 85 | fn eq(&self, other: &Self) -> bool { 86 | unsafe { 87 | let new = _mm256_xor_pd(self.0, other.0); 88 | let neq = _mm256_castpd_si256(new); 89 | _mm256_testz_si256(neq, neq) == 1 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/block/sse2.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::undocumented_unsafe_blocks)] 2 | 3 | #[cfg(target_arch = "x86")] 4 | use core::arch::x86::*; 5 | #[cfg(target_arch = "x86_64")] 6 | use core::arch::x86_64::*; 7 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; 8 | 9 | #[derive(Copy, Clone, Debug)] 10 | #[repr(transparent)] 11 | pub struct Block(pub(super) __m128i); 12 | 13 | impl Block { 14 | #[inline] 15 | pub fn is_empty(self) -> bool { 16 | #[cfg(not(target_feature = "sse4.1"))] 17 | { 18 | self == Self::NONE 19 | } 20 | #[cfg(target_feature = "sse4.1")] 21 | { 22 | unsafe { _mm_test_all_zeros(self.0, self.0) == 1 } 23 | } 24 | } 25 | 26 | #[inline] 27 | pub fn andnot(self, other: Self) -> Self { 28 | Self(unsafe { _mm_andnot_si128(other.0, self.0) }) 29 | } 30 | } 31 | 32 | impl Not for Block { 33 | type Output = Block; 34 | #[inline] 35 | fn not(self) -> Self::Output { 36 | unsafe { Self(_mm_xor_si128(self.0, Self::ALL.0)) } 37 | } 38 | } 39 | 40 | impl BitAnd for Block { 41 | type Output = Block; 42 | #[inline] 43 | fn bitand(self, other: Self) -> Self::Output { 44 | unsafe { Self(_mm_and_si128(self.0, other.0)) } 45 | } 46 | } 47 | 48 | impl BitAndAssign for Block { 49 | #[inline] 50 | fn bitand_assign(&mut self, other: Self) { 51 | unsafe { 52 | self.0 = _mm_and_si128(self.0, other.0); 53 | } 54 | } 55 | } 56 | 57 | impl BitOr for Block { 58 | type Output = Block; 59 | #[inline] 60 | fn bitor(self, other: Self) -> Self::Output { 61 | unsafe { Self(_mm_or_si128(self.0, other.0)) } 62 | } 63 | } 64 | 65 | impl BitOrAssign for Block { 66 | #[inline] 67 | fn bitor_assign(&mut self, other: Self) { 68 | unsafe { 69 | self.0 = _mm_or_si128(self.0, other.0); 70 | } 71 | } 72 | } 73 | 74 | impl BitXor for Block { 75 | type Output = Block; 76 | #[inline] 77 | fn bitxor(self, other: Self) -> Self::Output { 78 | unsafe { Self(_mm_xor_si128(self.0, other.0)) } 79 | } 80 | } 81 | 82 | impl BitXorAssign for Block { 83 | #[inline] 84 | fn bitxor_assign(&mut self, other: Self) { 85 | unsafe { self.0 = _mm_xor_si128(self.0, other.0) } 86 | } 87 | } 88 | 89 | impl PartialEq for Block { 90 | #[inline] 91 | fn eq(&self, other: &Self) -> bool { 92 | unsafe { 93 | #[cfg(not(target_feature = "sse4.1"))] 94 | { 95 | _mm_movemask_epi8(_mm_cmpeq_epi8(self.0, other.0)) == 0xffff 96 | } 97 | #[cfg(target_feature = "sse4.1")] 98 | { 99 | let neq = _mm_xor_si128(self.0, other.0); 100 | _mm_test_all_zeros(neq, neq) == 1 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/block/mod.rs: -------------------------------------------------------------------------------- 1 | // TODO: Remove once MSRV supports undocumented_unsafe_blocks 2 | #![allow(unknown_lints)] 3 | #![allow(clippy::undocumented_unsafe_blocks)] 4 | #![allow(dead_code)] 5 | // TODO: Remove once the transmutes are fixed 6 | #![allow(clippy::missing_transmute_annotations)] 7 | // TODO: Remove once MSRV supports derived_hash_with_manual_eq 8 | #![allow(renamed_and_removed_lints)] 9 | #![allow(clippy::derive_hash_xor_eq)] 10 | #![allow(clippy::derived_hash_with_manual_eq)] 11 | 12 | use core::cmp::Ordering; 13 | use core::hash::{Hash, Hasher}; 14 | 15 | #[cfg(all( 16 | not(all(target_family = "wasm", target_feature = "simd128")), 17 | not(target_feature = "sse2"), 18 | not(target_feature = "avx"), 19 | not(target_feature = "avx2"), 20 | ))] 21 | mod default; 22 | #[cfg(all( 23 | not(all(target_family = "wasm", target_feature = "simd128")), 24 | not(target_feature = "sse2"), 25 | not(target_feature = "avx"), 26 | not(target_feature = "avx2"), 27 | ))] 28 | pub use self::default::*; 29 | 30 | #[cfg(all( 31 | any(target_arch = "x86", target_arch = "x86_64"), 32 | target_feature = "sse2", 33 | not(target_feature = "avx"), 34 | not(target_feature = "avx2"), 35 | ))] 36 | mod sse2; 37 | #[cfg(all( 38 | any(target_arch = "x86", target_arch = "x86_64"), 39 | target_feature = "sse2", 40 | not(target_feature = "avx"), 41 | not(target_feature = "avx2"), 42 | ))] 43 | pub use self::sse2::*; 44 | 45 | #[cfg(all( 46 | any(target_arch = "x86", target_arch = "x86_64"), 47 | target_feature = "avx", 48 | not(target_feature = "avx2") 49 | ))] 50 | mod avx; 51 | #[cfg(all( 52 | any(target_arch = "x86", target_arch = "x86_64"), 53 | target_feature = "avx", 54 | not(target_feature = "avx2") 55 | ))] 56 | pub use self::avx::*; 57 | 58 | #[cfg(all( 59 | any(target_arch = "x86", target_arch = "x86_64"), 60 | target_feature = "avx2" 61 | ))] 62 | mod avx2; 63 | #[cfg(all( 64 | any(target_arch = "x86", target_arch = "x86_64"), 65 | target_feature = "avx2" 66 | ))] 67 | pub use self::avx2::*; 68 | 69 | #[cfg(all(target_family = "wasm", target_feature = "simd128"))] 70 | mod wasm; 71 | #[cfg(all(target_family = "wasm", target_feature = "simd128"))] 72 | pub use self::wasm::*; 73 | 74 | impl Block { 75 | pub const USIZE_COUNT: usize = core::mem::size_of::() / core::mem::size_of::(); 76 | pub const NONE: Self = Self::from_usize_array([0; Self::USIZE_COUNT]); 77 | pub const ALL: Self = Self::from_usize_array([usize::MAX; Self::USIZE_COUNT]); 78 | pub const BITS: usize = core::mem::size_of::() * 8; 79 | 80 | #[inline] 81 | pub fn into_usize_array(self) -> [usize; Self::USIZE_COUNT] { 82 | unsafe { core::mem::transmute(self.0) } 83 | } 84 | 85 | #[inline] 86 | pub const fn from_usize_array(array: [usize; Self::USIZE_COUNT]) -> Self { 87 | Self(unsafe { core::mem::transmute(array) }) 88 | } 89 | } 90 | 91 | impl Eq for Block {} 92 | 93 | impl PartialOrd for Block { 94 | #[inline] 95 | fn partial_cmp(&self, other: &Self) -> Option { 96 | Some(self.cmp(other)) 97 | } 98 | } 99 | 100 | impl Ord for Block { 101 | #[inline] 102 | fn cmp(&self, other: &Self) -> Ordering { 103 | self.into_usize_array().cmp(&other.into_usize_array()) 104 | } 105 | } 106 | 107 | impl Default for Block { 108 | #[inline] 109 | fn default() -> Self { 110 | Self::NONE 111 | } 112 | } 113 | 114 | impl Hash for Block { 115 | #[inline] 116 | fn hash(&self, hasher: &mut H) { 117 | Hash::hash_slice(&self.into_usize_array(), hasher); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Continuous integration 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | CARGO_INCREMENTAL: 0 12 | 13 | jobs: 14 | # Ensure the crate builds on x86 15 | build_x86_64: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | rust: [stable, nightly] 20 | features: ["+avx2", "+avx", "+sse2,+sse4.1", "+sse2"] 21 | env: 22 | RUSTFLAGS: "-C target-feature=${{matrix.features}} -D warnings" 23 | steps: 24 | - uses: actions/checkout@v4 25 | - uses: dtolnay/rust-toolchain@stable 26 | with: 27 | target: x86_64-unknown-linux-gnu 28 | toolchain: ${{ matrix.rust }} 29 | components: clippy 30 | - name: Tests (x86_64) 31 | run: | 32 | cargo clippy && 33 | cargo test -v --no-default-features --tests --lib && 34 | cargo build --verbose --features "$FEATURES" && 35 | cargo test --verbose --features "$FEATURES" && 36 | cargo test --verbose --release --features "$FEATURES" 37 | 38 | # Ensure the crate builds on x86 39 | build_MSRV: 40 | runs-on: ubuntu-latest 41 | strategy: 42 | matrix: 43 | rust: [1.56.0] 44 | features: ["+avx2", "+sse2"] 45 | env: 46 | RUSTFLAGS: "-C target-feature=${{matrix.features}}" 47 | steps: 48 | - uses: actions/checkout@v4 49 | - uses: dtolnay/rust-toolchain@stable 50 | with: 51 | target: x86_64-unknown-linux-gnu 52 | toolchain: ${{ matrix.rust }} 53 | components: clippy 54 | - name: Tests (x86_64) 55 | run: | 56 | cargo clippy && 57 | cargo test -v --no-default-features --tests --lib && 58 | cargo build --verbose --features "$FEATURES" && 59 | cargo test --verbose --features "$FEATURES" && 60 | cargo test --verbose --release --features "$FEATURES" 61 | 62 | # Ensure the crate builds on ARM 63 | build_aarch64: 64 | runs-on: macos-14 65 | strategy: 66 | matrix: 67 | rust: [stable, nightly] 68 | features: ["+neon", "-neon"] 69 | env: 70 | RUSTFLAGS: "-C target-feature=${{matrix.features}} -D warnings" 71 | steps: 72 | - uses: actions/checkout@v4 73 | - uses: dtolnay/rust-toolchain@stable 74 | with: 75 | target: aarch64-apple-darwin 76 | toolchain: ${{ matrix.rust }} 77 | components: clippy 78 | - name: Tests (aarch64) 79 | run: | 80 | cargo clippy && 81 | cargo test -v --no-default-features --tests --lib && 82 | cargo build --verbose --features "$FEATURES" && 83 | cargo test --verbose --features "$FEATURES" && 84 | cargo test --verbose --release --features "$FEATURES" 85 | 86 | # Enforce rustfmt formatting 87 | formatting: 88 | runs-on: ubuntu-latest 89 | strategy: 90 | matrix: 91 | # Run formatting checks only on stable 92 | rust: [stable] 93 | steps: 94 | - uses: actions/checkout@v4 95 | - uses: dtolnay/rust-toolchain@stable 96 | with: 97 | toolchain: ${{ matrix.rust }} 98 | components: rustfmt 99 | - name: Run Clippy 100 | run: | 101 | cargo fmt --all --check 102 | 103 | # Ensure the benchmarks compile 104 | benchmark_compiles: 105 | runs-on: ubuntu-latest 106 | strategy: 107 | matrix: 108 | # Check builds only on stable 109 | rust: [stable] 110 | steps: 111 | - uses: actions/checkout@v4 112 | - uses: dtolnay/rust-toolchain@stable 113 | with: 114 | toolchain: ${{ matrix.rust }} 115 | components: clippy 116 | - name: Run Clippy 117 | run: | 118 | cd benches 119 | cargo bench --bench benches --no-run 120 | 121 | build-wasm: 122 | runs-on: ubuntu-latest 123 | strategy: 124 | matrix: 125 | features: ["+simd128", "-simd128"] 126 | env: 127 | RUSTFLAGS: "-C target-feature=${{matrix.features}} -D warnings" 128 | steps: 129 | - uses: actions/checkout@v4 130 | - name: Install 131 | run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 132 | - run: cat .github/Cargo.toml.wasm_ci >> Cargo.toml 133 | - run: wasm-pack test --headless --chrome 134 | - run: wasm-pack test --headless --firefox 135 | 136 | miri: 137 | runs-on: ubuntu-latest 138 | strategy: 139 | matrix: 140 | # Check builds only on nightly 141 | rust: [nightly] 142 | steps: 143 | - uses: actions/checkout@v4 144 | - uses: dtolnay/rust-toolchain@stable 145 | with: 146 | toolchain: ${{ matrix.rust }} 147 | components: miri 148 | - name: Run miri 149 | run: cargo miri test 150 | -------------------------------------------------------------------------------- /src/serde_impl.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(feature = "std"))] 2 | use core as std; 3 | 4 | use crate::{Block, FixedBitSet, BYTES}; 5 | use alloc::vec::Vec; 6 | use core::{convert::TryFrom, fmt}; 7 | use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor}; 8 | use serde::ser::{Serialize, SerializeStruct, Serializer}; 9 | 10 | struct BitSetByteSerializer<'a>(&'a FixedBitSet); 11 | 12 | impl Serialize for FixedBitSet { 13 | fn serialize(&self, serializer: S) -> Result 14 | where 15 | S: Serializer, 16 | { 17 | let mut struct_serializer = serializer.serialize_struct("FixedBitset", 2)?; 18 | struct_serializer.serialize_field("length", &(self.length as u64))?; 19 | struct_serializer.serialize_field("data", &BitSetByteSerializer(self))?; 20 | struct_serializer.end() 21 | } 22 | } 23 | 24 | impl<'a> Serialize for BitSetByteSerializer<'a> { 25 | fn serialize(&self, serializer: S) -> Result 26 | where 27 | S: Serializer, 28 | { 29 | let len = self.0.as_slice().len() * BYTES; 30 | // PERF: Figure out a way to do this without allocating. 31 | let mut temp = Vec::with_capacity(len); 32 | for block in self.0.as_slice() { 33 | temp.extend(&block.to_le_bytes()); 34 | } 35 | serializer.serialize_bytes(&temp) 36 | } 37 | } 38 | 39 | impl<'de> Deserialize<'de> for FixedBitSet { 40 | fn deserialize(deserializer: D) -> Result 41 | where 42 | D: Deserializer<'de>, 43 | { 44 | enum Field { 45 | Length, 46 | Data, 47 | } 48 | 49 | fn bytes_to_data(length: usize, input: &[u8]) -> Vec { 50 | let block_len = length / BYTES + 1; 51 | let mut data = Vec::with_capacity(block_len); 52 | for chunk in input.chunks(BYTES) { 53 | match <&[u8; BYTES]>::try_from(chunk) { 54 | Ok(bytes) => data.push(usize::from_le_bytes(*bytes)), 55 | Err(_) => { 56 | let mut bytes = [0u8; BYTES]; 57 | bytes[0..BYTES].copy_from_slice(chunk); 58 | data.push(usize::from_le_bytes(bytes)); 59 | } 60 | } 61 | } 62 | data 63 | } 64 | 65 | impl<'de> Deserialize<'de> for Field { 66 | fn deserialize(deserializer: D) -> Result 67 | where 68 | D: Deserializer<'de>, 69 | { 70 | struct FieldVisitor; 71 | 72 | impl<'de> Visitor<'de> for FieldVisitor { 73 | type Value = Field; 74 | 75 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 76 | formatter.write_str("`length` or `data`") 77 | } 78 | 79 | fn visit_str(self, value: &str) -> Result 80 | where 81 | E: de::Error, 82 | { 83 | match value { 84 | "length" => Ok(Field::Length), 85 | "data" => Ok(Field::Data), 86 | _ => Err(de::Error::unknown_field(value, FIELDS)), 87 | } 88 | } 89 | } 90 | 91 | deserializer.deserialize_identifier(FieldVisitor) 92 | } 93 | } 94 | 95 | struct FixedBitSetVisitor; 96 | 97 | impl<'de> Visitor<'de> for FixedBitSetVisitor { 98 | type Value = FixedBitSet; 99 | 100 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 101 | formatter.write_str("struct Duration") 102 | } 103 | 104 | fn visit_seq(self, mut seq: V) -> Result 105 | where 106 | V: SeqAccess<'de>, 107 | { 108 | let length = seq 109 | .next_element()? 110 | .ok_or_else(|| de::Error::invalid_length(0, &self))?; 111 | let data: &[u8] = seq 112 | .next_element()? 113 | .ok_or_else(|| de::Error::invalid_length(1, &self))?; 114 | let data = bytes_to_data(length, data); 115 | Ok(FixedBitSet::with_capacity_and_blocks(length, data)) 116 | } 117 | 118 | fn visit_map(self, mut map: V) -> Result 119 | where 120 | V: MapAccess<'de>, 121 | { 122 | let mut length = None; 123 | let mut temp: Option<&[u8]> = None; 124 | while let Some(key) = map.next_key()? { 125 | match key { 126 | Field::Length => { 127 | if length.is_some() { 128 | return Err(de::Error::duplicate_field("length")); 129 | } 130 | length = Some(map.next_value()?); 131 | } 132 | Field::Data => { 133 | if temp.is_some() { 134 | return Err(de::Error::duplicate_field("data")); 135 | } 136 | temp = Some(map.next_value()?); 137 | } 138 | } 139 | } 140 | let length = length.ok_or_else(|| de::Error::missing_field("length"))?; 141 | let data = temp.ok_or_else(|| de::Error::missing_field("data"))?; 142 | let data = bytes_to_data(length, data); 143 | Ok(FixedBitSet::with_capacity_and_blocks(length, data)) 144 | } 145 | } 146 | 147 | const FIELDS: &'static [&'static str] = &["length", "data"]; 148 | deserializer.deserialize_struct("Duration", FIELDS, FixedBitSetVisitor) 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fixedbitset 2 | --- 3 | 4 | A simple fixed size bitset container for Rust. 5 | 6 | Please read the [API documentation here](https://docs.rs/fixedbitset/) 7 | 8 | [![build\_status](https://github.com/petgraph/fixedbitset/actions/workflows/rust.yml/badge.svg)](https://github.com/petgraph/fixedbitset/actions) 9 | [![crates](https://img.shields.io/crates/v/fixedbitset.svg)](https://crates.io/crates/fixedbitset) 10 | 11 | # Recent Changes 12 | 13 | - 0.5.7 14 | - [#127](https://github.com/petgraph/fixedbitset/pull/127) and [#128](https://github.com/petgraph/fixedbitset/pull/128): Optimize `Clone::clone_from` to avoid 15 | extra allocations and copies. 16 | - 0.5.6 17 | - Fixed FixedBitset not implementing Send/Sync due to the stack size shrink. 18 | - 0.5.5 (yanked) 19 | - [#116](https://github.com/petgraph/fixedbitset/pull/116): Add functions for counting the results of a set operation (`union_count`, 20 | `intersection_count`, `difference_count`, `symmetric_difference_count`) by @james7132. 21 | - [#118](https://github.com/petgraph/fixedbitset/pull/118): Shrink the stack size of FixedBitset. There should be zero stack size overhead 22 | compared to a Vec. 23 | - [#119](https://github.com/petgraph/fixedbitset/pull/119): Fix builds for wasm32. 24 | - [#120](https://github.com/petgraph/fixedbitset/pull/119): Add more utility functions that were previously missing from the public interface: 25 | `contains_any_in_range`, `contains_all_in_range`, `minimum`, `maximum`, `is_full`, `count_zeroes`, and `remove_range`. 26 | - [#121](https://github.com/petgraph/fixedbitset/pull/121): Add support for SIMD acceleration for AVX builds. 27 | - 0.5.4 28 | - [#112](https://github.com/petgraph/fixedbitset/pull/112): Fix undefined behavior in IntoOnes and setup testing with MIRI by @SkiFire13 29 | - 0.5.3 (yanked) 30 | - [#109](https://github.com/petgraph/fixedbitset/pull/109): Fix non-x86(_64) builds by @james7132 31 | - 0.5.2 (yanked) 32 | - [#86](https://github.com/petgraph/fixedbitset/pull/86): Explicit SIMD vectorization for set operations by @james7132. 33 | - 0.5.1 34 | - [#102](https://github.com/petgraph/fixedbitset/pull/102): Added `contains_unchecked`, `insert_unchecked`, `put_unchecked`, 35 | `set_unchecked`, `toggle_unchecked`, `removed_unchecked`, `copy_bit_unchecked` unsafe variants of the safe functions, by @james7132 36 | - [#103](https://github.com/petgraph/fixedbitset/pull/103): Added `into_ones` which returns a owned iterator over the one 37 | values from a bitset, by @james7132. 38 | - [#104](https://github.com/petgraph/fixedbitset/pull/104): Implemented `DoubleEndedIterator` for `Union`, `Intersection`, 39 | `Difference`, and `SymmetricDifference` , by @james7132. 40 | - 0.5.0 41 | - [#74](https://github.com/petgraph/fixedbitset/pull/74): Accelerated set operations (union, intersection, difference, 42 | symmetric difference) by using larger blocks internally, by @james7132. 43 | - [#88](https://github.com/petgraph/fixedbitset/pull/88): Added `FixedBitSet::remove` by @james7132. 44 | - [#89](https://github.com/petgraph/fixedbitset/pull/89): Added `FixedBitSet::zeros` and the `Zeros` iterator by @james7132. 45 | - [#92](https://github.com/petgraph/fixedbitset/pull/92): Added `FixedBitSet::grow_and_insert` function, a 46 | non-panicking version of `insert` that grows the underlying storage as need, by @shuoli84. 47 | - [#98](https://github.com/petgraph/fixedbitset/pull/98): `Ones` now implements `DoubleEndedIterator`, by @tikhu. 48 | - [#99](https://github.com/petgraph/fixedbitset/pull/99): **Breaking change**: serde now serializes and deserializes from a little-endian encoded 49 | raw byte buffer. Existing stored instances of the serialized bitsets will need to be 50 | re-encoded. 51 | - Bumped MSRV to 1.56. 52 | - 0.4.2 53 | - [#79](https://github.com/petgraph/fixedbitset/pull/79): Add `is_clear`, 54 | clarify `is_empty` and `len` documentation by \@nicopap. 55 | - 0.4.1 56 | - Documentation and formatting fixes. 57 | - 0.4.0 58 | - [#61](https://github.com/petgraph/fixedbitset/pull/61): Require 59 | Rust 1.39. 60 | - [#60](https://github.com/petgraph/fixedbitset/pull/60): Add 61 | `const` `FixedBitSet::new` consructor 62 | by \@jakobhellermann. 63 | - [#59](https://github.com/petgraph/fixedbitset/pull/59): Add 64 | optional `serde` support by \@keshavsn. 65 | - 0.3.2 66 | - [#18](https://github.com/petgraph/fixedbitset/pull/18): Optimize 67 | `ones` using `trailing_zeroes` by \@vks 68 | - 0.3.1 69 | - Add bit assign operators for references by \@flaghacker 70 | - Improve assertion error messages by \@lovasoa 71 | - Add documentation examples for `with_capacity_and_blocks` 72 | - 0.3.0 73 | - Add `with_capacity_and_blocks` by \@luizirber 74 | - Add `difference_with` by \@sunshowers 75 | - Implement `Binary` and `Display` traits by \@Dolphindalt 76 | - Add `toggle_range` by \@wirelyre 77 | - 0.2.0 78 | - Add assign operators for the bit operations by \@jrraymond 79 | - Add `symmetric_difference`, `union_with`, `intersection_with` by 80 | \@jrraymond 81 | - Add `is_subset`, `is_superset`, `is_disjoint` by \@nwn 82 | - Add `.toggle(i)` method by \@ShiroUsagi-san 83 | - Add default feature \"std\" which can be disabled to make the 84 | crate not link the std library. By \@jonimake and \@bluss 85 | - Require Rust 1.31. 86 | - 0.1.9 87 | - Add intersection, union, difference iterators by \@jrraymond 88 | - Add intersection: `&` and union: `|` operator implementations by 89 | \@jrraymond 90 | - Add Extend and FromIterator implementations (from sequences of 91 | bit indices) by \@jrraymond 92 | - 0.1.8 93 | - Add missing `#[inline]` on the ones iterator 94 | - Fix docs for `insert_range, set_range` 95 | - 0.1.7 96 | - Add fast methods `.insert_range`, `.set_range` by \@kennytm 97 | - 0.1.6 98 | - Add iterator `.ones()` by \@mneumann 99 | - Fix bug with `.count_ones()` where it would erronously have an 100 | out-of-bounds panic for even block endpoints 101 | - 0.1.5 102 | - Add method `.count_ones(range)`. 103 | - 0.1.4 104 | - Remove an assertion in `.copy_bit(from, to)` so that it is in 105 | line with the documentation. The `from` bit does not need to be 106 | in bounds. 107 | - Improve `.grow()` to use `Vec::resize` internally. 108 | - 0.1.3 109 | - Add method `.put()` to enable a bit and return previous value 110 | - 0.1.2 111 | - Add method `.copy_bit()` (by fuine) 112 | - impl Default 113 | - 0.1.1 114 | - Update documentation URL 115 | - 0.1.0 116 | - Add method `.grow()` 117 | 118 | # License 119 | 120 | Dual-licensed to be compatible with the Rust project. 121 | 122 | Licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) 123 | or the [MIT license](https://opensource.org/licenses/MIT), 124 | at your option. This file may not be copied, modified, or distributed except 125 | according to those terms. 126 | -------------------------------------------------------------------------------- /benches/benches/benches.rs: -------------------------------------------------------------------------------- 1 | extern crate criterion; 2 | extern crate fixedbitset; 3 | use criterion::{criterion_group, criterion_main, Criterion}; 4 | use fixedbitset::FixedBitSet; 5 | use std::hint::black_box; 6 | 7 | #[inline] 8 | fn iter_ones_using_contains(fb: &FixedBitSet, f: &mut F) { 9 | for bit in 0..fb.len() { 10 | if fb.contains(bit) { 11 | f(bit); 12 | } 13 | } 14 | } 15 | 16 | fn iter_ones_using_contains_all_zeros(c: &mut Criterion) { 17 | const N: usize = 1_000_000; 18 | let fb = FixedBitSet::with_capacity(N); 19 | 20 | c.bench_function("iter_ones/contains_all_zeros", |b| { 21 | b.iter(|| { 22 | let mut count = 0; 23 | iter_ones_using_contains(&fb, &mut |_bit| count += 1); 24 | count 25 | }) 26 | }); 27 | } 28 | 29 | fn iter_ones_using_contains_all_ones(c: &mut Criterion) { 30 | const N: usize = 1_000_000; 31 | let mut fb = FixedBitSet::with_capacity(N); 32 | fb.insert_range(..); 33 | 34 | c.bench_function("iter_ones/contains_all_ones", |b| { 35 | b.iter(|| { 36 | let mut count = 0; 37 | iter_ones_using_contains(&fb, &mut |_bit| count += 1); 38 | count 39 | }) 40 | }); 41 | } 42 | 43 | fn iter_ones_all_zeros(c: &mut Criterion) { 44 | const N: usize = 1_000_000; 45 | let fb = FixedBitSet::with_capacity(N); 46 | 47 | c.bench_function("iter_ones/all_zeros", |b| { 48 | b.iter(|| { 49 | let mut count = 0; 50 | for _ in fb.ones() { 51 | count += 1; 52 | } 53 | count 54 | }) 55 | }); 56 | } 57 | 58 | fn iter_ones_sparse(c: &mut Criterion) { 59 | const N: usize = 1_000_000; 60 | let mut fb = FixedBitSet::with_capacity(N); 61 | for i in 0..N { 62 | if i % 2 == 0 { 63 | fb.insert(i); 64 | } 65 | } 66 | c.bench_function("iter_ones/sparse", |b| { 67 | b.iter(|| { 68 | let mut count = 0; 69 | for _ in fb.ones() { 70 | count += 1; 71 | } 72 | count 73 | }) 74 | }); 75 | } 76 | 77 | fn iter_ones_all_ones(c: &mut Criterion) { 78 | const N: usize = 1_000_000; 79 | let mut fb = FixedBitSet::with_capacity(N); 80 | fb.insert_range(..); 81 | 82 | c.bench_function("iter_ones/all_ones", |b| { 83 | b.iter(|| { 84 | let mut count = 0; 85 | for _ in fb.ones() { 86 | count += 1; 87 | } 88 | count 89 | }) 90 | }); 91 | } 92 | 93 | fn iter_ones_all_ones_rev(c: &mut Criterion) { 94 | const N: usize = 1_000_000; 95 | let mut fb = FixedBitSet::with_capacity(N); 96 | fb.insert_range(..); 97 | 98 | c.bench_function("iter_ones/all_ones", |b| { 99 | b.iter(|| { 100 | let mut count = 0; 101 | for _ in fb.ones().rev() { 102 | count += 1; 103 | } 104 | count 105 | }) 106 | }); 107 | } 108 | 109 | fn insert_range(c: &mut Criterion) { 110 | const N: usize = 1_000_000; 111 | let mut fb = FixedBitSet::with_capacity(N); 112 | 113 | c.bench_function("insert_range/1m", |b| b.iter(|| fb.insert_range(..))); 114 | } 115 | 116 | fn insert(c: &mut Criterion) { 117 | const N: usize = 1_000_000; 118 | let mut fb = FixedBitSet::with_capacity(N); 119 | 120 | c.bench_function("insert/1m", |b| { 121 | b.iter(|| { 122 | for i in 0..N { 123 | fb.insert(i); 124 | } 125 | }) 126 | }); 127 | } 128 | 129 | fn grow_and_insert(c: &mut Criterion) { 130 | const N: usize = 1_000_000; 131 | let mut fb = FixedBitSet::with_capacity(N); 132 | 133 | c.bench_function("grow_and_insert", |b| { 134 | b.iter(|| { 135 | for i in 0..N { 136 | fb.grow_and_insert(i); 137 | } 138 | }) 139 | }); 140 | } 141 | 142 | fn iter_union_count(c: &mut Criterion) { 143 | const N: usize = 1_000_000; 144 | let mut fb_a = FixedBitSet::with_capacity(N); 145 | let mut fb_b = FixedBitSet::with_capacity(N); 146 | 147 | fb_a.insert_range(..); 148 | fb_b.insert_range(..); 149 | 150 | c.bench_function("iter_union_count/1m", |b| { 151 | b.iter(|| black_box(fb_a.union(&fb_b).count())) 152 | }); 153 | } 154 | 155 | fn iter_intersect_count(c: &mut Criterion) { 156 | const N: usize = 1_000_000; 157 | let mut fb_a = FixedBitSet::with_capacity(N); 158 | let mut fb_b = FixedBitSet::with_capacity(N); 159 | 160 | fb_a.insert_range(..); 161 | fb_b.insert_range(..); 162 | 163 | c.bench_function("iter_intersection_count/1m", |b| { 164 | b.iter(|| black_box(fb_a.intersection(&fb_b).count())); 165 | }); 166 | } 167 | 168 | fn iter_difference_count(c: &mut Criterion) { 169 | const N: usize = 1_000_000; 170 | let mut fb_a = FixedBitSet::with_capacity(N); 171 | let mut fb_b = FixedBitSet::with_capacity(N); 172 | 173 | fb_a.insert_range(..); 174 | fb_b.insert_range(..); 175 | 176 | c.bench_function("iter_difference_count/1m", |b| { 177 | b.iter(|| black_box(fb_a.difference(&fb_b).count())); 178 | }); 179 | } 180 | 181 | fn iter_symmetric_difference_count(c: &mut Criterion) { 182 | const N: usize = 1_000_000; 183 | let mut fb_a = FixedBitSet::with_capacity(N); 184 | let mut fb_b = FixedBitSet::with_capacity(N); 185 | 186 | fb_a.insert_range(..); 187 | fb_b.insert_range(..); 188 | 189 | c.bench_function("iter_symmetric_difference_count/1m", |b| { 190 | b.iter(|| black_box(fb_a.symmetric_difference(&fb_b).count())); 191 | }); 192 | } 193 | 194 | fn union_count(c: &mut Criterion) { 195 | const N: usize = 1_000_000; 196 | let mut fb_a = FixedBitSet::with_capacity(N); 197 | let mut fb_b = FixedBitSet::with_capacity(N); 198 | 199 | fb_a.insert_range(..); 200 | fb_b.insert_range(..); 201 | 202 | c.bench_function("union_count/1m", |b| { 203 | b.iter(|| black_box(fb_a.union_count(&fb_b))) 204 | }); 205 | } 206 | 207 | fn intersect_count(c: &mut Criterion) { 208 | const N: usize = 1_000_000; 209 | let mut fb_a = FixedBitSet::with_capacity(N); 210 | let mut fb_b = FixedBitSet::with_capacity(N); 211 | 212 | fb_a.insert_range(..); 213 | fb_b.insert_range(..); 214 | 215 | c.bench_function("intersection_count/1m", |b| { 216 | b.iter(|| black_box(fb_a.intersection_count(&fb_b))); 217 | }); 218 | } 219 | 220 | fn difference_count(c: &mut Criterion) { 221 | const N: usize = 1_000_000; 222 | let mut fb_a = FixedBitSet::with_capacity(N); 223 | let mut fb_b = FixedBitSet::with_capacity(N); 224 | 225 | fb_a.insert_range(..); 226 | fb_b.insert_range(..); 227 | 228 | c.bench_function("difference_count/1m", |b| { 229 | b.iter(|| black_box(fb_a.difference_count(&fb_b))); 230 | }); 231 | } 232 | 233 | fn symmetric_difference_count(c: &mut Criterion) { 234 | const N: usize = 1_000_000; 235 | let mut fb_a = FixedBitSet::with_capacity(N); 236 | let mut fb_b = FixedBitSet::with_capacity(N); 237 | 238 | fb_a.insert_range(..); 239 | fb_b.insert_range(..); 240 | 241 | c.bench_function("symmetric_difference_count/1m", |b| { 242 | b.iter(|| black_box(fb_a.symmetric_difference_count(&fb_b))); 243 | }); 244 | } 245 | 246 | fn union_with(c: &mut Criterion) { 247 | const N: usize = 1_000_000; 248 | let mut fb_a = FixedBitSet::with_capacity(N); 249 | let fb_b = FixedBitSet::with_capacity(N); 250 | 251 | c.bench_function("union_with/1m", |b| b.iter(|| fb_a.union_with(&fb_b))); 252 | } 253 | 254 | fn intersect_with(c: &mut Criterion) { 255 | const N: usize = 1_000_000; 256 | let mut fb_a = FixedBitSet::with_capacity(N); 257 | let fb_b = FixedBitSet::with_capacity(N); 258 | 259 | c.bench_function("intersect_with/1m", |b| { 260 | b.iter(|| fb_a.intersect_with(&fb_b)) 261 | }); 262 | } 263 | 264 | fn difference_with(c: &mut Criterion) { 265 | const N: usize = 1_000_000; 266 | let mut fb_a = FixedBitSet::with_capacity(N); 267 | let fb_b = FixedBitSet::with_capacity(N); 268 | 269 | c.bench_function("difference_with/1m", |b| { 270 | b.iter(|| fb_a.difference_with(&fb_b)) 271 | }); 272 | } 273 | 274 | fn symmetric_difference_with(c: &mut Criterion) { 275 | const N: usize = 1_000_000; 276 | let mut fb_a = FixedBitSet::with_capacity(N); 277 | let fb_b = FixedBitSet::with_capacity(N); 278 | 279 | c.bench_function("symmetric_difference_with/1m", |b| { 280 | b.iter(|| fb_a.symmetric_difference_with(&fb_b)) 281 | }); 282 | } 283 | 284 | fn clear(c: &mut Criterion) { 285 | const N: usize = 1_000_000; 286 | let mut fb_a = FixedBitSet::with_capacity(N); 287 | 288 | c.bench_function("clear/1m", |b| b.iter(|| fb_a.clear())); 289 | } 290 | 291 | fn count_ones(c: &mut Criterion) { 292 | const N: usize = 1_000_000; 293 | let fb_a = FixedBitSet::with_capacity(N); 294 | 295 | c.bench_function("count_ones/1m", |b| { 296 | b.iter(|| black_box(fb_a.count_ones(..))) 297 | }); 298 | } 299 | 300 | criterion_group!( 301 | benches, 302 | iter_ones_using_contains_all_zeros, 303 | iter_ones_using_contains_all_ones, 304 | iter_ones_all_zeros, 305 | iter_ones_sparse, 306 | iter_ones_all_ones, 307 | iter_ones_all_ones_rev, 308 | iter_union_count, 309 | iter_intersect_count, 310 | iter_difference_count, 311 | iter_symmetric_difference_count, 312 | union_count, 313 | intersect_count, 314 | difference_count, 315 | symmetric_difference_count, 316 | insert_range, 317 | insert, 318 | intersect_with, 319 | difference_with, 320 | union_with, 321 | symmetric_difference_with, 322 | count_ones, 323 | clear, 324 | grow_and_insert, 325 | ); 326 | criterion_main!(benches); 327 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /tests/tests.rs: -------------------------------------------------------------------------------- 1 | use fixedbitset::*; 2 | 3 | #[cfg(target_family = "wasm")] 4 | use wasm_bindgen_test::*; 5 | #[cfg(target_family = "wasm")] 6 | wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); 7 | 8 | extern crate alloc; 9 | 10 | const BITS: usize = core::mem::size_of::() * 8; 11 | 12 | #[test] 13 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 14 | fn it_works() { 15 | const N: usize = 50; 16 | let mut fb = FixedBitSet::with_capacity(N); 17 | 18 | for i in 0..(N + 10) { 19 | assert_eq!(fb.contains(i), false); 20 | } 21 | 22 | fb.insert(10); 23 | fb.set(11, false); 24 | fb.set(12, false); 25 | fb.set(12, true); 26 | fb.set(N - 1, true); 27 | 28 | assert!(fb.contains(10)); 29 | assert!(!fb.contains(11)); 30 | assert!(fb.contains(12)); 31 | assert!(fb.contains(N - 1)); 32 | for i in 0..N { 33 | let contain = i == 10 || i == 12 || i == N - 1; 34 | assert_eq!(contain, fb[i]); 35 | } 36 | 37 | fb.clear(); 38 | } 39 | 40 | #[test] 41 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 42 | fn with_blocks() { 43 | let fb = FixedBitSet::with_capacity_and_blocks(50, vec![8, 0]); 44 | assert!(fb.contains(3)); 45 | 46 | let ones: Vec<_> = fb.ones().collect(); 47 | assert_eq!(ones.len(), 1); 48 | 49 | let ones: Vec<_> = fb.ones().rev().collect(); 50 | assert_eq!(ones.len(), 1); 51 | 52 | let ones: Vec<_> = fb.ones().rev().alternate().collect(); 53 | assert_eq!(ones.len(), 1); 54 | } 55 | 56 | #[test] 57 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 58 | fn with_blocks_too_small() { 59 | let mut fb = FixedBitSet::with_capacity_and_blocks(500, vec![8, 0]); 60 | fb.insert(400); 61 | assert!(fb.contains(400)); 62 | } 63 | 64 | #[test] 65 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 66 | fn with_blocks_too_big() { 67 | let fb = FixedBitSet::with_capacity_and_blocks(1, vec![8]); 68 | 69 | // since capacity is 1, 3 shouldn't be set here 70 | assert!(!fb.contains(3)); 71 | } 72 | 73 | #[test] 74 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 75 | fn with_blocks_too_big_range_check() { 76 | let fb = FixedBitSet::with_capacity_and_blocks(1, vec![0xff]); 77 | 78 | // since capacity is 1, only 0 should be set 79 | assert!(fb.contains(0)); 80 | for i in 1..0xff { 81 | assert!(!fb.contains(i)); 82 | } 83 | } 84 | 85 | #[test] 86 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 87 | fn grow() { 88 | let mut fb = FixedBitSet::with_capacity(48); 89 | for i in 0..fb.len() { 90 | fb.set(i, true); 91 | } 92 | 93 | let old_len = fb.len(); 94 | fb.grow(72); 95 | for j in 0..fb.len() { 96 | assert_eq!(fb.contains(j), j < old_len); 97 | } 98 | fb.set(64, true); 99 | assert!(fb.contains(64)); 100 | } 101 | 102 | #[test] 103 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 104 | fn grow_and_insert() { 105 | let mut fb = FixedBitSet::default(); 106 | for i in 0..100 { 107 | if i % 3 == 0 { 108 | fb.grow_and_insert(i); 109 | } 110 | } 111 | 112 | assert_eq!(fb.count_ones(..), 34); 113 | } 114 | 115 | #[test] 116 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 117 | fn test_toggle() { 118 | let mut fb = FixedBitSet::with_capacity(16); 119 | fb.toggle(1); 120 | fb.put(2); 121 | fb.toggle(2); 122 | fb.put(3); 123 | assert!(fb.contains(1)); 124 | assert!(!fb.contains(2)); 125 | assert!(fb.contains(3)); 126 | } 127 | 128 | #[test] 129 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 130 | fn copy_bit() { 131 | let mut fb = FixedBitSet::with_capacity(48); 132 | for i in 0..fb.len() { 133 | fb.set(i, true); 134 | } 135 | fb.set(42, false); 136 | fb.copy_bit(42, 2); 137 | assert!(!fb.contains(42)); 138 | assert!(!fb.contains(2)); 139 | assert!(fb.contains(1)); 140 | fb.copy_bit(1, 42); 141 | assert!(fb.contains(42)); 142 | fb.copy_bit(1024, 42); 143 | assert!(!fb[42]); 144 | } 145 | 146 | #[test] 147 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 148 | fn count_ones() { 149 | let mut fb = FixedBitSet::with_capacity(100); 150 | fb.set(11, true); 151 | fb.set(12, true); 152 | fb.set(7, true); 153 | fb.set(35, true); 154 | fb.set(40, true); 155 | fb.set(77, true); 156 | fb.set(95, true); 157 | fb.set(50, true); 158 | fb.set(99, true); 159 | assert_eq!(fb.count_ones(..7), 0); 160 | assert_eq!(fb.count_ones(..8), 1); 161 | assert_eq!(fb.count_ones(..11), 1); 162 | assert_eq!(fb.count_ones(..12), 2); 163 | assert_eq!(fb.count_ones(..13), 3); 164 | assert_eq!(fb.count_ones(..35), 3); 165 | assert_eq!(fb.count_ones(..36), 4); 166 | assert_eq!(fb.count_ones(..40), 4); 167 | assert_eq!(fb.count_ones(..41), 5); 168 | assert_eq!(fb.count_ones(50..), 4); 169 | assert_eq!(fb.count_ones(70..95), 1); 170 | assert_eq!(fb.count_ones(70..96), 2); 171 | assert_eq!(fb.count_ones(70..99), 2); 172 | assert_eq!(fb.count_ones(..), 9); 173 | assert_eq!(fb.count_ones(0..100), 9); 174 | assert_eq!(fb.count_ones(0..0), 0); 175 | assert_eq!(fb.count_ones(100..100), 0); 176 | assert_eq!(fb.count_ones(7..), 9); 177 | assert_eq!(fb.count_ones(8..), 8); 178 | } 179 | 180 | #[test] 181 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 182 | fn count_zeroes() { 183 | let mut fb = FixedBitSet::with_capacity(100); 184 | fb.set(11, true); 185 | fb.set(12, true); 186 | fb.set(7, true); 187 | fb.set(35, true); 188 | fb.set(40, true); 189 | fb.set(77, true); 190 | fb.set(95, true); 191 | fb.set(50, true); 192 | fb.set(99, true); 193 | assert_eq!(fb.count_zeroes(..7), 7); 194 | assert_eq!(fb.count_zeroes(..8), 7); 195 | assert_eq!(fb.count_zeroes(..11), 10); 196 | assert_eq!(fb.count_zeroes(..12), 10); 197 | assert_eq!(fb.count_zeroes(..13), 10); 198 | assert_eq!(fb.count_zeroes(..35), 32); 199 | assert_eq!(fb.count_zeroes(..36), 32); 200 | assert_eq!(fb.count_zeroes(..40), 36); 201 | assert_eq!(fb.count_zeroes(..41), 36); 202 | assert_eq!(fb.count_zeroes(50..), 46); 203 | assert_eq!(fb.count_zeroes(70..95), 24); 204 | assert_eq!(fb.count_zeroes(70..96), 24); 205 | assert_eq!(fb.count_zeroes(70..99), 27); 206 | assert_eq!(fb.count_zeroes(..), 91); 207 | assert_eq!(fb.count_zeroes(0..100), 91); 208 | assert_eq!(fb.count_zeroes(0..0), 0); 209 | assert_eq!(fb.count_zeroes(100..100), 0); 210 | assert_eq!(fb.count_zeroes(7..), 84); 211 | assert_eq!(fb.count_zeroes(8..), 84); 212 | } 213 | 214 | #[test] 215 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 216 | fn minimum() { 217 | let mut fb = FixedBitSet::with_capacity(100); 218 | assert_eq!(fb.minimum(), None); 219 | fb.set(95, true); 220 | assert_eq!(fb.minimum(), Some(95)); 221 | fb.set(77, true); 222 | assert_eq!(fb.minimum(), Some(77)); 223 | fb.set(12, true); 224 | assert_eq!(fb.minimum(), Some(12)); 225 | fb.set(40, true); 226 | assert_eq!(fb.minimum(), Some(12)); 227 | fb.set(35, true); 228 | assert_eq!(fb.minimum(), Some(12)); 229 | fb.set(11, true); 230 | assert_eq!(fb.minimum(), Some(11)); 231 | fb.set(7, true); 232 | assert_eq!(fb.minimum(), Some(7)); 233 | fb.set(50, true); 234 | assert_eq!(fb.minimum(), Some(7)); 235 | fb.set(99, true); 236 | assert_eq!(fb.minimum(), Some(7)); 237 | fb.clear(); 238 | assert_eq!(fb.minimum(), None); 239 | } 240 | 241 | #[test] 242 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 243 | fn maximum() { 244 | let mut fb = FixedBitSet::with_capacity(100); 245 | assert_eq!(fb.maximum(), None); 246 | fb.set(11, true); 247 | assert_eq!(fb.maximum(), Some(11)); 248 | fb.set(12, true); 249 | assert_eq!(fb.maximum(), Some(12)); 250 | fb.set(7, true); 251 | assert_eq!(fb.maximum(), Some(12)); 252 | fb.set(40, true); 253 | assert_eq!(fb.maximum(), Some(40)); 254 | fb.set(35, true); 255 | assert_eq!(fb.maximum(), Some(40)); 256 | fb.set(95, true); 257 | assert_eq!(fb.maximum(), Some(95)); 258 | fb.set(50, true); 259 | assert_eq!(fb.maximum(), Some(95)); 260 | fb.set(77, true); 261 | assert_eq!(fb.maximum(), Some(95)); 262 | fb.set(99, true); 263 | assert_eq!(fb.maximum(), Some(99)); 264 | fb.clear(); 265 | assert_eq!(fb.maximum(), None); 266 | } 267 | 268 | /* Helper for testing double ended iterator */ 269 | #[cfg(test)] 270 | struct Alternating { 271 | iter: I, 272 | front: bool, 273 | } 274 | 275 | #[cfg(test)] 276 | impl Iterator for Alternating { 277 | type Item = I::Item; 278 | 279 | fn size_hint(&self) -> (usize, Option) { 280 | self.iter.size_hint() 281 | } 282 | fn next(&mut self) -> Option { 283 | if self.front { 284 | self.front = false; 285 | self.iter.next() 286 | } else { 287 | self.front = true; 288 | self.iter.next_back() 289 | } 290 | } 291 | } 292 | #[cfg(test)] 293 | trait AlternatingExt: Iterator + DoubleEndedIterator + Sized { 294 | fn alternate(self) -> Alternating { 295 | Alternating { 296 | iter: self, 297 | front: true, 298 | } 299 | } 300 | } 301 | 302 | #[cfg(test)] 303 | impl AlternatingExt for I {} 304 | 305 | #[test] 306 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 307 | fn ones() { 308 | let mut fb = FixedBitSet::with_capacity(100); 309 | fb.set(11, true); 310 | fb.set(12, true); 311 | fb.set(7, true); 312 | fb.set(35, true); 313 | fb.set(40, true); 314 | fb.set(77, true); 315 | fb.set(95, true); 316 | fb.set(50, true); 317 | fb.set(99, true); 318 | 319 | let ones: Vec<_> = fb.ones().collect(); 320 | let ones_rev: Vec<_> = fb.ones().rev().collect(); 321 | let ones_alternating: Vec<_> = fb.ones().alternate().collect(); 322 | 323 | let mut known_result = vec![7, 11, 12, 35, 40, 50, 77, 95, 99]; 324 | 325 | assert_eq!(known_result, ones); 326 | known_result.reverse(); 327 | assert_eq!(known_result, ones_rev); 328 | let known_result: Vec<_> = known_result.into_iter().rev().alternate().collect(); 329 | assert_eq!(known_result, ones_alternating); 330 | } 331 | 332 | #[test] 333 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 334 | fn into_ones() { 335 | fn create() -> FixedBitSet { 336 | let mut fb = FixedBitSet::with_capacity(100); 337 | fb.set(11, true); 338 | fb.set(12, true); 339 | fb.set(7, true); 340 | fb.set(35, true); 341 | fb.set(40, true); 342 | fb.set(77, true); 343 | fb.set(95, true); 344 | fb.set(50, true); 345 | fb.set(99, true); 346 | fb 347 | } 348 | 349 | let ones: Vec<_> = create().into_ones().collect(); 350 | let ones_rev: Vec<_> = create().into_ones().rev().collect(); 351 | let ones_alternating: Vec<_> = create().into_ones().alternate().collect(); 352 | 353 | let mut known_result = vec![7, 11, 12, 35, 40, 50, 77, 95, 99]; 354 | 355 | assert_eq!(known_result, ones); 356 | known_result.reverse(); 357 | assert_eq!(known_result, ones_rev); 358 | let known_result: Vec<_> = known_result.into_iter().rev().alternate().collect(); 359 | assert_eq!(known_result, ones_alternating); 360 | } 361 | 362 | #[test] 363 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 364 | fn size_hint() { 365 | let iters = if cfg!(miri) { 250 } else { 1000 }; 366 | for s in 0..iters { 367 | let mut bitset = FixedBitSet::with_capacity(s); 368 | bitset.insert_range(..); 369 | let mut t = s; 370 | let mut iter = bitset.ones().rev(); 371 | loop { 372 | match iter.next() { 373 | None => break, 374 | Some(_) => { 375 | t -= 1; 376 | assert!(iter.size_hint().1.unwrap() >= t); 377 | // factor two, because we have first block and last block 378 | assert!(iter.size_hint().1.unwrap() <= t + 2 * BITS); 379 | } 380 | } 381 | } 382 | assert_eq!(t, 0); 383 | } 384 | } 385 | 386 | #[test] 387 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 388 | fn size_hint_alternate() { 389 | let iters = if cfg!(miri) { 250 } else { 1000 }; 390 | for s in 0..iters { 391 | let mut bitset = FixedBitSet::with_capacity(s); 392 | bitset.insert_range(..); 393 | let mut t = s; 394 | extern crate std; 395 | let mut iter = bitset.ones().alternate(); 396 | loop { 397 | match iter.next() { 398 | None => break, 399 | Some(_) => { 400 | t -= 1; 401 | assert!(iter.size_hint().1.unwrap() >= t); 402 | assert!(iter.size_hint().1.unwrap() <= t + 3 * BITS); 403 | } 404 | } 405 | } 406 | assert_eq!(t, 0); 407 | } 408 | } 409 | 410 | #[test] 411 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 412 | fn iter_ones_range() { 413 | fn test_range(from: usize, to: usize, capa: usize) { 414 | assert!(to <= capa); 415 | let mut fb = FixedBitSet::with_capacity(capa); 416 | for i in from..to { 417 | fb.insert(i); 418 | } 419 | let ones: Vec<_> = fb.ones().collect(); 420 | let expected: Vec<_> = (from..to).collect(); 421 | let ones_rev: Vec<_> = fb.ones().rev().collect(); 422 | let expected_rev: Vec<_> = (from..to).rev().collect(); 423 | let ones_rev_alt: Vec<_> = fb.ones().rev().alternate().collect(); 424 | let expected_rev_alt: Vec<_> = (from..to).rev().alternate().collect(); 425 | assert_eq!(expected, ones); 426 | assert_eq!(expected_rev, ones_rev); 427 | assert_eq!(expected_rev_alt, ones_rev_alt); 428 | } 429 | 430 | for i in 0..100 { 431 | test_range(i, 100, 100); 432 | test_range(0, i, 100); 433 | } 434 | } 435 | 436 | #[should_panic] 437 | #[test] 438 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 439 | fn count_ones_oob() { 440 | let fb = FixedBitSet::with_capacity(100); 441 | fb.count_ones(90..101); 442 | } 443 | 444 | #[should_panic] 445 | #[test] 446 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 447 | fn count_ones_negative_range() { 448 | let fb = FixedBitSet::with_capacity(100); 449 | fb.count_ones(90..80); 450 | } 451 | 452 | #[test] 453 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 454 | fn count_ones_panic() { 455 | let iters = if cfg!(miri) { 48 } else { 128 }; 456 | for i in 1..iters { 457 | let fb = FixedBitSet::with_capacity(i); 458 | for j in 0..fb.len() + 1 { 459 | for k in j..fb.len() + 1 { 460 | assert_eq!(fb.count_ones(j..k), 0); 461 | } 462 | } 463 | } 464 | } 465 | 466 | #[test] 467 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 468 | fn default() { 469 | let fb = FixedBitSet::default(); 470 | assert_eq!(fb.len(), 0); 471 | } 472 | 473 | #[test] 474 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 475 | fn insert_range() { 476 | let mut fb = FixedBitSet::with_capacity(97); 477 | fb.insert_range(..3); 478 | fb.insert_range(9..32); 479 | fb.insert_range(37..81); 480 | fb.insert_range(90..); 481 | for i in 0..97 { 482 | assert_eq!( 483 | fb.contains(i), 484 | i < 3 || 9 <= i && i < 32 || 37 <= i && i < 81 || 90 <= i 485 | ); 486 | } 487 | assert!(!fb.contains(97)); 488 | assert!(!fb.contains(127)); 489 | assert!(!fb.contains(128)); 490 | } 491 | 492 | #[test] 493 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 494 | fn contains_all_in_range() { 495 | let mut fb = FixedBitSet::with_capacity(48); 496 | fb.insert_range(..); 497 | 498 | fb.remove_range(..32); 499 | fb.remove_range(37..); 500 | 501 | assert!(fb.contains_all_in_range(32..37)); 502 | assert!(fb.contains_all_in_range(32..35)); 503 | assert!(!fb.contains_all_in_range(32..)); 504 | assert!(!fb.contains_all_in_range(..37)); 505 | assert!(!fb.contains_all_in_range(..)); 506 | } 507 | 508 | #[test] 509 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 510 | fn contains_any_in_range() { 511 | let mut fb = FixedBitSet::with_capacity(48); 512 | fb.insert_range(..); 513 | 514 | fb.remove_range(..32); 515 | fb.remove_range(37..); 516 | 517 | assert!(!fb.contains_any_in_range(..32)); 518 | assert!(fb.contains_any_in_range(32..37)); 519 | assert!(fb.contains_any_in_range(32..35)); 520 | assert!(fb.contains_any_in_range(32..)); 521 | assert!(fb.contains_any_in_range(..37)); 522 | assert!(!fb.contains_any_in_range(37..)); 523 | assert!(fb.contains_any_in_range(..)); 524 | } 525 | 526 | #[test] 527 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 528 | fn remove_range() { 529 | let mut fb = FixedBitSet::with_capacity(48); 530 | fb.insert_range(..); 531 | 532 | fb.remove_range(..32); 533 | fb.remove_range(37..); 534 | 535 | for i in 0..48 { 536 | assert_eq!(fb.contains(i), 32 <= i && i < 37); 537 | } 538 | } 539 | 540 | #[test] 541 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 542 | fn set_range() { 543 | let mut fb = FixedBitSet::with_capacity(48); 544 | fb.insert_range(..); 545 | 546 | fb.set_range(..32, false); 547 | fb.set_range(37.., false); 548 | fb.set_range(5..9, true); 549 | fb.set_range(40..40, true); 550 | 551 | for i in 0..48 { 552 | assert_eq!(fb.contains(i), 5 <= i && i < 9 || 32 <= i && i < 37); 553 | } 554 | assert!(!fb.contains(48)); 555 | assert!(!fb.contains(64)); 556 | } 557 | 558 | #[test] 559 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 560 | fn toggle_range() { 561 | let mut fb = FixedBitSet::with_capacity(40); 562 | fb.insert_range(..10); 563 | fb.insert_range(34..38); 564 | 565 | fb.toggle_range(5..12); 566 | fb.toggle_range(30..); 567 | 568 | for i in 0..40 { 569 | assert_eq!( 570 | fb.contains(i), 571 | i < 5 || 10 <= i && i < 12 || 30 <= i && i < 34 || 38 <= i 572 | ); 573 | } 574 | assert!(!fb.contains(40)); 575 | assert!(!fb.contains(64)); 576 | } 577 | 578 | #[test] 579 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 580 | fn bitand_equal_lengths() { 581 | let len = 109; 582 | let a_end = 59; 583 | let b_start = 23; 584 | let mut a = FixedBitSet::with_capacity(len); 585 | let mut b = FixedBitSet::with_capacity(len); 586 | a.set_range(..a_end, true); 587 | b.set_range(b_start.., true); 588 | let ab = &a & &b; 589 | for i in 0..b_start { 590 | assert!(!ab.contains(i)); 591 | } 592 | for i in b_start..a_end { 593 | assert!(ab.contains(i)); 594 | } 595 | for i in a_end..len { 596 | assert!(!ab.contains(i)); 597 | } 598 | assert_eq!(a.len(), ab.len()); 599 | } 600 | 601 | #[test] 602 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 603 | fn bitand_first_smaller() { 604 | let a_len = 113; 605 | let b_len = 137; 606 | let len = core::cmp::min(a_len, b_len); 607 | let a_end = 97; 608 | let b_start = 89; 609 | let mut a = FixedBitSet::with_capacity(a_len); 610 | let mut b = FixedBitSet::with_capacity(b_len); 611 | a.set_range(..a_end, true); 612 | b.set_range(b_start.., true); 613 | let ab = &a & &b; 614 | for i in 0..b_start { 615 | assert!(!ab.contains(i)); 616 | } 617 | for i in b_start..a_end { 618 | assert!(ab.contains(i)); 619 | } 620 | for i in a_end..len { 621 | assert!(!ab.contains(i)); 622 | } 623 | assert_eq!(a.len(), ab.len()); 624 | } 625 | 626 | #[test] 627 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 628 | fn bitand_first_larger() { 629 | let a_len = 173; 630 | let b_len = 137; 631 | let len = core::cmp::min(a_len, b_len); 632 | let a_end = 107; 633 | let b_start = 43; 634 | let mut a = FixedBitSet::with_capacity(a_len); 635 | let mut b = FixedBitSet::with_capacity(b_len); 636 | a.set_range(..a_end, true); 637 | b.set_range(b_start.., true); 638 | let ab = &a & &b; 639 | for i in 0..b_start { 640 | assert!(!ab.contains(i)); 641 | } 642 | for i in b_start..a_end { 643 | assert!(ab.contains(i)); 644 | } 645 | for i in a_end..len { 646 | assert!(!ab.contains(i)); 647 | } 648 | assert_eq!(b.len(), ab.len()); 649 | } 650 | 651 | #[test] 652 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 653 | fn intersection() { 654 | let len = 109; 655 | let a_end = 59; 656 | let b_start = 23; 657 | let mut a = FixedBitSet::with_capacity(len); 658 | let mut b = FixedBitSet::with_capacity(len); 659 | a.set_range(..a_end, true); 660 | b.set_range(b_start.., true); 661 | let count = a.intersection_count(&b); 662 | let iterator_count = a.intersection(&b).count(); 663 | let mut ab = a.intersection(&b).collect::(); 664 | 665 | for i in 0..b_start { 666 | assert!(!ab.contains(i)); 667 | } 668 | for i in b_start..a_end { 669 | assert!(ab.contains(i)); 670 | } 671 | for i in a_end..len { 672 | assert!(!ab.contains(i)); 673 | } 674 | 675 | a.intersect_with(&b); 676 | // intersection + collect produces the same results but with a shorter length. 677 | ab.grow(a.len()); 678 | assert_eq!( 679 | ab, a, 680 | "intersection and intersect_with produce the same results" 681 | ); 682 | assert_eq!( 683 | ab.count_ones(..), 684 | count, 685 | "intersection and intersection_count produce the same results" 686 | ); 687 | assert_eq!( 688 | count, iterator_count, 689 | "intersection and intersection_count produce the same results" 690 | ); 691 | } 692 | 693 | #[test] 694 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 695 | fn union() { 696 | let a_len = 173; 697 | let b_len = 137; 698 | let a_start = 139; 699 | let b_end = 107; 700 | let mut a = FixedBitSet::with_capacity(a_len); 701 | let mut b = FixedBitSet::with_capacity(b_len); 702 | a.set_range(a_start.., true); 703 | b.set_range(..b_end, true); 704 | let count = a.union_count(&b); 705 | let iterator_count = a.union(&b).count(); 706 | let ab = a.union(&b).collect::(); 707 | for i in a_start..a_len { 708 | assert!(ab.contains(i)); 709 | } 710 | for i in 0..b_end { 711 | assert!(ab.contains(i)); 712 | } 713 | for i in b_end..a_start { 714 | assert!(!ab.contains(i)); 715 | } 716 | 717 | a.union_with(&b); 718 | assert_eq!(ab, a, "union and union_with produce the same results"); 719 | assert_eq!( 720 | count, 721 | ab.count_ones(..), 722 | "union and union_count produce the same results" 723 | ); 724 | assert_eq!( 725 | count, iterator_count, 726 | "union and union_count produce the same results" 727 | ); 728 | } 729 | 730 | #[test] 731 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 732 | fn difference() { 733 | let a_len = 83; 734 | let b_len = 151; 735 | let a_start = 0; 736 | let a_end = 79; 737 | let b_start = 53; 738 | let mut a = FixedBitSet::with_capacity(a_len); 739 | let mut b = FixedBitSet::with_capacity(b_len); 740 | a.set_range(a_start..a_end, true); 741 | b.set_range(b_start..b_len, true); 742 | let count = a.difference_count(&b); 743 | let iterator_count = a.difference(&b).count(); 744 | let mut a_diff_b = a.difference(&b).collect::(); 745 | for i in a_start..b_start { 746 | assert!(a_diff_b.contains(i)); 747 | } 748 | for i in b_start..b_len { 749 | assert!(!a_diff_b.contains(i)); 750 | } 751 | 752 | a.difference_with(&b); 753 | // difference + collect produces the same results but with a shorter length. 754 | a_diff_b.grow(a.len()); 755 | assert_eq!( 756 | a_diff_b, a, 757 | "difference and difference_with produce the same results" 758 | ); 759 | assert_eq!( 760 | a_diff_b.count_ones(..), 761 | count, 762 | "difference and difference_count produce the same results" 763 | ); 764 | assert_eq!( 765 | count, iterator_count, 766 | "intersection and intersection_count produce the same results" 767 | ); 768 | 769 | let a_len = 151; 770 | let b_len = 83; 771 | let a_start = 0; 772 | let a_end = 134; 773 | let b_start = 53; 774 | let mut a = FixedBitSet::with_capacity(a_len); 775 | let mut b = FixedBitSet::with_capacity(b_len); 776 | a.set_range(a_start..a_end, true); 777 | b.set_range(b_start..b_len, true); 778 | let count = a.difference_count(&b); 779 | let iterator_count = a.difference(&b).count(); 780 | let mut a_diff_b = a.difference(&b).collect::(); 781 | for i in a_start..b_start { 782 | assert!(a_diff_b.contains(i)); 783 | } 784 | for i in b_start..b_len { 785 | assert!(!a_diff_b.contains(i)); 786 | } 787 | for i in b_len..a_end { 788 | assert!(a_diff_b.contains(i)); 789 | } 790 | 791 | a.difference_with(&b); 792 | // difference + collect produces the same results but with a shorter length. 793 | a_diff_b.grow(a.len()); 794 | assert_eq!( 795 | a_diff_b, a, 796 | "difference and difference_with produce the same results" 797 | ); 798 | assert_eq!( 799 | a_diff_b.count_ones(..), 800 | count, 801 | "difference and difference_count produce the same results" 802 | ); 803 | assert_eq!( 804 | count, iterator_count, 805 | "intersection and intersection_count produce the same results" 806 | ); 807 | } 808 | 809 | #[test] 810 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 811 | fn symmetric_difference() { 812 | let a_len = 83; 813 | let b_len = 151; 814 | let a_start = 47; 815 | let a_end = 79; 816 | let b_start = 53; 817 | let mut a = FixedBitSet::with_capacity(a_len); 818 | let mut b = FixedBitSet::with_capacity(b_len); 819 | a.set_range(a_start..a_end, true); 820 | b.set_range(b_start..b_len, true); 821 | let count = a.symmetric_difference_count(&b); 822 | let iterator_count = a.symmetric_difference(&b).count(); 823 | let a_sym_diff_b = a.symmetric_difference(&b).collect::(); 824 | for i in 0..a_start { 825 | assert!(!a_sym_diff_b.contains(i)); 826 | } 827 | for i in a_start..b_start { 828 | assert!(a_sym_diff_b.contains(i)); 829 | } 830 | for i in b_start..a_end { 831 | assert!(!a_sym_diff_b.contains(i)); 832 | } 833 | for i in a_end..b_len { 834 | assert!(a_sym_diff_b.contains(i)); 835 | } 836 | 837 | a.symmetric_difference_with(&b); 838 | assert_eq!( 839 | a_sym_diff_b, a, 840 | "symmetric_difference and _with produce the same results" 841 | ); 842 | assert_eq!( 843 | a_sym_diff_b.count_ones(..), 844 | count, 845 | "symmetric_difference and _count produce the same results" 846 | ); 847 | assert_eq!( 848 | count, iterator_count, 849 | "symmetric_difference and _count produce the same results" 850 | ); 851 | } 852 | 853 | #[test] 854 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 855 | fn bitor_equal_lengths() { 856 | let len = 109; 857 | let a_start = 17; 858 | let a_end = 23; 859 | let b_start = 19; 860 | let b_end = 59; 861 | let mut a = FixedBitSet::with_capacity(len); 862 | let mut b = FixedBitSet::with_capacity(len); 863 | a.set_range(a_start..a_end, true); 864 | b.set_range(b_start..b_end, true); 865 | let ab = &a | &b; 866 | for i in 0..a_start { 867 | assert!(!ab.contains(i)); 868 | } 869 | for i in a_start..b_end { 870 | assert!(ab.contains(i)); 871 | } 872 | for i in b_end..len { 873 | assert!(!ab.contains(i)); 874 | } 875 | assert_eq!(ab.len(), len); 876 | } 877 | 878 | #[test] 879 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 880 | fn bitor_first_smaller() { 881 | let a_len = 113; 882 | let b_len = 137; 883 | let a_end = 89; 884 | let b_start = 97; 885 | let mut a = FixedBitSet::with_capacity(a_len); 886 | let mut b = FixedBitSet::with_capacity(b_len); 887 | a.set_range(..a_end, true); 888 | b.set_range(b_start.., true); 889 | let ab = &a | &b; 890 | for i in 0..a_end { 891 | assert!(ab.contains(i)); 892 | } 893 | for i in a_end..b_start { 894 | assert!(!ab.contains(i)); 895 | } 896 | for i in b_start..b_len { 897 | assert!(ab.contains(i)); 898 | } 899 | assert_eq!(b_len, ab.len()); 900 | } 901 | 902 | #[test] 903 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 904 | fn bitor_first_larger() { 905 | let a_len = 173; 906 | let b_len = 137; 907 | let a_start = 139; 908 | let b_end = 107; 909 | let mut a = FixedBitSet::with_capacity(a_len); 910 | let mut b = FixedBitSet::with_capacity(b_len); 911 | a.set_range(a_start.., true); 912 | b.set_range(..b_end, true); 913 | let ab = &a | &b; 914 | for i in a_start..a_len { 915 | assert!(ab.contains(i)); 916 | } 917 | for i in 0..b_end { 918 | assert!(ab.contains(i)); 919 | } 920 | for i in b_end..a_start { 921 | assert!(!ab.contains(i)); 922 | } 923 | assert_eq!(a_len, ab.len()); 924 | } 925 | 926 | #[test] 927 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 928 | fn bitxor_equal_lengths() { 929 | let len = 109; 930 | let a_end = 59; 931 | let b_start = 23; 932 | let mut a = FixedBitSet::with_capacity(len); 933 | let mut b = FixedBitSet::with_capacity(len); 934 | a.set_range(..a_end, true); 935 | b.set_range(b_start.., true); 936 | let ab = &a ^ &b; 937 | for i in 0..b_start { 938 | assert!(ab.contains(i)); 939 | } 940 | for i in b_start..a_end { 941 | assert!(!ab.contains(i)); 942 | } 943 | for i in a_end..len { 944 | assert!(ab.contains(i)); 945 | } 946 | assert_eq!(a.len(), ab.len()); 947 | } 948 | 949 | #[test] 950 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 951 | fn bitxor_first_smaller() { 952 | let a_len = 113; 953 | let b_len = 137; 954 | let len = core::cmp::max(a_len, b_len); 955 | let a_end = 97; 956 | let b_start = 89; 957 | let mut a = FixedBitSet::with_capacity(a_len); 958 | let mut b = FixedBitSet::with_capacity(b_len); 959 | a.set_range(..a_end, true); 960 | b.set_range(b_start.., true); 961 | let ab = &a ^ &b; 962 | for i in 0..b_start { 963 | assert!(ab.contains(i)); 964 | } 965 | for i in b_start..a_end { 966 | assert!(!ab.contains(i)); 967 | } 968 | for i in a_end..len { 969 | assert!(ab.contains(i)); 970 | } 971 | assert_eq!(b.len(), ab.len()); 972 | } 973 | 974 | #[test] 975 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 976 | fn bitxor_first_larger() { 977 | let a_len = 173; 978 | let b_len = 137; 979 | let len = core::cmp::max(a_len, b_len); 980 | let a_end = 107; 981 | let b_start = 43; 982 | let mut a = FixedBitSet::with_capacity(a_len); 983 | let mut b = FixedBitSet::with_capacity(b_len); 984 | a.set_range(..a_end, true); 985 | b.set_range(b_start.., true); 986 | let ab = &a ^ &b; 987 | for i in 0..b_start { 988 | assert!(ab.contains(i)); 989 | } 990 | for i in b_start..a_end { 991 | assert!(!ab.contains(i)); 992 | } 993 | for i in a_end..b_len { 994 | assert!(ab.contains(i)); 995 | } 996 | for i in b_len..len { 997 | assert!(!ab.contains(i)); 998 | } 999 | assert_eq!(a.len(), ab.len()); 1000 | } 1001 | 1002 | #[test] 1003 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1004 | fn bitand_assign_shorter() { 1005 | let a_ones: Vec = vec![2, 3, 7, 19, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1006 | let b_ones: Vec = vec![2, 7, 8, 11, 23, 31, 32]; 1007 | let a_and_b: Vec = vec![2, 7, 31, 32]; 1008 | let mut a = a_ones.iter().cloned().collect::(); 1009 | let b = b_ones.iter().cloned().collect::(); 1010 | a &= b; 1011 | let res = a.ones().collect::>(); 1012 | 1013 | assert!(res == a_and_b); 1014 | } 1015 | 1016 | #[test] 1017 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1018 | fn bitand_assign_longer() { 1019 | let a_ones: Vec = vec![2, 7, 8, 11, 23, 31, 32]; 1020 | let b_ones: Vec = vec![2, 3, 7, 19, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1021 | let a_and_b: Vec = vec![2, 7, 31, 32]; 1022 | let mut a = a_ones.iter().cloned().collect::(); 1023 | let b = b_ones.iter().cloned().collect::(); 1024 | a &= b; 1025 | let res = a.ones().collect::>(); 1026 | assert!(res == a_and_b); 1027 | } 1028 | 1029 | #[test] 1030 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1031 | fn bitor_assign_shorter() { 1032 | let a_ones: Vec = vec![2, 3, 7, 19, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1033 | let b_ones: Vec = vec![2, 7, 8, 11, 23, 31, 32]; 1034 | let a_or_b: Vec = vec![2, 3, 7, 8, 11, 19, 23, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1035 | let mut a = a_ones.iter().cloned().collect::(); 1036 | let b = b_ones.iter().cloned().collect::(); 1037 | a |= b; 1038 | let res = a.ones().collect::>(); 1039 | assert!(res == a_or_b); 1040 | } 1041 | 1042 | #[test] 1043 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1044 | fn bitor_assign_longer() { 1045 | let a_ones: Vec = vec![2, 7, 8, 11, 23, 31, 32]; 1046 | let b_ones: Vec = vec![2, 3, 7, 19, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1047 | let a_or_b: Vec = vec![2, 3, 7, 8, 11, 19, 23, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1048 | let mut a = a_ones.iter().cloned().collect::(); 1049 | let b = b_ones.iter().cloned().collect::(); 1050 | a |= b; 1051 | let res = a.ones().collect::>(); 1052 | assert_eq!(res, a_or_b); 1053 | } 1054 | 1055 | #[test] 1056 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1057 | fn bitxor_assign_shorter() { 1058 | let a_ones: Vec = vec![2, 3, 7, 19, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1059 | let b_ones: Vec = vec![2, 7, 8, 11, 23, 31, 32]; 1060 | let a_xor_b: Vec = vec![3, 8, 11, 19, 23, 37, 41, 43, 47, 71, 73, 101]; 1061 | let mut a = a_ones.iter().cloned().collect::(); 1062 | let b = b_ones.iter().cloned().collect::(); 1063 | a ^= b; 1064 | let res = a.ones().collect::>(); 1065 | assert!(res == a_xor_b); 1066 | } 1067 | 1068 | #[test] 1069 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1070 | fn bitxor_assign_longer() { 1071 | let a_ones: Vec = vec![2, 7, 8, 11, 23, 31, 32]; 1072 | let b_ones: Vec = vec![2, 3, 7, 19, 31, 32, 37, 41, 43, 47, 71, 73, 101]; 1073 | let a_xor_b: Vec = vec![3, 8, 11, 19, 23, 37, 41, 43, 47, 71, 73, 101]; 1074 | let mut a = a_ones.iter().cloned().collect::(); 1075 | let b = b_ones.iter().cloned().collect::(); 1076 | a ^= b; 1077 | let res = a.ones().collect::>(); 1078 | assert!(res == a_xor_b); 1079 | } 1080 | 1081 | #[test] 1082 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1083 | fn op_assign_ref() { 1084 | let mut a = FixedBitSet::with_capacity(8); 1085 | let b = FixedBitSet::with_capacity(8); 1086 | 1087 | //check that all assign type operators work on references 1088 | a &= &b; 1089 | a |= &b; 1090 | a ^= &b; 1091 | } 1092 | 1093 | #[test] 1094 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1095 | fn subset_superset_shorter() { 1096 | let a_ones: Vec = vec![7, 31, 32, 63]; 1097 | let b_ones: Vec = vec![2, 7, 19, 31, 32, 37, 41, 43, 47, 63, 73, 101]; 1098 | let mut a = a_ones.iter().cloned().collect::(); 1099 | let b = b_ones.iter().cloned().collect::(); 1100 | assert!(a.is_subset(&b) && b.is_superset(&a)); 1101 | a.insert(14); 1102 | assert!(!a.is_subset(&b) && !b.is_superset(&a)); 1103 | } 1104 | 1105 | #[test] 1106 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1107 | fn subset_superset_longer() { 1108 | let a_len = 153; 1109 | let b_len = 75; 1110 | let a_ones: Vec = vec![7, 31, 32, 63]; 1111 | let b_ones: Vec = vec![2, 7, 19, 31, 32, 37, 41, 43, 47, 63, 73]; 1112 | let mut a = FixedBitSet::with_capacity(a_len); 1113 | let mut b = FixedBitSet::with_capacity(b_len); 1114 | a.extend(a_ones.iter().cloned()); 1115 | b.extend(b_ones.iter().cloned()); 1116 | assert!(a.is_subset(&b) && b.is_superset(&a)); 1117 | a.insert(100); 1118 | assert!(!a.is_subset(&b) && !b.is_superset(&a)); 1119 | } 1120 | 1121 | #[test] 1122 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1123 | fn is_disjoint_first_shorter() { 1124 | let a_len = 75; 1125 | let b_len = 153; 1126 | let a_ones: Vec = vec![2, 19, 32, 37, 41, 43, 47, 73]; 1127 | let b_ones: Vec = vec![7, 23, 31, 63, 124]; 1128 | let mut a = FixedBitSet::with_capacity(a_len); 1129 | let mut b = FixedBitSet::with_capacity(b_len); 1130 | a.extend(a_ones.iter().cloned()); 1131 | b.extend(b_ones.iter().cloned()); 1132 | assert!(a.is_disjoint(&b)); 1133 | a.insert(63); 1134 | assert!(!a.is_disjoint(&b)); 1135 | } 1136 | 1137 | #[test] 1138 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1139 | fn is_disjoint_first_longer() { 1140 | let a_ones: Vec = vec![2, 19, 32, 37, 41, 43, 47, 73, 101]; 1141 | let b_ones: Vec = vec![7, 23, 31, 63]; 1142 | let a = a_ones.iter().cloned().collect::(); 1143 | let mut b = b_ones.iter().cloned().collect::(); 1144 | assert!(a.is_disjoint(&b)); 1145 | b.insert(2); 1146 | assert!(!a.is_disjoint(&b)); 1147 | } 1148 | 1149 | #[test] 1150 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1151 | fn extend_on_empty() { 1152 | let items: Vec = vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 167]; 1153 | let mut fbs = FixedBitSet::with_capacity(0); 1154 | fbs.extend(items.iter().cloned()); 1155 | let ones = fbs.ones().collect::>(); 1156 | assert!(ones == items); 1157 | } 1158 | 1159 | #[test] 1160 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1161 | fn extend() { 1162 | let items: Vec = vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 167]; 1163 | let mut fbs = FixedBitSet::with_capacity(168); 1164 | let new: Vec = vec![7, 37, 67, 137]; 1165 | for i in &new { 1166 | fbs.put(*i); 1167 | } 1168 | 1169 | fbs.extend(items.iter().cloned()); 1170 | 1171 | let ones = fbs.ones().collect::>(); 1172 | let expected = { 1173 | let mut tmp = items.clone(); 1174 | tmp.extend(new); 1175 | tmp.sort(); 1176 | tmp.dedup(); 1177 | tmp 1178 | }; 1179 | 1180 | assert_eq!(ones, expected); 1181 | } 1182 | 1183 | #[test] 1184 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1185 | fn from_iterator() { 1186 | let items: Vec = vec![0, 2, 4, 6, 8]; 1187 | let fb = items.iter().cloned().collect::(); 1188 | for i in items { 1189 | assert!(fb.contains(i)); 1190 | } 1191 | for i in vec![1, 3, 5, 7] { 1192 | assert!(!fb.contains(i)); 1193 | } 1194 | assert_eq!(fb.len(), 9); 1195 | } 1196 | 1197 | #[test] 1198 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1199 | fn from_iterator_ones() { 1200 | let len = 257; 1201 | let mut fb = FixedBitSet::with_capacity(len); 1202 | for i in (0..len).filter(|i| i % 7 == 0) { 1203 | fb.put(i); 1204 | } 1205 | fb.put(len - 1); 1206 | let dup = fb.ones().collect::(); 1207 | 1208 | assert_eq!(fb.len(), dup.len()); 1209 | assert_eq!( 1210 | fb.ones().collect::>(), 1211 | dup.ones().collect::>() 1212 | ); 1213 | } 1214 | 1215 | #[test] 1216 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1217 | fn zeroes() { 1218 | let len = 232; 1219 | let mut fb = FixedBitSet::with_capacity(len); 1220 | for i in (0..len).filter(|i| i % 7 == 0) { 1221 | fb.insert(i); 1222 | } 1223 | let zeroes = fb.zeroes().collect::>(); 1224 | 1225 | assert_eq!( 1226 | zeroes, 1227 | vec![ 1228 | 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 1229 | 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 1230 | 54, 55, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 78, 79, 1231 | 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 1232 | 104, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118, 120, 121, 122, 123, 1233 | 124, 125, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 141, 142, 143, 1234 | 144, 145, 146, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 162, 163, 1235 | 164, 165, 166, 167, 169, 170, 171, 172, 173, 174, 176, 177, 178, 179, 180, 181, 183, 1236 | 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 197, 198, 199, 200, 201, 202, 1237 | 204, 205, 206, 207, 208, 209, 211, 212, 213, 214, 215, 216, 218, 219, 220, 221, 222, 1238 | 223, 225, 226, 227, 228, 229, 230 1239 | ] 1240 | ); 1241 | } 1242 | 1243 | #[cfg(feature = "std")] 1244 | #[test] 1245 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1246 | fn binary_trait() { 1247 | let items: Vec = vec![1, 5, 7, 10, 14, 15]; 1248 | let fb = items.iter().cloned().collect::(); 1249 | 1250 | assert_eq!(alloc::format!("{:b}", fb), "0100010100100011"); 1251 | assert_eq!(alloc::format!("{:#b}", fb), "0b0100010100100011"); 1252 | } 1253 | 1254 | #[cfg(feature = "std")] 1255 | #[test] 1256 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1257 | fn display_trait() { 1258 | let len = 8; 1259 | let mut fb = FixedBitSet::with_capacity(len); 1260 | 1261 | fb.put(4); 1262 | fb.put(2); 1263 | 1264 | assert_eq!(alloc::format!("{}", fb), "00101000"); 1265 | assert_eq!(alloc::format!("{:#}", fb), "0b00101000"); 1266 | } 1267 | 1268 | // TODO: Rewite this test to be platform agnostic. 1269 | #[test] 1270 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1271 | #[cfg(all(feature = "serde", target_pointer_width = "64"))] 1272 | fn test_serialize() { 1273 | let mut fb = FixedBitSet::with_capacity(10); 1274 | fb.put(2); 1275 | fb.put(3); 1276 | fb.put(6); 1277 | fb.put(8); 1278 | let serialized = serde_json::to_string(&fb).unwrap(); 1279 | assert_eq!(r#"{"length":10,"data":[76,1,0,0,0,0,0,0]}"#, serialized); 1280 | } 1281 | 1282 | #[test] 1283 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1284 | fn test_is_clear() { 1285 | let mut fb = FixedBitSet::with_capacity(0); 1286 | assert!(fb.is_clear()); 1287 | 1288 | fb.grow(1); 1289 | assert!(fb.is_clear()); 1290 | 1291 | fb.put(0); 1292 | assert!(!fb.is_clear()); 1293 | 1294 | fb.grow(42); 1295 | fb.clear(); 1296 | assert!(fb.is_clear()); 1297 | 1298 | fb.put(17); 1299 | fb.put(19); 1300 | assert!(!fb.is_clear()); 1301 | } 1302 | 1303 | #[test] 1304 | #[cfg_attr(target_family = "wasm", wasm_bindgen_test)] 1305 | fn test_is_full() { 1306 | let mut fb = FixedBitSet::with_capacity(0); 1307 | assert!(fb.is_full()); 1308 | 1309 | fb.grow(1); 1310 | assert!(!fb.is_full()); 1311 | 1312 | fb.put(0); 1313 | assert!(fb.is_full()); 1314 | 1315 | fb.grow(42); 1316 | fb.clear(); 1317 | assert!(!fb.is_full()); 1318 | 1319 | fb.put(17); 1320 | fb.put(19); 1321 | assert!(!fb.is_full()); 1322 | 1323 | fb.insert_range(..); 1324 | assert!(fb.is_full()); 1325 | } 1326 | 1327 | #[test] 1328 | fn clone() { 1329 | let mut fb = FixedBitSet::with_capacity(10000); 1330 | fb.set(11, true); 1331 | fb.set(12, true); 1332 | fb.set(7, true); 1333 | fb.set(35, true); 1334 | fb.set(40, true); 1335 | fb.set(77, true); 1336 | fb.set(95, true); 1337 | fb.set(50, true); 1338 | fb.set(99, true); 1339 | 1340 | let fb_clone = fb.clone(); 1341 | let mut fb_clone_from_smaller = FixedBitSet::with_capacity(1000000); 1342 | let mut fb_clone_from_same = FixedBitSet::with_capacity(10000); 1343 | let mut fb_clone_from_bigger = FixedBitSet::with_capacity(100); 1344 | fb_clone_from_smaller.clone_from(&fb); 1345 | fb_clone_from_same.clone_from(&fb); 1346 | fb_clone_from_bigger.clone_from(&fb); 1347 | 1348 | assert_eq!(&fb, &fb_clone); 1349 | assert_eq!(&fb, &fb_clone_from_smaller); 1350 | assert_eq!(&fb, &fb_clone_from_same); 1351 | assert_eq!(&fb, &fb_clone_from_bigger); 1352 | } 1353 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `FixedBitSet` is a simple fixed size set of bits. 2 | //! 3 | //! ### Crate features 4 | //! 5 | //! - `std` (default feature) 6 | //! Disabling this feature disables using std and instead uses crate alloc. 7 | //! 8 | //! ### SIMD Acceleration 9 | //! `fixedbitset` is written with SIMD in mind. The backing store and set operations will use aligned SIMD data types and instructions when compiling 10 | //! for compatible target platforms. The use of SIMD generally enables better performance in many set and batch operations (i.e. intersection/union/inserting a range). 11 | //! 12 | //! When SIMD is not available on the target, the crate will gracefully fallback to a default implementation. It is intended to add support for other SIMD architectures 13 | //! once they appear in stable Rust. 14 | //! 15 | //! Currently only SSE2/AVX/AVX2 on x86/x86_64 and wasm32 SIMD are supported as this is what stable Rust supports. 16 | #![no_std] 17 | // TODO: Remove once MSRV supports undocumented_unsafe_blocks 18 | #![allow(unknown_lints)] 19 | #![deny(clippy::undocumented_unsafe_blocks)] 20 | // TODO our MSRV supports older versions of Cargo that do not know the following are unsafe: 21 | // - Vec::from_raw_parts 22 | // - get_unchecked_mut 23 | #![allow(unused_unsafe)] 24 | 25 | extern crate alloc; 26 | use alloc::{vec, vec::Vec}; 27 | 28 | mod block; 29 | mod range; 30 | 31 | #[cfg(feature = "serde")] 32 | extern crate serde; 33 | #[cfg(feature = "serde")] 34 | mod serde_impl; 35 | 36 | use core::fmt::Write; 37 | use core::fmt::{Binary, Display, Error, Formatter}; 38 | 39 | use core::cmp::Ordering; 40 | use core::hash::Hash; 41 | use core::iter::{Chain, FusedIterator}; 42 | use core::mem::ManuallyDrop; 43 | use core::mem::MaybeUninit; 44 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index}; 45 | use core::ptr::NonNull; 46 | pub use range::IndexRange; 47 | 48 | pub(crate) const BITS: usize = core::mem::size_of::() * 8; 49 | #[cfg(feature = "serde")] 50 | pub(crate) const BYTES: usize = core::mem::size_of::(); 51 | 52 | use block::Block as SimdBlock; 53 | pub type Block = usize; 54 | 55 | #[inline] 56 | fn div_rem(x: usize, denominator: usize) -> (usize, usize) { 57 | (x / denominator, x % denominator) 58 | } 59 | 60 | fn vec_into_parts(vec: Vec) -> (NonNull, usize, usize) { 61 | let mut vec = ManuallyDrop::new(vec); 62 | ( 63 | // SAFETY: A Vec's internal pointer is always non-null. 64 | unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) }, 65 | vec.capacity(), 66 | vec.len(), 67 | ) 68 | } 69 | 70 | /// `FixedBitSet` is a simple fixed size set of bits that each can 71 | /// be enabled (1 / **true**) or disabled (0 / **false**). 72 | /// 73 | /// The bit set has a fixed capacity in terms of enabling bits (and the 74 | /// capacity can grow using the `grow` method). 75 | /// 76 | /// Derived traits depend on both the zeros and ones, so [0,1] is not equal to 77 | /// [0,1,0]. 78 | #[derive(Debug, Eq)] 79 | pub struct FixedBitSet { 80 | pub(crate) data: NonNull>, 81 | capacity: usize, 82 | /// length in bits 83 | pub(crate) length: usize, 84 | } 85 | 86 | // SAFETY: FixedBitset contains no thread-local state and can be safely sent between threads 87 | unsafe impl Send for FixedBitSet {} 88 | // SAFETY: FixedBitset does not provide simultaneous unsynchronized mutable access to the 89 | // underlying buffer. 90 | unsafe impl Sync for FixedBitSet {} 91 | 92 | impl FixedBitSet { 93 | /// Create a new empty **FixedBitSet**. 94 | pub const fn new() -> Self { 95 | FixedBitSet { 96 | data: NonNull::dangling(), 97 | capacity: 0, 98 | length: 0, 99 | } 100 | } 101 | 102 | /// Create a new **FixedBitSet** with a specific number of bits, 103 | /// all initially clear. 104 | pub fn with_capacity(bits: usize) -> Self { 105 | let (mut blocks, rem) = div_rem(bits, SimdBlock::BITS); 106 | blocks += (rem > 0) as usize; 107 | Self::from_blocks_and_len(vec![SimdBlock::NONE; blocks], bits) 108 | } 109 | 110 | #[inline] 111 | fn from_blocks_and_len(data: Vec, length: usize) -> Self { 112 | let (data, capacity, _) = vec_into_parts(data); 113 | FixedBitSet { 114 | data: data.cast(), 115 | capacity, 116 | length, 117 | } 118 | } 119 | 120 | /// Create a new **FixedBitSet** with a specific number of bits, 121 | /// initialized from provided blocks. 122 | /// 123 | /// If the blocks are not the exact size needed for the capacity 124 | /// they will be padded with zeros (if shorter) or truncated to 125 | /// the capacity (if longer). 126 | /// 127 | /// For example: 128 | /// ``` 129 | /// let data = vec![4]; 130 | /// let bs = fixedbitset::FixedBitSet::with_capacity_and_blocks(4, data); 131 | /// assert_eq!(format!("{:b}", bs), "0010"); 132 | /// ``` 133 | pub fn with_capacity_and_blocks>(bits: usize, blocks: I) -> Self { 134 | let mut bitset = Self::with_capacity(bits); 135 | for (subblock, value) in bitset.as_mut_slice().iter_mut().zip(blocks.into_iter()) { 136 | *subblock = value; 137 | } 138 | bitset 139 | } 140 | 141 | /// Grow capacity to **bits**, all new bits initialized to zero 142 | #[inline] 143 | pub fn grow(&mut self, bits: usize) { 144 | #[cold] 145 | #[track_caller] 146 | #[inline(never)] 147 | fn do_grow(slf: &mut FixedBitSet, bits: usize) { 148 | // SAFETY: The provided fill is initialized to NONE. 149 | unsafe { slf.grow_inner(bits, MaybeUninit::new(SimdBlock::NONE)) }; 150 | } 151 | 152 | if bits > self.length { 153 | do_grow(self, bits); 154 | } 155 | } 156 | 157 | /// # Safety 158 | /// If `fill` is uninitialized, the memory must not be accessed and must be immediately 159 | /// written over 160 | #[inline(always)] 161 | unsafe fn grow_inner(&mut self, bits: usize, fill: MaybeUninit) { 162 | // SAFETY: The data pointer and capacity were created from a Vec initially. The block 163 | // len is identical to that of the original. 164 | let mut data = unsafe { 165 | Vec::from_raw_parts(self.data.as_ptr(), self.simd_block_len(), self.capacity) 166 | }; 167 | let (mut blocks, rem) = div_rem(bits, SimdBlock::BITS); 168 | blocks += (rem > 0) as usize; 169 | data.resize(blocks, fill); 170 | let (data, capacity, _) = vec_into_parts(data); 171 | self.data = data; 172 | self.capacity = capacity; 173 | self.length = bits; 174 | } 175 | 176 | #[inline] 177 | unsafe fn get_unchecked(&self, subblock: usize) -> &Block { 178 | &*self.data.as_ptr().cast::().add(subblock) 179 | } 180 | 181 | #[inline] 182 | unsafe fn get_unchecked_mut(&mut self, subblock: usize) -> &mut Block { 183 | &mut *self.data.as_ptr().cast::().add(subblock) 184 | } 185 | 186 | #[inline] 187 | fn usize_len(&self) -> usize { 188 | let (mut blocks, rem) = div_rem(self.length, BITS); 189 | blocks += (rem > 0) as usize; 190 | blocks 191 | } 192 | 193 | #[inline] 194 | fn simd_block_len(&self) -> usize { 195 | let (mut blocks, rem) = div_rem(self.length, SimdBlock::BITS); 196 | blocks += (rem > 0) as usize; 197 | blocks 198 | } 199 | 200 | #[inline] 201 | fn batch_count_ones(blocks: impl IntoIterator) -> usize { 202 | blocks.into_iter().map(|x| x.count_ones() as usize).sum() 203 | } 204 | 205 | #[inline] 206 | fn as_simd_slice(&self) -> &[SimdBlock] { 207 | // SAFETY: The slice constructed is within bounds of the underlying allocation. This function 208 | // is called with a read-only borrow so no other write can happen as long as the returned borrow lives. 209 | unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.simd_block_len()) } 210 | } 211 | 212 | #[inline] 213 | fn as_mut_simd_slice(&mut self) -> &mut [SimdBlock] { 214 | // SAFETY: The slice constructed is within bounds of the underlying allocation. This function 215 | // is called with a mutable borrow so no other read or write can happen as long as the returned borrow lives. 216 | unsafe { core::slice::from_raw_parts_mut(self.data.as_ptr().cast(), self.simd_block_len()) } 217 | } 218 | 219 | #[inline] 220 | fn as_simd_slice_uninit(&self) -> &[MaybeUninit] { 221 | // SAFETY: The slice constructed is within bounds of the underlying allocation. This function 222 | // is called with a read-only borrow so no other write can happen as long as the returned borrow lives. 223 | unsafe { core::slice::from_raw_parts(self.data.as_ptr(), self.simd_block_len()) } 224 | } 225 | 226 | #[inline] 227 | fn as_mut_simd_slice_uninit(&mut self) -> &mut [MaybeUninit] { 228 | // SAFETY: The slice constructed is within bounds of the underlying allocation. This function 229 | // is called with a mutable borrow so no other read or write can happen as long as the returned borrow lives. 230 | unsafe { core::slice::from_raw_parts_mut(self.data.as_ptr(), self.simd_block_len()) } 231 | } 232 | 233 | /// Grows the internal size of the bitset before inserting a bit 234 | /// 235 | /// Unlike `insert`, this cannot panic, but may allocate if the bit is outside of the existing buffer's range. 236 | /// 237 | /// This is faster than calling `grow` then `insert` in succession. 238 | #[inline] 239 | pub fn grow_and_insert(&mut self, bits: usize) { 240 | self.grow(bits + 1); 241 | 242 | let (blocks, rem) = div_rem(bits, BITS); 243 | // SAFETY: The above grow ensures that the block is inside the Vec's allocation. 244 | unsafe { 245 | *self.get_unchecked_mut(blocks) |= 1 << rem; 246 | } 247 | } 248 | 249 | /// The length of the [`FixedBitSet`] in bits. 250 | /// 251 | /// Note: `len` includes both set and unset bits. 252 | /// ``` 253 | /// # use fixedbitset::FixedBitSet; 254 | /// let bitset = FixedBitSet::with_capacity(10); 255 | /// // there are 0 set bits, but 10 unset bits 256 | /// assert_eq!(bitset.len(), 10); 257 | /// ``` 258 | /// `len` does not return the count of set bits. For that, use 259 | /// [`bitset.count_ones(..)`](FixedBitSet::count_ones) instead. 260 | #[inline] 261 | pub fn len(&self) -> usize { 262 | self.length 263 | } 264 | 265 | /// `true` if the [`FixedBitSet`] is empty. 266 | /// 267 | /// Note that an "empty" `FixedBitSet` is a `FixedBitSet` with 268 | /// no bits (meaning: it's length is zero). If you want to check 269 | /// if all bits are unset, use [`FixedBitSet::is_clear`]. 270 | /// 271 | /// ``` 272 | /// # use fixedbitset::FixedBitSet; 273 | /// let bitset = FixedBitSet::with_capacity(10); 274 | /// assert!(!bitset.is_empty()); 275 | /// 276 | /// let bitset = FixedBitSet::with_capacity(0); 277 | /// assert!(bitset.is_empty()); 278 | /// ``` 279 | #[inline] 280 | pub fn is_empty(&self) -> bool { 281 | self.len() == 0 282 | } 283 | 284 | /// `true` if all bits in the [`FixedBitSet`] are unset. 285 | /// 286 | /// As opposed to [`FixedBitSet::is_empty`], which is `true` only for 287 | /// sets without any bits, set or unset. 288 | /// 289 | /// ``` 290 | /// # use fixedbitset::FixedBitSet; 291 | /// let mut bitset = FixedBitSet::with_capacity(10); 292 | /// assert!(bitset.is_clear()); 293 | /// 294 | /// bitset.insert(2); 295 | /// assert!(!bitset.is_clear()); 296 | /// ``` 297 | /// 298 | /// This is equivalent to [`bitset.count_ones(..) == 0`](FixedBitSet::count_ones). 299 | #[inline] 300 | pub fn is_clear(&self) -> bool { 301 | self.as_simd_slice().iter().all(|block| block.is_empty()) 302 | } 303 | 304 | /// Finds the lowest set bit in the bitset. 305 | /// 306 | /// Returns `None` if there aren't any set bits. 307 | /// 308 | /// ``` 309 | /// # use fixedbitset::FixedBitSet; 310 | /// let mut bitset = FixedBitSet::with_capacity(10); 311 | /// assert_eq!(bitset.minimum(), None); 312 | /// 313 | /// bitset.insert(2); 314 | /// assert_eq!(bitset.minimum(), Some(2)); 315 | /// bitset.insert(8); 316 | /// assert_eq!(bitset.minimum(), Some(2)); 317 | /// ``` 318 | #[inline] 319 | pub fn minimum(&self) -> Option { 320 | let (block_idx, block) = self 321 | .as_simd_slice() 322 | .iter() 323 | .enumerate() 324 | .find(|&(_, block)| !block.is_empty())?; 325 | let mut inner = 0; 326 | let mut trailing = 0; 327 | for subblock in block.into_usize_array() { 328 | if subblock != 0 { 329 | trailing = subblock.trailing_zeros() as usize; 330 | break; 331 | } else { 332 | inner += BITS; 333 | } 334 | } 335 | Some(block_idx * SimdBlock::BITS + inner + trailing) 336 | } 337 | 338 | /// Finds the highest set bit in the bitset. 339 | /// 340 | /// Returns `None` if there aren't any set bits. 341 | /// 342 | /// ``` 343 | /// # use fixedbitset::FixedBitSet; 344 | /// let mut bitset = FixedBitSet::with_capacity(10); 345 | /// assert_eq!(bitset.maximum(), None); 346 | /// 347 | /// bitset.insert(8); 348 | /// assert_eq!(bitset.maximum(), Some(8)); 349 | /// bitset.insert(2); 350 | /// assert_eq!(bitset.maximum(), Some(8)); 351 | /// ``` 352 | #[inline] 353 | pub fn maximum(&self) -> Option { 354 | let (block_idx, block) = self 355 | .as_simd_slice() 356 | .iter() 357 | .rev() 358 | .enumerate() 359 | .find(|&(_, block)| !block.is_empty())?; 360 | let mut inner = 0; 361 | let mut leading = 0; 362 | for subblock in block.into_usize_array().iter().rev() { 363 | if *subblock != 0 { 364 | leading = subblock.leading_zeros() as usize; 365 | break; 366 | } else { 367 | inner += BITS; 368 | } 369 | } 370 | let max = self.simd_block_len() * SimdBlock::BITS; 371 | Some(max - block_idx * SimdBlock::BITS - inner - leading - 1) 372 | } 373 | 374 | /// `true` if all bits in the [`FixedBitSet`] are set. 375 | /// 376 | /// ``` 377 | /// # use fixedbitset::FixedBitSet; 378 | /// let mut bitset = FixedBitSet::with_capacity(10); 379 | /// assert!(!bitset.is_full()); 380 | /// 381 | /// bitset.insert_range(..); 382 | /// assert!(bitset.is_full()); 383 | /// ``` 384 | /// 385 | /// This is equivalent to [`bitset.count_ones(..) == bitset.len()`](FixedBitSet::count_ones). 386 | #[inline] 387 | pub fn is_full(&self) -> bool { 388 | self.contains_all_in_range(..) 389 | } 390 | 391 | /// Return **true** if the bit is enabled in the **FixedBitSet**, 392 | /// **false** otherwise. 393 | /// 394 | /// Note: bits outside the capacity are always disabled. 395 | /// 396 | /// Note: Also available with index syntax: `bitset[bit]`. 397 | #[inline] 398 | pub fn contains(&self, bit: usize) -> bool { 399 | if bit < self.length { 400 | // SAFETY: The above check ensures that the block and bit are within bounds. 401 | unsafe { self.contains_unchecked(bit) } 402 | } else { 403 | false 404 | } 405 | } 406 | 407 | /// Return **true** if the bit is enabled in the **FixedBitSet**, 408 | /// **false** otherwise. 409 | /// 410 | /// Note: unlike `contains`, calling this with an invalid `bit` 411 | /// is undefined behavior. 412 | /// 413 | /// # Safety 414 | /// `bit` must be less than `self.len()` 415 | #[inline] 416 | pub unsafe fn contains_unchecked(&self, bit: usize) -> bool { 417 | let (block, i) = div_rem(bit, BITS); 418 | (self.get_unchecked(block) & (1 << i)) != 0 419 | } 420 | 421 | /// Clear all bits. 422 | #[inline] 423 | pub fn clear(&mut self) { 424 | for elt in self.as_mut_simd_slice().iter_mut() { 425 | *elt = SimdBlock::NONE 426 | } 427 | } 428 | 429 | /// Enable `bit`. 430 | /// 431 | /// **Panics** if **bit** is out of bounds. 432 | #[inline] 433 | pub fn insert(&mut self, bit: usize) { 434 | assert!( 435 | bit < self.length, 436 | "insert at index {} exceeds fixedbitset size {}", 437 | bit, 438 | self.length 439 | ); 440 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 441 | unsafe { 442 | self.insert_unchecked(bit); 443 | } 444 | } 445 | 446 | /// Enable `bit` without any length checks. 447 | /// 448 | /// # Safety 449 | /// `bit` must be less than `self.len()` 450 | #[inline] 451 | pub unsafe fn insert_unchecked(&mut self, bit: usize) { 452 | let (block, i) = div_rem(bit, BITS); 453 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 454 | unsafe { 455 | *self.get_unchecked_mut(block) |= 1 << i; 456 | } 457 | } 458 | 459 | /// Disable `bit`. 460 | /// 461 | /// **Panics** if **bit** is out of bounds. 462 | #[inline] 463 | pub fn remove(&mut self, bit: usize) { 464 | assert!( 465 | bit < self.length, 466 | "remove at index {} exceeds fixedbitset size {}", 467 | bit, 468 | self.length 469 | ); 470 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 471 | unsafe { 472 | self.remove_unchecked(bit); 473 | } 474 | } 475 | 476 | /// Disable `bit` without any bounds checking. 477 | /// 478 | /// # Safety 479 | /// `bit` must be less than `self.len()` 480 | #[inline] 481 | pub unsafe fn remove_unchecked(&mut self, bit: usize) { 482 | let (block, i) = div_rem(bit, BITS); 483 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 484 | unsafe { 485 | *self.get_unchecked_mut(block) &= !(1 << i); 486 | } 487 | } 488 | 489 | /// Enable `bit`, and return its previous value. 490 | /// 491 | /// **Panics** if **bit** is out of bounds. 492 | #[inline] 493 | pub fn put(&mut self, bit: usize) -> bool { 494 | assert!( 495 | bit < self.length, 496 | "put at index {} exceeds fixedbitset size {}", 497 | bit, 498 | self.length 499 | ); 500 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 501 | unsafe { self.put_unchecked(bit) } 502 | } 503 | 504 | /// Enable `bit`, and return its previous value without doing any bounds checking. 505 | /// 506 | /// # Safety 507 | /// `bit` must be less than `self.len()` 508 | #[inline] 509 | pub unsafe fn put_unchecked(&mut self, bit: usize) -> bool { 510 | let (block, i) = div_rem(bit, BITS); 511 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 512 | unsafe { 513 | let word = self.get_unchecked_mut(block); 514 | let prev = *word & (1 << i) != 0; 515 | *word |= 1 << i; 516 | prev 517 | } 518 | } 519 | 520 | /// Toggle `bit` (inverting its state). 521 | /// 522 | /// ***Panics*** if **bit** is out of bounds 523 | #[inline] 524 | pub fn toggle(&mut self, bit: usize) { 525 | assert!( 526 | bit < self.length, 527 | "toggle at index {} exceeds fixedbitset size {}", 528 | bit, 529 | self.length 530 | ); 531 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 532 | unsafe { 533 | self.toggle_unchecked(bit); 534 | } 535 | } 536 | 537 | /// Toggle `bit` (inverting its state) without any bounds checking. 538 | /// 539 | /// # Safety 540 | /// `bit` must be less than `self.len()` 541 | #[inline] 542 | pub unsafe fn toggle_unchecked(&mut self, bit: usize) { 543 | let (block, i) = div_rem(bit, BITS); 544 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 545 | unsafe { 546 | *self.get_unchecked_mut(block) ^= 1 << i; 547 | } 548 | } 549 | 550 | /// Sets a bit to the provided `enabled` value. 551 | /// 552 | /// **Panics** if **bit** is out of bounds. 553 | #[inline] 554 | pub fn set(&mut self, bit: usize, enabled: bool) { 555 | assert!( 556 | bit < self.length, 557 | "set at index {} exceeds fixedbitset size {}", 558 | bit, 559 | self.length 560 | ); 561 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 562 | unsafe { 563 | self.set_unchecked(bit, enabled); 564 | } 565 | } 566 | 567 | /// Sets a bit to the provided `enabled` value without doing any bounds checking. 568 | /// 569 | /// # Safety 570 | /// `bit` must be less than `self.len()` 571 | #[inline] 572 | pub unsafe fn set_unchecked(&mut self, bit: usize, enabled: bool) { 573 | let (block, i) = div_rem(bit, BITS); 574 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 575 | let elt = unsafe { self.get_unchecked_mut(block) }; 576 | if enabled { 577 | *elt |= 1 << i; 578 | } else { 579 | *elt &= !(1 << i); 580 | } 581 | } 582 | 583 | /// Copies boolean value from specified bit to the specified bit. 584 | /// 585 | /// If `from` is out-of-bounds, `to` will be unset. 586 | /// 587 | /// **Panics** if **to** is out of bounds. 588 | #[inline] 589 | pub fn copy_bit(&mut self, from: usize, to: usize) { 590 | assert!( 591 | to < self.length, 592 | "copy to index {} exceeds fixedbitset size {}", 593 | to, 594 | self.length 595 | ); 596 | let enabled = self.contains(from); 597 | // SAFETY: The above assertion ensures that the block is inside the Vec's allocation. 598 | unsafe { self.set_unchecked(to, enabled) }; 599 | } 600 | 601 | /// Copies boolean value from specified bit to the specified bit. 602 | /// 603 | /// Note: unlike `copy_bit`, calling this with an invalid `from` 604 | /// is undefined behavior. 605 | /// 606 | /// # Safety 607 | /// `to` must both be less than `self.len()` 608 | #[inline] 609 | pub unsafe fn copy_bit_unchecked(&mut self, from: usize, to: usize) { 610 | // SAFETY: Caller must ensure that `from` is within bounds. 611 | let enabled = self.contains_unchecked(from); 612 | // SAFETY: Caller must ensure that `to` is within bounds. 613 | self.set_unchecked(to, enabled); 614 | } 615 | 616 | /// Count the number of set bits in the given bit range. 617 | /// 618 | /// This function is potentially much faster than using `ones(other).count()`. 619 | /// Use `..` to count the whole content of the bitset. 620 | /// 621 | /// **Panics** if the range extends past the end of the bitset. 622 | #[inline] 623 | pub fn count_ones(&self, range: T) -> usize { 624 | Self::batch_count_ones(Masks::new(range, self.length).map(|(block, mask)| { 625 | // SAFETY: Masks cannot return a block index that is out of range. 626 | unsafe { *self.get_unchecked(block) & mask } 627 | })) 628 | } 629 | 630 | /// Count the number of unset bits in the given bit range. 631 | /// 632 | /// This function is potentially much faster than using `zeroes(other).count()`. 633 | /// Use `..` to count the whole content of the bitset. 634 | /// 635 | /// **Panics** if the range extends past the end of the bitset. 636 | #[inline] 637 | pub fn count_zeroes(&self, range: T) -> usize { 638 | Self::batch_count_ones(Masks::new(range, self.length).map(|(block, mask)| { 639 | // SAFETY: Masks cannot return a block index that is out of range. 640 | unsafe { !*self.get_unchecked(block) & mask } 641 | })) 642 | } 643 | 644 | /// Sets every bit in the given range to the given state (`enabled`) 645 | /// 646 | /// Use `..` to set the whole bitset. 647 | /// 648 | /// **Panics** if the range extends past the end of the bitset. 649 | #[inline] 650 | pub fn set_range(&mut self, range: T, enabled: bool) { 651 | if enabled { 652 | self.insert_range(range); 653 | } else { 654 | self.remove_range(range); 655 | } 656 | } 657 | 658 | /// Enables every bit in the given range. 659 | /// 660 | /// Use `..` to make the whole bitset ones. 661 | /// 662 | /// **Panics** if the range extends past the end of the bitset. 663 | #[inline] 664 | pub fn insert_range(&mut self, range: T) { 665 | for (block, mask) in Masks::new(range, self.length) { 666 | // SAFETY: Masks cannot return a block index that is out of range. 667 | let block = unsafe { self.get_unchecked_mut(block) }; 668 | *block |= mask; 669 | } 670 | } 671 | 672 | /// Disables every bit in the given range. 673 | /// 674 | /// Use `..` to make the whole bitset ones. 675 | /// 676 | /// **Panics** if the range extends past the end of the bitset. 677 | #[inline] 678 | pub fn remove_range(&mut self, range: T) { 679 | for (block, mask) in Masks::new(range, self.length) { 680 | // SAFETY: Masks cannot return a block index that is out of range. 681 | let block = unsafe { self.get_unchecked_mut(block) }; 682 | *block &= !mask; 683 | } 684 | } 685 | 686 | /// Toggles (inverts) every bit in the given range. 687 | /// 688 | /// Use `..` to toggle the whole bitset. 689 | /// 690 | /// **Panics** if the range extends past the end of the bitset. 691 | #[inline] 692 | pub fn toggle_range(&mut self, range: T) { 693 | for (block, mask) in Masks::new(range, self.length) { 694 | // SAFETY: Masks cannot return a block index that is out of range. 695 | let block = unsafe { self.get_unchecked_mut(block) }; 696 | *block ^= mask; 697 | } 698 | } 699 | 700 | /// Checks if the bitset contains every bit in the given range. 701 | /// 702 | /// **Panics** if the range extends past the end of the bitset. 703 | #[inline] 704 | pub fn contains_all_in_range(&self, range: T) -> bool { 705 | for (block, mask) in Masks::new(range, self.length) { 706 | // SAFETY: Masks cannot return a block index that is out of range. 707 | let block = unsafe { self.get_unchecked(block) }; 708 | if block & mask != mask { 709 | return false; 710 | } 711 | } 712 | true 713 | } 714 | 715 | /// Checks if the bitset contains at least one set bit in the given range. 716 | /// 717 | /// **Panics** if the range extends past the end of the bitset. 718 | #[inline] 719 | pub fn contains_any_in_range(&self, range: T) -> bool { 720 | for (block, mask) in Masks::new(range, self.length) { 721 | // SAFETY: Masks cannot return a block index that is out of range. 722 | let block = unsafe { self.get_unchecked(block) }; 723 | if block & mask != 0 { 724 | return true; 725 | } 726 | } 727 | false 728 | } 729 | 730 | /// View the bitset as a slice of `Block` blocks 731 | #[inline] 732 | pub fn as_slice(&self) -> &[Block] { 733 | // SAFETY: The bits from both usize and Block are required to be reinterprettable, and 734 | // neither have any padding or alignment issues. The slice constructed is within bounds 735 | // of the underlying allocation. This function is called with a read-only borrow so 736 | // no other write can happen as long as the returned borrow lives. 737 | unsafe { 738 | let ptr = self.data.as_ptr().cast::(); 739 | core::slice::from_raw_parts(ptr, self.usize_len()) 740 | } 741 | } 742 | 743 | /// View the bitset as a mutable slice of `Block` blocks. Writing past the bitlength in the last 744 | /// will cause `contains` to return potentially incorrect results for bits past the bitlength. 745 | #[inline] 746 | pub fn as_mut_slice(&mut self) -> &mut [Block] { 747 | // SAFETY: The bits from both usize and Block are required to be reinterprettable, and 748 | // neither have any padding or alignment issues. The slice constructed is within bounds 749 | // of the underlying allocation. This function is called with a mutable borrow so 750 | // no other read or write can happen as long as the returned borrow lives. 751 | unsafe { 752 | let ptr = self.data.as_ptr().cast::(); 753 | core::slice::from_raw_parts_mut(ptr, self.usize_len()) 754 | } 755 | } 756 | 757 | /// Iterates over all enabled bits. 758 | /// 759 | /// Iterator element is the index of the `1` bit, type `usize`. 760 | #[inline] 761 | pub fn ones(&self) -> Ones<'_> { 762 | match self.as_slice().split_first() { 763 | Some((&first_block, rem)) => { 764 | let (&last_block, rem) = rem.split_last().unwrap_or((&0, rem)); 765 | Ones { 766 | bitset_front: first_block, 767 | bitset_back: last_block, 768 | block_idx_front: 0, 769 | block_idx_back: (1 + rem.len()) * BITS, 770 | remaining_blocks: rem.iter(), 771 | } 772 | } 773 | None => Ones { 774 | bitset_front: 0, 775 | bitset_back: 0, 776 | block_idx_front: 0, 777 | block_idx_back: 0, 778 | remaining_blocks: [].iter(), 779 | }, 780 | } 781 | } 782 | 783 | /// Iterates over all enabled bits. 784 | /// 785 | /// Iterator element is the index of the `1` bit, type `usize`. 786 | /// Unlike `ones`, this function consumes the `FixedBitset`. 787 | pub fn into_ones(self) -> IntoOnes { 788 | let ptr = self.data.as_ptr().cast(); 789 | let len = self.simd_block_len() * SimdBlock::USIZE_COUNT; 790 | // SAFETY: 791 | // - ptr comes from self.data, so it is valid; 792 | // - self.data is valid for self.data.len() SimdBlocks, 793 | // which is exactly self.data.len() * SimdBlock::USIZE_COUNT usizes; 794 | // - we will keep this slice around only as long as self.data is, 795 | // so it won't become dangling. 796 | let slice = unsafe { core::slice::from_raw_parts(ptr, len) }; 797 | // SAFETY: The data pointer and capacity were created from a Vec initially. The block 798 | // len is identical to that of the original. 799 | let data: Vec = unsafe { 800 | Vec::from_raw_parts( 801 | self.data.as_ptr().cast(), 802 | self.simd_block_len(), 803 | self.capacity, 804 | ) 805 | }; 806 | let mut iter = slice.iter().copied(); 807 | 808 | core::mem::forget(self); 809 | 810 | IntoOnes { 811 | bitset_front: iter.next().unwrap_or(0), 812 | bitset_back: iter.next_back().unwrap_or(0), 813 | block_idx_front: 0, 814 | block_idx_back: len.saturating_sub(1) * BITS, 815 | remaining_blocks: iter, 816 | _buf: data, 817 | } 818 | } 819 | 820 | /// Iterates over all disabled bits. 821 | /// 822 | /// Iterator element is the index of the `0` bit, type `usize`. 823 | #[inline] 824 | pub fn zeroes(&self) -> Zeroes<'_> { 825 | match self.as_slice().split_first() { 826 | Some((&block, rem)) => Zeroes { 827 | bitset: !block, 828 | block_idx: 0, 829 | len: self.len(), 830 | remaining_blocks: rem.iter(), 831 | }, 832 | None => Zeroes { 833 | bitset: !0, 834 | block_idx: 0, 835 | len: self.len(), 836 | remaining_blocks: [].iter(), 837 | }, 838 | } 839 | } 840 | 841 | /// Returns a lazy iterator over the intersection of two `FixedBitSet`s 842 | pub fn intersection<'a>(&'a self, other: &'a FixedBitSet) -> Intersection<'a> { 843 | Intersection { 844 | iter: self.ones(), 845 | other, 846 | } 847 | } 848 | 849 | /// Returns a lazy iterator over the union of two `FixedBitSet`s. 850 | pub fn union<'a>(&'a self, other: &'a FixedBitSet) -> Union<'a> { 851 | Union { 852 | iter: self.ones().chain(other.difference(self)), 853 | } 854 | } 855 | 856 | /// Returns a lazy iterator over the difference of two `FixedBitSet`s. The difference of `a` 857 | /// and `b` is the elements of `a` which are not in `b`. 858 | pub fn difference<'a>(&'a self, other: &'a FixedBitSet) -> Difference<'a> { 859 | Difference { 860 | iter: self.ones(), 861 | other, 862 | } 863 | } 864 | 865 | /// Returns a lazy iterator over the symmetric difference of two `FixedBitSet`s. 866 | /// The symmetric difference of `a` and `b` is the elements of one, but not both, sets. 867 | pub fn symmetric_difference<'a>(&'a self, other: &'a FixedBitSet) -> SymmetricDifference<'a> { 868 | SymmetricDifference { 869 | iter: self.difference(other).chain(other.difference(self)), 870 | } 871 | } 872 | 873 | /// In-place union of two `FixedBitSet`s. 874 | /// 875 | /// On calling this method, `self`'s capacity may be increased to match `other`'s. 876 | pub fn union_with(&mut self, other: &FixedBitSet) { 877 | if other.len() >= self.len() { 878 | self.grow(other.len()); 879 | } 880 | self.as_mut_simd_slice() 881 | .iter_mut() 882 | .zip(other.as_simd_slice().iter()) 883 | .for_each(|(x, y)| *x |= *y); 884 | } 885 | 886 | /// In-place intersection of two `FixedBitSet`s. 887 | /// 888 | /// On calling this method, `self`'s capacity will remain the same as before. 889 | pub fn intersect_with(&mut self, other: &FixedBitSet) { 890 | let me = self.as_mut_simd_slice(); 891 | let other = other.as_simd_slice(); 892 | me.iter_mut().zip(other.iter()).for_each(|(x, y)| { 893 | *x &= *y; 894 | }); 895 | let mn = core::cmp::min(me.len(), other.len()); 896 | for wd in &mut me[mn..] { 897 | *wd = SimdBlock::NONE; 898 | } 899 | } 900 | 901 | /// In-place difference of two `FixedBitSet`s. 902 | /// 903 | /// On calling this method, `self`'s capacity will remain the same as before. 904 | pub fn difference_with(&mut self, other: &FixedBitSet) { 905 | self.as_mut_simd_slice() 906 | .iter_mut() 907 | .zip(other.as_simd_slice().iter()) 908 | .for_each(|(x, y)| { 909 | *x &= !*y; 910 | }); 911 | 912 | // There's no need to grow self or do any other adjustments. 913 | // 914 | // * If self is longer than other, the bits at the end of self won't be affected since other 915 | // has them implicitly set to 0. 916 | // * If other is longer than self, the bits at the end of other are irrelevant since self 917 | // has them set to 0 anyway. 918 | } 919 | 920 | /// In-place symmetric difference of two `FixedBitSet`s. 921 | /// 922 | /// On calling this method, `self`'s capacity may be increased to match `other`'s. 923 | pub fn symmetric_difference_with(&mut self, other: &FixedBitSet) { 924 | if other.len() >= self.len() { 925 | self.grow(other.len()); 926 | } 927 | self.as_mut_simd_slice() 928 | .iter_mut() 929 | .zip(other.as_simd_slice().iter()) 930 | .for_each(|(x, y)| { 931 | *x ^= *y; 932 | }); 933 | } 934 | 935 | /// Computes how many bits would be set in the union between two bitsets. 936 | /// 937 | /// This is potentially much faster than using `union(other).count()`. Unlike 938 | /// other methods like using [`union_with`] followed by [`count_ones`], this 939 | /// does not mutate in place or require separate allocations. 940 | #[inline] 941 | pub fn union_count(&self, other: &FixedBitSet) -> usize { 942 | let me = self.as_slice(); 943 | let other = other.as_slice(); 944 | let count = Self::batch_count_ones(me.iter().zip(other.iter()).map(|(x, y)| (*x | *y))); 945 | match other.len().cmp(&me.len()) { 946 | Ordering::Greater => count + Self::batch_count_ones(other[me.len()..].iter().copied()), 947 | Ordering::Less => count + Self::batch_count_ones(me[other.len()..].iter().copied()), 948 | Ordering::Equal => count, 949 | } 950 | } 951 | 952 | /// Computes how many bits would be set in the intersection between two bitsets. 953 | /// 954 | /// This is potentially much faster than using `intersection(other).count()`. Unlike 955 | /// other methods like using [`intersect_with`] followed by [`count_ones`], this 956 | /// does not mutate in place or require separate allocations. 957 | #[inline] 958 | pub fn intersection_count(&self, other: &FixedBitSet) -> usize { 959 | Self::batch_count_ones( 960 | self.as_slice() 961 | .iter() 962 | .zip(other.as_slice()) 963 | .map(|(x, y)| (*x & *y)), 964 | ) 965 | } 966 | 967 | /// Computes how many bits would be set in the difference between two bitsets. 968 | /// 969 | /// This is potentially much faster than using `difference(other).count()`. Unlike 970 | /// other methods like using [`difference_with`] followed by [`count_ones`], this 971 | /// does not mutate in place or require separate allocations. 972 | #[inline] 973 | pub fn difference_count(&self, other: &FixedBitSet) -> usize { 974 | Self::batch_count_ones( 975 | self.as_slice() 976 | .iter() 977 | .zip(other.as_slice().iter()) 978 | .map(|(x, y)| (*x & !*y)), 979 | ) + Self::batch_count_ones(self.as_slice().iter().skip(other.as_slice().len()).copied()) 980 | } 981 | 982 | /// Computes how many bits would be set in the symmetric difference between two bitsets. 983 | /// 984 | /// This is potentially much faster than using `symmetric_difference(other).count()`. Unlike 985 | /// other methods like using [`symmetric_difference_with`] followed by [`count_ones`], this 986 | /// does not mutate in place or require separate allocations. 987 | #[inline] 988 | pub fn symmetric_difference_count(&self, other: &FixedBitSet) -> usize { 989 | let me = self.as_slice(); 990 | let other = other.as_slice(); 991 | let count = Self::batch_count_ones(me.iter().zip(other.iter()).map(|(x, y)| (*x ^ *y))); 992 | match other.len().cmp(&me.len()) { 993 | Ordering::Greater => count + Self::batch_count_ones(other[me.len()..].iter().copied()), 994 | Ordering::Less => count + Self::batch_count_ones(me[other.len()..].iter().copied()), 995 | Ordering::Equal => count, 996 | } 997 | } 998 | 999 | /// Returns `true` if `self` has no elements in common with `other`. This 1000 | /// is equivalent to checking for an empty intersection. 1001 | pub fn is_disjoint(&self, other: &FixedBitSet) -> bool { 1002 | self.as_simd_slice() 1003 | .iter() 1004 | .zip(other.as_simd_slice()) 1005 | .all(|(x, y)| (*x & *y).is_empty()) 1006 | } 1007 | 1008 | /// Returns `true` if the set is a subset of another, i.e. `other` contains 1009 | /// at least all the values in `self`. 1010 | pub fn is_subset(&self, other: &FixedBitSet) -> bool { 1011 | let me = self.as_simd_slice(); 1012 | let other = other.as_simd_slice(); 1013 | me.iter() 1014 | .zip(other.iter()) 1015 | .all(|(x, y)| x.andnot(*y).is_empty()) 1016 | && me.iter().skip(other.len()).all(|x| x.is_empty()) 1017 | } 1018 | 1019 | /// Returns `true` if the set is a superset of another, i.e. `self` contains 1020 | /// at least all the values in `other`. 1021 | pub fn is_superset(&self, other: &FixedBitSet) -> bool { 1022 | other.is_subset(self) 1023 | } 1024 | } 1025 | 1026 | impl Hash for FixedBitSet { 1027 | fn hash(&self, state: &mut H) { 1028 | self.length.hash(state); 1029 | self.as_simd_slice().hash(state); 1030 | } 1031 | } 1032 | 1033 | impl PartialEq for FixedBitSet { 1034 | fn eq(&self, other: &Self) -> bool { 1035 | self.length == other.length && self.as_simd_slice().eq(other.as_simd_slice()) 1036 | } 1037 | } 1038 | 1039 | impl PartialOrd for FixedBitSet { 1040 | fn partial_cmp(&self, other: &Self) -> Option { 1041 | Some(self.cmp(other)) 1042 | } 1043 | } 1044 | 1045 | impl Ord for FixedBitSet { 1046 | fn cmp(&self, other: &Self) -> Ordering { 1047 | self.length 1048 | .cmp(&other.length) 1049 | .then_with(|| self.as_simd_slice().cmp(other.as_simd_slice())) 1050 | } 1051 | } 1052 | 1053 | impl Default for FixedBitSet { 1054 | fn default() -> Self { 1055 | Self::new() 1056 | } 1057 | } 1058 | 1059 | impl Drop for FixedBitSet { 1060 | fn drop(&mut self) { 1061 | // SAFETY: The data pointer and capacity were created from a Vec initially. The block 1062 | // len is identical to that of the original. 1063 | drop(unsafe { 1064 | Vec::from_raw_parts(self.data.as_ptr(), self.simd_block_len(), self.capacity) 1065 | }); 1066 | } 1067 | } 1068 | 1069 | impl Binary for FixedBitSet { 1070 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { 1071 | if f.alternate() { 1072 | f.write_str("0b")?; 1073 | } 1074 | 1075 | for i in 0..self.length { 1076 | if self[i] { 1077 | f.write_char('1')?; 1078 | } else { 1079 | f.write_char('0')?; 1080 | } 1081 | } 1082 | 1083 | Ok(()) 1084 | } 1085 | } 1086 | 1087 | impl Display for FixedBitSet { 1088 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { 1089 | Binary::fmt(&self, f) 1090 | } 1091 | } 1092 | 1093 | /// An iterator producing elements in the difference of two sets. 1094 | /// 1095 | /// This struct is created by the [`FixedBitSet::difference`] method. 1096 | pub struct Difference<'a> { 1097 | iter: Ones<'a>, 1098 | other: &'a FixedBitSet, 1099 | } 1100 | 1101 | impl<'a> Iterator for Difference<'a> { 1102 | type Item = usize; 1103 | 1104 | #[inline] 1105 | fn next(&mut self) -> Option { 1106 | self.iter.by_ref().find(|&nxt| !self.other.contains(nxt)) 1107 | } 1108 | 1109 | #[inline] 1110 | fn size_hint(&self) -> (usize, Option) { 1111 | self.iter.size_hint() 1112 | } 1113 | } 1114 | 1115 | impl<'a> DoubleEndedIterator for Difference<'a> { 1116 | fn next_back(&mut self) -> Option { 1117 | self.iter 1118 | .by_ref() 1119 | .rev() 1120 | .find(|&nxt| !self.other.contains(nxt)) 1121 | } 1122 | } 1123 | 1124 | // Difference will continue to return None once it first returns None. 1125 | impl<'a> FusedIterator for Difference<'a> {} 1126 | 1127 | /// An iterator producing elements in the symmetric difference of two sets. 1128 | /// 1129 | /// This struct is created by the [`FixedBitSet::symmetric_difference`] method. 1130 | pub struct SymmetricDifference<'a> { 1131 | iter: Chain, Difference<'a>>, 1132 | } 1133 | 1134 | impl<'a> Iterator for SymmetricDifference<'a> { 1135 | type Item = usize; 1136 | 1137 | #[inline] 1138 | fn next(&mut self) -> Option { 1139 | self.iter.next() 1140 | } 1141 | 1142 | #[inline] 1143 | fn size_hint(&self) -> (usize, Option) { 1144 | self.iter.size_hint() 1145 | } 1146 | } 1147 | 1148 | impl<'a> DoubleEndedIterator for SymmetricDifference<'a> { 1149 | fn next_back(&mut self) -> Option { 1150 | self.iter.next_back() 1151 | } 1152 | } 1153 | 1154 | // SymmetricDifference will continue to return None once it first returns None. 1155 | impl<'a> FusedIterator for SymmetricDifference<'a> {} 1156 | 1157 | /// An iterator producing elements in the intersection of two sets. 1158 | /// 1159 | /// This struct is created by the [`FixedBitSet::intersection`] method. 1160 | pub struct Intersection<'a> { 1161 | iter: Ones<'a>, 1162 | other: &'a FixedBitSet, 1163 | } 1164 | 1165 | impl<'a> Iterator for Intersection<'a> { 1166 | type Item = usize; // the bit position of the '1' 1167 | 1168 | #[inline] 1169 | fn next(&mut self) -> Option { 1170 | self.iter.by_ref().find(|&nxt| self.other.contains(nxt)) 1171 | } 1172 | 1173 | #[inline] 1174 | fn size_hint(&self) -> (usize, Option) { 1175 | self.iter.size_hint() 1176 | } 1177 | } 1178 | 1179 | impl<'a> DoubleEndedIterator for Intersection<'a> { 1180 | fn next_back(&mut self) -> Option { 1181 | self.iter 1182 | .by_ref() 1183 | .rev() 1184 | .find(|&nxt| self.other.contains(nxt)) 1185 | } 1186 | } 1187 | 1188 | // Intersection will continue to return None once it first returns None. 1189 | impl<'a> FusedIterator for Intersection<'a> {} 1190 | 1191 | /// An iterator producing elements in the union of two sets. 1192 | /// 1193 | /// This struct is created by the [`FixedBitSet::union`] method. 1194 | pub struct Union<'a> { 1195 | iter: Chain, Difference<'a>>, 1196 | } 1197 | 1198 | impl<'a> Iterator for Union<'a> { 1199 | type Item = usize; 1200 | 1201 | #[inline] 1202 | fn next(&mut self) -> Option { 1203 | self.iter.next() 1204 | } 1205 | 1206 | #[inline] 1207 | fn size_hint(&self) -> (usize, Option) { 1208 | self.iter.size_hint() 1209 | } 1210 | } 1211 | 1212 | impl<'a> DoubleEndedIterator for Union<'a> { 1213 | fn next_back(&mut self) -> Option { 1214 | self.iter.next_back() 1215 | } 1216 | } 1217 | 1218 | // Union will continue to return None once it first returns None. 1219 | impl<'a> FusedIterator for Union<'a> {} 1220 | 1221 | struct Masks { 1222 | first_block: usize, 1223 | first_mask: usize, 1224 | last_block: usize, 1225 | last_mask: usize, 1226 | } 1227 | 1228 | impl Masks { 1229 | #[inline] 1230 | fn new(range: T, length: usize) -> Masks { 1231 | let start = range.start().unwrap_or(0); 1232 | let end = range.end().unwrap_or(length); 1233 | assert!( 1234 | start <= end && end <= length, 1235 | "invalid range {}..{} for a fixedbitset of size {}", 1236 | start, 1237 | end, 1238 | length 1239 | ); 1240 | 1241 | let (first_block, first_rem) = div_rem(start, BITS); 1242 | let (last_block, last_rem) = div_rem(end, BITS); 1243 | 1244 | Masks { 1245 | first_block, 1246 | first_mask: usize::MAX << first_rem, 1247 | last_block, 1248 | last_mask: (usize::MAX >> 1) >> (BITS - last_rem - 1), 1249 | // this is equivalent to `MAX >> (BITS - x)` with correct semantics when x == 0. 1250 | } 1251 | } 1252 | } 1253 | 1254 | impl Iterator for Masks { 1255 | type Item = (usize, usize); 1256 | 1257 | #[inline] 1258 | fn next(&mut self) -> Option { 1259 | match self.first_block.cmp(&self.last_block) { 1260 | Ordering::Less => { 1261 | let res = (self.first_block, self.first_mask); 1262 | self.first_block += 1; 1263 | self.first_mask = !0; 1264 | Some(res) 1265 | } 1266 | Ordering::Equal => { 1267 | let mask = self.first_mask & self.last_mask; 1268 | let res = if mask == 0 { 1269 | None 1270 | } else { 1271 | Some((self.first_block, mask)) 1272 | }; 1273 | self.first_block += 1; 1274 | res 1275 | } 1276 | Ordering::Greater => None, 1277 | } 1278 | } 1279 | 1280 | #[inline] 1281 | fn size_hint(&self) -> (usize, Option) { 1282 | (self.first_block..=self.last_block).size_hint() 1283 | } 1284 | } 1285 | 1286 | // Masks will continue to return None once it first returns None. 1287 | impl FusedIterator for Masks {} 1288 | 1289 | // Masks's size_hint implementation is exact. It never returns an 1290 | // unbounded value and always returns an exact number of values. 1291 | impl ExactSizeIterator for Masks {} 1292 | 1293 | /// An iterator producing the indices of the set bit in a set. 1294 | /// 1295 | /// This struct is created by the [`FixedBitSet::ones`] method. 1296 | #[derive(Clone)] 1297 | pub struct Ones<'a> { 1298 | bitset_front: usize, 1299 | bitset_back: usize, 1300 | block_idx_front: usize, 1301 | block_idx_back: usize, 1302 | remaining_blocks: core::slice::Iter<'a, usize>, 1303 | } 1304 | 1305 | impl<'a> Ones<'a> { 1306 | #[inline] 1307 | pub fn last_positive_bit_and_unset(n: &mut usize) -> usize { 1308 | // Find the last set bit using x & -x 1309 | let last_bit = *n & n.wrapping_neg(); 1310 | 1311 | // Find the position of the last set bit 1312 | let position = last_bit.trailing_zeros(); 1313 | 1314 | // Unset the last set bit 1315 | *n &= *n - 1; 1316 | 1317 | position as usize 1318 | } 1319 | 1320 | #[inline] 1321 | fn first_positive_bit_and_unset(n: &mut usize) -> usize { 1322 | /* Identify the first non zero bit */ 1323 | let bit_idx = n.leading_zeros(); 1324 | 1325 | /* set that bit to zero */ 1326 | let mask = !((1_usize) << (BITS as u32 - bit_idx - 1)); 1327 | n.bitand_assign(mask); 1328 | 1329 | bit_idx as usize 1330 | } 1331 | } 1332 | 1333 | impl<'a> DoubleEndedIterator for Ones<'a> { 1334 | fn next_back(&mut self) -> Option { 1335 | while self.bitset_back == 0 { 1336 | match self.remaining_blocks.next_back() { 1337 | None => { 1338 | if self.bitset_front != 0 { 1339 | self.bitset_back = 0; 1340 | self.block_idx_back = self.block_idx_front; 1341 | return Some( 1342 | self.block_idx_front + BITS 1343 | - Self::first_positive_bit_and_unset(&mut self.bitset_front) 1344 | - 1, 1345 | ); 1346 | } else { 1347 | return None; 1348 | } 1349 | } 1350 | Some(next_block) => { 1351 | self.bitset_back = *next_block; 1352 | self.block_idx_back -= BITS; 1353 | } 1354 | }; 1355 | } 1356 | 1357 | Some( 1358 | self.block_idx_back - Self::first_positive_bit_and_unset(&mut self.bitset_back) + BITS 1359 | - 1, 1360 | ) 1361 | } 1362 | } 1363 | 1364 | impl<'a> Iterator for Ones<'a> { 1365 | type Item = usize; // the bit position of the '1' 1366 | 1367 | #[inline] 1368 | fn next(&mut self) -> Option { 1369 | while self.bitset_front == 0 { 1370 | match self.remaining_blocks.next() { 1371 | Some(next_block) => { 1372 | self.bitset_front = *next_block; 1373 | self.block_idx_front += BITS; 1374 | } 1375 | None => { 1376 | if self.bitset_back != 0 { 1377 | // not needed for iteration, but for size_hint 1378 | self.block_idx_front = self.block_idx_back; 1379 | self.bitset_front = 0; 1380 | 1381 | return Some( 1382 | self.block_idx_back 1383 | + Self::last_positive_bit_and_unset(&mut self.bitset_back), 1384 | ); 1385 | } else { 1386 | return None; 1387 | } 1388 | } 1389 | }; 1390 | } 1391 | 1392 | Some(self.block_idx_front + Self::last_positive_bit_and_unset(&mut self.bitset_front)) 1393 | } 1394 | 1395 | #[inline] 1396 | fn size_hint(&self) -> (usize, Option) { 1397 | ( 1398 | 0, 1399 | (Some(self.block_idx_back - self.block_idx_front + 2 * BITS)), 1400 | ) 1401 | } 1402 | } 1403 | 1404 | // Ones will continue to return None once it first returns None. 1405 | impl<'a> FusedIterator for Ones<'a> {} 1406 | 1407 | /// An iterator producing the indices of the set bit in a set. 1408 | /// 1409 | /// This struct is created by the [`FixedBitSet::ones`] method. 1410 | pub struct Zeroes<'a> { 1411 | bitset: usize, 1412 | block_idx: usize, 1413 | len: usize, 1414 | remaining_blocks: core::slice::Iter<'a, usize>, 1415 | } 1416 | 1417 | impl<'a> Iterator for Zeroes<'a> { 1418 | type Item = usize; // the bit position of the '1' 1419 | 1420 | #[inline] 1421 | fn next(&mut self) -> Option { 1422 | while self.bitset == 0 { 1423 | self.bitset = !*self.remaining_blocks.next()?; 1424 | self.block_idx += BITS; 1425 | } 1426 | let t = self.bitset & (0_usize).wrapping_sub(self.bitset); 1427 | let r = self.bitset.trailing_zeros() as usize; 1428 | self.bitset ^= t; 1429 | let bit = self.block_idx + r; 1430 | // The remaining zeroes beyond the length of the bitset must be excluded. 1431 | if bit < self.len { 1432 | Some(bit) 1433 | } else { 1434 | None 1435 | } 1436 | } 1437 | 1438 | #[inline] 1439 | fn size_hint(&self) -> (usize, Option) { 1440 | (0, Some(self.len)) 1441 | } 1442 | } 1443 | 1444 | // Zeroes will stop returning Some when exhausted. 1445 | impl<'a> FusedIterator for Zeroes<'a> {} 1446 | 1447 | impl Clone for FixedBitSet { 1448 | #[inline] 1449 | fn clone(&self) -> Self { 1450 | Self::from_blocks_and_len(Vec::from(self.as_simd_slice()), self.length) 1451 | } 1452 | 1453 | #[inline] 1454 | fn clone_from(&mut self, source: &Self) { 1455 | if self.length < source.length { 1456 | // SAFETY: `fill` is uninitialized, but is immediately initialized from `source`. 1457 | unsafe { self.grow_inner(source.length, MaybeUninit::uninit()) }; 1458 | } 1459 | let me = self.as_mut_simd_slice_uninit(); 1460 | let them = source.as_simd_slice_uninit(); 1461 | match me.len().cmp(&them.len()) { 1462 | Ordering::Greater => { 1463 | let (head, tail) = me.split_at_mut(them.len()); 1464 | head.copy_from_slice(them); 1465 | tail.fill(MaybeUninit::new(SimdBlock::NONE)); 1466 | } 1467 | Ordering::Equal => me.copy_from_slice(them), 1468 | // The grow_inner above ensures that self is at least as large as source. 1469 | // so this branch is unreachable. 1470 | Ordering::Less => {} 1471 | } 1472 | self.length = source.length; 1473 | } 1474 | } 1475 | 1476 | /// Return **true** if the bit is enabled in the bitset, 1477 | /// or **false** otherwise. 1478 | /// 1479 | /// Note: bits outside the capacity are always disabled, and thus 1480 | /// indexing a FixedBitSet will not panic. 1481 | impl Index for FixedBitSet { 1482 | type Output = bool; 1483 | 1484 | #[inline] 1485 | fn index(&self, bit: usize) -> &bool { 1486 | if self.contains(bit) { 1487 | &true 1488 | } else { 1489 | &false 1490 | } 1491 | } 1492 | } 1493 | 1494 | /// Sets the bit at index **i** to **true** for each item **i** in the input **src**. 1495 | impl Extend for FixedBitSet { 1496 | fn extend>(&mut self, src: I) { 1497 | let iter = src.into_iter(); 1498 | for i in iter { 1499 | if i >= self.len() { 1500 | self.grow(i + 1); 1501 | } 1502 | self.put(i); 1503 | } 1504 | } 1505 | } 1506 | 1507 | /// Return a FixedBitSet containing bits set to **true** for every bit index in 1508 | /// the iterator, other bits are set to **false**. 1509 | impl FromIterator for FixedBitSet { 1510 | fn from_iter>(src: I) -> Self { 1511 | let mut fbs = FixedBitSet::with_capacity(0); 1512 | fbs.extend(src); 1513 | fbs 1514 | } 1515 | } 1516 | 1517 | pub struct IntoOnes { 1518 | bitset_front: Block, 1519 | bitset_back: Block, 1520 | block_idx_front: usize, 1521 | block_idx_back: usize, 1522 | remaining_blocks: core::iter::Copied>, 1523 | // Keep buf along so that `remaining_blocks` remains valid. 1524 | _buf: Vec, 1525 | } 1526 | 1527 | impl IntoOnes { 1528 | #[inline] 1529 | pub fn last_positive_bit_and_unset(n: &mut Block) -> usize { 1530 | // Find the last set bit using x & -x 1531 | let last_bit = *n & n.wrapping_neg(); 1532 | 1533 | // Find the position of the last set bit 1534 | let position = last_bit.trailing_zeros(); 1535 | 1536 | // Unset the last set bit 1537 | *n &= *n - 1; 1538 | 1539 | position as usize 1540 | } 1541 | 1542 | #[inline] 1543 | fn first_positive_bit_and_unset(n: &mut Block) -> usize { 1544 | /* Identify the first non zero bit */ 1545 | let bit_idx = n.leading_zeros(); 1546 | 1547 | /* set that bit to zero */ 1548 | let mask = !((1_usize) << (BITS as u32 - bit_idx - 1)); 1549 | n.bitand_assign(mask); 1550 | 1551 | bit_idx as usize 1552 | } 1553 | } 1554 | 1555 | impl DoubleEndedIterator for IntoOnes { 1556 | fn next_back(&mut self) -> Option { 1557 | while self.bitset_back == 0 { 1558 | match self.remaining_blocks.next_back() { 1559 | None => { 1560 | if self.bitset_front != 0 { 1561 | self.bitset_back = 0; 1562 | self.block_idx_back = self.block_idx_front; 1563 | return Some( 1564 | self.block_idx_front + BITS 1565 | - Self::first_positive_bit_and_unset(&mut self.bitset_front) 1566 | - 1, 1567 | ); 1568 | } else { 1569 | return None; 1570 | } 1571 | } 1572 | Some(next_block) => { 1573 | self.bitset_back = next_block; 1574 | self.block_idx_back -= BITS; 1575 | } 1576 | }; 1577 | } 1578 | 1579 | Some( 1580 | self.block_idx_back - Self::first_positive_bit_and_unset(&mut self.bitset_back) + BITS 1581 | - 1, 1582 | ) 1583 | } 1584 | } 1585 | 1586 | impl Iterator for IntoOnes { 1587 | type Item = usize; // the bit position of the '1' 1588 | 1589 | #[inline] 1590 | fn next(&mut self) -> Option { 1591 | while self.bitset_front == 0 { 1592 | match self.remaining_blocks.next() { 1593 | Some(next_block) => { 1594 | self.bitset_front = next_block; 1595 | self.block_idx_front += BITS; 1596 | } 1597 | None => { 1598 | if self.bitset_back != 0 { 1599 | // not needed for iteration, but for size_hint 1600 | self.block_idx_front = self.block_idx_back; 1601 | self.bitset_front = 0; 1602 | 1603 | return Some( 1604 | self.block_idx_back 1605 | + Self::last_positive_bit_and_unset(&mut self.bitset_back), 1606 | ); 1607 | } else { 1608 | return None; 1609 | } 1610 | } 1611 | }; 1612 | } 1613 | 1614 | Some(self.block_idx_front + Self::last_positive_bit_and_unset(&mut self.bitset_front)) 1615 | } 1616 | 1617 | #[inline] 1618 | fn size_hint(&self) -> (usize, Option) { 1619 | ( 1620 | 0, 1621 | (Some(self.block_idx_back - self.block_idx_front + 2 * BITS)), 1622 | ) 1623 | } 1624 | } 1625 | 1626 | // Ones will continue to return None once it first returns None. 1627 | impl FusedIterator for IntoOnes {} 1628 | 1629 | impl BitAnd for &FixedBitSet { 1630 | type Output = FixedBitSet; 1631 | fn bitand(self, other: &FixedBitSet) -> FixedBitSet { 1632 | let (short, long) = { 1633 | if self.len() <= other.len() { 1634 | (self.as_simd_slice(), other.as_simd_slice()) 1635 | } else { 1636 | (other.as_simd_slice(), self.as_simd_slice()) 1637 | } 1638 | }; 1639 | let mut data = Vec::from(short); 1640 | for (data, block) in data.iter_mut().zip(long.iter()) { 1641 | *data &= *block; 1642 | } 1643 | let len = core::cmp::min(self.len(), other.len()); 1644 | FixedBitSet::from_blocks_and_len(data, len) 1645 | } 1646 | } 1647 | 1648 | impl BitAndAssign for FixedBitSet { 1649 | fn bitand_assign(&mut self, other: Self) { 1650 | self.intersect_with(&other); 1651 | } 1652 | } 1653 | 1654 | impl BitAndAssign<&Self> for FixedBitSet { 1655 | fn bitand_assign(&mut self, other: &Self) { 1656 | self.intersect_with(other); 1657 | } 1658 | } 1659 | 1660 | impl BitOr for &FixedBitSet { 1661 | type Output = FixedBitSet; 1662 | fn bitor(self, other: &FixedBitSet) -> FixedBitSet { 1663 | let (short, long) = { 1664 | if self.len() <= other.len() { 1665 | (self.as_simd_slice(), other.as_simd_slice()) 1666 | } else { 1667 | (other.as_simd_slice(), self.as_simd_slice()) 1668 | } 1669 | }; 1670 | let mut data = Vec::from(long); 1671 | for (data, block) in data.iter_mut().zip(short.iter()) { 1672 | *data |= *block; 1673 | } 1674 | let len = core::cmp::max(self.len(), other.len()); 1675 | FixedBitSet::from_blocks_and_len(data, len) 1676 | } 1677 | } 1678 | 1679 | impl BitOrAssign for FixedBitSet { 1680 | fn bitor_assign(&mut self, other: Self) { 1681 | self.union_with(&other); 1682 | } 1683 | } 1684 | 1685 | impl BitOrAssign<&Self> for FixedBitSet { 1686 | fn bitor_assign(&mut self, other: &Self) { 1687 | self.union_with(other); 1688 | } 1689 | } 1690 | 1691 | impl BitXor for &FixedBitSet { 1692 | type Output = FixedBitSet; 1693 | fn bitxor(self, other: &FixedBitSet) -> FixedBitSet { 1694 | let (short, long) = { 1695 | if self.len() <= other.len() { 1696 | (self.as_simd_slice(), other.as_simd_slice()) 1697 | } else { 1698 | (other.as_simd_slice(), self.as_simd_slice()) 1699 | } 1700 | }; 1701 | let mut data = Vec::from(long); 1702 | for (data, block) in data.iter_mut().zip(short.iter()) { 1703 | *data ^= *block; 1704 | } 1705 | let len = core::cmp::max(self.len(), other.len()); 1706 | FixedBitSet::from_blocks_and_len(data, len) 1707 | } 1708 | } 1709 | 1710 | impl BitXorAssign for FixedBitSet { 1711 | fn bitxor_assign(&mut self, other: Self) { 1712 | self.symmetric_difference_with(&other); 1713 | } 1714 | } 1715 | 1716 | impl BitXorAssign<&Self> for FixedBitSet { 1717 | fn bitxor_assign(&mut self, other: &Self) { 1718 | self.symmetric_difference_with(other); 1719 | } 1720 | } 1721 | --------------------------------------------------------------------------------