From 6797acbe323ded70ef9beb1af864adf0a669788a Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 5 Mar 2026 08:53:24 +0100 Subject: [PATCH 01/24] Implement `BitBlockOrStore` --- .vscode/settings.json | 2 +- Cargo.toml | 6 +- benches/bench.rs | 8 +- docs/README.md | 185 ++++++++ src/lib.rs | 1056 +++++++++++++++++++++++++---------------- 5 files changed, 849 insertions(+), 408 deletions(-) create mode 100644 docs/README.md diff --git a/.vscode/settings.json b/.vscode/settings.json index 93704c9..ea54d8d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust-analyzer.cargo.features": ["serde", "nanoserde"] + "rust-analyzer.cargo.features": ["serde", "nanoserde", "smallvec"] } diff --git a/Cargo.toml b/Cargo.toml index 6ee3fd0..625af1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,11 +17,13 @@ borsh = { version = "1.6.0", default-features = false, features = ["derive"], op serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } miniserde = { version = "0.1", optional = true } nanoserde = { version = "0.2", optional = true } +smallvec = { version = "1.15", optional = true } [dev-dependencies] serde_json = "1.0" -rand = "0.9" -rand_xorshift = "0.4" +rand = "0.10" +rand_xorshift = "0.5" +generic-tests = "0.1" [features] default = ["std"] diff --git a/benches/bench.rs b/benches/bench.rs index b78b934..8795b12 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -18,7 +18,7 @@ extern crate rand_xorshift; extern crate test; use bit_vec::BitVec; -use rand::{Rng, RngCore, SeedableRng}; +use rand::{Rng, RngExt, SeedableRng}; use rand_xorshift::XorShiftRng; use test::{black_box, Bencher}; @@ -27,7 +27,7 @@ const BENCH_BITS: usize = 1 << 14; const U32_BITS: usize = 32; fn small_rng() -> XorShiftRng { - XorShiftRng::from_os_rng() + XorShiftRng::from_rng(&mut rand::rng()) } #[bench] @@ -137,7 +137,7 @@ fn bench_bit_get_unchecked_small_assume(b: &mut Bencher) { for _ in 0..100 { unsafe { let idx = (r.next_u32() as usize) % size; - ::std::hint::assert_unchecked(!(idx >= bit_vec.len())); + ::std::hint::assert_unchecked(idx < bit_vec.len()); black_box(bit_vec.get(idx)); } } @@ -256,7 +256,7 @@ fn bench_erathostenes_set_all(b: &mut test::Bencher) { b.iter(|| { primes.clear(); black_box(&mut sieve); - sieve.set_all(); + sieve.fill(true); black_box(&mut sieve); let mut i = 2; while i < sieve.len() { diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..4108499 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,185 @@ +# stackoverflow question + +Rust: Mark the method as unsafe, or just add "unsafe" to its name? Dilemma with library API design. + +Hi. I am maintaining a dynamic array of bits just like C++'s `vector`. + +The thing in question, is the method for getting access to the underlying `Vec`, which may let the caller mess up the dynamic array. It's not inherently memory-unsafe, but currently marked as such. My idea is to change this unsafe fn to be marked as safe, while adding a prefix `unsafe_` to its name. + +# code review request + +maintainer of `bit-vec` here. It's a Rust library for lists of booleans. + +The library is used by a couple thousand people, so I'd appreciate thorough review. You have a compact dynamic arrays of bits like `vector` in C++ and fill all elements with the given value, or remove one of the elements at the given index. This is basically it. But I had to deprecate `fn clear` by renaming it to `fn fill` because the name was inconsistent with other collections having `clear` truncate the list to zero elements: https://github.com/contain-rs/bit-vec/issues/16 + +You may see the code here: https://github.com/contain-rs/bit-vec/pull/134/changes https://github.com/contain-rs/bit-vec/pull/135/changes All of it except the tests is included below. + +```rust + /// Assigns all bits in this vector to the given boolean value. + /// + /// # Invariants + /// + /// - After a call to `.fill(true)`, the result of [`all`] is `true`. + /// - After a call to `.fill(false)`, the result of [`none`] is `true`. + /// + /// [`all`]: Self::all + /// [`none`]: Self::none + #[inline] + pub fn fill(&mut self, bit: bool) { + self.ensure_invariant(); + let block = if bit { !B::zero() } else { B::zero() }; + for w in &mut self.storage { + *w = block; + } + if bit { + self.fix_last_block(); + } + } + + /// Clears all bits in this vector. + #[inline] + #[deprecated(since = "0.9.0", note = "please use `.fill(false)` instead")] + pub fn clear(&mut self) { + self.ensure_invariant(); + for w in &mut self.storage { + *w = B::zero(); + } + } + + /// Remove a bit at index `at`, shifting all bits after by one. + /// + /// # Panics + /// Panics if `at` is out of bounds for `BitVec`'s length (that is, if `at >= BitVec::len()`) + /// + /// # Examples + ///``` + /// use bit_vec::BitVec; + /// + /// let mut b = BitVec::new(); + /// + /// b.push(true); + /// b.push(false); + /// b.push(false); + /// b.push(true); + /// assert!(!b.remove(1)); + /// + /// assert!(b.eq_vec(&[true, false, true])); + ///``` + /// + /// # Time complexity + /// Takes O([`len`]) time. All items after the removal index must be + /// shifted to the left. In the worst case, all elements are shifted when + /// the removal index is 0. + /// + /// [`len`]: Self::len + pub fn remove(&mut self, at: usize) -> bool { + assert!( + at < self.nbits, + "removal index (is {at}) should be < len (is {nbits})", + nbits = self.nbits + ); + self.ensure_invariant(); + + self.nbits -= 1; + + let last_block_bits = self.nbits % B::bits(); + let block_at = at / B::bits(); // needed block + let bit_at = at % B::bits(); // index within the block + + let lsbits_mask = (B::one() << bit_at) - B::one(); + + let mut carry = B::zero(); + + for block_ref in self.storage[block_at + 1..].iter_mut().rev() { + let curr_carry = *block_ref & B::one(); + *block_ref = *block_ref >> 1 | (carry << (B::bits() - 1)); + carry = curr_carry; + } + + // Safety: thanks to the assert above. + let result = unsafe { self.get_unchecked(at) }; + + self.storage[block_at] = (self.storage[block_at] & lsbits_mask) + | ((self.storage[block_at] & (!lsbits_mask << 1)) >> 1) + | carry << (B::bits() - 1); + + if last_block_bits == 0 { + self.storage.pop(); + } + + result + } +``` + +```rust +pub struct BitVec { + /// Internal representation of the bit vector + storage: Vec, + /// The number of valid bits in the internal representation + nbits: usize, +} + +/// Abstracts over a pile of bits (basically unsigned primitives) +pub trait BitBlock: + Copy + + Add + + Sub + + Shl + + Shr + + Not + + BitAnd + + BitOr + + BitXor + + Rem + + Eq + + Ord + + hash::Hash +{ + /// How many bits it has + fn bits() -> usize; + /// How many bytes it has + #[inline] + fn bytes() -> usize { + Self::bits() / 8 + } + /// Convert a byte into this type (lowest-order bits set) + fn from_byte(byte: u8) -> Self; + /// Count the number of 1's in the bitwise repr + fn count_ones(self) -> usize; + /// Count the number of 0's in the bitwise repr + fn count_zeros(self) -> usize { + Self::bits() - self.count_ones() + } + /// Get `0` + fn zero() -> Self; + /// Get `1` + fn one() -> Self; +} + +macro_rules! bit_block_impl { + ($(($t: ident, $size: expr)),*) => ($( + impl BitBlock for $t { + #[inline] + fn bits() -> usize { $size } + #[inline] + fn from_byte(byte: u8) -> Self { $t::from(byte) } + #[inline] + fn count_ones(self) -> usize { self.count_ones() as usize } + #[inline] + fn count_zeros(self) -> usize { self.count_zeros() as usize } + #[inline] + fn one() -> Self { 1 } + #[inline] + fn zero() -> Self { 0 } + } + )*) +} + +bit_block_impl! { + (u8, 8), + (u16, 16), + (u32, 32), + (u64, 64), + (usize, core::mem::size_of::() * 8) +} +``` \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 782fe91..a647993 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,7 @@ #![warn(clippy::multiple_crate_versions)] #![warn(clippy::single_match)] #![warn(clippy::missing_safety_doc)] +#![allow(type_alias_bounds)] #[cfg(any(test, feature = "std"))] #[macro_use] @@ -126,17 +127,17 @@ use alloc::string::String; use alloc::vec::Vec; use core::cell::RefCell; -use core::cmp; use core::cmp::Ordering; use core::fmt::{self, Write}; use core::hash; -use core::iter::repeat; use core::iter::FromIterator; use core::mem; use core::ops::*; use core::slice; +use core::{cmp, iter}; -type MutBlocks<'a, B> = slice::IterMut<'a, B>; +type BlocksMut<'a, B: BitBlockOrStore> = slice::IterMut<'a, Block>; +type Block = ::Block; /// Abstracts over a pile of bits (basically unsigned primitives) pub trait BitBlock: @@ -156,41 +157,223 @@ pub trait BitBlock: + hash::Hash { /// How many bits it has - fn bits() -> usize; + const BITS_: usize; /// How many bytes it has - #[inline] - fn bytes() -> usize { - Self::bits() / 8 - } + const BYTES_: usize = Self::BITS_ / 8; /// Convert a byte into this type (lowest-order bits set) fn from_byte(byte: u8) -> Self; /// Count the number of 1's in the bitwise repr fn count_ones(self) -> usize; /// Count the number of 0's in the bitwise repr fn count_zeros(self) -> usize { - Self::bits() - self.count_ones() + Self::BITS_ - self.count_ones() } /// Get `0` - fn zero() -> Self; + const ZERO_: Self; /// Get `1` - fn one() -> Self; + const ONE_: Self; +} + +pub trait BitBlockOrStore { + type Store: BitStore; + const BITS: usize = ::Block::BITS_; + const BYTES: usize = ::Block::BYTES_; + const ONE: ::Block = ::Block::ONE_; + const ZERO: ::Block = ::Block::ZERO_; +} + +#[allow(clippy::len_without_is_empty)] +pub trait BitStore: Clone + Default { + type Block: BitBlock; + fn slice(&self) -> &[Self::Block]; + fn slice_mut(&mut self) -> &mut [Self::Block]; + fn len(&self) -> usize { + self.slice().len() + } + fn pop(&mut self) -> Option; + fn drain>(&mut self, range: R) -> impl Iterator; + fn capacity(&self) -> usize; + fn append(&mut self, other: &mut Self); + fn reserve(&mut self, additional: usize); + fn push(&mut self, value: Self::Block); + fn split_off(&mut self, at: usize) -> Self; + fn truncate(&mut self, len: usize); + fn reserve_exact(&mut self, len: usize); + fn shrink_to_fit(&mut self); + fn extend(&mut self, iter: T) + where + T: IntoIterator; + fn with_capacity(capacity: usize) -> Self; + fn clear(&mut self); +} + +impl BitStore for Vec { + type Block = T; + + fn slice(&self) -> &[Self::Block] { + &self[..] + } + + fn slice_mut(&mut self) -> &mut [Self::Block] { + &mut self[..] + } + + fn pop(&mut self) -> Option { + self.pop() + } + + fn drain>(&mut self, range: R) -> impl Iterator { + self.drain(range) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn append(&mut self, other: &mut Self) { + self.append(other); + } + + fn reserve(&mut self, additional: usize) { + self.reserve(additional); + } + + fn push(&mut self, value: Self::Block) { + self.push(value); + } + + fn split_off(&mut self, at: usize) -> Self { + self.split_off(at) + } + + fn truncate(&mut self, len: usize) { + self.truncate(len); + } + + fn reserve_exact(&mut self, len: usize) { + self.reserve_exact(len); + } + + fn shrink_to_fit(&mut self) { + self.shrink_to_fit(); + } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + iter::Extend::extend(self, iter); + } + + fn with_capacity(capacity: usize) -> Self { + Vec::with_capacity(capacity) + } + + fn clear(&mut self) { + Vec::clear(self) + } +} + +impl BitBlockOrStore for Vec { + type Store = Self; +} + +#[cfg(feature = "smallvec")] +impl BitBlockOrStore for smallvec::SmallVec +where + A::Item: BitBlock, +{ + type Store = Self; +} + +#[cfg(feature = "smallvec")] +impl BitStore for smallvec::SmallVec +where + A::Item: BitBlock, +{ + type Block = A::Item; + + fn slice(&self) -> &[Self::Block] { + &self[..] + } + + fn slice_mut(&mut self) -> &mut [Self::Block] { + &mut self[..] + } + + fn pop(&mut self) -> Option { + self.pop() + } + + fn drain>(&mut self, range: R) -> impl Iterator { + self.drain(range) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn append(&mut self, other: &mut Self) { + self.append(other); + } + + fn reserve(&mut self, additional: usize) { + self.reserve(additional); + } + + fn push(&mut self, value: Self::Block) { + self.push(value); + } + + fn split_off(&mut self, at: usize) -> Self { + // TODO + self.to_vec().split_off(at).into() + } + + fn truncate(&mut self, len: usize) { + self.truncate(len); + } + + fn reserve_exact(&mut self, len: usize) { + self.reserve_exact(len); + } + + fn shrink_to_fit(&mut self) { + self.shrink_to_fit(); + } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + iter::Extend::extend(self, iter); + } + + fn with_capacity(capacity: usize) -> Self { + smallvec::SmallVec::with_capacity(capacity) + } + + fn clear(&mut self) { + self.clear(); + } } macro_rules! bit_block_impl { ($(($t: ident, $size: expr)),*) => ($( impl BitBlock for $t { - #[inline] - fn bits() -> usize { $size } + const BITS_: usize = $size; #[inline] fn from_byte(byte: u8) -> Self { $t::from(byte) } #[inline] fn count_ones(self) -> usize { self.count_ones() as usize } #[inline] fn count_zeros(self) -> usize { self.count_zeros() as usize } - #[inline] - fn one() -> Self { 1 } - #[inline] - fn zero() -> Self { 0 } + const ONE_: Self = 1; + const ZERO_: Self = 0; + } + + impl BitBlockOrStore for $t { + type Store = Vec; } )*) } @@ -200,13 +383,13 @@ bit_block_impl! { (u16, 16), (u32, 32), (u64, 64), - (usize, core::mem::size_of::() * 8) + (usize, usize::BITS as usize) } fn reverse_bits(byte: u8) -> u8 { let mut result = 0; - for i in 0..u8::bits() { - result |= ((byte >> i) & 1) << (u8::bits() - 1 - i); + for i in 0..u8::BITS { + result |= ((byte >> i) & 1) << (u8::BITS - 1 - i); } result } @@ -244,7 +427,6 @@ type B = u32; /// println!("{:?}", bv); /// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); /// ``` -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( feature = "borsh", derive(borsh::BorshDeserialize, borsh::BorshSerialize) @@ -257,15 +439,15 @@ type B = u32; feature = "nanoserde", derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) )] -pub struct BitVec { +pub struct BitVec { /// Internal representation of the bit vector - storage: Vec, + storage: B::Store, /// The number of valid bits in the internal representation nbits: usize, } // FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing) -impl Index for BitVec { +impl Index for BitVec { type Output = bool; #[inline] @@ -279,7 +461,7 @@ impl Index for BitVec { } /// Computes how many blocks are needed to store that many bits -fn blocks_for_bits(bits: usize) -> usize { +fn blocks_for_bits(bits: usize) -> usize { // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we // reserve enough. But if we want exactly a multiple of 32, this will actually allocate // one too many. So we need to check if that's the case. We can do that by computing if @@ -288,17 +470,17 @@ fn blocks_for_bits(bits: usize) -> usize { // // Note that we can technically avoid this branch with the expression // `(nbits + U32_BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. - if bits % B::bits() == 0 { - bits / B::bits() + if bits % B::BITS == 0 { + bits / B::BITS } else { - bits / B::bits() + 1 + bits / B::BITS + 1 } } /// Computes the bitmask for the final word of the vector -fn mask_for_bits(bits: usize) -> B { +fn mask_for_bits(bits: usize) -> Block { // Note especially that a perfect multiple of U32_BITS should mask all 1s. - (!B::zero()) >> ((B::bits() - bits % B::bits()) % B::bits()) + (!B::ZERO) >> ((B::BITS - bits % B::BITS) % B::BITS) } impl BitVec { @@ -385,7 +567,7 @@ impl BitVec { } } -impl BitVec { +impl BitVec { /// Creates an empty `BitVec`. /// /// # Examples @@ -416,8 +598,13 @@ impl BitVec { #[inline] pub fn from_elem_general(len: usize, bit: bool) -> Self { let nblocks = blocks_for_bits::(len); + let mut storage: B::Store = B::Store::with_capacity(nblocks); + storage.extend(iter::repeat_n( + if bit { !B::ZERO } else { B::ZERO }, + nblocks, + )); let mut bit_vec = BitVec { - storage: vec![if bit { !B::zero() } else { B::zero() }; nblocks], + storage, nbits: len, }; bit_vec.fix_last_block(); @@ -434,7 +621,7 @@ impl BitVec { #[inline] pub fn with_capacity_general(capacity: usize) -> Self { BitVec { - storage: Vec::with_capacity(blocks_for_bits::(capacity)), + storage: B::Store::with_capacity(blocks_for_bits::(capacity)), nbits: 0, } } @@ -457,26 +644,29 @@ impl BitVec { pub fn from_bytes_general(bytes: &[u8]) -> Self { let len = bytes .len() - .checked_mul(u8::bits()) + .checked_mul(u8::BITS as usize) .expect("capacity overflow"); - let mut bit_vec = BitVec::with_capacity_general(len); - let complete_words = bytes.len() / B::bytes(); - let extra_bytes = bytes.len() % B::bytes(); + let mut bit_vec = BitVec::::with_capacity_general(len); + let complete_words = bytes.len() / B::BYTES; + let extra_bytes = bytes.len() % B::BYTES; bit_vec.nbits = len; for i in 0..complete_words { - let mut accumulator = B::zero(); - for idx in 0..B::bytes() { - accumulator |= B::from_byte(reverse_bits(bytes[i * B::bytes() + idx])) << (idx * 8) + let mut accumulator = B::ZERO; + for idx in 0..B::BYTES { + accumulator |= ::Block::from_byte(reverse_bits( + bytes[i * B::BYTES + idx], + )) << (idx * 8) } bit_vec.storage.push(accumulator); } if extra_bytes > 0 { - let mut last_word = B::zero(); - for (i, &byte) in bytes[complete_words * B::bytes()..].iter().enumerate() { - last_word |= B::from_byte(reverse_bits(byte)) << (i * 8); + let mut last_word = B::ZERO; + for (i, &byte) in bytes[complete_words * B::BYTES..].iter().enumerate() { + last_word |= + ::Block::from_byte(reverse_bits(byte)) << (i * 8); } bit_vec.storage.push(last_word); } @@ -513,24 +703,24 @@ impl BitVec { #[inline] fn process(&mut self, other: &BitVec, mut op: F) -> bool where - F: FnMut(B, B) -> B, + F: FnMut(Block, Block) -> Block, { assert_eq!(self.len(), other.len()); debug_assert_eq!(self.storage.len(), other.storage.len()); - let mut changed_bits = B::zero(); + let mut changed_bits = B::ZERO; for (a, b) in self.blocks_mut().zip(other.blocks()) { let w = op(*a, b); - changed_bits = changed_bits | (*a ^ w); + changed_bits |= *a ^ w; *a = w; } - changed_bits != B::zero() + changed_bits != B::ZERO } /// Iterator over mutable refs to the underlying blocks of data. #[inline] - fn blocks_mut(&mut self) -> MutBlocks<'_, B> { + fn blocks_mut(&mut self) -> BlocksMut<'_, B> { // (2) - self.storage.iter_mut() + self.storage.slice_mut().iter_mut() } /// Iterator over the underlying blocks of data @@ -538,7 +728,7 @@ impl BitVec { pub fn blocks(&self) -> Blocks<'_, B> { // (2) Blocks { - iter: self.storage.iter(), + iter: self.storage.slice().iter(), } } @@ -546,8 +736,8 @@ impl BitVec { /// /// Only really intended for `BitSet`. #[inline] - pub fn storage(&self) -> &[B] { - &self.storage + pub fn storage(&self) -> &[Block] { + self.storage.slice() } /// Exposes the raw block storage of this `BitVec`. @@ -556,18 +746,18 @@ impl BitVec { /// /// Can probably cause unsafety. Only really intended for `BitSet`. #[inline] - pub unsafe fn storage_mut(&mut self) -> &mut Vec { + pub unsafe fn storage_mut(&mut self) -> &mut B::Store { &mut self.storage } /// Helper for procedures involving spare space in the last block. #[inline] - fn last_block_with_mask(&self) -> Option<(B, B)> { - let extra_bits = self.len() % B::bits(); + fn last_block_with_mask(&self) -> Option<(Block, Block)> { + let extra_bits = self.len() % B::BITS; if extra_bits > 0 { - let mask = (B::one() << extra_bits) - B::one(); + let mask = (B::ONE << extra_bits) - B::ONE; let storage_len = self.storage.len(); - Some((self.storage[storage_len - 1], mask)) + Some((self.storage.slice()[storage_len - 1], mask)) } else { None } @@ -575,12 +765,12 @@ impl BitVec { /// Helper for procedures involving spare space in the last block. #[inline] - fn last_block_mut_with_mask(&mut self) -> Option<(&mut B, B)> { - let extra_bits = self.len() % B::bits(); + fn last_block_mut_with_mask(&mut self) -> Option<(&mut Block, Block)> { + let extra_bits = self.len() % B::BITS; if extra_bits > 0 { - let mask = (B::one() << extra_bits) - B::one(); + let mask = (B::ONE << extra_bits) - B::ONE; let storage_len = self.storage.len(); - Some((&mut self.storage[storage_len - 1], mask)) + Some((&mut self.storage.slice_mut()[storage_len - 1], mask)) } else { None } @@ -598,14 +788,14 @@ impl BitVec { /// to implement when unused bits are all set to 1s. fn fix_last_block_with_ones(&mut self) { if let Some((last_block, used_bits)) = self.last_block_mut_with_mask() { - *last_block = *last_block | !used_bits; + *last_block |= !used_bits; } } /// Check whether last block's invariant is fine. fn is_last_block_fixed(&self) -> bool { if let Some((last_block, used_bits)) = self.last_block_with_mask() { - last_block & !used_bits == B::zero() + last_block & !used_bits == B::ZERO } else { true } @@ -646,11 +836,12 @@ impl BitVec { if i >= self.nbits { return None; } - let w = i / B::bits(); - let b = i % B::bits(); + let w = i / B::BITS; + let b = i % B::BITS; self.storage + .slice() .get(w) - .map(|&block| (block & (B::one() << b)) != B::zero()) + .map(|&block| (block & (B::ONE << b)) != B::ZERO) } /// Retrieves the value at index `i`, without doing bounds checking. @@ -676,10 +867,10 @@ impl BitVec { #[inline] pub unsafe fn get_unchecked(&self, i: usize) -> bool { self.ensure_invariant(); - let w = i / B::bits(); - let b = i % B::bits(); - let block = *self.storage.get_unchecked(w); - block & (B::one() << b) != B::zero() + let w = i / B::BITS; + let b = i % B::BITS; + let block = *self.storage.slice().get_unchecked(w); + block & (B::ONE << b) != B::ZERO } /// Retrieves a smart pointer to the value at index `i`, or `None` if the index is out of bounds. @@ -761,15 +952,15 @@ impl BitVec { i, self.nbits ); - let w = i / B::bits(); - let b = i % B::bits(); - let flag = B::one() << b; + let w = i / B::BITS; + let b = i % B::BITS; + let flag = B::ONE << b; let val = if x { - self.storage[w] | flag + self.storage.slice()[w] | flag } else { - self.storage[w] & !flag + self.storage.slice()[w] & !flag }; - self.storage[w] = val; + self.storage.slice_mut()[w] = val; } /// Sets all bits to 1. @@ -790,8 +981,8 @@ impl BitVec { #[deprecated(since = "0.9.0", note = "please use `.fill(true)` instead")] pub fn set_all(&mut self) { self.ensure_invariant(); - for w in &mut self.storage { - *w = !B::zero(); + for w in self.storage.slice_mut() { + *w = !B::ZERO; } self.fix_last_block(); } @@ -813,7 +1004,7 @@ impl BitVec { #[inline] pub fn negate(&mut self) { self.ensure_invariant(); - for w in &mut self.storage { + for w in self.storage.slice_mut() { *w = !*w; } self.fix_last_block(); @@ -1131,14 +1322,14 @@ impl BitVec { #[inline] pub fn all(&self) -> bool { self.ensure_invariant(); - let mut last_word = !B::zero(); + let mut last_word = !B::ZERO; // Check that every block but the last is all-ones... self.blocks().all(|elem| { let tmp = last_word; last_word = elem; - tmp == !B::zero() + tmp == !B::ZERO // and then check the last one has enough ones - }) && (last_word == mask_for_bits(self.nbits)) + }) && (last_word == mask_for_bits::(self.nbits)) } /// Returns the number of ones in the binary representation. @@ -1184,7 +1375,7 @@ impl BitVec { pub fn count_zeros(&self) -> u64 { self.ensure_invariant(); // Add the number of zeros of each block. - let extra_zeros = (B::bits() - (self.len() % B::bits())) % B::bits(); + let extra_zeros = (B::BITS - (self.len() % B::BITS)) % B::BITS; self.blocks() .map(|elem| elem.count_zeros() as u64) .sum::() @@ -1256,9 +1447,9 @@ impl BitVec { self.ensure_invariant(); debug_assert!(other.is_last_block_fixed()); - let b = self.len() % B::bits(); - let o = other.len() % B::bits(); - let will_overflow = (b + o > B::bits()) || (o == 0 && b != 0); + let b = self.len() % B::BITS; + let o = other.len() % B::BITS; + let will_overflow = (b + o > B::BITS) || (o == 0 && b != 0); self.nbits += other.len(); other.nbits = 0; @@ -1270,10 +1461,10 @@ impl BitVec { for block in other.storage.drain(..) { { - let last = self.storage.last_mut().unwrap(); - *last = *last | (block << b); + let last = self.storage.slice_mut().last_mut().unwrap(); + *last |= block << b; } - self.storage.push(block >> (B::bits() - b)); + self.storage.push(block >> (B::BITS - b)); } // Remove additional block if the last shift did not overflow @@ -1320,8 +1511,8 @@ impl BitVec { return other; } - let w = at / B::bits(); - let b = at % B::bits(); + let w = at / B::BITS; + let b = at % B::BITS; other.nbits = self.nbits - at; self.nbits = at; if b == 0 { @@ -1331,10 +1522,10 @@ impl BitVec { other.storage.reserve(self.storage.len() - w); { - let mut iter = self.storage[w..].iter(); + let mut iter = self.storage.slice()[w..].iter(); let mut last = *iter.next().unwrap(); for &cur in iter { - other.storage.push((last >> b) | (cur << (B::bits() - b))); + other.storage.push((last >> b) | (cur << (B::BITS - b))); last = cur; } other.storage.push(last >> b); @@ -1362,7 +1553,7 @@ impl BitVec { /// ``` #[inline] pub fn none(&self) -> bool { - self.blocks().all(|w| w == B::zero()) + self.blocks().all(|w| w == B::ZERO) } /// Returns `true` if any bit is 1. @@ -1562,7 +1753,7 @@ impl BitVec { /// ``` #[inline] pub fn capacity(&self) -> usize { - self.storage.capacity().saturating_mul(B::bits()) + self.storage.capacity().saturating_mul(B::BITS) } /// Grows the `BitVec` in-place, adding `n` copies of `value` to the `BitVec`. @@ -1590,15 +1781,15 @@ impl BitVec { let new_nbits = self.nbits.checked_add(n).expect("capacity overflow"); let new_nblocks = blocks_for_bits::(new_nbits); - let full_value = if value { !B::zero() } else { B::zero() }; + let full_value = if value { !B::ZERO } else { B::ZERO }; // Correct the old tail word, setting or clearing formerly unused bits let num_cur_blocks = blocks_for_bits::(self.nbits); - if self.nbits % B::bits() > 0 { + if self.nbits % B::BITS > 0 { let mask = mask_for_bits::(self.nbits); if value { - let block = &mut self.storage[num_cur_blocks - 1]; - *block = *block | !mask; + let block = &mut self.storage.slice_mut()[num_cur_blocks - 1]; + *block |= !mask; } else { // Extra bits are already zero by invariant. } @@ -1607,13 +1798,13 @@ impl BitVec { // Fill in words after the old tail word let stop_idx = cmp::min(self.storage.len(), new_nblocks); for idx in num_cur_blocks..stop_idx { - self.storage[idx] = full_value; + self.storage.slice_mut()[idx] = full_value; } // Allocate new words, if needed if new_nblocks > self.storage.len() { let to_add = new_nblocks - self.storage.len(); - self.storage.extend(repeat(full_value).take(to_add)); + self.storage.extend(iter::repeat_n(full_value, to_add)); } // Adjust internal bit count @@ -1646,7 +1837,7 @@ impl BitVec { // (3) self.set(i, false); self.nbits = i; - if self.nbits % B::bits() == 0 { + if self.nbits % B::BITS == 0 { // (2) self.storage.pop(); } @@ -1668,8 +1859,8 @@ impl BitVec { /// ``` #[inline] pub fn push(&mut self, elem: bool) { - if self.nbits % B::bits() == 0 { - self.storage.push(B::zero()); + if self.nbits % B::BITS == 0 { + self.storage.push(B::ZERO); } let insert_pos = self.nbits; self.nbits = self.nbits.checked_add(1).expect("Capacity overflow"); @@ -1703,8 +1894,8 @@ impl BitVec { #[deprecated(since = "0.9.0", note = "please use `.fill(false)` instead")] pub fn clear(&mut self) { self.ensure_invariant(); - for w in &mut self.storage { - *w = B::zero(); + for w in self.storage.slice_mut() { + *w = B::ZERO; } } @@ -1720,8 +1911,8 @@ impl BitVec { #[inline] pub fn fill(&mut self, bit: bool) { self.ensure_invariant(); - let block = if bit { !B::zero() } else { B::zero() }; - for w in &mut self.storage { + let block = if bit { !B::ZERO } else { B::ZERO }; + for w in self.storage.slice_mut() { *w = block; } if bit { @@ -1771,25 +1962,25 @@ impl BitVec { ); self.ensure_invariant(); - let last_block_bits = self.nbits % B::bits(); - let block_at = at / B::bits(); // needed block - let bit_at = at % B::bits(); // index within the block + let last_block_bits = self.nbits % B::BITS; + let block_at = at / B::BITS; // needed block + let bit_at = at % B::BITS; // index within the block if last_block_bits == 0 { - self.storage.push(B::zero()); + self.storage.push(B::ZERO); } self.nbits += 1; - let mut carry = self.storage[block_at] >> (B::bits() - 1); - let lsbits_mask = (B::one() << bit_at) - B::one(); - let set_bit = if bit { B::one() } else { B::zero() } << bit_at; - self.storage[block_at] = (self.storage[block_at] & lsbits_mask) - | ((self.storage[block_at] & !lsbits_mask) << 1) + let mut carry = self.storage.slice()[block_at] >> (B::BITS - 1); + let lsbits_mask = (B::ONE << bit_at) - B::ONE; + let set_bit = if bit { B::ONE } else { B::ZERO } << bit_at; + self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) + | ((self.storage.slice()[block_at] & !lsbits_mask) << 1) | set_bit; - for block_ref in &mut self.storage[block_at + 1..] { - let curr_carry = *block_ref >> (B::bits() - 1); + for block_ref in &mut self.storage.slice_mut()[block_at + 1..] { + let curr_carry = *block_ref >> (B::BITS - 1); *block_ref = *block_ref << 1 | carry; carry = curr_carry; } @@ -1831,25 +2022,27 @@ impl BitVec { self.nbits -= 1; - let last_block_bits = self.nbits % B::bits(); - let block_at = at / B::bits(); // needed block - let bit_at = at % B::bits(); // index within the block + let last_block_bits = self.nbits % B::BITS; + let block_at = at / B::BITS; // needed block + let bit_at = at % B::BITS; // index within the block - let lsbits_mask = (B::one() << bit_at) - B::one(); + let lsbits_mask = (B::ONE << bit_at) - B::ONE; - let mut carry = B::zero(); + let mut carry = B::ZERO; - for block_ref in self.storage[block_at + 1..].iter_mut().rev() { - let curr_carry = *block_ref & B::one(); - *block_ref = *block_ref >> 1 | (carry << (B::bits() - 1)); + for block_ref in self.storage.slice_mut()[block_at + 1..].iter_mut().rev() { + let curr_carry = *block_ref & B::ONE; + *block_ref = *block_ref >> 1 | (carry << (B::BITS - 1)); carry = curr_carry; } - let result = (self.storage[block_at] >> bit_at) & B::one() == B::one(); + // Note: this is equivalent to `.get_unchecked(at)`, but we do + // not want to introduce unsafe code here. + let result = (self.storage.slice()[block_at] >> bit_at) & B::ONE == B::ONE; - self.storage[block_at] = (self.storage[block_at] & lsbits_mask) - | ((self.storage[block_at] & (!lsbits_mask << 1)) >> 1) - | carry << (B::bits() - 1); + self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) + | ((self.storage.slice()[block_at] & (!lsbits_mask << 1)) >> 1) + | carry << (B::BITS - 1); if last_block_bits == 0 { self.storage.pop(); @@ -1909,37 +2102,37 @@ impl BitVec { return Err(bit); } - let bits = B::bits(); + let bits = B::BITS; if len % bits == 0 { - self.storage.push(B::zero()); + self.storage.push(B::ZERO); } let block_at = len / bits; let bit_at = len % bits; - let flag = if bit { B::one() << bit_at } else { B::zero() }; + let flag = if bit { B::ONE << bit_at } else { B::ZERO }; self.ensure_invariant(); self.nbits += 1; - self.storage[block_at] = self.storage[block_at] | flag; // set the bit + self.storage.slice_mut()[block_at] = self.storage.slice()[block_at] | flag; // set the bit Ok(()) } } -impl Default for BitVec { +impl Default for BitVec { #[inline] fn default() -> Self { BitVec { - storage: Vec::new(), + storage: B::Store::default(), nbits: 0, } } } -impl FromIterator for BitVec { +impl FromIterator for BitVec { #[inline] fn from_iter>(iter: I) -> Self { let mut ret: Self = Default::default(); @@ -1948,7 +2141,7 @@ impl FromIterator for BitVec { } } -impl Extend for BitVec { +impl Extend for BitVec { #[inline] fn extend>(&mut self, iterable: I) { self.ensure_invariant(); @@ -1961,7 +2154,7 @@ impl Extend for BitVec { } } -impl Clone for BitVec { +impl Clone for BitVec { #[inline] fn clone(&self) -> Self { self.ensure_invariant(); @@ -1979,14 +2172,14 @@ impl Clone for BitVec { } } -impl PartialOrd for BitVec { +impl PartialOrd for BitVec { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for BitVec { +impl Ord for BitVec { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.ensure_invariant(); @@ -2007,7 +2200,7 @@ impl Ord for BitVec { } } -impl fmt::Display for BitVec { +impl fmt::Display for BitVec { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.ensure_invariant(); for bit in self { @@ -2017,12 +2210,12 @@ impl fmt::Display for BitVec { } } -impl fmt::Debug for BitVec { +impl fmt::Debug for BitVec { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.ensure_invariant(); - let mut storage = String::with_capacity(self.len() + self.len() / B::bits()); + let mut storage = String::with_capacity(self.len() + self.len() / B::BITS); for (i, bit) in self.iter().enumerate() { - if i != 0 && i % B::bits() == 0 { + if i != 0 && i % B::BITS == 0 { storage.push(' '); } storage.push(if bit { '1' } else { '0' }); @@ -2034,7 +2227,7 @@ impl fmt::Debug for BitVec { } } -impl hash::Hash for BitVec { +impl hash::Hash for BitVec { #[inline] fn hash(&self, state: &mut H) { self.ensure_invariant(); @@ -2045,7 +2238,7 @@ impl hash::Hash for BitVec { } } -impl cmp::PartialEq for BitVec { +impl cmp::PartialEq for BitVec { #[inline] fn eq(&self, other: &Self) -> bool { if self.nbits != other.nbits { @@ -2057,17 +2250,17 @@ impl cmp::PartialEq for BitVec { } } -impl cmp::Eq for BitVec {} +impl cmp::Eq for BitVec {} /// An iterator for `BitVec`. #[derive(Clone)] -pub struct Iter<'a, B: 'a = u32> { +pub struct Iter<'a, B: 'a + BitBlockOrStore = u32> { bit_vec: &'a BitVec, range: Range, } #[derive(Debug)] -pub struct MutBorrowedBit<'a, B: 'a + BitBlock> { +pub struct MutBorrowedBit<'a, B: 'a + BitBlockOrStore> { vec: Rc>>, index: usize, #[cfg(debug_assertions)] @@ -2076,12 +2269,12 @@ pub struct MutBorrowedBit<'a, B: 'a + BitBlock> { } /// An iterator for mutable references to the bits in a `BitVec`. -pub struct IterMut<'a, B: 'a + BitBlock = u32> { +pub struct IterMut<'a, B: 'a + BitBlockOrStore = u32> { vec: Rc>>, range: Range, } -impl<'a, B: 'a + BitBlock> IterMut<'a, B> { +impl<'a, B: 'a + BitBlockOrStore> IterMut<'a, B> { fn get(&mut self, index: Option) -> Option> { let value = (*self.vec).borrow().get(index?)?; Some(MutBorrowedBit { @@ -2094,7 +2287,7 @@ impl<'a, B: 'a + BitBlock> IterMut<'a, B> { } } -impl Deref for MutBorrowedBit<'_, B> { +impl Deref for MutBorrowedBit<'_, B> { type Target = bool; fn deref(&self) -> &Self::Target { @@ -2102,13 +2295,13 @@ impl Deref for MutBorrowedBit<'_, B> { } } -impl DerefMut for MutBorrowedBit<'_, B> { +impl DerefMut for MutBorrowedBit<'_, B> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.new_value } } -impl Drop for MutBorrowedBit<'_, B> { +impl Drop for MutBorrowedBit<'_, B> { fn drop(&mut self) { let mut vec = (*self.vec).borrow_mut(); #[cfg(debug_assertions)] @@ -2121,7 +2314,7 @@ impl Drop for MutBorrowedBit<'_, B> { } } -impl Iterator for Iter<'_, B> { +impl Iterator for Iter<'_, B> { type Item = bool; #[inline] @@ -2143,7 +2336,7 @@ impl Iterator for Iter<'_, B> { } } -impl<'a, B: BitBlock> Iterator for IterMut<'a, B> { +impl<'a, B: BitBlockOrStore> Iterator for IterMut<'a, B> { type Item = MutBorrowedBit<'a, B>; #[inline] @@ -2157,14 +2350,14 @@ impl<'a, B: BitBlock> Iterator for IterMut<'a, B> { } } -impl DoubleEndedIterator for Iter<'_, B> { +impl DoubleEndedIterator for Iter<'_, B> { #[inline] fn next_back(&mut self) -> Option { self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) } } -impl DoubleEndedIterator for IterMut<'_, B> { +impl DoubleEndedIterator for IterMut<'_, B> { #[inline] fn next_back(&mut self) -> Option { let index = self.range.next_back(); @@ -2172,11 +2365,11 @@ impl DoubleEndedIterator for IterMut<'_, B> { } } -impl ExactSizeIterator for Iter<'_, B> {} +impl ExactSizeIterator for Iter<'_, B> {} -impl ExactSizeIterator for IterMut<'_, B> {} +impl ExactSizeIterator for IterMut<'_, B> {} -impl<'a, B: BitBlock> IntoIterator for &'a BitVec { +impl<'a, B: BitBlockOrStore> IntoIterator for &'a BitVec { type Item = bool; type IntoIter = Iter<'a, B>; @@ -2186,12 +2379,12 @@ impl<'a, B: BitBlock> IntoIterator for &'a BitVec { } } -pub struct IntoIter { +pub struct IntoIter { bit_vec: BitVec, range: Range, } -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = bool; #[inline] @@ -2200,16 +2393,16 @@ impl Iterator for IntoIter { } } -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) } } -impl ExactSizeIterator for IntoIter {} +impl ExactSizeIterator for IntoIter {} -impl IntoIterator for BitVec { +impl IntoIterator for BitVec { type Item = bool; type IntoIter = IntoIter; @@ -2225,15 +2418,15 @@ impl IntoIterator for BitVec { /// An iterator over the blocks of a `BitVec`. #[derive(Clone)] -pub struct Blocks<'a, B: 'a> { - iter: slice::Iter<'a, B>, +pub struct Blocks<'a, B: 'a + BitBlockOrStore> { + iter: slice::Iter<'a, Block>, } -impl Iterator for Blocks<'_, B> { - type Item = B; +impl Iterator for Blocks<'_, B> { + type Item = Block; #[inline] - fn next(&mut self) -> Option { + fn next(&mut self) -> Option> { self.iter.next().cloned() } @@ -2243,20 +2436,24 @@ impl Iterator for Blocks<'_, B> { } } -impl DoubleEndedIterator for Blocks<'_, B> { +impl DoubleEndedIterator for Blocks<'_, B> { #[inline] - fn next_back(&mut self) -> Option { + fn next_back(&mut self) -> Option> { self.iter.next_back().cloned() } } -impl ExactSizeIterator for Blocks<'_, B> {} +impl ExactSizeIterator for Blocks<'_, B> {} #[cfg(test)] +#[generic_tests::define] mod tests { #![allow(clippy::shadow_reuse)] #![allow(clippy::shadow_same)] #![allow(clippy::shadow_unrelated)] + #![allow(clippy::extra_unused_type_parameters)] + + use crate::BitBlockOrStore; use super::{BitVec, Iter, Vec}; @@ -2264,60 +2461,66 @@ mod tests { const U32_BITS: usize = 32; #[test] - fn test_display_output() { - assert_eq!(format!("{}", BitVec::new()), ""); - assert_eq!(format!("{}", BitVec::from_elem(1, true)), "1"); - assert_eq!(format!("{}", BitVec::from_elem(8, false)), "00000000") + fn test_display_output() { + assert_eq!(format!("{}", BitVec::::new_general()), ""); + assert_eq!(format!("{}", BitVec::::from_elem_general(1, true)), "1"); + assert_eq!( + format!("{}", BitVec::::from_elem_general(8, false)), + "00000000" + ) } #[test] - fn test_debug_output() { + fn test_debug_output() { assert_eq!( - format!("{:?}", BitVec::new()), + format!("{:?}", BitVec::::new_general()), "BitVec { storage: \"\", nbits: 0 }" ); assert_eq!( - format!("{:?}", BitVec::from_elem(1, true)), + format!("{:?}", BitVec::::from_elem_general(1, true)), "BitVec { storage: \"1\", nbits: 1 }" ); assert_eq!( - format!("{:?}", BitVec::from_elem(8, false)), + format!("{:?}", BitVec::::from_elem_general(8, false)), "BitVec { storage: \"00000000\", nbits: 8 }" ); assert_eq!( - format!("{:?}", BitVec::from_elem(33, true)), - "BitVec { storage: \"11111111111111111111111111111111 1\", nbits: 33 }" + format!("{:?}", BitVec::::from_elem_general(33, true)).replace(" ", ""), + "BitVec{storage:\"111111111111111111111111111111111\",nbits:33}" ); assert_eq!( format!( "{:?}", - BitVec::from_bytes(&[0b111, 0b000, 0b1110, 0b0001, 0b11111111, 0b00000000]) - ), - "BitVec { storage: \"00000111000000000000111000000001 1111111100000000\", nbits: 48 }" + BitVec::::from_bytes_general(&[ + 0b111, 0b000, 0b1110, 0b0001, 0b11111111, 0b00000000 + ]) + ) + .replace(" ", ""), + "BitVec{storage:\"000001110000000000001110000000011111111100000000\",nbits:48}" ) } #[test] - fn test_0_elements() { - let act = BitVec::new(); + fn test_0_elements() { + let act = BitVec::::new_general(); let exp = Vec::new(); assert!(act.eq_vec(&exp)); assert!(act.none() && act.all()); } #[test] - fn test_1_element() { - let mut act = BitVec::from_elem(1, false); + fn test_1_element() { + let mut act = BitVec::::from_elem_general(1, false); assert!(act.eq_vec(&[false])); assert!(act.none() && !act.all()); - act = BitVec::from_elem(1, true); + act = BitVec::::from_elem_general(1, true); assert!(act.eq_vec(&[true])); assert!(!act.none() && act.all()); } #[test] - fn test_2_elements() { - let mut b = BitVec::from_elem(2, false); + fn test_2_elements() { + let mut b = BitVec::::from_elem_general(2, false); b.set(0, true); b.set(1, false); assert_eq!(format!("{}", b), "10"); @@ -2325,22 +2528,22 @@ mod tests { } #[test] - fn test_10_elements() { + fn test_10_elements() { // all 0 - let mut act = BitVec::from_elem(10, false); + let mut act = BitVec::::from_elem_general(10, false); assert!( (act.eq_vec(&[false, false, false, false, false, false, false, false, false, false])) ); assert!(act.none() && !act.all()); // all 1 - act = BitVec::from_elem(10, true); + act = BitVec::::from_elem_general(10, true); assert!((act.eq_vec(&[true, true, true, true, true, true, true, true, true, true]))); assert!(!act.none() && act.all()); // mixed - act = BitVec::from_elem(10, false); + act = BitVec::::from_elem_general(10, false); act.set(0, true); act.set(1, true); act.set(2, true); @@ -2350,7 +2553,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(10, false); + act = BitVec::::from_elem_general(10, false); act.set(5, true); act.set(6, true); act.set(7, true); @@ -2360,7 +2563,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(10, false); + act = BitVec::::from_elem_general(10, false); act.set(0, true); act.set(3, true); act.set(6, true); @@ -2370,10 +2573,10 @@ mod tests { } #[test] - fn test_31_elements() { + fn test_31_elements() { // all 0 - let mut act = BitVec::from_elem(31, false); + let mut act = BitVec::::from_elem_general(31, false); assert!(act.eq_vec(&[ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, @@ -2382,7 +2585,7 @@ mod tests { assert!(act.none() && !act.all()); // all 1 - act = BitVec::from_elem(31, true); + act = BitVec::::from_elem_general(31, true); assert!(act.eq_vec(&[ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, @@ -2391,7 +2594,7 @@ mod tests { assert!(!act.none() && act.all()); // mixed - act = BitVec::from_elem(31, false); + act = BitVec::::from_elem_general(31, false); act.set(0, true); act.set(1, true); act.set(2, true); @@ -2408,7 +2611,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(31, false); + act = BitVec::::from_elem_general(31, false); act.set(16, true); act.set(17, true); act.set(18, true); @@ -2425,7 +2628,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(31, false); + act = BitVec::::from_elem_general(31, false); act.set(24, true); act.set(25, true); act.set(26, true); @@ -2441,7 +2644,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(31, false); + act = BitVec::::from_elem_general(31, false); act.set(3, true); act.set(17, true); act.set(30, true); @@ -2454,10 +2657,10 @@ mod tests { } #[test] - fn test_32_elements() { + fn test_32_elements() { // all 0 - let mut act = BitVec::from_elem(32, false); + let mut act = BitVec::::from_elem_general(32, false); assert!(act.eq_vec(&[ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, @@ -2466,7 +2669,7 @@ mod tests { assert!(act.none() && !act.all()); // all 1 - act = BitVec::from_elem(32, true); + act = BitVec::::from_elem_general(32, true); assert!(act.eq_vec(&[ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, @@ -2475,7 +2678,7 @@ mod tests { assert!(!act.none() && act.all()); // mixed - act = BitVec::from_elem(32, false); + act = BitVec::::from_elem_general(32, false); act.set(0, true); act.set(1, true); act.set(2, true); @@ -2492,7 +2695,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(32, false); + act = BitVec::::from_elem_general(32, false); act.set(16, true); act.set(17, true); act.set(18, true); @@ -2509,7 +2712,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(32, false); + act = BitVec::::from_elem_general(32, false); act.set(24, true); act.set(25, true); act.set(26, true); @@ -2526,7 +2729,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(32, false); + act = BitVec::::from_elem_general(32, false); act.set(3, true); act.set(17, true); act.set(30, true); @@ -2540,10 +2743,10 @@ mod tests { } #[test] - fn test_33_elements() { + fn test_33_elements() { // all 0 - let mut act = BitVec::from_elem(33, false); + let mut act = BitVec::::from_elem_general(33, false); assert!(act.eq_vec(&[ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, @@ -2552,7 +2755,7 @@ mod tests { assert!(act.none() && !act.all()); // all 1 - act = BitVec::from_elem(33, true); + act = BitVec::::from_elem_general(33, true); assert!(act.eq_vec(&[ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, @@ -2561,7 +2764,7 @@ mod tests { assert!(!act.none() && act.all()); // mixed - act = BitVec::from_elem(33, false); + act = BitVec::::from_elem_general(33, false); act.set(0, true); act.set(1, true); act.set(2, true); @@ -2578,7 +2781,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(33, false); + act = BitVec::::from_elem_general(33, false); act.set(16, true); act.set(17, true); act.set(18, true); @@ -2595,7 +2798,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(33, false); + act = BitVec::::from_elem_general(33, false); act.set(24, true); act.set(25, true); act.set(26, true); @@ -2612,7 +2815,7 @@ mod tests { assert!(!act.none() && !act.all()); // mixed - act = BitVec::from_elem(33, false); + act = BitVec::::from_elem_general(33, false); act.set(3, true); act.set(17, true); act.set(30, true); @@ -2627,38 +2830,38 @@ mod tests { } #[test] - fn test_equal_differing_sizes() { - let v0 = BitVec::from_elem(10, false); - let v1 = BitVec::from_elem(11, false); + fn test_equal_differing_sizes() { + let v0 = BitVec::::from_elem_general(10, false); + let v1 = BitVec::::from_elem_general(11, false); assert_ne!(v0, v1); } #[test] - fn test_equal_greatly_differing_sizes() { - let v0 = BitVec::from_elem(10, false); - let v1 = BitVec::from_elem(110, false); + fn test_equal_greatly_differing_sizes() { + let v0 = BitVec::::from_elem_general(10, false); + let v1 = BitVec::::from_elem_general(110, false); assert_ne!(v0, v1); } #[test] - fn test_equal_sneaky_small() { - let mut a = BitVec::from_elem(1, false); + fn test_equal_sneaky_small() { + let mut a = BitVec::::from_elem_general(1, false); a.set(0, true); - let mut b = BitVec::from_elem(1, true); + let mut b = BitVec::::from_elem_general(1, true); b.set(0, true); assert_eq!(a, b); } #[test] - fn test_equal_sneaky_big() { - let mut a = BitVec::from_elem(100, false); + fn test_equal_sneaky_big() { + let mut a = BitVec::::from_elem_general(100, false); for i in 0..100 { a.set(i, true); } - let mut b = BitVec::from_elem(100, true); + let mut b = BitVec::::from_elem_general(100, true); for i in 0..100 { b.set(i, true); } @@ -2667,36 +2870,36 @@ mod tests { } #[test] - fn test_from_bytes() { - let bit_vec = BitVec::from_bytes(&[0b10110110, 0b00000000, 0b11111111]); + fn test_from_bytes() { + let bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b11111111]); let str = concat!("10110110", "00000000", "11111111"); assert_eq!(format!("{}", bit_vec), str); } #[test] - fn test_to_bytes() { - let mut bv = BitVec::from_elem(3, true); + fn test_to_bytes() { + let mut bv = BitVec::::from_elem_general(3, true); bv.set(1, false); assert_eq!(bv.to_bytes(), [0b10100000]); - let mut bv = BitVec::from_elem(9, false); + let mut bv = BitVec::::from_elem_general(9, false); bv.set(2, true); bv.set(8, true); assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); } #[test] - fn test_from_bools() { + fn test_from_bools() { let bools = [true, false, true, true]; let bit_vec: BitVec = bools.iter().copied().collect(); assert_eq!(format!("{}", bit_vec), "1011"); } #[test] - fn test_to_bools() { + fn test_to_bools() { let bools = vec![false, false, true, false, false, true, true, false]; assert_eq!( - BitVec::from_bytes(&[0b00100110]) + BitVec::::from_bytes_general(&[0b00100110]) .iter() .collect::>(), bools @@ -2704,7 +2907,7 @@ mod tests { } #[test] - fn test_bit_vec_iterator() { + fn test_bit_vec_iterator() { let bools = vec![true, false, true, true]; let bit_vec: BitVec = bools.iter().copied().collect(); @@ -2716,9 +2919,9 @@ mod tests { } #[test] - fn test_small_difference() { - let mut b1 = BitVec::from_elem(3, false); - let mut b2 = BitVec::from_elem(3, false); + fn test_small_difference() { + let mut b1 = BitVec::::from_elem_general(3, false); + let mut b2 = BitVec::::from_elem_general(3, false); b1.set(0, true); b1.set(1, true); b2.set(1, true); @@ -2730,9 +2933,9 @@ mod tests { } #[test] - fn test_big_difference() { - let mut b1 = BitVec::from_elem(100, false); - let mut b2 = BitVec::from_elem(100, false); + fn test_big_difference() { + let mut b1 = BitVec::::from_elem_general(100, false); + let mut b2 = BitVec::::from_elem_general(100, false); b1.set(0, true); b1.set(40, true); b2.set(40, true); @@ -2744,52 +2947,52 @@ mod tests { } #[test] - fn test_small_xor() { - let mut a = BitVec::from_bytes(&[0b0011]); - let b = BitVec::from_bytes(&[0b0101]); - let c = BitVec::from_bytes(&[0b0110]); + fn test_small_xor() { + let mut a = BitVec::::from_bytes_general(&[0b0011]); + let b = BitVec::::from_bytes_general(&[0b0101]); + let c = BitVec::::from_bytes_general(&[0b0110]); assert!(a.xor(&b)); assert_eq!(a, c); } #[test] - fn test_small_xnor() { - let mut a = BitVec::from_bytes(&[0b0011]); - let b = BitVec::from_bytes(&[0b1111_0101]); - let c = BitVec::from_bytes(&[0b1001]); + fn test_small_xnor() { + let mut a = BitVec::::from_bytes_general(&[0b0011]); + let b = BitVec::::from_bytes_general(&[0b1111_0101]); + let c = BitVec::::from_bytes_general(&[0b1001]); assert!(a.xnor(&b)); assert_eq!(a, c); } #[test] - fn test_small_nand() { - let mut a = BitVec::from_bytes(&[0b1111_0011]); - let b = BitVec::from_bytes(&[0b1111_0101]); - let c = BitVec::from_bytes(&[0b1110]); + fn test_small_nand() { + let mut a = BitVec::::from_bytes_general(&[0b1111_0011]); + let b = BitVec::::from_bytes_general(&[0b1111_0101]); + let c = BitVec::::from_bytes_general(&[0b1110]); assert!(a.nand(&b)); assert_eq!(a, c); } #[test] - fn test_small_nor() { - let mut a = BitVec::from_bytes(&[0b0011]); - let b = BitVec::from_bytes(&[0b1111_0101]); - let c = BitVec::from_bytes(&[0b1000]); + fn test_small_nor() { + let mut a = BitVec::::from_bytes_general(&[0b0011]); + let b = BitVec::::from_bytes_general(&[0b1111_0101]); + let c = BitVec::::from_bytes_general(&[0b1000]); assert!(a.nor(&b)); assert_eq!(a, c); } #[test] - fn test_big_xor() { - let mut a = BitVec::from_bytes(&[ + fn test_big_xor() { + let mut a = BitVec::::from_bytes_general(&[ // 88 bits 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, ]); - let b = BitVec::from_bytes(&[ + let b = BitVec::::from_bytes_general(&[ // 88 bits 0, 0, 0b00010100, 0, 0, 0, 0, 0, 0, 0, 0b00110100, ]); - let c = BitVec::from_bytes(&[ + let c = BitVec::::from_bytes_general(&[ // 88 bits 0, 0, 0, 0, 0, 0, 0, 0b00110100, 0, 0, 0b00110100, ]); @@ -2798,16 +3001,16 @@ mod tests { } #[test] - fn test_big_xnor() { - let mut a = BitVec::from_bytes(&[ + fn test_big_xnor() { + let mut a = BitVec::::from_bytes_general(&[ // 88 bits 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, ]); - let b = BitVec::from_bytes(&[ + let b = BitVec::::from_bytes_general(&[ // 88 bits 0, 0, 0b00010100, 0, 0, 0, 0, 0, 0, 0, 0b00110100, ]); - let c = BitVec::from_bytes(&[ + let c = BitVec::::from_bytes_general(&[ // 88 bits !0, !0, @@ -2826,8 +3029,8 @@ mod tests { } #[test] - fn test_small_fill() { - let mut b = BitVec::from_elem(14, true); + fn test_small_fill() { + let mut b = BitVec::::from_elem_general(14, true); assert!(!b.none() && b.all()); b.fill(false); assert!(b.none() && !b.all()); @@ -2836,8 +3039,8 @@ mod tests { } #[test] - fn test_big_fill() { - let mut b = BitVec::from_elem(140, true); + fn test_big_fill() { + let mut b = BitVec::::from_elem_general(140, true); assert!(!b.none() && b.all()); b.fill(false); assert!(b.none() && !b.all()); @@ -2846,9 +3049,9 @@ mod tests { } #[test] - fn test_bit_vec_lt() { - let mut a = BitVec::from_elem(5, false); - let mut b = BitVec::from_elem(5, false); + fn test_bit_vec_lt() { + let mut a = BitVec::::from_elem_general(5, false); + let mut b = BitVec::::from_elem_general(5, false); assert!(a >= b && b >= a); b.set(2, true); @@ -2862,9 +3065,9 @@ mod tests { } #[test] - fn test_ord() { - let mut a = BitVec::from_elem(5, false); - let mut b = BitVec::from_elem(5, false); + fn test_ord() { + let mut a = BitVec::::from_elem_general(5, false); + let mut b = BitVec::::from_elem_general(5, false); assert!(a == b); a.set(1, true); @@ -2877,26 +3080,26 @@ mod tests { } #[test] - fn test_small_bit_vec_tests() { - let v = BitVec::from_bytes(&[0]); + fn test_small_bit_vec_tests() { + let v = BitVec::::from_bytes_general(&[0]); assert!(!v.all()); assert!(!v.any()); assert!(v.none()); - let v = BitVec::from_bytes(&[0b00010100]); + let v = BitVec::::from_bytes_general(&[0b00010100]); assert!(!v.all()); assert!(v.any()); assert!(!v.none()); - let v = BitVec::from_bytes(&[0xFF]); + let v = BitVec::::from_bytes_general(&[0xFF]); assert!(v.all()); assert!(v.any()); assert!(!v.none()); } #[test] - fn test_big_bit_vec_tests() { - let v = BitVec::from_bytes(&[ + fn test_big_bit_vec_tests() { + let v = BitVec::::from_bytes_general(&[ // 88 bits 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]); @@ -2904,7 +3107,7 @@ mod tests { assert!(!v.any()); assert!(v.none()); - let v = BitVec::from_bytes(&[ + let v = BitVec::::from_bytes_general(&[ // 88 bits 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, ]); @@ -2912,7 +3115,7 @@ mod tests { assert!(v.any()); assert!(!v.none()); - let v = BitVec::from_bytes(&[ + let v = BitVec::::from_bytes_general(&[ // 88 bits 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ]); @@ -2922,8 +3125,8 @@ mod tests { } #[test] - fn test_bit_vec_push_pop() { - let mut s = BitVec::from_elem(5 * U32_BITS - 2, false); + fn test_bit_vec_push_pop() { + let mut s = BitVec::::from_elem_general(5 * U32_BITS - 2, false); assert_eq!(s.len(), 5 * U32_BITS - 2); assert!(!s[5 * U32_BITS - 3]); s.push(true); @@ -2945,29 +3148,29 @@ mod tests { } #[test] - fn test_bit_vec_truncate() { - let mut s = BitVec::from_elem(5 * U32_BITS, true); + fn test_bit_vec_truncate() { + let mut s = BitVec::::from_elem_general(5 * U32_BITS, true); - assert_eq!(s, BitVec::from_elem(5 * U32_BITS, true)); + assert_eq!(s, BitVec::::from_elem_general(5 * U32_BITS, true)); assert_eq!(s.len(), 5 * U32_BITS); s.truncate(4 * U32_BITS); - assert_eq!(s, BitVec::from_elem(4 * U32_BITS, true)); + assert_eq!(s, BitVec::::from_elem_general(4 * U32_BITS, true)); assert_eq!(s.len(), 4 * U32_BITS); // Truncating to a size > s.len() should be a noop s.truncate(5 * U32_BITS); - assert_eq!(s, BitVec::from_elem(4 * U32_BITS, true)); + assert_eq!(s, BitVec::::from_elem_general(4 * U32_BITS, true)); assert_eq!(s.len(), 4 * U32_BITS); s.truncate(3 * U32_BITS - 10); - assert_eq!(s, BitVec::from_elem(3 * U32_BITS - 10, true)); + assert_eq!(s, BitVec::::from_elem_general(3 * U32_BITS - 10, true)); assert_eq!(s.len(), 3 * U32_BITS - 10); s.truncate(0); - assert_eq!(s, BitVec::from_elem(0, true)); + assert_eq!(s, BitVec::::from_elem_general(0, true)); assert_eq!(s.len(), 0); } #[test] - fn test_bit_vec_reserve() { - let mut s = BitVec::from_elem(5 * U32_BITS, true); + fn test_bit_vec_reserve() { + let mut s = BitVec::::from_elem_general(5 * U32_BITS, true); // Check capacity assert!(s.capacity() >= 5 * U32_BITS); s.reserve(2 * U32_BITS); @@ -2990,24 +3193,26 @@ mod tests { } #[test] - fn test_bit_vec_grow() { - let mut bit_vec = BitVec::from_bytes(&[0b10110110, 0b00000000, 0b10101010]); + fn test_bit_vec_grow() { + let mut bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b10101010]); bit_vec.grow(32, true); assert_eq!( bit_vec, - BitVec::from_bytes(&[0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF]) + BitVec::::from_bytes_general(&[ + 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF + ]) ); bit_vec.grow(64, false); assert_eq!( bit_vec, - BitVec::from_bytes(&[ + BitVec::::from_bytes_general(&[ 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0 ]) ); bit_vec.grow(16, true); assert_eq!( bit_vec, - BitVec::from_bytes(&[ + BitVec::::from_bytes_general(&[ 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF ]) @@ -3015,23 +3220,24 @@ mod tests { } #[test] - fn test_bit_vec_extend() { - let mut bit_vec = BitVec::from_bytes(&[0b10110110, 0b00000000, 0b11111111]); - let ext = BitVec::from_bytes(&[0b01001001, 0b10010010, 0b10111101]); + fn test_bit_vec_extend() { + let mut bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b11111111]); + let ext = BitVec::::from_bytes_general(&[0b01001001, 0b10010010, 0b10111101]); bit_vec.extend(ext.iter()); assert_eq!( bit_vec, - BitVec::from_bytes(&[ + BitVec::::from_bytes_general(&[ 0b10110110, 0b00000000, 0b11111111, 0b01001001, 0b10010010, 0b10111101 ]) ); } #[test] - fn test_bit_vec_append() { + fn test_bit_vec_append() { // Append to BitVec that holds a multiple of U32_BITS bits - let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011]); - let mut b = BitVec::new(); + let mut a = + BitVec::::from_bytes_general(&[0b10100000, 0b00010010, 0b10010010, 0b00110011]); + let mut b = BitVec::::new_general(); b.push(false); b.push(true); b.push(true); @@ -3049,12 +3255,13 @@ mod tests { ])); // Append to arbitrary BitVec - let mut a = BitVec::new(); + let mut a = BitVec::::new_general(); a.push(true); a.push(false); - let mut b = - BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]); + let mut b = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, + ]); a.append(&mut b); @@ -3070,9 +3277,10 @@ mod tests { ])); // Append to empty BitVec - let mut a = BitVec::new(); - let mut b = - BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]); + let mut a = BitVec::::new_general(); + let mut b = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, + ]); a.append(&mut b); @@ -3088,9 +3296,10 @@ mod tests { ])); // Append empty BitVec - let mut a = - BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]); - let mut b = BitVec::new(); + let mut a = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, + ]); + let mut b = BitVec::::new_general(); a.append(&mut b); @@ -3106,9 +3315,9 @@ mod tests { } #[test] - fn test_bit_vec_split_off() { + fn test_bit_vec_split_off() { // Split at 0 - let mut a = BitVec::new(); + let mut a = BitVec::::new_general(); a.push(true); a.push(false); a.push(false); @@ -3136,8 +3345,9 @@ mod tests { assert!(a.eq_vec(&[true, false, false, true])); // Split at block boundary - let mut a = - BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b11110011]); + let mut a = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b11110011, + ]); let b = a.split_off(32); @@ -3152,7 +3362,7 @@ mod tests { assert!(b.eq_vec(&[true, true, true, true, false, false, true, true])); // Don't split at block boundary - let mut a = BitVec::from_bytes(&[ + let mut a = BitVec::::from_bytes_general(&[ 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b01101011, 0b10101101, ]); @@ -3172,7 +3382,7 @@ mod tests { } #[test] - fn test_into_iter() { + fn test_into_iter() { let bools = [true, false, true, true]; let bit_vec: BitVec = bools.iter().copied().collect(); let mut iter = bit_vec.into_iter(); @@ -3203,15 +3413,15 @@ mod tests { } #[test] - fn iter() { - let b = BitVec::with_capacity(10); - let _a: Iter = b.iter(); + fn test_iter() { + let b = BitVec::::with_capacity_general(10); + let _a: Iter = b.iter(); } #[cfg(feature = "serde")] #[test] - fn test_serialization() { - let bit_vec: BitVec = BitVec::new(); + fn test_serialization() { + let bit_vec: BitVec = BitVec::::new_general(); let serialized = serde_json::to_string(&bit_vec).unwrap(); let unserialized: BitVec = serde_json::from_str(&serialized).unwrap(); assert_eq!(bit_vec, unserialized); @@ -3225,8 +3435,8 @@ mod tests { #[cfg(feature = "miniserde")] #[test] - fn test_miniserde_serialization() { - let bit_vec: BitVec = BitVec::new(); + fn test_miniserde_serialization() { + let bit_vec: BitVec = BitVec::::new_general(); let serialized = miniserde::json::to_string(&bit_vec); let unserialized: BitVec = miniserde::json::from_str(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); @@ -3240,25 +3450,25 @@ mod tests { #[cfg(feature = "nanoserde")] #[test] - fn test_nanoserde_json_serialization() { + fn test_nanoserde_json_serialization() { use nanoserde::{DeJson, SerJson}; - let bit_vec: BitVec = BitVec::new(); + let bit_vec: BitVec = BitVec::::new_general(); let serialized = bit_vec.serialize_json(); - let unserialized: BitVec = BitVec::deserialize_json(&serialized[..]).unwrap(); + let unserialized: BitVec = BitVec::::deserialize_json(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); let bools = vec![true, false, true, true]; let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); let serialized = bit_vec.serialize_json(); - let unserialized = BitVec::deserialize_json(&serialized[..]).unwrap(); + let unserialized = BitVec::::deserialize_json(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); } #[cfg(feature = "borsh")] #[test] - fn test_borsh_serialization() { - let bit_vec: BitVec = BitVec::new(); + fn test_borsh_serialization() { + let bit_vec: BitVec = BitVec::::new_general(); let serialized = borsh::to_vec(&bit_vec).unwrap(); let unserialized: BitVec = borsh::from_slice(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); @@ -3271,14 +3481,14 @@ mod tests { } #[test] - fn test_bit_vec_unaligned_small_append() { - let mut a = BitVec::from_elem(8, false); + fn test_bit_vec_unaligned_small_append() { + let mut a = BitVec::::from_elem_general(8, false); a.set(7, true); - let mut b = BitVec::from_elem(16, false); + let mut b = BitVec::::from_elem_general(16, false); b.set(14, true); - let mut c = BitVec::from_elem(8, false); + let mut c = BitVec::::from_elem_general(8, false); c.set(6, true); c.set(7, true); @@ -3289,14 +3499,14 @@ mod tests { } #[test] - fn test_bit_vec_unaligned_large_append() { - let mut a = BitVec::from_elem(48, false); + fn test_bit_vec_unaligned_large_append() { + let mut a = BitVec::::from_elem_general(48, false); a.set(47, true); - let mut b = BitVec::from_elem(48, false); + let mut b = BitVec::::from_elem_general(48, false); b.set(46, true); - let mut c = BitVec::from_elem(48, false); + let mut c = BitVec::::from_elem_general(48, false); c.set(46, true); c.set(47, true); @@ -3313,20 +3523,20 @@ mod tests { } #[test] - fn test_bit_vec_append_aligned_to_unaligned() { - let mut a = BitVec::from_elem(2, true); - let mut b = BitVec::from_elem(32, false); - let mut c = BitVec::from_elem(8, true); + fn test_bit_vec_append_aligned_to_unaligned() { + let mut a = BitVec::::from_elem_general(2, true); + let mut b = BitVec::::from_elem_general(32, false); + let mut c = BitVec::::from_elem_general(8, true); a.append(&mut b); a.append(&mut c); assert_eq!(&[0xc0, 0x00, 0x00, 0x00, 0x3f, 0xc0][..], &*a.to_bytes()); } #[test] - fn test_count_ones() { + fn test_count_ones() { for i in 0..1000 { - let mut t = BitVec::from_elem(i, true); - let mut f = BitVec::from_elem(i, false); + let mut t = BitVec::::from_elem_general(i, true); + let mut f = BitVec::::from_elem_general(i, false); assert_eq!(i as u64, t.count_ones()); assert_eq!(0_u64, f.count_ones()); if i > 20 { @@ -3341,10 +3551,10 @@ mod tests { } #[test] - fn test_count_zeros() { + fn test_count_zeros() { for i in 0..1000 { - let mut tbits = BitVec::from_elem(i, true); - let mut fbits = BitVec::from_elem(i, false); + let mut tbits = BitVec::::from_elem_general(i, true); + let mut fbits = BitVec::::from_elem_general(i, false); assert_eq!(i as u64, fbits.count_zeros()); assert_eq!(0_u64, tbits.count_zeros()); if i > 20 { @@ -3359,17 +3569,18 @@ mod tests { } #[test] - fn test_get_mut() { - let mut a = BitVec::from_elem(3, false); + fn test_get_mut() { + let mut a = BitVec::::from_elem_general(3, false); let mut a_bit_1 = a.get_mut(1).unwrap(); assert!(!*a_bit_1); *a_bit_1 = true; drop(a_bit_1); assert!(a.eq_vec(&[false, true, false])); } + #[test] - fn test_iter_mut() { - let mut a = BitVec::from_elem(8, false); + fn test_iter_mut() { + let mut a = BitVec::::from_elem_general(8, false); a.iter_mut().enumerate().for_each(|(index, mut bit)| { *bit = index % 2 == 1; }); @@ -3377,8 +3588,8 @@ mod tests { } #[test] - fn test_insert_at_zero() { - let mut v = BitVec::new(); + fn test_insert_at_zero() { + let mut v = BitVec::::new_general(); v.insert(0, false); v.insert(0, true); @@ -3393,8 +3604,8 @@ mod tests { } #[test] - fn test_insert_at_end() { - let mut v = BitVec::new(); + fn test_insert_at_end() { + let mut v = BitVec::::new_general(); v.insert(v.len(), true); v.insert(v.len(), false); @@ -3409,10 +3620,10 @@ mod tests { } #[test] - fn test_insert_at_block_boundaries() { - let mut v = BitVec::from_elem(32, false); + fn test_insert_at_block_boundaries() { + let mut v = BitVec::::from_elem_general(32, false); - assert_eq!(v.storage().len(), 1); + assert_eq!(v.storage().len(), (4 / S::BYTES).max(1)); v.insert(31, true); @@ -3425,14 +3636,14 @@ mod tests { false, false, false, false, false, false, false, true, false ])); - assert_eq!(v.storage().len(), 2); + assert_eq!(v.storage().len(), 1 + 4 / S::BYTES); } #[test] - fn test_insert_at_block_boundaries_1() { - let mut v = BitVec::from_elem(64, false); + fn test_insert_at_block_boundaries_1() { + let mut v = BitVec::::from_elem_general(64, false); - assert_eq!(v.storage().len(), 2); + assert_eq!(v.storage().len(), 8 / S::BYTES); v.insert(63, true); @@ -3448,35 +3659,46 @@ mod tests { false, false, false, true, false ])); - assert_eq!(v.storage().len(), 3); + assert_eq!(v.storage().len(), 1 + 8 / S::BYTES); } #[test] - fn test_push_within_capacity_with_suffice_cap() { - let mut v = BitVec::from_elem(16, true); + fn test_push_within_capacity_with_suffice_cap() { + let mut v = BitVec::::from_elem_general(16, true); - assert!(v.push_within_capacity(false).is_ok()); + if S::BYTES > 2 { + assert!(v.push_within_capacity(false).is_ok()); + } for i in 0..16 { assert_eq!(v.get(i), Some(true)); } - assert_eq!(v.get(16), Some(false)); - assert_eq!(v.len(), 17); + if S::BYTES > 2 { + assert_eq!(v.get(16), Some(false)); + assert_eq!(v.len(), 17); + } } #[test] - fn test_push_within_capacity_at_brink() { - let mut v = BitVec::from_elem(31, true); + fn test_push_within_capacity_at_brink() { + let mut v = BitVec::::from_elem_general(31, true); assert!(v.push_within_capacity(false).is_ok()); assert_eq!(v.get(31), Some(false)); - assert_eq!(v.len(), v.capacity()); + if v.capacity() < 256 { + assert_eq!(if S::BYTES == 8 { 64 } else { v.len() }, v.capacity()); + } assert_eq!(v.len(), 32); - assert_eq!(v.push_within_capacity(false), Err(false)); - assert_eq!(v.capacity(), 32); + if v.capacity() < 256 { + assert_eq!( + v.push_within_capacity(false), + if S::BYTES == 8 { Ok(()) } else { Err(false) } + ); + assert_eq!(v.capacity(), if S::BYTES == 8 { 64 } else { 32 }); + } for i in 0..31 { assert_eq!(v.get(i), Some(true)); @@ -3485,17 +3707,26 @@ mod tests { } #[test] - fn test_push_within_capacity_at_brink_with_mul_blocks() { - let mut v = BitVec::from_elem(95, true); + fn test_push_within_capacity_at_brink_with_mul_blocks() { + let mut v = BitVec::::from_elem_general(95, true); assert!(v.push_within_capacity(false).is_ok()); assert_eq!(v.get(95), Some(false)); - assert_eq!(v.len(), v.capacity()); + if S::BYTES <= 4 && v.capacity() < 256 { + assert_eq!(v.len(), v.capacity()); + } assert_eq!(v.len(), 96); - assert_eq!(v.push_within_capacity(false), Err(false)); - assert_eq!(v.capacity(), 96); + if S::BYTES == 8 { + assert_eq!(v.push_within_capacity(false), Ok(())); + if v.capacity() < 256 { + assert_eq!(v.capacity(), 128); + } + } else if v.capacity() < 256 { + assert_eq!(v.push_within_capacity(false), Err(false)); + assert_eq!(v.capacity(), 96); + } for i in 0..95 { assert_eq!(v.get(i), Some(true)); @@ -3504,8 +3735,8 @@ mod tests { } #[test] - fn test_push_within_capacity_storage_push() { - let mut v = BitVec::with_capacity(64); + fn test_push_within_capacity_storage_push() { + let mut v = BitVec::::with_capacity_general(64); for _ in 0..32 { v.push(true); @@ -3524,9 +3755,9 @@ mod tests { } #[test] - fn test_insert_remove() { + fn test_insert_remove() { // two primes for no common divisors with 32 - let mut v = BitVec::from_fn(1024, |i| i % 11 < 7); + let mut v = BitVec::::from_fn_general(1024, |i| i % 11 < 7); for i in 0..1024 { let result = v.remove(i); v.insert(i, result); @@ -3549,8 +3780,8 @@ mod tests { } #[test] - fn test_remove_last() { - let mut v = BitVec::from_fn(1025, |i| i % 11 < 7); + fn test_remove_last() { + let mut v = BitVec::::from_fn_general(1025, |i| i % 11 < 7); assert_eq!(v.len(), 1025); assert_eq!(v.remove(1024), 1024 % 11 < 7); assert_eq!(v.len(), 1024); @@ -3558,14 +3789,37 @@ mod tests { } #[test] - fn test_remove_all() { - let v = BitVec::from_elem(1024, false); + fn test_remove_all() { + let v = BitVec::::from_elem_general(1024, false); for _ in 0..1024 { let mut v2 = v.clone(); v2.remove_all(); assert_eq!(v2.len(), 0); assert_eq!(v2.get(0), None); - assert_eq!(v2, BitVec::new()); + assert_eq!(v2, BitVec::new_general()); } } + + #[instantiate_tests(>)] + mod vec32 {} + + #[cfg(feature = "smallvec")] + #[instantiate_tests(>)] + mod smallvec32x8 {} + + #[cfg(feature = "smallvec")] + #[instantiate_tests(>)] + mod smallvec64x8 {} + + #[instantiate_tests()] + mod integer32 {} + + #[instantiate_tests()] + mod native {} + + #[instantiate_tests()] + mod integer16 {} + + #[instantiate_tests()] + mod integer8 {} } From 4578f8762a8201945034c9858139803d1c989630 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 12 Mar 2026 13:54:22 +0100 Subject: [PATCH 02/24] Feature: allow allocator_api --- Cargo.toml | 1 + src/lib.rs | 169 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 156 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 625af1d..04d3904 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ serde_std = ["std", "serde/std"] serde_no_std = [] borsh_std = ["borsh/std"] std = ["serde?/std"] +allocator_api = [] [package.metadata.docs.rs] features = ["borsh", "serde", "miniserde", "nanoserde"] diff --git a/src/lib.rs b/src/lib.rs index a647993..4c4c360 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,6 +93,8 @@ #![warn(clippy::missing_safety_doc)] #![allow(type_alias_bounds)] +#![cfg_attr(feature = "allocator_api", feature(allocator_api))] + #[cfg(any(test, feature = "std"))] #[macro_use] extern crate std; @@ -183,8 +185,10 @@ pub trait BitBlockOrStore { } #[allow(clippy::len_without_is_empty)] -pub trait BitStore: Clone + Default { +pub trait BitStore: Clone { type Block: BitBlock; + type Alloc: Default; + fn new_in(alloc: Self::Alloc) -> Self; fn slice(&self) -> &[Self::Block]; fn slice_mut(&mut self) -> &mut [Self::Block]; fn len(&self) -> usize { @@ -205,10 +209,17 @@ pub trait BitStore: Clone + Default { T: IntoIterator; fn with_capacity(capacity: usize) -> Self; fn clear(&mut self); + fn with_capacity_in(capacity: usize, alloc: Self::Alloc) -> Self; } +#[cfg(not(feature = "allocator_api"))] impl BitStore for Vec { type Block = T; + type Alloc = (); + + fn new_in(_alloc: Self::Alloc) -> Self { + Vec::new() + } fn slice(&self) -> &[Self::Block] { &self[..] @@ -219,50 +230,54 @@ impl BitStore for Vec { } fn pop(&mut self) -> Option { - self.pop() + Vec::pop(self) } fn drain>(&mut self, range: R) -> impl Iterator { - self.drain(range) + Vec::drain(self, range) } fn capacity(&self) -> usize { - self.capacity() + Vec::capacity(self) } fn append(&mut self, other: &mut Self) { - self.append(other); + Vec::append(self, other); } fn reserve(&mut self, additional: usize) { - self.reserve(additional); + Vec::reserve(self, additional); } fn push(&mut self, value: Self::Block) { - self.push(value); + Vec::push(self, value); } fn split_off(&mut self, at: usize) -> Self { - self.split_off(at) + Vec::split_off(self, at) } fn truncate(&mut self, len: usize) { - self.truncate(len); + Vec::truncate(self, len); } fn reserve_exact(&mut self, len: usize) { - self.reserve_exact(len); + Vec::reserve_exact(self, len); } fn shrink_to_fit(&mut self) { - self.shrink_to_fit(); + Vec::shrink_to_fit(self); } fn extend(&mut self, iter: I) where I: IntoIterator, { - iter::Extend::extend(self, iter); + Extend::extend(self, iter); + } + + fn with_capacity_in(capacity: usize, _alloc: Self::Alloc) -> Self { + Vec::with_capacity(capacity) } fn with_capacity(capacity: usize) -> Self { @@ -274,6 +289,82 @@ impl BitStore for Vec { } } +#[cfg(feature = "allocator_api")] +impl BitStore for Vec +where + A: core::alloc::Allocator + Clone + Default, +{ + type Block = T; + type Alloc = A; + + fn new_in(alloc: Self::Alloc) -> Self { + Vec::new_in(alloc) + } + + fn slice(&self) -> &[Self::Block] { + &self[..] + } + + fn slice_mut(&mut self) -> &mut [Self::Block] { + &mut self[..] + } + + fn pop(&mut self) -> Option { + Vec::pop(self) + } + + fn drain>(&mut self, range: R) -> impl Iterator { + Vec::drain(self, range) + } + + fn capacity(&self) -> usize { + Vec::capacity(self) + } + + fn append(&mut self, other: &mut Self) { + Vec::append(self, other); + } + + fn reserve(&mut self, additional: usize) { + Vec::reserve(self, additional); + } + + fn push(&mut self, value: Self::Block) { + Vec::push(self, value); + } + + fn split_off(&mut self, at: usize) -> Self { + Vec::split_off(self, at) + } + + fn truncate(&mut self, len: usize) { + Vec::truncate(self, len); + } + + fn reserve_exact(&mut self, len: usize) { + Vec::reserve_exact(self, len); + } + + fn shrink_to_fit(&mut self) { + Vec::shrink_to_fit(self); + } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + Extend::extend(self, iter); + } + + fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Vec::with_capacity_in(capacity, alloc) + } + + fn with_capacity(capacity: usize) -> Self { + Vec::with_capacity_in(capacity, A::default()) + } +} + impl BitBlockOrStore for Vec { type Store = Self; } @@ -292,6 +383,7 @@ where A::Item: BitBlock, { type Block = A::Item; + type Alloc = (); fn slice(&self) -> &[Self::Block] { &self[..] @@ -356,6 +448,14 @@ where fn clear(&mut self) { self.clear(); } + + fn new_in(alloc: ()) -> Self { + smallvec::SmallVec::new() + } + + fn with_capacity_in(capacity: usize, alloc: ()) -> Self { + smallvec::SmallVec::with_capacity(capacity) + } } macro_rules! bit_block_impl { @@ -581,6 +681,12 @@ impl BitVec { Default::default() } + /// Creates an empty `BitVec` using the provided allocator. + #[inline] + pub fn new_general_in(alloc: ::Alloc) -> Self { + Self::with_capacity_general_in(0, alloc) + } + /// Creates a `BitVec` that holds `nbits` elements, setting each element /// to `bit`. /// @@ -626,6 +732,21 @@ impl BitVec { } } + /// Constructs a new, empty `BitVec` with the specified capacity. + /// + /// The bitvector will be able to hold at least `capacity` bits without + /// reallocating. If `capacity` is 0, it will not allocate. + /// + /// It is important to note that this function does not specify the + /// *length* of the returned bitvector, but only the *capacity*. + #[inline] + pub fn with_capacity_general_in(capacity: usize, alloc: ::Alloc) -> Self { + BitVec { + storage: B::Store::with_capacity_in(blocks_for_bits::(capacity), alloc), + nbits: 0, + } + } + /// Transforms a byte-vector into a `BitVec`. Each byte becomes eight bits, /// with the most significant bits of each byte coming first. Each /// bit becomes `true` if equal to 1 or `false` if equal to 0. @@ -1502,7 +1623,7 @@ impl BitVec { self.ensure_invariant(); assert!(at <= self.len(), "`at` out of bounds"); - let mut other = BitVec::::default(); + let mut other = BitVec::::new_general(); if at == 0 { mem::swap(self, &mut other); @@ -2126,7 +2247,7 @@ impl Default for BitVec { #[inline] fn default() -> Self { BitVec { - storage: B::Store::default(), + storage: B::Store::new_in(Default::default()), nbits: 0, } } @@ -3823,3 +3944,23 @@ mod tests { #[instantiate_tests()] mod integer8 {} } + +#[cfg(test)] +#[cfg(feature = "allocator_api")] +mod alloc_tests { + use std::alloc::Global; + use std::vec::Vec; + + use crate::BitVec; + + #[test] + fn test_new_in() { + let alloc = Global; + let mut v: BitVec> = BitVec::new_general_in(alloc); + v.push(true); + v.push(false); + assert_eq!(v.len(), 2); + assert_eq!(v.pop(), Some(false)); + assert_eq!(v.pop(), Some(true)); + } +} From 69c5be82c77af9f987c70bf17676546493348b74 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 5 Mar 2026 18:42:56 +0100 Subject: [PATCH 03/24] Fuzzing --- fuzz/.gitignore | 2 + fuzz/Cargo.toml | 27 +++++ fuzz/README.md | 9 ++ fuzz/fuzz_targets/bitvec_ops.rs | 186 ++++++++++++++++++++++++++++++++ fuzz/in/stub | 1 + 5 files changed, 225 insertions(+) create mode 100644 fuzz/.gitignore create mode 100644 fuzz/Cargo.toml create mode 100644 fuzz/README.md create mode 100644 fuzz/fuzz_targets/bitvec_ops.rs create mode 100644 fuzz/in/stub diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..8505faf --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,2 @@ +/out + diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..30ea9b4 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "bit-vec-fuzz" +version = "0.1.0" +authors = ["Dawid Ciężarkiewicz ", "Peter Blackson "] +edition = "2021" +publish = false + +[package.metadata] +cargo-fuzz = true + +[features] +afl_fuzz = ["afl"] +honggfuzz_fuzz = ["honggfuzz"] + + +[dependencies] +honggfuzz = { version = "0.5", optional = true } +afl = { version = "0.17", optional = true } +bit-vec = { path = "..", features = ["smallvec"] } +smallvec = "1.15" + +[workspace] +members = ["."] + +[[bin]] +name = "bitvec_ops" +path = "fuzz_targets/bitvec_ops.rs" diff --git a/fuzz/README.md b/fuzz/README.md new file mode 100644 index 0000000..694faf6 --- /dev/null +++ b/fuzz/README.md @@ -0,0 +1,9 @@ +# fuzzer for bit-vec + +Based on fuzzing in `smallvec`. + +# fuzzing + +```sh +cargo afl build --release --bin bitvec_ops --features afl && cargo afl fuzz -i in -o out target/release/bitvec_ops +``` diff --git a/fuzz/fuzz_targets/bitvec_ops.rs b/fuzz/fuzz_targets/bitvec_ops.rs new file mode 100644 index 0000000..8a7c3ee --- /dev/null +++ b/fuzz/fuzz_targets/bitvec_ops.rs @@ -0,0 +1,186 @@ +//! Simple fuzzer testing all available `SmallVec` operations +use bit_vec::{BitVec, BitBlockOrStore, BitStore, BitBlock}; +use smallvec::SmallVec; + +// There's no point growing too much, so try not to grow +// over this size. +const CAP_GROWTH: usize = 256; + +macro_rules! next_usize { + ($b:ident) => { + $b.next().unwrap_or(0) as usize + }; +} + +macro_rules! next_u8 { + ($b:ident) => { + $b.next().unwrap_or(0) + }; +} + +fn black_box_bit_vec(s: &BitVec) { + // print to work as a black_box + print!("{}", s); +} + +fn do_test(data: &[u8]) -> BitVec { + let mut v = BitVec::::new_general(); + + let mut bytes = data.iter().copied(); + + while let Some(op) = bytes.next() { + match op % 22 { + 0 => { + v = BitVec::new_general(); + } + 1 => { + v = BitVec::with_capacity_general(next_usize!(bytes)); + } + 2 => { + v = BitVec::from_bytes_general(&v.to_bytes()[..]); + } + 3 => { + } + 4 => { + if v.len() < CAP_GROWTH { + v.push(next_u8!(bytes) < 128) + } + } + 5 => { + v.pop(); + } + 6 => v.grow(next_usize!(bytes) + v.len(), next_u8!(bytes) < 128), + 7 => { + if v.len() < CAP_GROWTH { + v.reserve(next_usize!(bytes)) + } + } + 8 => { + if v.len() < CAP_GROWTH { + v.reserve_exact(next_usize!(bytes)) + } + } + 9 => v.shrink_to_fit(), + 10 => v.truncate(next_usize!(bytes)), + 11 => black_box_bit_vec(&v), + 12 => { + if !v.is_empty() { + v.remove(next_usize!(bytes) % v.len()); + } + } + 13 => { + v.clear(); + } + 14 => { + if !v.is_empty() { + v.remove(next_usize!(bytes) % v.len()); + } + } + 15 => { + let insert_pos = next_usize!(bytes) % (v.len() + 1); + v.insert(insert_pos, next_u8!(bytes) < 128); + } + + 16 => { + v = BitVec::from_bytes_general(&v.to_bytes()[..]); + } + + 17 => { + v = BitVec::from_bytes_general(data); + } + + 18 => { + if v.len() < CAP_GROWTH { + let mut v2 = BitVec::::from_bytes_general(data); + v.append(&mut v2); + } + } + + 19 => { + if v.len() < CAP_GROWTH { + v.reserve(next_usize!(bytes)); + } + } + + 20 => { + if v.len() < CAP_GROWTH { + v.reserve_exact(next_usize!(bytes)); + } + } + 21 => { + let slice = vec![next_u8!(bytes); next_usize!(bytes)]; + v = BitVec::::from_bytes_general(&slice[..]); + } + _ => panic!("booo"), + } + } + v +} + +fn do_test_all(data: &[u8]) { + do_test::(data); + do_test::(data); + do_test::(data); + do_test::(data); + do_test::>(data); + do_test::>(data); +} + +#[cfg(feature = "afl")] +fn main() { + afl::fuzz!(|data| { + // Remove the panic hook so we can actually catch panic + // See https://github.com/rust-fuzz/afl.rs/issues/150 + std::panic::set_hook(Box::new(|_| {})); + do_test_all(data); + }); +} + +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + honggfuzz::fuzz!(|data| { + // Remove the panic hook so we can actually catch panic + // See https://github.com/rust-fuzz/afl.rs/issues/150 + std::panic::set_hook(Box::new(|_| {})); + do_test_all(data); + }); + } +} + +#[cfg(test)] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + b'\n' => {} + b' ' => {} + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + // paste the output of `xxd -p ` here and run `cargo test` + extend_vec_from_hex( + r#" + 646e21f9f910f90200f9d9f9c7030000def9000010646e2af9f910f90264 + 6e21f9f910f90200f9d9f9c7030000def90000106400f9f9d9f9c7030000 + def90000106400f9d9f9e7f1000000d9f9e7f1000000f9 + "#, + &mut a, + ); + super::do_test_all(&a); + } +} \ No newline at end of file diff --git a/fuzz/in/stub b/fuzz/in/stub new file mode 100644 index 0000000..587be6b --- /dev/null +++ b/fuzz/in/stub @@ -0,0 +1 @@ +x From d62c445f1db8c51e1284aafbb34dee5041dbc2bc Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 6 Mar 2026 08:40:28 +0100 Subject: [PATCH 04/24] Create a Cargo workspace --- Cargo.toml | 45 +- fuzz/Cargo.toml | 6 +- fuzz/fuzz_targets/bitvec_ops.rs | 4 +- matrix/Cargo.toml | 33 + matrix/LICENSE-APACHE | 201 +++ matrix/LICENSE-MIT | 25 + matrix/README.md | 77 ++ matrix/docs/README.md | 4 + matrix/docs/ch08-2.pdf | Bin 0 -> 495785 bytes matrix/src/block.rs | 9 + matrix/src/lib.rs | 32 + matrix/src/matrix.rs | 288 ++++ matrix/src/row.rs | 95 ++ matrix/src/submatrix.rs | 253 ++++ matrix/src/util.rs | 12 + matrix/tests/serialize_deserialize.rs | 53 + matrix/tests/test_submatrix.rs | 26 + matrix/tests/transitive_closure.rs | 30 + set/Cargo.toml | 43 + set/LICENSE-APACHE | 201 +++ set/LICENSE-MIT | 25 + set/README.md | 133 ++ set/RELEASES.md | 10 + set/benches/bench.rs | 58 + set/src/lib.rs | 1778 +++++++++++++++++++++++++ vec/Cargo.toml | 37 + {benches => vec/benches}/bench.rs | 0 {docs => vec/docs}/README.md | 0 {src => vec/src}/lib.rs | 40 +- 29 files changed, 3464 insertions(+), 54 deletions(-) create mode 100644 matrix/Cargo.toml create mode 100644 matrix/LICENSE-APACHE create mode 100644 matrix/LICENSE-MIT create mode 100644 matrix/README.md create mode 100644 matrix/docs/README.md create mode 100644 matrix/docs/ch08-2.pdf create mode 100644 matrix/src/block.rs create mode 100644 matrix/src/lib.rs create mode 100644 matrix/src/matrix.rs create mode 100644 matrix/src/row.rs create mode 100644 matrix/src/submatrix.rs create mode 100644 matrix/src/util.rs create mode 100644 matrix/tests/serialize_deserialize.rs create mode 100644 matrix/tests/test_submatrix.rs create mode 100644 matrix/tests/transitive_closure.rs create mode 100644 set/Cargo.toml create mode 100644 set/LICENSE-APACHE create mode 100644 set/LICENSE-MIT create mode 100644 set/README.md create mode 100644 set/RELEASES.md create mode 100644 set/benches/bench.rs create mode 100644 set/src/lib.rs create mode 100644 vec/Cargo.toml rename {benches => vec/benches}/bench.rs (100%) rename {docs => vec/docs}/README.md (100%) rename {src => vec/src}/lib.rs (98%) diff --git a/Cargo.toml b/Cargo.toml index 04d3904..c0c462f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,16 @@ -[package] -name = "bit-vec" -version = "0.9.1" -authors = ["Alexis Beingessner "] -license = "Apache-2.0 OR MIT" -description = "A vector of bits" -repository = "https://github.com/contain-rs/bit-vec" -homepage = "https://github.com/contain-rs/bit-vec" -documentation = "https://docs.rs/bit-vec/" -keywords = ["data-structures", "bitvec", "bitmask", "bitmap", "bit"] -readme = "README.md" -edition = "2021" -rust-version = "1.82" +[workspace] -[dependencies] -borsh = { version = "1.6.0", default-features = false, features = ["derive"], optional = true } -serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } -miniserde = { version = "0.1", optional = true } -nanoserde = { version = "0.2", optional = true } -smallvec = { version = "1.15", optional = true } +members = [ + "vec", + "set", + "matrix", + "fuzz", +] -[dev-dependencies] -serde_json = "1.0" -rand = "0.10" -rand_xorshift = "0.5" -generic-tests = "0.1" +resolver = "2" -[features] -default = ["std"] -serde_std = ["std", "serde/std"] -serde_no_std = [] -borsh_std = ["borsh/std"] -std = ["serde?/std"] -allocator_api = [] +# add debug info for profiling? +[profile.release] +debug = false -[package.metadata.docs.rs] -features = ["borsh", "serde", "miniserde", "nanoserde"] +[workspace.dependencies] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 30ea9b4..f733eba 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -12,16 +12,12 @@ cargo-fuzz = true afl_fuzz = ["afl"] honggfuzz_fuzz = ["honggfuzz"] - [dependencies] honggfuzz = { version = "0.5", optional = true } afl = { version = "0.17", optional = true } -bit-vec = { path = "..", features = ["smallvec"] } +bit-vec = { path = "../vec/", features = ["smallvec"] } smallvec = "1.15" -[workspace] -members = ["."] - [[bin]] name = "bitvec_ops" path = "fuzz_targets/bitvec_ops.rs" diff --git a/fuzz/fuzz_targets/bitvec_ops.rs b/fuzz/fuzz_targets/bitvec_ops.rs index 8a7c3ee..ddde46f 100644 --- a/fuzz/fuzz_targets/bitvec_ops.rs +++ b/fuzz/fuzz_targets/bitvec_ops.rs @@ -1,5 +1,5 @@ //! Simple fuzzer testing all available `SmallVec` operations -use bit_vec::{BitVec, BitBlockOrStore, BitStore, BitBlock}; +use bit_vec::{BitVec, BitBlockOrStore}; use smallvec::SmallVec; // There's no point growing too much, so try not to grow @@ -183,4 +183,4 @@ mod tests { ); super::do_test_all(&a); } -} \ No newline at end of file +} diff --git a/matrix/Cargo.toml b/matrix/Cargo.toml new file mode 100644 index 0000000..f12c8c4 --- /dev/null +++ b/matrix/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "bit-matrix" +version = "0.9.0" + +authors = [ "Piotr Czarnecki " ] +description = "Library for bit matrices and vectors." +keywords = ["container", "bit", "bitfield", "algebra"] +documentation = "https://docs.rs/bit-matrix/latest/bit_matrix/" +repository = "https://github.com/pczarn/bit-matrix" +license = "MIT/Apache-2.0" +edition = "2021" +rust-version = "1.77" + +[lib] +name = "bit_matrix" + +[dependencies] +serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +miniserde = { version = "0.1", optional = true } +bit-vec = { version = "0.8", default-features = false } + +[dev-dependencies] +serde_json = "1.0" + + +[features] +default = ["std"] +std = ["bit-vec/std"] + +serde = ["dep:serde", "bit-vec/serde"] +serde_std = ["std", "serde/std"] +serde_no_std = ["serde/alloc"] +miniserde = ["dep:miniserde", "bit-vec/miniserde"] diff --git a/matrix/LICENSE-APACHE b/matrix/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/matrix/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/matrix/LICENSE-MIT b/matrix/LICENSE-MIT new file mode 100644 index 0000000..29256f3 --- /dev/null +++ b/matrix/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015-2016 Piotr Czarnecki + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/matrix/README.md b/matrix/README.md new file mode 100644 index 0000000..50e2e4f --- /dev/null +++ b/matrix/README.md @@ -0,0 +1,77 @@ +
+

bit-matrix

+

+ A compact matrix of bits. +

+

+ +[![crates.io][crates.io shield]][crates.io link] +[![Documentation][docs.rs badge]][docs.rs link] +![Rust CI][github ci badge] +![MSRV][rustc 1.65+] +
+
+[![Dependency Status][deps.rs status]][deps.rs link] +[![Download Status][shields.io download count]][crates.io link] + +

+
+ +[crates.io shield]: https://img.shields.io/crates/v/bit-matrix?label=latest +[crates.io link]: https://crates.io/crates/bit-matrix +[docs.rs badge]: https://docs.rs/bit-matrix/badge.svg?version=0.8.1 +[docs.rs link]: https://docs.rs/bit-matrix/0.8.1/bit-matrix/ +[github ci badge]: https://github.com/pczarn/bit-matrix/workflows/CI/badge.svg?branch=master +[rustc 1.65+]: https://img.shields.io/badge/rustc-1.65%2B-blue.svg +[deps.rs status]: https://deps.rs/crate/bit-matrix/0.8.1/status.svg +[deps.rs link]: https://deps.rs/crate/bit-matrix/0.8.1 +[shields.io download count]: https://img.shields.io/crates/d/bit-matrix.svg + +Rust library that implements bit matrices. +[You can check the documentation here](https://docs.rs/bit-matrix/latest/bit_matrix/). + +Built on top of [contain-rs/bit-vec](https://github.com/contain-rs/bit-vec/). + +## Examples + +This simple example calculates the transitive closure of 4x4 bit matrix. + +```rust +use bit_matrix::BitMatrix; + +fn main() { + let mut matrix = BitMatrix::new(4, 4); + let points = &[ + (0, 0), + (0, 1), + (0, 3), + (1, 0), + (1, 2), + (2, 0), + (2, 1), + (3, 1), + (3, 3), + ]; + for &(i, j) in points { + matrix.set(i, j, true); + } + matrix.transitive_closure(); + + let mut expected_matrix = BitMatrix::new(4, 4); + for i in 0..4 { + for j in 0..4 { + expected_matrix.set(i, j, true); + } + } + + assert_eq!(matrix, expected_matrix); +} +``` + +## License + +Dual-licensed for compatibility with the Rust project. + +Licensed under the Apache License Version 2.0: +http://www.apache.org/licenses/LICENSE-2.0, or the MIT license: +http://opensource.org/licenses/MIT, at your option. diff --git a/matrix/docs/README.md b/matrix/docs/README.md new file mode 100644 index 0000000..ae701e8 --- /dev/null +++ b/matrix/docs/README.md @@ -0,0 +1,4 @@ +## ch08-2.pdf + +A file from Winona State University about the transitive closure +algorithm on pages 4-5. diff --git a/matrix/docs/ch08-2.pdf b/matrix/docs/ch08-2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..40471696843be21dc1cf6170c6de7069e3b3b020 GIT binary patch literal 495785 zcma&NWq2Gxt}g7DnVC6`+2a{AGcz-@$IQ&k%*@Qpjvn#p8f?~5`y5t}>c5-%h4t)Uu z6mziI-=WC={r86li0!|4h?$!@n3*dXJKMYb;V9~0=VlLfAqTQ3Ih&hVo4PtUld}N? z1Xv`j?Oe^BStRU?UCsab2#d6sE}t+rkV_oE1p)xsB*cMSY#?DafUu~rH~_>Y2IS@d z3GfL60PG^-+#=lK;=&@VKz43!QDKlcn}md@H~=8R!78B7A`Lb(_tgEXIS}xdvTz^= z0J#2$sKO#=4z_f)`lBM~uR!kqR1?Ue;^5%=2L;xD^ill-5IKO8jYZAN(VRs~#oU5L zQ;Le*s=oJ=niihl=sH7rj zGa@LerKoqggjB5fr7}2f=ELnt|)QHM0l$Hn2k-ex-}EM{r>OSP@ZYXrX{L50`^)<})y<8&z22istL=hZB! z^{P|eoxTwrW6-N*5}dJ8$ZhPW(RGPPKF=ism&xWJi_>xlqFFj^^A#K*YB6S(@NX$N ze)#}fC{BWcOiDtY3?%|&WtD;Wjf_k#OuGbMiJgf?>)45KoQet?Z)Hf%1Ub4--oa+W z`V+wF{wg?puii3$pza`R*R+RSlv8gQr`?7p-}O%KzMpK4R6l)-5b{)(6GYX5U5XYt z0O>>qC25WpI!gzIZUoT))XDu1VE@xA{)MN!xvR06v8ypT8}OgLqGW7oE@y0FZs+m` zKaPL6&)-XbC;;a_sDJp7=$}XI94!AUfc^yBe;G;G*;T~BQHmo`u&X)P)kPP;{tvEyT=^gF{-^yL{VL>ue~SC3 z{mb_+4ft2f{;wAJxBWAcvxDP5Sp6aYiU9!p5#vt~$^QvnG0MI{J{0S}BKOs*3XHIdpw*S9s@eio}qWAAO{T<~0?939@&MvOxY#{dk<;rZF zoE(3rFs^?FucC>Ks;m9KyY*MCGw=onwtsLRQ~;Q+c_fDpfew-juR=VBBeKszD4i@? zeq6_VGVMF{_QF+SDx-FK4iPId9a>}Y$zD!9&UWU1eSWCUh*Au=X;m2BKtPK09-DvHvddti* z8V=Mf_06xuJZbjITKe|NI$L)0pUh*v*c^!Ie_t~zowDuZA{f>ZOy`VVjJD6jOe`200X`Wl=m@1ZX)%J}`Y>lFFZUqStlPqGom&=NeQhj=yJGb*G;@Z0^ z$6mPI^)(`b>w!9d+O>Wmin*S96G0|wS1D7K@>>LDR5bTX$xW;$vBetw$NW%Af9iZl zlAUSUVm|yq4B`}_LHIH1TM9~Jc&uSMC=~Y25bjYeB=R7b(nO3g>hDTI()gB*{Z(pm zAJ>2iSG6V~CdCWMN?h^jWScSqH@lvsKRg`=cyRXcGk`kUIL5I^dv8j&gc&5e&K~HZ zQ8Bnn3Q8^&95%Tk&{#b`c6P;jexP!p7-x!kz$D%GC&V|8pFw?wawhlf6^@1reJVJ&C@JVNqle?i*i?aX2Vhv+<45PQ#LQ=1s~p zwbF@7VOxTsGrHnOZ|D7M;3MhlELOlsw?%yf+#V~$@m<91Q(B%B{&66vx zh?X{O+w4SY2>Isi(gozksTcn*hxJI+=nhs(+l@?KVON54Ms!`QPN7!w$QDciO2Ujr z5op}V5g)M~gFBcZ%xsdovx(&y@Mj|L+^*|#T}DCZ-4|5{gLzh9hlCyU)u`0ai0-t`EE1DC2G4H6lF)I-Z4;FUls4hS5Va@ z2p^2zCtT`K+%*K>X1+iwqrKu7nq!JyY6tXi&Tc#1@up!{DGuf7=vKRs2+(c#BCKBj zT$K~F9;uO_Kd@eQffna~+40II^J(qD{!H<1o!VMUKIhp1Hp#%WXBA&rS!m%9|( zaqBAmE&u*c$ZN79I4O+l1;Sj-V`TdC?FZNmrc63&MY!}m?#ww59a`E!YclOqXBwR4 z95*tS>o9F$g%9u2K6e;z)2O^)D>nPEHrh-K7DtL1fJw2h*fhfRCuC(>UlBvdBkDp& zVaO;T_s_jA&gRH|SYpu*2MDqclG)%9%Y|Pt}f`MUA2=8MN^rc?I`QR&dp=S(#HbG z>0Lsd!r?(z`Xh!!o%04J)$LKA?mDQzt5B`R8Jzu0_xE3X%&|4}L&Ih(3ZMJ^QWr`T zr+vZHm;TOJS!XI(x*cvdo%$K_6GkI6y@wqcwsub&rlAj%`JN_Z0pV2HaQlmIFf9_I zxkbW+3wn#8bG_JG@2q3hIdJ)H4yLW~a^+6d1&1+*EE2YTU$q??r}6l^ZTku$;!pgd ze)0Ku#%#G$_kA-7`S@PC)}+;6!09}2`1>25kWN*D`P7#SqD7=G`G&T09dKXxd>eDl zR5KdRS9NlpZv1JQlF~lj+7gsEhCv8Yqv=2S|NoXe0@(j9`Tyr7^7yF+CSk=wM z^=}URcV%W1{r6>5Eej!$TH9;KXT?lCcm;)#SuGDC%NCVlFnF*CXJQP%m@%Jkm9C%8 zeGKN1$ zg-#@80b^@PUps5(`rZGX#UaOg>O!?+%U$=-0DNYwm(&no#j1i?=Wz&v=MNfey+Ps-k+o~A?S5>xk1`_fc0+X z^;F-XIB@WK^_arj;-PW%^1CO#?+ow#7VpZR?-_W<{KUEA!+T?Ew^u*lwPSjMK1G{}T0^zi3h_3RIN)I9K&zfUxqQ~jTitM(J{&>~ zLeWyPVUsUA3USi+M(a$=nJ4$-Z|sNEDF2K+(jN|l15a(SF26e6Qs3fsvihzJ?zf*U z-j^gROD-p^(xWVMTx?@rKVOs~b=`eo4j@nY@+STYc>U$}k;@3}rOvzK1g#mo!0YHe zk=I0|5qxUa1PL*l@8^C0HH)~*`>EA2S%CeB^Js0UbFtD*X5_TqF-a}_sZ6l&t@^#B zrhzrXz2VlNv_TI&=4j33bKhED#iVUjP*eFm!6mn~EZS_iWp4^9H$P^>3w_$BElnSZ zue>^?9OmDyH|dNzP@in$0&k1^`$PxaQHLYjnBW<4g`pFLbs%}3L0<@WBsWp6;KuRk zAlH<*Koz;^h~DzbVk(MA*3feLCA~Z%B+Fe*_F=aJ0l2{*Y>_*5y~f$02)#O~>4=`V z44awOiqky2ri4JUt-zSYv%)@!BF@3%gVE#H6Nd^Y?4nTNIQ+0%vP)6?MrOyL679i* zVjSO8NM;eYp1s7!MSrOxw?{^&Ek40QwdutZU&IRKi10D%X7JauwQEV$gN=DnrBE^B zCB5>5L%GtH?3z&(B%L_`u`@FacHT<#_uJ)ZxOYm`DU3nZLgAY1i__Y@;6`E4!q1(e z0!)_Uqcr9c*DeV*%8~u*9x*cRI%y<31MMF!Woar^)Y#Hl3k)-TgV1-5G5HYx{grQwvOTG1gXcMd8mHHXKT#6HxrwP@)Navovep0SkE$r>l9|A zG%uW^5k>ZA%R#_(-&dzjlZjXgB#|x&L_KweZ^6gm0ERH{%|adb{c*WfD^Nt7a0{6m zKjxBBos7H(xc@4HKv@ZUq*6MVlBje>T_{Pwsl1JIeCA5Mz%Q-aKoB3yN;EQUmZ3l? z8nvo)E#7c?RAR%Jq@uS%tOjG|24c@MfRm^xZp}_*b`6{66i5 z01QX=j@k&9;W1^*JLOnHbEkgm@r{U^P=dafM~}#z>d#rL##>WmbY+Vi@sx`{BZTTN zd!7(meQPM+?Vi_MmyxtXj7nTgHW`M)88}V`JFR7xbR`!Zt~G05BQ5#1WwJ0=C+j8S zNio5tA63m?zJEPN48=s^o=-iw78F_TvMO1~J8AcsC)~2LQVFq_!8pp09ym{p!B%lw zD69y0JNKj?xwfejNqeRgNEHQRLS(LXKh zc5$Dmo%L^fYjE3Av)1~4y>{qyld4@xFj3fa$&)QxUBCA`)xoEJYSf8k&F=m#9Rmsz z7R4n_z(e3X*EB-9V@r#Q$S;7k)Z5#Tloe%ld09*)hR}&r|~Wx{A@oH zR$6D+_Ss*ou1##Ny#ZB!&&W|P*WNm;M@UGWRr5lfElNtmAf8n9`>aV-R}UuvZHj3( z=q`2PMI@ae?H$)?o>GZHnPYGzQwF<1_q&3$EPnE4iBh#TwNzaPol(M1u?{q2^JmBV5&5WsnnMtUIIrYD@Dy)a2Iuf9K zl4_>cx^+XE#X%Z)ZD{$~GYWo!=n&1D@0O938o)@np{6sncb%Oll>%cEs8n$2%d3@5yj2}+`*E$}ZKO-}TjB+!mcALiz|a-p&|yk0 z{DgMm(T5H$Vhb-Kq+IT$pCjkyf7^QZa}gY&K`9d-ciTu_>7S zm}XL^@_Pq+LiIzku(wqC7O62zPQCOx6DG!-P*?>iB_J!h0KZ`-k*oY%po7amP~-4Y z=b(8BHlpV#E2|O8-HfOwNWN}N7Hw*#t?}mbt6<@AXSs~_kO3wu-=^4L>7Wj5*>-9qXzk;@fg=CZ z@RA<*?^MXxV8ZTD^Yup*6lsTD`)_^iv>a>U_)g%oQOnF%LYRz5v@)c`5PB$- z!ZWS$4}pOOkmlr&zzmcR##i;)ZcjK;$Psh+jmp&-HiOa;dx~y_me6ub`eP?*y#!ky zqzk&!{VC!Mf&)ScrwwYB;w*~6;}`n?08mfDrqVO{V^6PsTa5-roz}sF1)ed%7v#~x z8e8tJa+^T4Z-gpLSxp|yMR>>lNW-v5DG)lX2UOV2%7puaLW*tbL>bta#4|K*XhwZ~ znGzXar*ZF6Zf`cj%9t!%uFVcUb*n(?Br#d5%PZBW6ea7{*FHG zRxzf{)+ZWwr-b808L{azEp=Aw?PmPohVj5t`=Bj#H9@kLA#LasO8>cnOkOZOUvWg# zk#ye}%@LYFxaL?~$_6$R7D?ULa?!OTe?BQ5dCdPBa=p|r9NKDZ?g5Iuyv{M%5b0>e z^e{xG(5v(^Bu|r04Ng$_XqOrBY0IF5XeP8znl(b-ziTEO=O~LsCE}Yp`+$_XBh4Pr zq@$3KKAi?7J&@J;4Fc=ZY3(17ZX9u>Gzw*C6`IC4mB`ENQ19c@ zdO++*)A$$_4s{{<0Efl?-;-b0#6`8uHPd<AWznoq6_OJLWPHjP53Psw+vSjYlOAH<(TO#ufE zW3L(^cC9{dJbfKQEFNo@&aRIXr%sMCQ|w%C~Y$IhAump!F9T-9-F^x}!Lqe8?P-Q`~<>rYJQd10KI)o>D8bEB# ztDd{DrY#maaSRLxeOsfMa>wNE)7RvaL|AR>8?o0DwydWTITJoBh6JX-Hc3uU=QGqH z4R@xscJBju*VX)DYM<^voc7XmR^vM_I?Cp__&tHDZI*+3-&<&I2Y4!%279de7C4m1nK=&12<#xL;btryl3Iq|C3&=1DG-Py)at@Wbhem++hh~%IXr;&^tS54_U3v#d z!Wm6DDWp%4aHPex_LRUB4xAzMmKyFZ(LKTc<=B+}=#H=ApUw^7&Vnvjz zj+H7AkZZ&<`}_Y8_QyR&YA}z%i_w&wt=pV1A-V{HKvSF&r*+ZjgJCtjOBteq{Q{0=)sifvWhp4Fex7jU^d zvD6H|30dGL*(vb1^@l)VD8x24w!xjL(3qEI_)E98=V@_G?@W#G-f#Km`wMHvML%@vjh=e-4;0mn1-sM zJcY8>O*Sqp!jrG=pvuIbL|Lx;DV)Jo9x{AbA;G`>(rj}u_L##a6N9p@4|n-aFi=wo znWe=3almz7mqoG<>AYq`li5yC5iGd#IMz|A8A|lqR_<;6yv%ZDx}NOBpNS%5A%W*% z&SR%U8m;N$5=>iV@@%QowXvby5>}0{F59Is&##ZNAMvPK9 zfuRqttS(klIt0EjjgG1Txl36~-UG4jU(_iA1`Q@03NFZKpCyYM{IhtfNw5@Izg?gD zRw;dD(X`-Jsrw$we!IthZ4}1T@jdShyZb{xa6T1}g@e=(8M>e>uLZjDp5q3$q+)`= z-H68qidjR8Mo%2i4$olhvwogc`A@T(q$?A`Tc-%;_P`@=oM|b#tDo_gUn@ziM&wza z?(E>&YGF;=2v><;&tdez%|)bYA?7*bay7~1_l5Es%pw9YzeoEm>Nl`sqj+pu>7E5K zq?F`HLfZcvR*!eX&IA`T6E#=UWm~{YAS4jhA``zVodPKXgBU|#KAaa+%ysN>Ms?$G z3mhEW@OC!nLfOW=#f$500M%ksZ1k*hoxCL5e@YYEAy{#WRnF{7Ur46@!eb4^h_nFW z&;xthc7`r^aZBiM7iRbAX1UM3k|Qtx0M zLqW9gRQe&gLu|!5^HbiRGd~gWS&(=Fh=5-O;$8iZ&F3_*HYVS*MdEne6_l-p6JPU% zJwLpCs@(x(UDn+dabL6aj`x5*9;Nwxf?zS5cY`zltT^5hHZGK8(+Rs-+{Rz)uaFWk zYmddUbS2j%rnr@}t+AfL-cteGsnq+*HLpX}3!_0;C+S~0wfwE|bgOV}FI*EP1K`Gv zVabg!g%kX7e1ZlzKa#c(F7crtv`2?wl5eT|aepO@$Bew|3CMaKJVu@V+%lS9WfYYH z1AIWwMD}JHz<9|uA9MuOjuuS@m+6U8_EneL zl!vNGIE)QeP_07yZE-ZuDM8n}KAvnw*CUy<>Clt%0(di~Qsy}9#ftnOdqUa?y3~wl z8>fsCQS{I8A*Wo3$J$MLY(4VwHy)&k4FpF`$AdUZPCJijOC(He8{su~P04-CaM!q( zXX>9dN|gz& z>Bp+g3t5Gh)Wr=o4u3D0+rcZwPLR7aqQnUxEqfQrl9jq_YY(8yT*qQt=ed0$@Eavj zulKu!J5WT2&xTMUO&F=)IE~drigv2^0cIgZ6BSGvNOwhH=?b^5_=8{FHe5^xek|q9 z-Aj7J-Z!rbq|M84z1iJ=xD9p7PLh-3M=Gpkh^>$A6uOa+J^*^so^^4(&)l6Y-`rku z8xc1?y%EA&@7((324wIoW+S1*jKUv3ag4GYYYqu)E=n%!CK!tn`f(AJUMtx=%5myF zcz`deoKQ+=gBC*in7(~nCS0MIXz}WVR}^(FgD}og2flQdLIz%7E77-kffe-BZ9fVK zyqCQ!Yyt)br>&Ejt()UNsK~d9#kJ{15T;15e#i=7f6A*}r_*aVzZoHT@h<$$ovPkM zQ8Iqz5+ySo%BL$`Lz}-J%Ukr(QTT-6k_l1II~pK|gBS~V3kJN^`b#iO{E7{<-%FC# zI$ya@6jYul*nDxwf)4GDVVhBA#IRmgK5N;2G}Q+BvnT_dP5?X-I5OeM6voNSpR|U` z7!UEL3&C}vnb6|2^}Y|o;?DrTMz|qdTRS&nG2ZRbM-$9z62umi<@KFPtVUA~)6;S5 zM_4CrlI%y##)R&%%HUV-u}lKNOD<7wm%=E&_A2VOPN6X`2kUh2XxfNKX!D zbtJ9Y5cd#miSxt6yEDCkApaUgV#NrF@zvZ~&VH4F-#2os)_%JTcY1%egjf!kYc~ZX ze0qY?{i!x2wF91)D8F9F+-9^FM@7kxqx@+YdwKjVmsRwczwkCQt@HgBIlY@7uaAq& zySnfVc#hB&yypem@z&#cqwKWVO*KnRNz_L$p~hoS6^;+_wE2ODYt2 z4f=bi$FjQZD;5!ZI^XQwbEY*GZR*9L9E6@kdv=Q2?}|1}AGc1utMpH?lSPDJ!^ADq z4{Zl4n=yAm=ijgqp39>L5t1YOGe8m##iYg~lP;|K?CLxP-aH*jSaBn1=f{(56VQF_ z3x#mD^ed)4dNt@QN!Q6eonlUncC`Qrbp~mgv=kTvC2Zlks#2Xg0#LWo?WuWtDm+S` z{3+AVZvjKEM?TVXC=(|!B?nmtZ&hQA3tYTj0F*hXR}H* zK(^dgr}Qu+eCAd}Dbf?}C4IZuD`F@;#wqv$jXXMz&G(|GW(j#MHtDB{jpiJui^7C> zT``uuYj&#k?7|dS6`bE#hXIbV@x1uE#1ZR&=ai#x-d*ulR3hlN7}-N_sW9vB2albD zfOhp z$!pg`*uaBSnkV_-2ay>qv}C5R*Yxs}58ZmxRLWS9=caCn$@!^bT0ugR5Zqudwy3IU zZ^D2BSAL<;SqTN}2*;y=yM{FdFIt>G))5Zujut~=N65Z~Uy~jgytO;UJBb@R);C?x zXv)d3EG!m@s~7(8@@irzO=bEE8*l58_6e0FG{thLkwnz;SLIf_9B1*b4@V4_DYNE+ zuL~(~dW@#ENg-LB_4+&8cApKV&Ym+)wQoD3M%ia966s7c=eXdJ7{6*33a!}CRyS4B z9uRm?hS7+P7%b0K#(!Hp4M+N@=;bD_Ok>`rR-5+NkSEZmlQeNvKA#Xts=zyAxDty2 zBk3YW@wrC5u2@iwo5q>P>&&bpJ%B$EV&`XI#d8XGiNaG`w8o5*DMy|nOKIFShE^D* zk_9qx5G8q0k!YGm5h9Qn)vnRaW}Rdt7Ei8|OM)$W4)#ks#=L@?s-PMIKD9*#s%k)o zjw^CRQli~tx`}i;m$I9zB#%GAI<=#*)_8Zg$-+p~6T68K?Q)$TpB!zE?RPdmu>G&c z`N$rll_aA+a%^h-qQ02b+e$ZE{oUDH7ChCzKZ%+kbE!4Gejqs? zt-L%+P&lO{&aXU0*h#6Drzf9qIq*9j`9*d==kUYWshQ;h(YFkbt}>AOgW1`MWF?Gw zkZ!)+B1+*t3q;|>jfplz8X~NJw@&*OrLGG!^5^ObN$-?a@^YF(4aV{n@ODZ~6$)zNIO=|SrI42O(hINQ%mzkRj9j`~5^-cW8S24}p+ z1s7pwd3AS#4|?OYf_axi4AU`puSSROEmm*+@=(ge1?Qecsv)^z%^fne=8$Zx6x8?4 zAJPy_tjfN%hM^PkzBzda?5xGlN*}yf$)r_c+ALMWQ!D*uYa)LOSNIwmrv|$%{sQ-~ z-S^O6aMgoV$RZ=ZBYKXHp_Az%_kEq2ND3QNG*+Rpr$NZz+w{YS5dSkp=+m_I# zBi;HR>;0m@eJ$4t6^GF(`}L{~;Vy~$;7R4*NU7W;H?y}B7GIWv=?(W-(`1c>%DWbG z3|JuZ*iA+|j}-Y7xDTz~ueY58eyl8^@Ecy#UxBT!mb9oZO0i@gNqh%#SI`131J3fV zwJeE&94F;)CrxwTy@9AfWWLh53_&Ul>{c_?Phx&3T|w!NQ{*q`wS_XW7igadvRZ>| zx9^`W;+}J4wF>nE=J;y!)Cao#j&~M`iWShUrJ${m0Emeuqr2cIVkuPE5Zc$27uaOz zL59;1A#GJW${2cdnqN~cM{9*r7D5#6WeBDRY($!{elk9^(}k?`d}$kIq`^w~0%9x= z6Ev)gYzjbPICMF}GHVO7t?S2gYFmqVM~Ni`Dq0fV&LlDne7O7s4B;W<;vopg2wA=4 zp!UV>$ZM#UhGqps5sH)6jJ=6>H2~HoM_LFiTK}@Z~N{o1tRoz$`;2J)FrK{AcP2?J{E_GP16* zK3xxH>?l=qn{P7BT#7OnV)-utc)BW+3+mm>GOZ9d`Omc2w_DIym~<-wxU!s?YguaGwE9cPBy8?*=F2(h$=Q2Jaab5kqwTm!a zN@cLKJQ;BMy^B0wbjJR*N}pV|Br>~DuIjLh&)M`3P|^B0R~6J^ z*X7Y+NKLAC`qX^n17dPey|NS(qx)2_zW#dqKH{e}E^3ScXufQn$azE0>P;a(RF60x zag88OC`*g~qgg=zFJ}2$B>sOZP|@&m#9ARq{~#?3K|{glbib!BW6f(XB8MsStrP`| z92MFW@{qOP-b^)_iMRMkh~V_+ioaH;fy!p2uD zef9;Km!&n%8;g6ttB#$A=f0~4j)*p^4-6kaT7FI^>2dFG`f;*S8V8y_stg*xlI;QuKq(s9ViS z!{N%(yCJ#;>P;i*lyMQ`atha}YJ#K22kiCwU#vi)68)_U{j|y0qrn-MkmIBuFfL8 zUR6?-c%k}X(PC&ephB`Km0fzw(ZIods?R3XV7!R^p=QmI31yty1;}1^^mSzr zBS0-qrM21@*~cNDqS??FmA(#>(gf- zq8wQL?5@+Gp?RV^5!_eUgU<&QFdh_hf^j=$mH`qGtNoCo8{z5d4$Is|kHVwZV9UND_zY3V)|oMKY#TfvQD#zBpuNVqW@~Xr=Yg!WOzix-2IIg|8c@toN z-TCorx9Gg3a)Ye>o<%AB>Ar-$YPOL;uqk$zT;gfTolf%T3$nL@|Sj|&w-h7l7XrZ6;VgAdH zSSD=32t&!^R}DaHnEp^A+5^wQ4BJs9`w#d#3OTGVr}JulQ3L3`I@Am`)bvw7HvD7k zW9&bNK4!z4$4#*`7s0xC`$Uv-XG zagoN9_J)v4YoiELR(jN&o51gPtt0J6Jz)=rcu*jLPJtvcbJW+PnRRTcJ5Jtj zCB6FGF<&)sXbfRse9X#_vs7S2Es(lw8;JvKpCqP89IsnhxMgC?RZ5BocoHb6*s9!U zLr*f{=9C|r9I+E5_Va4j`%98WWGNHpeEPWTQ$GrIi zag{2txZ92`_$B_Ls^;tf%D-iaoTk)UK1V!AE0x0-XKZKmM_s=!dL8^y9PogN%B8zu zXp*gmSKds|DIgL#<*k!9u9N*9%SEd_-k>SVr^q7U9kuZ$u(vq8vPucO6Nm%tL1yVH z*Sp}2^fm8dfJ@rd!Gx1c!#&%vX4wR&gOMU(hXs-J?UDl>S2Ci3K}-;Drmf$;#h6vF zheTfK(+&jwIj2;ynA$#fD;clR_bHlAF=haKR;WO2nDqPfbdY5 z%%j?45a)9qn<4AyrWi#v3oNBs#b?P!Cgv3Vh}Anum}gd=&w(t?iX^11;!e7Ym~5da z6mCMN!oA7M{T7Wb17-mxMBmgOE37@tW}GpGq5%{mhxDFP~%ub?8PUWdN}Y^ z*O3XixXN=~5IOvtw^MLrOz%rFTv>Y5pG~Vc3j_+&TWW0LJ<<4#Ny~PVnBYvwJ7mo+ z?CsgMY`p(w)-N$%@L@nmYlLuU^XdL5wcaqTuCAWEP*HQ%dL&1ROg%a|8Nb@(k5}Hf zb_Kn;00^)lEgZoBn)sNa>B7^{GS@aCOOXK*n6}1G0?)*0H5dHV)We6klQ*$7A<$Gg z=aUe$JlMVfvG`hVM0(B06gdjv-lrpY<^D9A2wu3QydINR>iVPDBij-aj2>Ow1|$h8 z!+s;FJ*ROuYRP;s5zwRt0w_)5k5Y6^Kt=M2Q1kFfM)hku9BsJ#8aX0Tm+SV_d0Uw4 z3`plQ6aP0?wU~!5&p>d<)Gnv^I)*IudKSdN2@ZQbQ>!jM4EMIXvHou8E9&d?Ry=CFnwchU`BohBzZ}lQg}9;?Y7>QRL`N3ePyYr6_Yto8*WyRaS{8_XjF?e! z**zd&bG!=m?w*{Ec$t@(_$lvZ;ey#H%LjAW=lY1S{^54W2K7$qv`haWa&MbZ~L z<@0Q>aK9Pt({}t0jSs>7F>Lrhrrv))Vf&wVM68_uZAX+OZ#%+@9DenN!{dIt>)R26 zj!zOsdOx&&k4;m{oK&7zXTN=Cq-f*>NqUXo6>Y=@3(`VFxr;%D8%HBUFx>pszK--VG| z^p4xB*W5lXbmFh36a zAzP>4GuNfYxp3 zR#!UxKb6O6PHl2u%=7@3Ge1bVSD2jlMWV4%MjA_S#^ckl{A)_lV|w9#op}j$_-DsF zES|D{o|6HaI9zjBaq?Ueu-q{XLQMK)B>hL^|9-glKOzrcV`cp>=%u2*YEFWwBr*F| zG`}}l1y*fl^t(-wj=^!+E>-#+mH%GXclRPN1UqPeI0I;YzJ++wIOlzdwc4VZc z`l7`t5$k(-Xy%u$!D{-iG4Z5ZnljELvBr=A=1g&W%5cX@;Tu*ITn(Lx%P`}e*nn?T z^e4&JqRgR6cCI-ZfX4YNb-&jj0;<(xr)E7r<0+qe_xnaYdCr6zP!D0Oe^oz$dI7^^ zc`ZPA$RuK6!geHl9SL0IE5)JPtS$3d-HPULNwS@s6IDmCS%Cf!h7XNdyTA@;RziLw zFw{SUuF~cdgqxo8bYaJusvtvZyBgINA)~1XH-gUhaMu%5n8B!w`>+az$gJgD7@94) znrzD1&t3{*D9NHqKu_H>06MouL-0K#)@ze>DW$_e3;Bo)Tl+>1(!z>Sh7o><53HL2 z7TR&Qm2|l@U-OseCU&mHC|fLXNB|tK{5YkwzyA=n@uCKV0TjXUHf)GK?yZq^uaG#WERa(omRWK%lPam&}V+72}N-FW5kB9 zKoJkkoOvy13N{EppD>~hZ9rCE{0GJ>#m!eU}j=xAhF3%3Il5;%Tf3}xIuH}OsHd| zv}LowOvcTwm_GlKWvYS&s_Jy-kY+WH{dcH(Rx8w|ka_`j4xtX~#X92`@8&0a=L|$R3#JRgmKznyy;u~)epv84 ze$Jcx*so1Xc>4u*oN&oysNLgDZ#IU0HvosT6_}#}bHOZOH&tMY1Vu^QOX(GX=E4r?6^)v|%4?PcEF`Jq(L+ z($#Besv$tbGdq@Z;@osGQ?~gDnr&alrxlDBl;><|#mB33=~}UglU2S+LSxHaWcq=& z8!V+DwV6wT9adABpwWgGNDKQezyM3D$S+t#Zbw`5IWw`q&kL&4)-jtujx)iQLm%S4 z$NIyYJA0QYer!Hz0HIwHoLnHHfcPb~oBw6;kXa~U38wd?(E?&C)K4#i;!dvN)4&XC z)Hl8PW0SOX9dfo%IC~!2!uyi3P(LD6lDshWD?5?dj-!C;f#0Tl0mULU$j&&>WjIzU z4pDN3(Ebd*s9K8K*t_8F(lol2XbQ4pOxoJh?S15*pwJw!dooSa+c^bRT$DX^v*S`1}j)7PrC(KDp4C| zMmie7!zg5QF_P&v+zBJx7LRD?yM(tba2G}KTgoz|y?>-Vq!Jd)vAi?k$9c-VWHFxP zkXGXfC@t10TPmq7)6dqCMCI?SX{bZA-ElMYp=;C^W1gLG>g2|u+Vz8*mDWYf93qQ4 z>0gH>9#ajFWi*p#`}he;Rz;E+F?m#uPl{|6NAoZ)atvwe6hy*z=W>#av+X8qh?;Gwr$(CZLhxl?Q?FjPqOblNoD@4q*6bs<~znS#zfM8j=1$2YQ;UM z3>reeM|j-kdwh+koh9wz6!rc=kEqo;s9YS9j~*>nRH3whCgu2>BUa4G4gynqeY=_A zN1!OdviDGIAQnYdW*cJRnkuMLK3oCVY41Eq@_xfDS!FC{Pl~ON(f!-GNDE9fK zwiW7!T|4As^N&#WE}0R(_CaM!gmBTS9`dAjE%(==SKx@V+4DPZe~+zvUF{a~816Ux zHRP4wZ=FPK=*`6cxcB%^S-}5w@4?K*@!tv}BqC%|rz=c5VS`UUDOVUEuR{Dteq?|> z{Gnkz{K-^|tf#XX!Q<60VfSdm?pjy^?)>x^Le86hC~9UfvV}J^!4# zWCC93hB2<+OiXBDWUD`SYIg2?>InhUU$(vf<6@ZV)ziB0HPj%JzGVc`uvV`c6&|GM z@sN3Nn^*tw{_gM1t=0RyHrA`&w?$m(kaqfJ{P*>$U#s`!%EJrISL>(u_u2JN>F48mx7N=)^43G&WKEOd=J?Qav!eCg)OVHdNf7^as~7#Q zyZ2r&mm7$AAqSZoKRdvu`;+Ww!*pV6=WsOx=J`~Wd8BgH!)v!_V5io{=Vxf>)bvvC zO0e23a|36wwZzrwsl=xeXPj3pvaxC0s?(~ol)fq(dCQQua?*2qaU?|E`$+CbAI7`W zNdcpJ#V;&Q{E(QhHN9P1;q+w%&LL17S>kEBZhp5WQUAl{A8Ckbz!Q7QWDKua!@hIq zzE;*e?QY0uV0v@0$eQKbgTW4D@CP>QrFIW_zm^SM0I7yO3}t3FuG z(r^khK*<^+4QX&W<8$qy5KBdEO$vU;-wpZ&O~_(khsNQR>UZXZYUEc4-bhgh4ZG$o zDy488XeyuR2%8>44Gfr^IKw>0+NT%*L?sTwL>UCActzM=x8~9)gJ_G92|yJkMh+E0 zLW!n{Ybx`;Tfrkhu#FJcANbQcIw%xSm-g!{Q`bTndlmt_QaYQtAYD=g zu`XzJE-F21=5~Vr#s>BjAmFTWVb=V_H0sq&3?x9%=0?9*P!qj{C8gn|2LJ=`NauZ- z2Go9$u32Cnt)sY8KwIMy@oaEBbIjN=YV!F_Qp~Hz>y`><|{Hfkf2+ITfP=W)*w{n<-oYj7) zL6=z(#q91lzK#+L&o$I2a1UYtIQf_c;=+Brim-N#xiA>!0C>$gD~VK~vuC9U;gj+9 zu`yIYf(l*Lg%VX|X98j3`4R@?2zOZV{$V=)yxP8lyH9XAdI zQB6D`-^YZcX=}0e1z!yoQO(HMbhP#C2ZWK1q3N2(uwq`Qg|^+iO*jpyGnT#TTGfnsDHj2v7UN;rn-Ip-|AG8RWGB!?mF<*y`Z&E9EKN zU3D;P9DwQfeLI_p$xt_(hk>isR}PEA30v*c>S+T)FAO@?l7oI=Tp+uopiAIg8%6(3apFhBz^r73zdJqB->U$v-i&65bkaP$R6!3(PGAAeJS@Xc-G= zNEGFs4M;*LakF20=m%+8jHk_&!LV^L$s-ixar(2;v?~GDhF9i>T)DksOfQS+ss|>X z*!RxDkpWWENuDydXP*^ga|$YYzZ8$h_Q}0uN))n0VBZ7Z7xFl8$b+j%RT3Xh4>H-h zG&T|_*i#a^A(uuU<7Scy?Nsr10F&9a9N*9ty)E!1fh7j{s+#EM*4-pt zpyy|V&kke}dzOX2fOr!o8!+`hkEgETo&@M_%-F6ZE}b%>XfOpHL29@JUl)@o)KkYW z#vUjVYd7t=1Ce4!bE3|RhlUDiTT0njum=-~`DguU<^U3^SBQ=VPfO;MSTJK9=yfrf zG*S05l^S%mbR}3KUkpi7D6@l>GzqL>>!lVY>2OI_oRUB#yZn8N8=-rg@NpQ?^X2q1 zc6GK=FT}6R*YNgWTO?iya+ja+-lO|at#9VC5{IF8bpefG=(daL%OG7U^O_1xtOHX) z`QE(`G5pB1QWxbRbysZaKT;tuYO6zRJPD6Pd0F zVLSQ=@OJ6oMnDG`FYH%X3im8^8@sC(^(R!MaMez`hXK4=ZfyUSlSVt>RBanu0IX!W zJa;m`?~;j@!8Kpoh&2%pjD%+U+VJIm^{31prX7uasb9b=pN5ud;^aOcqtPsN`S8u~ zH$+om@dQ4(nj{IxPqxy?7sYdZ>RR1^@YPN@tkv*iOG`Lrm=K!MquhCAFE-sJET-|W z4fS;?#`HUx^rLU`>~^hwE_T@b{+^#msSsF^+f%Vi+)n<&#bk1Z%z^~*oZ?G0MUZw6HiE%D>{IVar zt>EES1z!o06%s;SF@brF?&s7oR63g~g z&$muz?Rc%_WTVOG?W^Sc%(hchb)Tm(K~J1plWOE-tf~bGhBq5c$sc+SPO1)8XKWQ4 z=6DM5?6}wK8P!=S$>Koy6mka2lO$6jlxU%4Dz5)+%DF}3wE?MGxH?e^Ab}Z~Vy9Z1 zpur&|aZ8Eedyj{gTQF~Lp z%df`gpbP1|1DLmTpCHp?UDS|GW3}?vvJ z7qV(g4vZj?#+Q>)$gO9t& z&>@fOUwNH@wEQm6+KV$LzOb?wa^u=KlRz41tx@+@;vx(xz=sqPZ>!f{8%YPXtqopjv1h9 z)$uw=>mF%mW+5lqGHTF=TpqD>^vmi2CyO->*NeM<&_sHR@^Qg(cre&0C|-^H<3G~= zu{e9Vqh3Imq>A`0HF~vZU6{j{&`+I@BUUds+NCPOO|w|wMLkV?FJ5dew;6~no>#ym zT<(>`ic^`x4OWiUBLyI=ho`v+iOiM4r6Ub*G}xWuE}YV#^lcfVLvyy9KO_+yVWG!N z$QGpjN=h%5-!NG_^#uwPsbjBD zFZVeS4YGdU{T*k60;1PTz0w`D@0b9%EfUeSR_(Hr?j5mzL(Ky&A-EA2vE&JIpEK;= z!z5xz$EVG+h%S zkk4)|vIKC8m(PnKZryt`2WZpThJEwcEQ*)+AV)u8!E*zV#x%L;6-)gYc9=sX#+ z)ZF>7%$4f=*tW6UpWj*4d(aQ~f1FkSTbfWmlvLuq@w42iE{-qID@wr)t9$T$g+b93936-D|=lF}9Mt^D_o zlhv)s70s1X31;0lEm94>n)1cbm#e*79}-TzSNyhq|IR<&S5D>H9jl&LPTOvLSkPWv z?7WI~GDy}py}GglQN|t5Pwj5~d<)-}-Aesl2V3Eb7%#5WwRmq`ir2}=B%kTMi5`_} zOf9E9mVd#fnpb#zzpV$;afZfXMUIf`m*LyjR;9#g7lMQJmv~NsONB2l^Fk*ok(*l7 z?c9$8Y4DR$30GEp-vc@bZG3B;@}q`lbK__J4(3UR(k@4E>KYTZ8u|O%hKXK~s-?;! zmW{5z#j<|ms z>st1kKzx|-LjM^S@}h&u?o;Y142i$E)56)F5n2IK!^a);SrSS_{eg4hlvwjSJZAxlk2)Jo1s=2;m zj{|cc+Q=E|Ae`NiKlPJ8h}Dqz68CW&ALLc32OA$dl$2UuES30D_lPG9s*ySM1V4@{r=^#gWldl#v-oAl<}vb=0)|y*Hn-ekIg5d%-f8mcI75LiH*CQD-)s9vu&tc6fsbyqHA@Rj7ejAUEa^I z^qA+w@4M}&jGK*GsuY?|DfSX`lXF}ndRJ(D$ZIlGnh2P)c?m0!1T4o1Qrij}5{?0$ zAa13WZ6a3H3$0x;ycthFtRW z&I=AnQ28~aerWxmbv9zlga#I*c{!RqQK(6{h7KF93vLr*%$|y_;lW{O{E1H`x@EMp zl5Wz00{-TaIRaT{^Ztz=|1Mq^o5hGYnko+19X=+q`7x9u1QR^DUhq z)Nt`J`h*#L?6EYCF9h|#lYq};|4s~BZ$DScrhkN9>iwSvPEpSRNQUVr#!7~ zVi87dt&y=Osg~*gdjPCN_VpkN%I=HDo*%)EZTLeBUo4#)bL1&2%55Z53qdwKk zKp_}UpG1}4DYU#WF#!!LB|HeklPTh094a5?&k|s{PIpnEGs(- z>F$58Wr%@o3sg)F={TIp;BEm|&S%P{7GmEMdnkO=6wkwpV$eDKn0zh*y1zyqRtDY_ z?J|M`CH+|x*ckti3B)8z#doPd=4@pD7&_I{Hj+c!VXXkF2}1}kc~&-DwvY9M!W_-O zT$jIL)aL*@%x?yBWJHXb6m`_%9Sj1`63|TvNd0%NRo>iem;ir={-hhTivl%rl@MvV zT<8|toY;PaFEuw7KDbmW&r2W36>=yq3SfTUcRhC}V?B3rHg!1{szt4hRyE8ZzR+)u16mO{@ojW>=0F4I1Ds3)_r~uCH?&PIr2s zf*QhHB3}+~SOBe)^HRW4gS=%8J@qH{{z0tHeINE=Y%9S1C)#HRqJ%xi($8JI<(vn2 zrj%Hlr#9|P4{R@b$fW2cg(jx3Z|#)?Eku#Ok0}QFen5y|2ZD&Vhjr3}Sfi_cP5;DfE6i&jzXqG^@+? zIM5?US-el5$K2%2=vVVN+<@b@WXda{!Gj2BlR4ifx0KG6Um+!x$I9#=IO)$WDLLXS z-+XBqJ)0}Zci=?eId;sFV&*7vGteDfraHJ@Q1O#!58urSEuGOv@#pR`p= z4#3(Z{YG}DH*I-BBMl4N zj=pHd9Merr2HyLAS_}3OpnSG1{W~fQyI^zqRA0FqOq}K4z_g~xi!#mJ62^+=TIgq} zzuGXY%BtZCG8WEUTXeGc=pF3RUQC6@t|mDYtS@BR#oy}r8EK<2FY5~05KtZ0>hj8t ztgvEOL7Ct4v1_mCCtzHK@fr1lP|&`c$MUFpbn|N6=|s2zSYsJhiP^e14b{G(E$yEO zl;ZvT6}w$>?ena|!zH4*D2{8$L}m={6iKv@eX$)Ty{6#VO8;gyVl0Xc1_U295?=_% zPzHN+m_s5&t5i$xM=0Uxa)Flf9|z8^)%)y!nri;5p8Nmqz_D=t9}b*Os;n*Te;hcy z;dKG_CuzyaF)SbuI|KNJAITn~^*_XILDmlnq|GWMk*n>qUrnB?ynMU*tL>j04Pn!D zk=OFnuPrg(v#Y9;+iI#~8!zt;qgmIB8{4ljtbsPI>yV2Z@wztM2%T>2GY%jvwTFuz zyzYN)vinld?Ms(%n5wyuhxqO{*Oar*yXOT=0rH3>QML8Ey7H1uk zM#Q9Joa72L%<((Dq&sKJ0kpXVu}Zh0>J^bq>N~1CqcxT|juVVqawtkOQnJ*Li+4Yc zTy7b0igpX{#y{}}k%kmsyT6c*FtPx}|2%@$!$Qrnxfb9!iFc8^wo-jQHBF|hZ%T&u zmw%Qz9WwWr*k_~+vdI^$^#Q^k$O#;~)}7WsHoPgRW%=sGEw&i3u@fR3LeG{y>Y9@L zEo^X|b$&XD>A>H>#(zD3tQkf!S*04Ka`0A|j6b|eBWFp{r5HAHf2>Q!2UGolZG7E#cPOa+;hdbCL7~2!f+{~JmZE3(IU0F z03RdL+)%Jc)FA7^dWjPRDa3CekPlg88+f!LCFa*!K0%^T{2Tgg7^lZEzZTKl0*mRn66Kt8&*=#A^&^mJRr|Ae63@&@UNK?QQkM*prkyg?$@y-*0 zCN&f7pT)CeAcXQ|Gs0np@@=t7$tvBeyj2Uy%D@QL@{5=W3pIWnRTLOilt&7w(emI9 zl2N>KfPsnu9XCSEHSCY6BVUO0pHF;aS(f!!6{8lgk0Tp77EfQ6y&`#D$dQb%zEq*N-%RzG#*!o4s{WdHh$+-kr(gyMK~q? z%<%*b_+Fgrd__D?n^fGI?SwSRyh~}d|Lv!;U9Q_mS+*)7-vw8-Q_WcO^3Z-rOsl$i zF6dApN*DVg0~BsBDXI?;5iqf~k;u5(FH5Z4mNYgxXC=vc1-Rf>|NatFWz!^l^Z=9S z?m`8xHOS{Fzmf5WxYeM@T$6~`&cgx`5=-k zdc`||Sj?n7Xr*%XDBuA7r-6!gBtg(V8wj>IRu9Yx%$&q$ps;X~)nFq+EcA{eQm_bLw`c-~*d;z&) zUy!u2njW=H&dyuddH@5H=hogAEtHmAaxUFN*{&#hHV3csO3$5Vy z_nIb5MnYp-q0-ws0z;^*DGj@B7?H#zo<#K~A|@HonV`+b47I^2?qhlAMs7t)d%+9d zyYaORSrBvY1(%m0oQznqj{lfjJ6QkSA~uhXPd}fw?J{*QxilJiQZh8`)f^V|)xL44 zTt$|FR8q3yO`2_;x%({l4Ru}g2gSfs%trg#jkm=)GFI1cW^eZ;Uz|j*r>pH>-fVWN zV4gbtzUsH|H-Z;IIYcacy#0g|Kv_3RlIm3}tXabqx(MWvA^enPQThnQ9uQ1f)bI7xO3wH-Lx zdSDqGPj?@EuCs|}2>Wci%;mAtPb{Z&1`)g{Z(g9yrg+4bCZ;IU4Hh?j;`ub>WN{=l z8GEK%<;PdW?eoyLFCB3HD&C&(ifA=pS^`PEsOlp$L?QKnK?E@JbyLCO+_%gB3xa$=#Oq#F$y>|J*paKaC z_6GrAgQuh>@`?JiUv0Sv*d2CKJ*MO*)Jq?p=7x1LUmbx+dmLRIun))5mYtT%C5}bw z8-K+yj8$pi?eOIvc2(C`DLej7ZbcMg@d)H46B(hZGM&E{8I$h*Ld1yOi4GD9Gje)V zZ;o9gkGYGa(?EP=VNf^x`j;|TVcOcyJaC}uUx`W!kopruqtDX1lO|y zeKpM^zGNQaJU3c7s45no}DAq^R_p)?&Yv+tu8> zR`rF`Fd2XOm&Tu(AYn%xdA#r4JB5-`6VslBrh7SfbWGuY&URf4I+*rd1|6}jQ|C$- z9z*W;#MY8reJr_h#yxQgFP3AN*it-V45fX{!QpyJk#PC-VIr#=L*qD!s5+p45K z0)$YW&MX3YPgQ+Nqh6k1mE*WdOd{v8GDD}#1iJB(`4YI+%D4tb)7X0?&W8ueKn)9fBWi&l8H>)e{>r>v*kuR3&LEV9qv2+^y?r)N__cNtg@ zkDGowSv*bFYYC6N)gKQ+yWVpdaCc+Dm{(J-D4-{shpYvB1&8>t3f57Thy!2vi^mC9 z8ZZNM)lXo0%gxb#+!ulkKbH7}4_v~PFyqOf;aiz9m(;U*V=bmCXd6>pgA<^VXlG_% zBYs*GKSWnvK2X*X!Cu8-R@F#zu2=m{hTX^<2+5t=vuW45qrMB8PA(0VPAQ2MRpj2} z_HLe&Ik3`w4VpaVc!0A}cCBxVZ&BHoTV3N8eh-{}>|EO%-@W83?S-Wo3O9gX)un#k zwFz_ZIV>w!fwf%@#Hp=j#eh+d$4ftE3LSn>zGU^?ey(9RB->u$p&kn&!5>~)8wV}Q zKfJvE98H0zKATM-&o)1`R92c}UQ;h%d9M!tbnHM%toLpv`#b+bi)_TJ?s$-EY*1+S zB!Irj?u+jPyM+_-dUEqOzK?%-fLS=I$hefo!!ijeFXnjWQ+Ym2OZG)05D%Ggq|Nf$ zn&@9c{!A%JU|^%fpngq8k3kcHUKCiZ)OM8A9|OmJPCsuartZC}uBdz>ml+Y9Hk>gI$1WO4(ff`nRT3l&Wly~bE!{5B$K22c-8 zn;k<49=o*HNx=vB8~Nmne&AB!o*f(m^QwzW?9^w!TE9Vc+E1*&7`rS! zGd*=Q@{eW1ePKoYPY*K30WF^os)3chqK|m-aY$oV??u5((28*CY|h zK1WSJAgp7I!c3U^1jPgzkqMdGIL7!Y>>SWx3Tbzy4`9yml;ojRT>)NMn*N+?_88;S zP)k6&v4L(vqWYwKADM&))48*Jm^+-~2odgpe-9QQ2AsQdrkK9h*WR)Ov)y3vP5nraJ- zmn`!%W~BJ6qL5lH#oqSzLdEojs-;85_8prP;xd{A>#!Oi(X9nZjnv7+r9}N{PMFuz zQ!73G)z1=b;EI)SHoRbM$KJtbQmDPokQd>TS3|rI3m(a?Nfd%FqbxN^O*j3lSS#xa zb7Rs76H76gat7R~6C210z}ztq{tyrL#lA2AA`H^Hfh4bYH_kxN(|2?Qcwcl3p`)js z!6#C8ayR7^&!l4j;RIoiym2F>gK>ZMDRiI&=}UqL9-6l19OCxOTZ~UM##+Xt|Gos9 zjS-bSz#FW4X_T5>o_`Hm0po*&CfJZjY>@^C$hX`KRO2&}Dfh4Agy%gkp7qf}IO>eC zeIXT!fPV0&8$h+fB}Y>3Yrlh&Wcj3JyG~_6uc;9@%%@;{QxRljf{?N=0y_ClES}v4 zVl=uo_4tdH9}_CRV%S`Vb43_L4<_a1x*|-=@q?7RK|1orgT|ndQu$<{>QV36XO=$^ z2REU1oqP%Bqf`&RXV{{MAu*Cb^8o8hn{w3gpq!#)aZE62aR%Y?X7@d)^og_l1(s%G z%3jk6lP;wcwELrZT?Z$~S-T*~?+&gg3q}(NXaga}ND5N?kTpa+!X#Z_f-9ykMuby? zRBX^jgfNM?WWoiZbrg`Er*)|i$@avSipU1cTfhjjGGk^*0vw;qZQqDD!wZ5qOF+R& zhl~kE9%03<(<#)Gw%|jA!P)#fT{l$z(NuEg<}@i)PE zNS$ zTC@^e4aj@w%Ha4YmoxHGgTH7gq<4cTlR=m=YQJ+zqp<}zyW<0)M3DsuC9Q$tMG*$- zi$Nb;LYzJET=vOT8mwQuSGJFEaP215w=F4VL_7?zD@XL)_{@W$is|)u{5NVz1tJFY znqYNVOED`jn&9B~1#Hw&m8!m`x;Z`@wmyWCejgl1u$#(7B{1}Q9&6x&E@Xos#)SKr zX*%w*irMt6nhL*%+$)`V9KSoGOXt%g=LH7B5ETTUp6|)+Dl{SZfJY=G*gi-HeqRN7 z>(5K7G-`1Tb`G7NZ|}Eb`9p01iBhsV0BdrBY|FZ(c-gjQ#TVN-`V4Pb0VeymkH^<> z@o{EiXZF`Ux9gX;;#i`0AIV$+4zF7c>0_^>%wFsv%yB!SwAuk)?p0W+^qK?+6_P)4 zt0C&+%kHSOGl&mnx1D`Wf>x+9X(`Vg4b(*M0=g-v2i@5J9RV$V$_x#=P z$uin3>JKm&B6R8}O@t^3Sch!+@xi(+vHizGfbgPY6$4zNjdth0# z&FQ(&JJSlFkyp&PPr9R+di#NQJ9M#{b9)1J`vG@*0eAaAx@URyEyeCF#r6%YcevGi zw$*jC)pfGfeYEw7w&&Qq=NP-E7`tbf9RfWtL&#s*i%UQ#N;=Yky&j)Z2F3QCDL8X& z_xUXk*ceIV`r~{KqKyHEbj@fRHaB@zN*yD(V4Dx44UNz&Nfmlo-D5M^DY&xZQr8%B zZv3w1fgI}dZ_fzViPLg5f?=lD=)FxQ()?<1!M9oCL40VnW6lUgR?DK5g>QZ+IqedY zik2AhFaI+t-B>l&ut6a@UngL}Mu9|{d=ZuEVt}*a8UchFMrKigU#Px5DqTQhw1{CY z3=w2IOLs>p>f;tmW--VWmXcLR#AB@6589!nh_NAqe!T-$RYFgc(A+kNbq8Y7m{VL% zDveg%rE|^7dvt^QdKfapK5b~y(yx5URU@ZdNdp8ethTd%^TzNVJ6KSvCG4U*a8&$e zM7X<|KMaJF!ln+>RIWp{uCRg5S2rk8qG_CQSnigwGWOU>R@!y{G5{zgC0l~Y6GTpV z`_U(NeRDI7DeXh>AB z<;^-fVym1V4`?3+G~Xy1>ZqBd{3=Y=h0?)Ftl3(*08CrEXc}Kx!ei3~kYX-IEwaLd zx&6BMZb-{|#2W@Sc``}U>idT=DWw+MOV88ZWAzT1R#Xd!rh{*X9Gik!auUs2!xU&) zXy2T2(f5f2Dr)2Bd|~*$0prEl@M9c=IHz?b-4wZb7V_cHuYA7iI<-SoJ6Mx*yI6+F ztC6MpY@kr(n?w!$mRG{=0It6_QRBrV?%3oVrvEOTQW?wA4?!lkg5_8Q*K*yK9EYeV zb7j~oy~u7!3Zt#^XIHa+(A z4u#;#FQD6kxms*hkKi_X1M3{fpp-{V#W)G9+VTq1d>&BvkcJ9Kh|~c2S64jELtKIO z_!@Gj!Z+cV#wlSctfHL9V0~i1---$z6PUl&PTC1ey1%!$vC^XfeZ`|?m2cujbB3Lk zPR|1|(3Jgop2}F==xyn*``aL`hkEh%^pn|9!K_AXcc%xS;0 zEI{z2&Q48353(uclVTO5fh_dhKD<7}HGO7tqSYk9AArm-@t=v!!Cm^>flySvrjSNM zg6n{yyMFk!h}LkFc=mOm$*5jNU4K&WSA7WP?_K*|r(K=ZFvt6AlFB zJ=K_<)2-cI?6~Xw*oIFVonG%Z$dNzr`1F6>o@uT;!ZN42Yyif-zW23?dNnrocCn3e3p(81a%X2N@!)13*=(=ho{c`VwViq# z-qZM3++W{=gL66AfA4FH^Xg>m!^qx)fj!ASI`Vr%3c9heA0ykppa-rtK!nf$f;A{w zgT%F`U5s1;TU?YOC#f_8?877M`H}Arr>nHX zTMj(Z7|v-%bf>GVLZ=wnlQb^zL!4+Q=b3p<@l~1`_mi_M<3-MlnfV(|+f)ExfU6d} zg#U5F{QrLn=>H3SvHzdpXy;Vv7}9oF(NjBAMm7XM9|@n7d1Cs!Jux^c*rr$hyY?cY zKYa{PW!~yYm?WZlO0S32y0OWg-~YB^X#-U0eX;nv&&}~aI4^$7nV!>+*Bcu*I9|Tf zU!In0UtqM$0AkEmb#qODzfMnMXZ7)KFD+MUH%1O4|M17U47AAYRz^YP`h|2XY^ zKEC$q{(QY{$y;Vs{+r^g*%UW7)OXvxq->T>>h2z$#T1GEx~x#&*YB=+GM{!))t9$h zt-aOw8Ch?jtFm?M%6HNIEdQhD#vCP{$A9D9sNQ1|*hmTDX6J2TZCD+5^U^jP!E4li z!hErpC{c5XcUiuuXjiPuPPj1?YIjp#Y=;z543C)528JdRnrGM2IHykcy{n$KZq<%OnYr&yM8T1u`ScR~8xrr#~ z;CY=-*%i&CJ*q8P#?Ghz^+#*YDp*#Zh>9O9xHBoU=6d~#hqi*5>Y1mb}8t6+%F3?;P(xs<`cdK=CM5ZblTT3 z?7Nr>K>05ChPokKy)VO6`sz0F?=>0NO-K-R1ru(w4HZ*COlAkvAg6WeYV%_2kV*(p zl_(IiA`GA+F3!=HD^^q*E$Frw=Ky3;YJ~1EWRz%~C^=e{1;LyuBBpH<4+xmQzWDH)@vCx`;>B1~I6rF)KQ&8-MS^l!^&)5fW<@>MU zRhA40f(BS`*9L~zl88Z)yFL|*b;HU3hd6T55MqRG!#yxGwFnV`x&X8TQ9#blgm#i^ z=>E-2F&0~5Jsi0}$xs(1ka6X$)uuwg0xdyJ^}p~vWd6y+#p0q2?3-B;fa<5wCC=$V zfMg1uY*FE`kAB?QtTa3qi8S!>lbi7OsaeXS24Cewjguh02+im&}v9y})vzJ!Xg8U=73p{||1IDBdq&FdA3G zNRD%t2VG}wE!zCT3iVNGIEWLaH1C06fkaT)SXuySbcW@K^w-u?&Vx|i0Wni<0-P}3 zP!y=h+*!*s&-Hgb#^?D@Zi*_v#q%kCAu_*^dH1T$Z-m(YJ6+OWS0!iU!{bUkSuU|lIn>7gn?+BJjT)i~2B0F9%+G2^xu2+M59u1+h5`Td4=y}| z9yN?Hu}t0*iC~Qg@-NFqNLw=1SAj6|$-!qLhdq8+4zMXm++l|zvX_R_fH%jsg6Tv- zbDap)FE(KZHO5jtR3)4~7tzm)#q@cA2I}rDB*k%)l&~7 z8xZ=n)BEw8fO`fA&j->RXQDI zg8qv&!d4%JN2fqx=`;hA-Wo%<=g&?@U5v2#$QM+-vbx_NM9^*{^G{cZ6_4@arJEZy z$SoVJ(jbS4XDvPGn;-4W>Avr{D{G8X9p+ZHZ!!hx_(hE#RO%=V?d4ue_qu;z-l!aT zoW7_G`Ra#%V^efW@rVCAHZ`Ie^Sy<4a*o-k+&`ea_xF`j)fx&Qsvh~TIvd%%kx{14IDHrT{wR{pqN0JDmJ?YN6v9Sg+HBp8?tuyVg6L@Qv@MVE1T!`PpXa~) zP|f4yap0-4b%I2{7?Gq*W=0CqUtmt#&r#5K4%YKA(C~^z*4=jCg-jhLeVl%CKi_|E zUoOj)cknCpLv%Z`D3r-}m)vYU{BAO!B6|AAf$!ZZLVZZRP9|>$X;PW?sL+J6U`r}I zcnbZ8Ow#b2ynoIg&!4kNW3feb5iGVWSCUB3T{d%5`toI2@1Ot5(M;#WQsD17#Z^ys zahJwdMep9am5nH~x}ovOT;wd&j5usOXD34P;BfjzhVSWyTX!u$i%k!SXFQO7pQ&+0 zQ8|WuwPe)I^IM9T2X-eCxub%d1BTIMSVIfn`{oc6Vf))VHgo(8 zfPrqy-}WM#UE2w<`3Z zllc4+GZys^DB@ecg$*|rK;%XrpIUElvFOcnr#?)A{`T@`e)yCrMbBOt+yUO7H%5L< zI!njv3@4i3$P}MshbOk3&5rPjz?#2hOD1Qo)#l~tTCHaboO?+xCv zjTSBW)5(L8dST;@Nlw*5(l)fdNs3bGJB)pdh;*^*Is2<&p}TiVVS`p;8b!fZ>@A3j zEjetQAe!AojFV`myP2(3t>Als<@uMa`s2H(=`G&>!`M5ot!Eg=B^g66qwMncf1k_w4JQtw$3Dgf|73l2ia~nDm#ECD~)yo*mtgF#D0X zq*TtKnF2W5D;hjgh+5Z&WD`N+f#ug=zgBSW@hBY8gxL(cJD8wVUR zK-U@4&XSdZ!mn@RMAw(qU@W()QMUy+|b1u3zXxCxI|NYw)o_ev^ z&g`J^gJoF1;;dLjPD{)WCz=)hJ=)H>Q~Rgnnd4n?zUbD36N91N7_CD&sYBzuD~PhzP`j}p2+m<3(KqGu01gwa z-fB=A8gwEGcldYs{brK^B30|7(gO7E@xbs~B)>OMYnPenP7%W!=pJkc!Hv0y1&*=9 z&#+Lao<#PmvMC}r3FcQm3vkSNZmn}*PHj*N5;^Q7Q2J$4_fKYb|6^Fv1o0;SueIy{ z3b)P7#Qy)1_8F^5#L#rYZoN?6gCx)K;0&5E=y!>%4!rDgfR$A2uzSplln6@_VZ!uG zbWK*M?Yil$-puCas%f}s9blbZmuuTm9;dC2xyiy>m5miDDX66y?pU$frq`KJf5_T6 zOiK%?KI=^Oh_+j48knR=i0E;nRKwb?Tj5a?JB`m6{E`yu_N3dWcW|dv^+thQ$sb!I zL}uLv42X6*)v$nwTm(m~ds+{$iuNku628>8=Pjd&GU32;X0U;XgcxqSL~(fSRX%lI z5dJ(o)aL%^zDd4Ls!c!PS?IPmcTNGmKC0mvoMTmPq0w%!jyl8^Me5$A`WlUNx@dH} zo1iEDH6-!5Nd7?Nz>WGJG8;^HAxyur-NC9smycUg-7UPf*ENn=_8U;Vsa)us7F1i8 zA6?K3U62@$Mfk=2uHpCf|i*O)N z1;M$E3C*7}@KB)hA|1|?AFX5@>8y@2@|^(Q&U|ODJ5$Be9a6jKdDTk+V_Nr;l4<@d zv#B|1H#|2mgReVM4=;rEMV9faj|L{b1;3$QTG=docYfvWKN;IG4!CcUVU`C6^4FMX z%BDO({2=FGd@fu8TddcC_*-S-p;-d7;j&?9)B`w_N$Hd3)irZkdhN2L`=ftNkpg0X z!q@x@G6uq`iAi68&MFTxY zoGuI;MPXNa)uwdMOjb{Deo4R%XI;IfV_P8{^$g5jD@JwUH%gBr@Zhz7@u_XbO1@x^Iolh=U}_ayZ2 zY9=O8h(6AmV0WC~zxgRb9_&Q;nLm}ezNxgzrWhN2E1$JtIs;U^{5Qp z_RBm(cPE&;k}akysJl$61@O5jSzhAEu0dNpU>;i%nLV|bkGa~*m4{k197#^5gwg#h z0FM0Opwr^BCfG`TR-#|B^5zSHuT?pgQrK^3peYLa?UBI3?R5ir8dtSQfh9ctu4l*j zF?I~*S`nr^0*2M3pxBitG{$3|$961!rZe(OS-sW}OJmTw01&1I1sgW%3jE}8_M%f} zep19!CdmnaUm;>@TS3Zb)f~$TM2wrIqH!SDZM!mMg%fz^>K_zOK;#9lWm?41A(U{4 z;iEi6LcX~i(Saec6zj#Ugd*fH&OD%}`!6ryegfyvdIJiu_Utz-{=CLHmEuxIj&6st zUYSd&Q)r|7RRYWKAJEAX%KmD)f*$GLINvX8}h5smk$6NT}|>-W`6HRCrv zfp;lJ*Eu?c^4a=4^^1?cvnj~v%vH!7clEMhV3otC7EGg4I@_$U>|a%{yvlKyCS_hN zG!DxIu|gJM!uAJX3^3G^Zj=GStf)Ed-R9*zC)VlON1oo6s!=D}8s)KMtbw;c`W4cS zAny2?LdIVPok2;I0g0c}Tfay~Ipkq+U+nURV{Yio@2KsLoflO&G z8I}VFBZqzZZf51wMODjP=oXMD(RY|H0kF(`*dxI^q`-%!jN=S4HZ?gZ6F;=Ys*ApIR=Xj~CWV+jYWFqe={g z!-RK8%71e4a)5u>H;0!EC)w3_n@!&zNl4b14Mce!XLEu{tn{qE+& z9%~y$hQkE`L3+6_DnmI;@nK_BTgrYVU@r4k56%S)D-^o{glBC6dyjfLAGJK8HY*q( z4K}?imbP4Pc*)C8iQJDG9mO=Dgk87Gmpjkdm4D6B%hhEL7q6d%Mkw;m2)I>TFVC|! zvGNGL361HX@?)Lm9C-^LROG`vf;)n-tDApL>~%hEd5^Ic6jz=fsgq+u;dy$PP7j{x z&OnC71R=0wtzxPK9`tbb^+p1AC8-{p1FbH_l7#VpQ8*Vblj|^u8Kj3L)-Zib&r%(? zmJ-M$VT%M2lQHf;qgZ~UH8BPrDu{=WF_MT*F`5pA*`b!Hu8< zePdn%q&-E*gnHKu%{q_ZPRWxHw9?Eh7UQlzxU(|$K2K=RW7zG^I6mjX!I(ydk5v$d zFOf!)0XwSpi&sR|29-?7P*Kquj9gA{jYlMtH+#Ox5$>w3DVChYsOi}W&I|YJ05W`I z;{=C6#h8jU(#R{^*9XW#qIMa{?hlHc}OW1~s|C;$DCoH{RepPPU{*VZUVySPT-LoytQ!HSM z1#UR?4?4HvQAxUL0|=dBLqEurYrQc0!{Zpi^K@Ur(|W!Tm}A=SF#JiHp6opF${COQ zlY`v3JMjytxl;FpOjm3_=iHQJ;^>+3ql@crY0wzvt+TM}yA9xEl;>d{7HuV-WK4CI zyY~;G%k!*-o;v7|GJb(DOExWuFz_1NmN8K_P+9pVL*jHe)u0a0EK(gs5Pn5F#RZ^M zp=UTp(D)u`$!21F4&e7hx$&ViT#T@FbQJ%l$_Wpoe;W^MIjWcf{DG z;4*@R0Y*X^LH3)_Q08i9>SJ&_23l%4bHvhhs`{zR!{4u(}y zeLjsrLK@I-A1!!|lO^mfchn_L;eoNgQ|ed)yf_$ZVn zP#8pyoF=~@bbWYS+PvZ063#E6@&+5c>22ZM)a}7u zqjWsoGK?iTm4hcQDE%dV$?OuvX4V|S1ritj5{I+NhhQ;*3=OKaA4VNg38X=S zOX`Pz;E1SI{At3sAD5=T&iFDg68wHBle^gn97I94L|V#WnWK0~q#+XZB%A}kcY^pU z&^WO1%@z=()8tRZ6%GuE-s4H9bZu%=#v9&Nrb{awf5RD6x%c>!w`mUJ$njwG5IC5d zA}?gZkAutEs0fShgcGHlC6Fvc&}#E!<;mnxCt)SAr(!VE{mKB(vwuD&L`q_Wh7y!- z?FLeq=f#c0zPW^PFLawrAS;HCCCC*cKy^#NEH|W;1}CUD9dWG3_KuzDR1|8a3(W$N z7aNJ{%s`sFPTPDXr{(Y{w0G*7h=?`2slBEw5K>m^y#Rt;9?a}c#}r^*etcLt2&QLu zdrEiyZmfs|^ArP06|1%7m3V@kYh9qkgwH!~=etggwCw zlPP`)`iqB&w$6HKK&}t}fE!|ROL!@Y88#lziynxBl`@~D$wGb+SkrUKJY;4tSMmCW zt`C&GWV`WSE294$c87(7^MA_Ux>BbjjQ@>r_$PmBZvwxU{iHU$=-GfmOykUibI)gsnMJ*tf`ECcy<36-E3TM7DZp$1bBh2sZlHS zB}AY+W5imjWzzb$WTME{o*C=4NOKjdx;fUwaPqe@aH&z&IK12I>lx7iS3W;FzMew( z+AmD9!a-kEO1A=+se)E@EL(o0z5uLgPL&1bFg)nakA44U3r@o9FyV?Zu#7dyBjMa~oPoGu|vB>>%mF{olp zUnG5*Us2hR&V^=HxiELu$n^O)<#i$G5CzA#Jnr!mZULzVB)LpeY4i+0LIS<<8`-!u z)N-b7Ue*z&W&aY`ktmHkB}jEe_N;+=;b&z78I;+tBS^U_fAgV;|1+Th9QRd?a3xYLLa1C9szkXoPcH;F$(?&At8&!Y=xN74HpX0uMZ# zpdOVnM&9(AiVkO*V8+@?_y%&kS|?YN5haTe?_Chi;Nby@ zF$c`x!4x@vOa?r?2KiwMx_((_kcbn6#o$^uv~B}YR$ZJpT+JD<0byBADs!)GAoN~O zF3GRM+)Y;#FDZk0_B(VlS{B+e8U~Zek~nHj=mNyG-nml^mEl>EJ_)!2W{%2%fUX^6 zC>KriFc)NKc!%77p~SDl)gyl@%$I7!)z*yAL#2<(Kp1RBY^5~rVoh-k(^#4(dYq7+ zB9Thioxx&MMt*Gt^m6QvpYFe-NYsdmLIKuXPS4h+4g1A`CQ72;3chSE3S!9A#F|nm zLCY2TYW$BwAX~C3raA!+uFhep&ylT3DyjYYH-n#Vj*%Qq-$6CX1D^OkcC6f9^m}h9 zr87HaXhwn|HIFq=eF1$(8G?8bc!Uj@83~~^^cJYellssOb?$&+auH{pXc`zzC9GqO z=nDwyioVj}m4ID@548}q{*df9$m5t33)^pyEb%{nCAaq1uETIrznd^ z;V~l$?qe_Fz2$t(zaJfQLyI7dxf`X1dm$NW3qYvE3frE?_-IUDOlD+F(M?1zotDZP zft2p%P29+ZecQc=eo{8%(d!yIXrZ{N1BA&%*zQKAt8`U?xu7cqH?N$L(O5$=rs(zs zmNh?X*u0Oi=Zy_!tn^LpKj5vl54D1d!m%m&#tDMJa`VG*ssq_!J7HitzbO z>iCT`{{8FcAMw-tx&>?%*}_Us{TT_DIDq!YmZcoD&A~*(4$Qk+; z@ExOJpM!ogQC_JnCOHEHE&wGxg?eKo8E+AjDP2Ta74G@E&I!60s5eV3;;`jY!b~h) zTn%Dezv^V&=qjbfj#k4Y{DNOBnaI#}`LO!%>>wCZ-p*N!t{uhl74uitysF+Sib_;7 z)P4;(`fRPhb3-LPD@rTkp#jyGJRwX=mCH7z%kn8APDpRobJ1PIFF;iB3hR-Ly!QSzuUUNQoYm9P}s3M>`=tMn%f8xio$v#t!=0^WvsZw`5V7OlO|Olb_2 zhboP08MiwKF5WPmoFj~8Oi`A8I)K=9y5#^G!;B0KyUf-@F<8AeRs=%dnSt-nYS{@-^XJ*xb;_v~89w9DGE-8GBRqb!k_lB`J(} zFRlBSLm|53J{$=eHmO4;+6?4QVijOnV@@nBtV@ancz)vF{8kb)qN3pnM)b0mB@p54 zbRI>VSfLiFXj?=dEl56m4Nsw|#}Y6N*=x8KK{By4yEzqO3OMttLPCLkvWD#4h8+`{ zvNU}}pBb<`*7{^h=tVrga+mZqW*$rT%@n`SJRA;O=~r$rXX`fA00>YnL0&ey{y@ z|9Sa0?B*c;r&%1pbG9D)^5-q|{Yq%jr*AkvjM8HZ!>(!d9vHFB3yI?C^k}=1?+D~QNyQt&M|ZwZIV^>wRw_Q- zEi$%7T1CR5Z8c$Fg2TQ69P>`B1RnxOTX%p8u zXiyMx;k}0FhC}T^v@h$BjmT{;(G5=-wC{6GD2QrF)p&m2Aqz=7G|_~UT`o%oh(c`W zShdK4dQTJkLuXgL6e*ObaL zs-Bjj7Ln!xRr8~Dk8U(t^mz;It;!4l7`FI`wYT{>#qRGw4^`(HU!JgqX1uH@+aKyA ztbXh6)rAdt6r+iCqJ>HrMr5g4q=m*dDN$iqYLU_VGB}qBaRb5 zAzf*5VQ0Z;1-GJj%jP)~q3&W(WpHbghjSUg8~^58YrD~B$oBYbRtLD-?NT7%34P$5 znw)UyK>IGb1H1GBU6FwK0V%H~Ss3-WCfLqSMYmOP%*^tr!qPlFaAB4R&wN`a`FVD) zriMgZGKAEQ1H|eKk^@A=E5h}dk)XvF#pn=8q-__S!W~(R9-bG z@hpzZJ`&G~G|7hH<+V$80?}yEYd5p^ z7#kZsKd}TdOyRG6N`$Ak%*f77KDiE`e`-MFhgUR;Lchgdsni*@!GL&vhe}r5ixiJQ zQPHK7h^GR_5JxOxn33y?4RjH=&rRx`y1bNJ0fkujO;@E8KZ)AT%^a2OFGNOZ0|S^ z>h=;QsFZ%AmrB9A<3d#R4?%!2^axPhB0;#L*#!@23KqhY}m$AbIVYfrk zjxl=i5-lxWZ`dl92)mMuCTjT&HQCqtjB(2$KVrLsn6qa+2T?2dId+ zfcRaSdI-gDQd=M)#n9M|2m}RMYJh5l_|%H6+bCU_D{bM2=ws47P#xi zrC>CuWhq<{RL@_%-UjgsD#q4O`i$ih6zJh6OzO+q0ZhB|wheo(NSQ=xs?XJESf4rS zy9&;0p2dG)ZZKs|bqg;PsLvvByA|Y>xk;Kmt;jip}|x{Z|KHmAe2%@kqHx|+eC_e+P04R2_pM^ zZC=gq{IqTs9?027+M%aa!{&vg0ne#2ZRn@$NmORweyvt+Z@ zM)^EXr)x+i$tAIq&}#Uq!-VT}YUiq*>;TPEdpTLYbK!tV09sOXSx<4{&nHgYKJsv1 z&kb=@pzi{2REBS^eXcx7oo=3bRosI5JA}+f0lr11R@fC z=Re^Ou=r<>$?2I~Y2c6CLX~n45YU+3(6O~Fm(I()zeH<4c&kXGk2e;gHx6D5kb-Ntj)vIjInp&Dz8JOul3S~bX zuk57PS47=VuUpJvD=(o}wV#UTK>AY=mW>ziT2nqiTrD63Za?su$Amy6BHmWLcf$bl zeLy%mgrZGUG&3`EbQ?}ed|O`cg)i49toI!+@ttdLYUuSuxCvC^Z)b;XbxH|JK|WsI zzPmHAl$^@Cn`- zgpdv>uVbo$#U6xNgM1DN++(%J$pSm+d%Klw1E~p&?Z3JOedY23$Meq}Y=qzsgMd{K zfB&qZ4D#+nh_CbDKLjWygRC37PL# zH{fC1OZz>=CCzvYRD$Y+$LxnWIAvI`4yXcNfx8GbF$7%$x%9bYyyUzjaK-sR6B{bu zpR&JhgTR4L4W%As-J975b3kqbbfM@%+XcQ1Hr}njB6;!lK>Pms6O&6Wj_eHK8l*1> zV!)gqFelh1>@MyuLV~m$zA^+vl-d@qF2Ez(C5S`XLp&b$C_z^wo)FiR=p5vn;~e`K zAx&nLh&zsG3=AM|kN1lIO#4&~ATl7?BkfOFqfj87r(>kJ6GWmfCp{x+S7j1w(7rD^ zgdMk_>`H1$ibPSe3{*~DqAWKk*RY6aDsRelZg8%5PJC23lfbNsYKh8((IV43uA34` zXM_@*&uf!cPohoom>`|tKowff_fSAC6Irq=`&z=(z+5+J$ZybSP-!qT7Bh#C$vhU3 zDoCD_oeMF)Nu{87&>YZcFp`)|=qGh@jBt!`#Az37S8eBZyg53%x4jR)?>yo@#HY+d zc|-+4VM2wY(pF4UEuz|>YCwTTm7~~E3rK!U21#C_#8o|4%1}{Nc$Sw{*{StX0B8o6 z?3X3vDV8{@nn)%WSk_Lc&?@nkzDLnXxfPJlQ=jraVzQF5%CY8aR%`Zdbaljdgn8t6 zRK63#27n0>s}@QZY8ih6#2N^n8$1oJFL4OEvpvu~kRwAQlOTH{gO@guR!cihcTNAc zEU_D5s$}Z4k!5pZ-!-ceCeJK5A>zL=n@StJmsEd04d{6Uq ztj*HqeiVmoU_ViG`_&(V1?FwTi{sIQg#Psj?=NI>>2|o45`!9}yO@ zv2t7WMu!*A0#O5jvq{uUW+kK23U!67nirWAb2y3%Gdcz?(l+9|@6l+5(afmJu)@ex zovzBe>cm>i71J}qXq56udT3)fWkhylefTOoGr}#5J~sEb!=AdG9+?N(66qM}3n`X_ zjwG10nd~5;Fj4N#*gd=}2PHYFD#>3ta4BFZo+Y!X+k)B4&PRwVsfVmvi68Y#`U%n{ zSSz>?^BGeG(~en)SH5^8^r;y;50(+T zgWb}4YL}yD+-PxrI%qmP(|3${oO;@`o77rLt;g}ZmSPb(9e1nL!ZaMQYV*;>rz z#P(*_pvUMZMlSerz)FNn=i`s^h}urMV~u6CYQ>HM zubZE@{%zhte+t%7MnT3)Xj|y@ipNsRs>NzD{s_(t$7d5?Q_qXl$Z9k!6s!m=e(Y^b z6b>xU#-jQ1+FH?)@&XJybY^Lc2wvw~^aXo1Z3u01b<;}0!QZyq*G9X-UR z9NiD;KCTbDi#+LX%(ilU>&^(@4fcr3#g1Z=@m9aeUW_inj>ggzR_A-j1?2Fe>PK>Z zlD-#1?>KF<>=Cc1OE--lOiTAAFZzLte+=m!T1{9{8Pn0AG)` zxURa}%zxgYm!OA_|C)sU52U4_g|m~qiKCK%jlH!A0mr{o)X2`*M2msoKZgAO`_Z8n zwzDy?u>H?F9eNSl|Fh4;%A)h%(p6CxTO(%+J6mOdy$JyW{r@o{v9oj1D;n6E{eQl! zWZ_|=#l*_0^Z&Fp%y)pkKtR5Jety2bzCJ%c-#ziBa8=GtEo2zRZE350v zt7}Uut4qtPi%TmDi_7ziOLGg0v-69ya|<)G^V73)Q!{gu)3cLPGZT~38duMlB zM^|fmS4&%GOIt^CYkN~mTVr!uLsM%*Q%ikgb6rDIZGBTsU1N1!Lv?L^RZU%GbzMbO zZFyBqd1ZB3MRjR;RY_T8aal!iX?amed0}x`K~ZUbQAvJbab7`jZhlctUSUpNL3VC_ zR!)9qcHY11gp915^vs;JjO^6(tkm?(l(fv`)QqH*^u*+}grwB?#FY5Nez~HcepwNK8 z5dXknzkpz0{~%w#Kp(#VZ{GkfAAc`zKTmI84=-O2PalAXx4Vaz8^F`e-P6_0!^I8Y z?CS39;_l?^=IHF|;N)WO=xp!cY-jIeYwu`d=U`)NZ*605Wo>6^Wouz&V_|7+Zee9+ zZe?m_X<}w!Y-(<7VrFD)YG`C?U}&OmV61Ooq^EDFt7o92tFNu2ucfW0rLC)}rK6## zt*)V^rmm@~rlF#$uB@V_q^zo>q@t*(te~JIFRv&krywgUFC!x-EiEf0B_k;*Eg>N# zE-oo9CLty&E-ES}A|fg*EFvT%EGQ@>ARx%kFYt$tpO5zsFApCNHxCylHzx-d2RjEl zD?1wtD+@CVGb1w-10y3n0|PA`9Stol6%7p~6*UDV6*&b3DH%BlDH$;dDG?C~0U`7nVp4R$;Ht5Ul7v&ClVQj{%3?00nCzc%+jyL+dBFBVD!x~ zRMu5mR#S~ujuX0m8`Z7;CD3Y#B9T&ULNygd_UJI$;iVb z1Q=_85Sv{Jt?3M8JOx8v4s0LUuUje%=6pP<|HkHsoaKFIJ}JBK%)Nn~{oql_?5J7W zYPMJ;`;2_C^ZmO+zujcjw`Jv7x7s{t$j5U(Hxs*MfywvWR}-z*R8K8)RayJl_YV5C zzdSbCJC4C}xV@3OL#^jM7+Q0_(Pg3Z0*l}6c|sT4{IU_N<5|^uLyxoE4EcS*gKX-FS5Gp>ayL{eqof^!Pnk?v8bcd>f+*^UwJX(=62=fxtd=? zC#9BJT6sYS(P|~Nx~x-c`~F#STawEDb#YvsiNC|s(|+G#V`rt~uXDGL+RGA!*<;s) zaWI0l5bA}#w)@@RTH9^(!5!|_ptj?5w7Po)NL}ImzMkzp$$0s_>vYzg>wfcB#k1yp z`J?ORXY)la!}f#!2YmNiz-^Y6cX#a`?veMD<=Nu0xiWjz>lq8!_m3@c4M|SB>*L1J zh4!lN^}A>7PdS_KnKyo$u{!+EiXX~GFI)4+s&Chh-Q|kWwuH_7!ltxL3li0DD&6Ho zr=zTO1pq`+(?t|_scS`NLZ0hd%+~0o6D({%KViiSg9i=!9LvFUyp!0s1^is#nEe11 z7xPS%*po{4avzBs2*;Bg#);QrKHBbKNud+t?d`7LY%9aNFn7g7ax~0)JAJmIN zjbHGu?TmKsREvG#??Ve`MvkM3ebiK1qy9_V5F*G3V;;CAQjdEU*%OtPprb}e0WzfV zA$Od}(Zc!Ph_O+jfTaQTafK|LW{wYvzru87)YIXh?jCMhj92ejPldjLx~uQG=zNiS zZBN6Yz1&deVH(ZJ;~Q&Lp2>XhU2^riZ=CN^XP&{ed+UqmhBgiI7Ro0Tc@bM|9yiya zcERLN_^djwx)7g54f}&c1>~_O`V4sRPXj{AxE+ z*Xy0-;)jWf!6kkHUJdN8))W5M$T)o2Pw%PHa7dbB^-TP&>=cmRPnKa=BfI33Y*?;Y zMVXimkblqkyo@|$|3%N4)BogF<2!_MWkSOT4-xdq6FmQ2ghC{URC&wVHzS<$fmyMQ z`15i|LMJVGWDO>+NR~bt!O2H}tRcxn4(IQ%`r6IKzt_d%cE(J`ThJ>*27BhgS!`&* zIUp4@RNVIa7t&OlC&sdG3{H&ZAaK?TGvOa_^)mYj zGqv;8Kz{6Cfo2gI7MT~+7#u+{LAHhHP6@NQ5DihsX+p!YJ%v{egn)i`pojN2em{uc z0Q_h!lZwN^?dhXAwR$zZia!o19Gxrf?eiOWULGIqzV*dTo zT}mXI)ZJojN8*X)1#szT5UNr&Dm9bJYfaGP3g_Z`THa9gd~MMpzoU+iMDl9xw3XT4io>OQTG;;n=fjgJP8?F=a(tYEV%K3&c;TG)*K?g3`~?jr((I!-ya=erefx z=QPzk%OZb~%c<Rpo;xqE!TmEBAF3wiVVL#PV>;C*|$uG)gD_*v=Xt^Jnx-8lN zu~f>*5>*=u?x*y!wC`El3H=c01_W{38k%Kj>dyM}8TuIrB)vIzG5y(5ZmbM^6+1?3>laFMaLJZ{ z7Dil#iU=4|jIlUS)6{WfSpv-js@FYepeXj!9&(AE<&55`?5`-mndMlC0@6JUGzJ+8 zoM9AqGAr^C@5cgoz0GF%UiQ$;o=_~@HBcaT+12LU)x=Es_UqyGGVuwm{^5Yrj#}M= znXyZ{Ivt%14UK;-VRz_z2>4c?Qy054#-=C7CPs*`zE<8UQ1`$3hU;DWUC;!Uo`$XD z~T($IIoaqkLf{|M%O_hwQS+rXtMy2e+Jmuo0TPdxFp4#rU=G+}^LNFpMl zuwwnd?~NH^^psb9ShP#mE3;IXl13-Q8gXgxi>7ns>^ES*pRRu53pqgo)MWT0t|>f8 zus#m%Yc@AO7}0D*Fp#}81o-qX7lNzQXeG_uexsruYwsp>(-ynj7vRgX`70R+n0|;X zjCg+G2vv0XD*@vYJX5G3EXA@aTC>EE#BPS;-p=Sx;%_5cY77_n4>%*fYOsee^FILu zxm<`xlS5u*BB?l}W~TBSzb7_go}hghwS3Wvo}rfw9_Jw2d;%y%{}C~1#HgLhp3NcC zbKyEPhk~Sd6E?tykfzf3?U+n z3X}nV5m}*|x7UlxKo(kS&c$i_pxdwMjP-pNbv84#yF$?A*}=%Em)1hVA(!B<$%5t$ ztJ|r!*a+w-z8Kjii@<@AQ~Ld8X%n7 z3v}m5C>Ib@N^zIYrijt09OF}OuH*jiM5K{gQ zKL({3(7(vgHbf>!@Fvzj2!jV#2lL=zkA6(jysCVVMjju)4ZB0T)vi^=6lBuV(cBz_t90y$f4*|K4K6W_l)FBmIPf% zK*gtO)bqP z1hLu9Zw=PnR1uk)3ASyC zTl7uNZ$K(CIz8sPjBKl;t3#Lwuu z%XaE7fIUKkRkxZyMlA-gBO`T-oCJMKOwTuFETT@h2lk^KtWBcsk{3GZOEF zh7bJO$-`U>g5lZ!mT;<|8l#iG}9_9 zb&t_dJ>N_I_Gz8@cA(6aM1P?^~mVe(?Q0Regsx z?}Li-a;tInV0B}soR@)x*@b)f3fOwH=#4Ugb7md>&n34?-sz90r;qJh|cTDu@0)I*F<#g5J zPu_{pa#<58(eMyThHONEUu3$XBa&3*`(#l)CS`*oKU|WB)+Wn|M`5Y{lJ=GHg&}}a zZ%wg6)iIhx-k>pi^@hD1Zb;UKW)Fp4jER73C}Q!nn0oIrC6Os7PKgpRML~HVwMugy z|Lw|Z0KxRkTnxlAR@|>W@U#P`9v*x#fHPP! zfTGx*vldE)CiRLYoaLjFbPt0co(P}IT`zYXWD3pWm4l0lTLp=H*|ID=n`=}3gDM^) zkv9U~>m87|nwx}46nA6*jjCi>6PB8x6kUupXD7NP>lQZDL9fbYSuw(-5RX16Xohic z$zdY0`XeFI)2K=m*~8QsOsO&mYi+`)lum3)J$-gBA+IZ&t1BeODD{XVJI$G)>TVOM zfj0t&=Zbqp+Jth?%WGRvLFg7EFLw0hmhTqw!i1Jp|C{%l0OGBCZn*PQc}48CF$#&& z-<%E1rs68KW8lZHD6DG+>22R`ow z-HjG!2tG%>@lRlOnpCP;IA&VOxdhkZfn&Tb{jUysOWHIta>Z#e?rs!Wmo&Ein9i6& zF8?-ayx=51>5fD=YkiJWEW#JEOB39I=W!3yJIf=3V23!$9?vRS zA3EaI9%x{M`-r!Ms(w%%io{^`%KFt6R)Jol&xo`6)OnqL4?oc`k~5vWsU`snqAmc7 zH&q)6yKPAvz0rao;!GGVGq(x93VGXeBXbjI4c)+>zA!Z(FbiAEs4_6(; zqxbtV87gO{E}hIk(+LUcnVu2M#rQ&?-0)^d@UrM?Sk#=5XO!D!lyQ zuc1B$z$1{Q7}(A34-ZpKuOUXHV%$0r%&0&BNwvDQS$}qfLsh>u_Slj|D+M*WY zudwH4U@q}UR;H@04XjuW+C=L6?b}PFoFs5D$qCk zW}bv(F&s&~4T?jtZSuZyXL&rtw zsw)?~h>4=P>5L^;+9&}UNt9hY<&b0ZQXmc5sT~+Q6wm2R@;DDrHH~kql>r< zrD+g}J+nj1mH%jz-}sZzgRfhOrQ}WtF(kjh8g_0HHa6Vg&cN?9gCUHfh6tX-B#lJ` zEetvqT0$98XfP7T)}fgg~*|TWt_%nlG(9bb}7$4ylJmQf$zm0nZfkJVDEymg5#R7*iC7$A10E6W!GTui0!(jWpZC z0-A_o@B)XkaHvEP(zuX6kTBhNh`c%78^H{ychewX`-xZHagZv7y{nQ#q2*Qiql*j+QxHxMs0%D}+uTNgxg; zDi%-RsXL5SRFu1DppjcxWMnRIZmI5`nHn{OI2w{INR^t|cA)%gEn?45#p3A#Pd>~P0+@{euXwr$(CwPV|M zvSZt}Z9CcV&3EfQoQJQ@JylaR(>>i?GgI@hdaWO5y!RbDIv)5PVk3lBPcbeU5LtK9 zoScc-1yr;-;=;Ze0;AVo{S)n-k9&c00-CbFtrCFDqN3iFvh(bRk2yzE&!_G|Nk0t) zgR&u;UJBj{aYyBS8W0#?#gN9)>qO!Upm~ZMOuGx9OYfBF7o zD`UGc{21H($YTh3FXm-mKIJa zJ1%v4&%jQKnt&aP!Xf<+jsiFwy->7%1P!{_F5#&z3`f6#^VnS&&s6NCZR0}*$ewNEnCaRKD z43mOT7|*=N!vMMFQb1v9B}`MA;^-1*RfP4UerYkwl2rpIhm*F($D{~-%;`itVJBwCD0g(`q&`4Np6wrOa7yDm2TUk*1 zzT}4_3jSp5N#f_Hr8Bck&};@65A7u6gMaLYMykJsM8OdmN}A|8|0r3XHnxO8BG+OV(=(8*_n9 zf-1<3O7n)=t=M%6b!_cs8(C_Yj}lAthbVLA>sL%Ciu2BUpe8<3E$f`p0Rhs zaPJg-s(l%kIJ|lnJAEw?D@K_NP{0+n3Xg_`_M;e$;LYID4#$hQIaZ-{oo54 zA`Hz)+$Dq~jQf$O{vsteLw@DFKX%-N^uWp5SNNA82}=5#Gv2{rL17{BLT?$Q(88eM z&9y(Nd0~lOZLP;PRzBjnJZ{!D>Sb0q6=OA;t{GNrM%+?h5M;y@xyM0~v7;4t85MrE zj;wzp6$T%v8$xFx3h;-xGv@T7n*>!r+pijWu%oo`k8N&#>wF6Fbalks)WdmrYkk+Mq%+taq7%wAj z>uSpg7hCx-k(UQD%}Xu2kCio z_zd$CulO^s9OKcP#&QAu7ER-gb!`#em69lu(M}C~!9%YSa#t26wAm?4sgX{|*0t(@ z5-exk->(X8x2;}u-CAV4wOdwsXoAtylq5sSQ0O7j1+x-57$q??ed}f)A$#Y5E74Cf zo>|e&3ZKbC7EgF~h-%_nb+`~fZ)o(o`@2!-=G*%d4JF~sC<_JE38SMfP`Ne@Ly*rz z8QF>*1L*n+!Pd7>X2+vLVzv|bmTpVz{Xd-Elie)YMUu3Iu2yr2C=PilqtZ?GqvqEz z4}H;+*Y=*>UtqC^7$R4D4B}sXMxARh>m-?sp;XNkR#4Lyi!fY~TR zO3h@+KY!4no-U=Klo6dK(Fi<%ZuA%NSeF!&ohkID(HE^z4=c(g!&u0Kq}aI-ZI$Oz zl&O+#1tEE<{3(pZ>rBd!^8QFSMW`mqI3UTjeV7h5!9ui=^y7;D!HR?>I(QCWil| zNXnezVUN9pJF+4{+*K0AB!5WRVZhcnY3v`|pB8}Dzr;^_uu3p&wy*S;W^CDDY}rS% z8%f;zY<c%%k$OE3vbWO z`V__n_lPM7T8_&l_wt$qELIwON04|C;z5$XwGpS{Tw%PY;}6Z8w! z4T2L4%O{#uD8rx(kjy`rg)D>dM6U3!$j1nt_2B0s09^;+ft)%*J!Uy+YvFD$wwt)B zj@-yuOEJhY6vmW_nvjNTh;7PtLEr{D@3Xi)a80ZCVx_ zxrV}+v-~i|0I}u)%#usmW~B>%uRxnYZ!MVljt7&0bnMhNZo|Nl>+9$rb%q?TZ=?+g z4yf#|J7Y6rhc5vaa)gNCb{P%urIC=4!atrNK_x61wqy@Dg0OMrY8iE-%Fcq5+ZI#V zWd=mJ{CxR&2SB;R&vUVkn*g3XMfN9klooqz|KZ{wnJ!TGG&VZQ$H+D`MOwj0I)`5;Ofl=I0 zeH!aAR6bg1=2L0evwkEmjDW_O&^$GaWDWV}!@AcLBUO&>Eeboyfa7MDwn#3Uo>1 z3LawFcNl`G3tYvc$-wt_o3Hu3x2xucCmX|v^@S)CH~$~(>9VYZ~6(_D3ZW+3DD^$l+vfrMsk2k=l zPl*A~oWHJd@p1%A6G=nxoX$i!HQ#2OvGu$2`E2H$Xifh!Keu2_TtK0mk~wwnB$Y?kL2nUsY$`28ZbO` zgMzeU?{CV{&lC$DCdS`8*PWVdvC}KrzX8HPk2)~!gABP3EyCC zjp1TU>YP~VuDb5?({pT<#EvX^l4G@N@#6CwA;wCUUl_;NjgT`-zbr#NSR+e^3Gu(l zEcvvubmzO|xZ;+W0*X8L=;J|a4oA;r*wvo35v|J0DV3uZSuu~CDUKBLD}I$>O*X0A z{+g+m2Gitts(Carb|HwH(zk=T^;{||*4dDNSaEK4VI%B(Ml66<+K}1)x@B^mK103^ zZ3NYx^pP}@oK0hth^GG&4Vld%a*Mb%lQ!rrgFHVv_Pj5RLg!s#IRnNLyoUh zb=KF);vWO9ZQFy)4&1j#&xpuC!JQ_?Kv@-3p6NE4S#^{XMG%P9ufxj#XJ7BnI<-P& z!V-;PLDi`?Grl9k8^59dE#DgEVrCSSO$5ajKGoNi3ALK_O|r;h#)`xr6yNHD1nKD& zO*?7x*D7pDU)@D@9$0DRCN8(G1iauAbRC=V{mHgVD?rMomlPGYi2!1J(C)TQ?#1rw zEsW)P>@wp6+1PgdxbWgIQnU+mS4K;%rcZBd#p>*S832#N|7Tm-(W?GlDM9U}Kjdp* zP3e^7Uhh(vS!9y1fg&3Jj|iB%3!=BU770=wutH>e%rZ=T9!uivd|>+@IuYc|qB1O2 zj=}z9fDJ!9OrO0RO1k6*aH9G+o`k!p|4FCI7jUQXbcLDxQzJ9&Z-1a%t4a}2!bsiF zu}2-KViaw^FI}R@&G`2S9z>Z|(s*ZWqHt@=_P5_388wR1rTBZ_1!wF!Rjs~vl-^Tq zINAJXt}V6xFn>uQ5|`OI51SBMaaZkM;vnu`Jz;#QT@&{#tng3?bjATeSW4K*xPQ=Y zhh`c_Q@dm9hma@QFGig$S20JBrt?-%!E0{Kjd1`i!OptMCn~#)T47Dw8kZF<5@M5P zO+v$n6XbR3?^Ud;Jd!^S%>$^oIf4m$wlp;G)zueSht1gwiOeF-y47m3jT`=5)h1<- z@#60^j?$(I=`N(nx|IwR<~?Uu2?Mx7jAH2L^6rZSLZkGR@BB=57;GHv0Tb*M3ccB+ z#fm`{s8?H!`WvD=+3KZQ=x5pPnj`fouh>e4{4Jh$X4YM2S59b?jH_I$e86vE5a9^Y zHQQ~v;s68G6s9tWSiqaVra^M<0et10LA1^Z>#szrMQkzduZAFk$y*L1{z5(*QFBJ) zX8)>j#Hi9Vlsw+~yC~pD<5C8bEPCRy>O)R5ysH~*P@{(lJ*BD3`rW#L$k!}eJV4WX zc$8mq)no{Jh_ofuQ%;Q8ZbmCt^uim3PDbD;bY^8G>!#1~uL=GeS)t0dh7oIqw8>C_ zK7-{OYPhVAt9*n;u93QT4ljB_?uHbgrz2Nq-Ss>v59PPy(vZmQ#bCWK1r}X)WfwVU zVADi~i}5F8d~101P{Z0kEb%JD)Y{&Qj2AGgGX1MXZ3~z|DXDP7qJL?k?l?p}6lQdi z3!U|p2<5J--H@pllq4)=MHwTN@jwzT#Wgq-wa%gy_2<9oXf!|*z_#we{^6e7uM%Qu zj2EGw9e1@Jstcr~J|&1;4n=QSyOb_c3ubKK5^#{hV=qMBCh*`!<;BZSGDHM}pz&10 zcPW`%wT3%MQw*hzLU`|^S>g6uT`e~nU17CJ(|}?bxH<8759*{_ie{1>Cs&SYuLFv1 zAPDp}Id%4r)rB=ZO0f=eIR++m+~Yp}eDeJQ2g;TG9s6ISQ;z>rbjr-i_P<1@*2xz3 z*hjd-M<`Z$nxZgZCjGRRikwMjvlK8Wp^P~BI5rtT7KX^u(nu3`Bx8SzmYSC9JJzLK ztu0)tu9J-~>P#efkxuaACLqNqoYQmqWPd3oSlygWUhH-PW)t_!P!+j<%G83_yhb_*|&;>qA@%ot(L z(6eBsvtssYXRdXzfU{)o!jkC`J(xAWRtzz}UdGP=n^H}68X@BHbn|}Zxlak}aB~@H zw6pkzEAEw*?|6b}soDO?Elf;tx!JnfLGHK+wLSAaUd31U*hZVXyqwkeRqyz`-QS9d z7p7CT)Tx@>9d4S?yOF%!nbpmke4j`2<)wn}R6G-uIEmC3eseYWXlOhi%;19JBZ)stfB8<>B;n@xr7O}EVMq5ur# z1NK_+fy>R_U0TFort(c09>e+kYneo$_9pNDYDaW7O`-Kacz4vQ%f3o#Ji zzz4*^=K@4HXDpy!p;LQWeUCm9)u>YWn^EnWcOM4d#G!Qn90@lfZ{VFJ4Azr}o{=7~ zqw9;34*7~eA(lLI{HiG*%TTIKB_rUwfRV~iuh}miIiBr+YY1WNfNj;st#-L})KAe1 z=PSa$%EdY)Rfm$A(RI-S66lg`+<;6uo<<%}Z;dj|y>dp?d}w1*{5eR!Kp+Wj%a*>v zqBUDF8&|2`@PA`#_CQ8vpA4~wDWl|U(EZZ(p#o)jy?-$VpkQDV9T>&(m2D%qA~*jv zHah^ccxd!m!E*~zbt20uZFATTd&AH#(6Pv^=}^6fkqrdFOZ9e=3<@1Z4kFd;Qz-KvJai#)>!Zc6}+1C)5c%njnplqMw)swWBnpPuWntl=)}EhZTpu zrZhU%6xwMh2@e7Ng%YMuj;%)1!tB+xsIij=eT_K&p zR-08haCrSazjMR#WK`~y&e9fdH@RfBWZ9%zRcv{7G?@OIoFBL5Azyd0WPrlhXUryT z;236X0Ai1=oS+o7iSsf564Y&^L3dIiqbiZgU-L*)%ATeZi6@A5bjVl~l=G-?ip=Cw zd@#Y@I7{QA;MMv>_vin_G*M}`xDuuoGVCMPTBjQ=lp8d9(YVDEL!{x@=e{;D#twA6yi(+FSCbTC>Q3>NjP69BTv zreqc0(LBysogVtSMN8i=IEu-fo)nUTm_}ruff^87^!N5r(2X@il5EbH5}k&y35n^4 zUbUU}N-oVmBm1~38asDo50>Tsd=DVwCY3?aDXUa3J{PY?h?r1kY*+X80#g?eESQyj zk?0!1o_S;Ni=mku2r=hP7fRIN(3&zmh<@x4ne{+p#FEzSux$KHo1e9FpUKEDUto^A z5qj=9<8;O0@}2DZ*7#T4AHV{_X@8$}0p<9EPq)#ZO5XRp%#vF_;*yna?d-j1WI#JS zl{Z)lPhaj#wH$lkJB0$Daf>iboFaBG93ESSZQQT*+U4{@?0z4!2 zZs1oObUvhs;Bxy%LxCp|kv205gtucw9S~Klpqh}CHYDuwr;{+a@o%%q7d1hn(^e#W6SdpE;#|xzOgv+p?~Zn&3+wKLuB7f@oKqo zt35xuCR`etLX?iPLS*RZC>=Tb0%Kd-NsP47R*oG@h2S zi_Ip(np5>NpDTQqCh1||)h!k6%cSs)N3USTETWLoTM;0%IhD(L{~(Ujn4BAoPDQC-hi~x1?Hos&WSY6o=@T~h}^XV1mz?i>D zbN1-Wkq9JK-~CiF17QrgOGA%-O)w7q)hDewO6cTtrwvJU{BUFp;@+t3Uu=O^$BbGK z2Sg(&5EUQ1Pgs=|(4Br}`=#z7A3b_Cev+Mg5us?`4TDaUyo!WnC2Z+rpJ=_BD&NVV zd7Zj5MwdDvmDibM$-L{4Kh7%eDp7{ED`}`pTi|Fx(2)Y{ltNDrtV zo;07t>4U^5%?7ZYyK0Rw0NnG?^oSyD*2w=7`AMr<*dw1{ru>qCmdTDY)oJ*# zJS|x;UO$u8a%5wc!Dh=E(#O{iy0e*B_Nkg)qS;6b=KM=-;ZkEemf&q*gdNa_1IJv{ zCxJ66l5iI1I!}5=oH$)IDp-1PTiWn`;nlNs;+6a2k^54)TdgrvSyuK>VQPA-KT~SuHd0R>I z{*0ZRjh(x;I=A-pt@l9L8m2aOz|)%XaMtfvJ6s@e`=ikVo;RnEd@s@j>?&jU#4Lv%~4? z$fa`mXvOC>O9}iJ^Sv6sjDhjk~r~-hl${5+QF((=z zQ-Lfs#OTmckjzCs z=tOdv)kd5>EGL<1*wObzs^kWb;&yTI-lFZMn)-o!$DAW;T+Sdrx*pCRh3xBrPU`S@ zD%@IA`MSGozS@_@%ueg0%o_GJC(P(A8?2e{QK4ez1y9nd+B~vw<>r~<( zwvNUWHX7F_2U8qWuTCEgx{wpEaM@`g%N-LNxltGGUG}lBTD3+xPi`L~ zY8&srKE3eGIDnPurFJ>nYA!_bpn>}EA;!j*%H;~J@g@uLtuZ{nOK0rHXq&V));VIf zbCCA_{G4bmu#9R6-1KzMgIi}5`*lJ+xC(J9qXcma^0Pro?K9t&I?-p%z=)6~h^M%@ z#Jt2^FnodGUDyKHfkG8WDhsicFT^1orhIGeqjbjsCMNC2Rw1###dF6Onl8()y{72N zCWx$|y^yC!8u|!R|A_Pz7u>on8bMsyXkyZmEt-NMQ1yesDx=$wq1Q1j8Z(BeG2ZOx zM*lhYvLvAsw_2RRX2WLV()0FUbJU?9#J4cLqHc)sn(=iwLp=td|54-tCmjnhFQP78T3UdP_!jumgKv- z!kNUN@oYQuF3DX4wrgv#TN&+oR;rCYXIiX6i0T-mbQR3;Z}CIx#L{{&OH!3y=rik9 zpnJ>)ZpcJOKP?_rJG&LiR?AmARUH#!@8i~8EUE)PQhl8kt$%XR>RVfAyhapwVnL-J z#e4JiW_1BIKG{6VQvgI|#?)~+24H1U)O0O@t@uT6_{$tNoo}f3$`@~A@YqRG=r#-_ zY|ICl0C;pP-;{tGl2MXZ!S{cmcg;d`U3uMe1?C~ue{xu-q{2OWY~JnarxsHl0o*ET z*6E4_!+~ zOA6xrwYc*@^^^H(f+4zOOicvFnUx0c&&JLh#zfof9F-ina7Fkze33oz~k z&S030-5N!ILk!juwbCx>UVb6&$hYdHzOV|}fd#9DH;|LpBFDNXMtTxKwL9rd&juCQ zb_nBg2mf`>ch1?N2P{Xw<1m$Wl;L0)oJ4Gpb{heaiLgw8L9Kv1My;qZ!L6vm`)_QX z$t)PmZS!K}bNf~v2Q+X5TyXZA*H2ss=Gj;N~B@12$)ol(@~SMWTdkmW3q3kHgOIhk>Z z>fquzXD7T@=r-??e@oQV>2!dy_b6TvgC8-HEWXPKXAIVzZn}yUJ&|e9I>|4`eq{W7 ziqmk|LtPl<9&h^9lvIL~@tcC7L!J@|$P*5v^IJIU%uj^+{>Fal*KMb!IPz7FlG-;p zGPN{ay&>t}JGV0=s-ecD@<46D0|=o8pLIo$Ms~DJY#}#VGnJyZh{@!ugBm)yGSDup zL32d{7=BY*Xa+~3ratK+JvAQ6t=?fG6MGq4d&xuZYKsj>bO%)Akb4{39-KjDXE16J z#)}qEz5a7VR(-2IbWG^MCq7EfP;w*l%D;jG#j;U~v~@Exg*T4{RM3Zg8z+-O{OYF= zIk+q1K{xy*uNbZJm#t?ril#d`^5KaHvOU#@!8~uk9??kduVa!IHl-da>|#2gjSbs+ zF~URNvjs4m|4|E(4jSPoI~!ikGd4^~j|j_dIbtvkhcslYA(f89CCGSrKQjX9F0lH-dRY z?Re&bbIrbjVoF5&jr0lS{w&awlwdU*Y}mkJG0-lL%JA?LL&sL+n=ZOOW4T6iW@71- zBY9z%Z1(5T3eLL@%8tAv>HE^Ugbr}y>a>T@v>(fmIXG%&sySSjC%p}3X}(u^mbG9$ zZ91ejZ`mOGDt)2h%9$1rZOW6XX)5g3?u6RZuOQz3Kpp}f*{8Rb*v}RF zk*^_d$gfMf^8NAdlmy%`gb96?$)$ZJOP4Hb!P7>0Gf_3IO`|1(z1?G<@EB!SANQrp zQx&m2U1^rKw7VN96(ss!pd~ro&TvbhcQIn z(027&qc7v^Ho)VqdgkaL0B|lb8TV`pcd#7sW9+N=VEg9;++a9)cj48q=sJK>uTrhi zu_9Z23^4A&h?E)Qey8qBO)4EZyF~Ao z#y;7dHgIOg=oZab;L?L+y3ES-@9o@r5$zTJl7Ahi3UoXWnuK}#Pc9avuz>TwMCAVw zIQai?0s@ZCf_Cm&^tALpowUqM_$(YO|G8#oX8398&B<$5iBhKbHtB?0iBSY zt+R=(vlIS*tXUQ5gdFYc|KIUHt^cgW$oR7sqYj;niLr&jf4d=X;P^8gpONuD6mLa3 zMH44G7e^x#CwvCx|HwoC^w>H7sD=HADkwWz*!-`L@*m1KoxFjW2`?|KiLLQ}Uh)6r z7t6rG#>VQ@{`d2pD%l8nTkZVxiU?5^GS`Fx&kkNAw8KbF|w82~4m4+g_M zM=$0hXyfdStOqKcPfHI2seUg?C*d(f#;~XCGfbZDi?P1{&S&8DJ{DH^z8;@1N=v_A z7WQuOa=SnGMs9q4-#YR6=5{>Mr!#Tu^po|dgrYBjS zZUj;`n|t(+`#XA?oF+H@7+G_`T2c5Yz$=jyXvVvhjVtPG#P}|D3`G z=ld+%3s_xvv!qSH8N4(AJ@lLew>VZ74F!}1J@*RGG zTss7O#-D`waeB|NbTudavci-S2+PM+lGL2on)kVIypL_+40qxjPO){lok<&K%bI8K zy&HJg>)4U07ykHqbz5NYxf|H?_CyH%!@GP|>^NC}Wrps=vtRfkLzm(Zg(=v9mwoeg zFo5p&vEe2QFNkNwbF~{e0MGXp$$Oo^*_{Z7S`k6RD~+yrrP#ymukZ~UsBTzu&N-Og;OF;+=y3{vf%#V${qz#{?|tE}#HCXWg-4K4%1dDG zGhj!4?i0ELanZTrv?bR)WK_*uq1<+vu7%7b%VRx_^8A;IlecHO7$1&SLG8fNa`!i+(egPCaC`oPiW2uRXzqaq zTPx??s^!QxWFqZI8_EaX6Q3U+@1xP_nihR238>!?HdD@BF7hPICYzVhx*ID^*P2@= z2c6yI`B7$1ADmE?hAW@KA1eMB@CPx z(rF~y6=PNRqbd$Dsy+GeXQSf``{~n+rFp6l9eChek;GVoT6Mn|livh_LM5**dHDFK zg7q~yb8mtXIr_CNcuIMV%hVkeZ`$pOqcU@sh|I&_3zGxhQR`l0*qRLx>0`8bb&A{$ ztK~fUws?)O18W?v@9!DZhaiP4KL3|}=isv_TP%hh(*v}^{!jU4{x5x=Nt$Xg7xKgE zBXu?Hu-^8mHSjz#4&5_OEX&Oy(Hw5C3n)_-EB9Sn9p*ZHeBb&qPNNQ@6d(SC#I@%5 z2!=!8K<&P5L1D^10iKgO8f<}=6lP1n5CM!Qa~Q+U9)1o4QMq+JFUIkZ|Jaxo@5LB9S2Y$ zErO*`q5L2VAX9Ro1)YLmwGg!Gjad&7$3BFT=#(&imuii0Hf#9pd2-gz^s`ZWiWhka zE+`c`sp|%{b4L}f2wIPzO;i(tSKYC{^9{YTqy+N1vY|ZSD*53?fw`fsJd&6vpH0Yn z2`gvfRNgKypsQ#}QZuYqRwYq5a`3%l;T2GYj{NK8nB>Btt_tu`L4oN{yUJ0?<>l86 z(ZF|XA%qJaW-}Lior#(K)AyqUh}OJ_6n8!Jtcuw5<4_WciGsjFMYD5b% z1K`)xp+#5f{7g!w*IXoMulJLg?Q4gNRK+*XcHa%~n6QW0>Ni2y+VI&wod&B})w3T2XE4Sn1or0t&ChLJb<_C@!{s3E|Tb zRA~H-IYbHU*(#(K4g%uitJ`q3|Lt$)IKk*D)Gx*+T#|VlZMWfm=RQLDqdzMTwBX>t zC%HSt5UQ2hZ<^xWc@)A7j92P@aW&k4r$tS4DvEl=(c#4Or=5;=kiI&O)chZ})2%uB zB(M$CEwT+_EKQ>j^|HYMM-s`$Hb}HkFPfQ*znGwrmKe>*kM)_#-%8hjSAj5=cbo!l z)K=GDf{}1Yq0Fl_LQek7YL*;_yqa8RUNmd(@}S|er%1A$v15vb1f&sEF|1Ko8x*Kk z5O0jI1y?-!ZLO!PZFALOF>Co-B-|L*feD4#BwMX~dE=+`@VOw&Mx?7{183=1P!S?t zX=na%4{;;DlH(B&y<{S>v|!r209*R?xIwdKre)}>_(~UgeZ1L{+j5lp?b9)2o= zz=<;8Y?jZd;oHuOg4x4zlMRPG@WC1k(%e&EN?xOiR z^E0`gG675GG;5uDpbk7lahJcP~;!iv;c!7x0#6kMq73&0S7XI2g zV~tcS*fCn>B$O|1?)1K>7X&L1wiFGVlXgde(@tOkIt!m88Hc;(*$5E@x?az0g+9t~ zccq*H;1tFuu|?q*02XRO=gOG9{E$-p$$F8{}zeN(|f4|HM8hUwKv zr6mDJs`=|rLV4Q~=%7r7n1=_7}#K{yD7-j4!ytYq1EYP}Ra!l?-PhdXM-R^?eo^$pwS{vl5 z@9g0aO)fO+ym`~536Dz(dZj$YxF3P}Fr(0rtVEGC>O*YJxsS39K=Om4Fs99nJ;HUK zq|4-boMg*0_jpRS#~sGcj4fhi1<0N3DfxdX^YE97-@x-40A`Sh1_Rd~x{G#*L>r~F zO7kQHKZ@YuGDfu(ktuo)~yLwMZ5;r8D!eUvO9czeVrhBD8icf{fTP*z!w7yj;Ic|(( zK=G`>@HmS@5uf1WC z<$YX*u^u#v+R%!4{yAS7B| zSXnv0?Ye8z1-ac#eWlj7;YoRgmnFPs9p0lod3>xO^~<2Myh@lXPi6lq>2+If zZ}Xzq@aA|{uax_1QMOv*D;c}X5*&%BY2U2nDcncFACrK`VoqpGO@Mnmj6VENM{oK#zn7mhQ}Dr=&t=T|GXc^38~Bgr?fD!bu+=X)Q143p-fMLS z3m-6MIXUsmdi#|5h=6Opp7vvhRx7x$z!Q7Cqx&>d|H!qY0s$+SUxXQ%(|WH*!i5d= zYtU)|bEqsn_&KY1^WcfQvn;E@VUOl$kR{Gfal^vMpD{HrOS(d360>vaaCcIdTyKi} zmWV=^sfNSrX21huDFt&^1SQnm;y~Mt!j5*SD3}9i0czzi6VX>-N0r8vro7br#(px2)G=i&eO8)0qT_ITJhkY* zd8SN7X<+M|>u@?Ee<$%$C3-4>raN6wJ1H`Ld$I$@CV`d=2y!e_4~&_ z!^!dN-6rvbk-bq-g&3P8R)HtkNxx6)?%sBW{W`KXXQwkQ%=3BR8`%C8ZNrj32zIy8 zpZ;#aEnIU3$vWpgdou_+CW>FCrop|3@(|&L$E=(18x0R-p%Bq#QnXn+YPf;+4fxG^ z6Bne6a^Zb?>#Tef+ynzPm z&z1dWM0$_W6pQl-Ilh~^2GIvG!g}+^wA(mUsgbTIA)O!ns7XpU6JHXCBNh04I?jUY zL5=!BTNk#FSPABy(~YPrSVot}*wLdY&cglKk92$e@ZfM)ndxlEad+c@>~0=5z-pD? z4U6S;_Kb{SW`zC;FIBy{C0+e$JR<$Q`$S6w_b^dIj%(@1r>)g*uZ9dWVAz`@*5F^pMTv-Ni;sZ@GYu`zR?hiLqG05FevNP_kPsq5Kn*jyAaSU}pks2l zRAo8_ow3+6g2O$34f#i1fg%xC;H{h2484DoZA^zwynnS|zrIP zjl5!Vshv8iZnSyQw%Ty|{mGLmpP?U?Su^ng<4lno>v9tP1j8^Q?6(^3q5fi>{cd$$P)UO9tichOn%pZPa93c7(pa; zSje&HwNzW^zh=~gln>k8TJs7gWY7Eu?G$W1A2~HrloDqLIG@1o$&urW;Z=OOtNF}y z;`mIVh6gi4BS4l2#-o`hK~tlIXB25G2eXcwT3Bds9TscYFjC8-*=b*1<*-6!4akVK z%@}T)7;XnqQTBsE_~22tn9?TozMw9x`1;-)xxy5*QDe4P5Hz(M@0l|CWLTSd{6>Q( zbBOZWUru1_#DaDY_Ti!+IiYO)+>vZ7Ol*Y%*4&Z?ERT}~eI?EHSLPy>zuDj(P{L#e znSxvxzFqDt9w$qOU204*L)vY$Zf=xyfu^(QwWMt^dJmR@Bp|gq4px_+U0R7znXX&a zeH=2iqH)i{UyeL?mgiOP)k`yt_y5cBePe#)282g4iwpzB{hk9%bt)8NL~qX#FS4Qe zyyKcG{;+<~WWF>A|dzyp{9!AZf%Z z%Tb7~eN|j{>2mV5D13T0<{#2}eiTj z#W!Zr2d3x{@a62MvDy-gIzi6H3;O{kO>wpn+8MQY2;pIg;94(uQu@fwn&Y&27gtS#jA zDIcvhKy&~6n}{1ox`q_iw&;PWw_uSXbg2xV$G$EGs>&EY;jdN+p{~QD2v%pPvXdjF zL#(FG!y`;kx1qbl;sO#pH^Wsl9BBcvkp@#)XD7|pq{*#?q_+TjU8&G;edY*{$~$5v zy3q{U;O2Q%e;Xt7b$qlycSM|Ej0m#Y?c;7H?z$`xqbx^xm}Fk`MjZc* zf87oWlw*ZUspJfy^{NNP=AGV4-0!2Fm%;O4?dSCcDzO=Pm+k>^^Ucil5|%?~5zS{;CDYKX(BSbif<}s` zS*1035}z!1hBfhN(5wbohP|exL+blZF+;cp|CxvEf-Ll>Rg%PI>CKq^)5eHRGNBR+ zi3zww?kVkK09~uREB{c%gdL|NtDg`NzzR2?`jZx&v#7<+p4Yd)N~zLV_E*WCV{Ko8 z;oxv^4($&L30$I%2Wzh7Z{b!aTgrZkt1JSB=8Bm2G9K@vuZ&joO3v*<(wIbxHL^ro zRF_~M6|o4y=dwfYh?T?}^7GXP&nO}WvO7=mtXl?2Z}j>Tmrj5iLwW&1Em<0v5{hWQ z@a${*$x{(etr&AaQ-x3;0Ocqv0Y`WD$+$qCu??`oSv!KH8ppS+5YO?K`<75sAKvWm zh=HxtCshEn`j66T%%VxpcCIW+e~j#4C>69{&GfE`C4$|8g;wiiAgEd ze%BNzn1~P(&4UUKJLzjPa2d5T&7c$Oqc(sK_R=AJ)P+3C#7!)8lMkj9D-TvlP z2>ZL*;ZIcnlwen7zD3Iuan1$g2c_ZHqx2zH?NT9ktuoJga+wCeUF?Y*53WcKK?Saa z^e#~?amHmi_oC{ira{;8OIu0**^;NcVcYV{H=6Sz_Lo`Fa+08_-d>W!X7(Ym!C!t| zRkwm!GB>xW6xkbEc(aa;{i6XSY787JW>jN9Q>_ge##q{T z`6^oG>_~1yeSejv0zm+B)8G)psjK=&QWW%5Uhqd0E#_eLNQibmu`oShzqYfNx^1gq z@u5+CPhz_{bX9rZsQQ8R#L(^29f21^JSqimy$rvBNNU3v)&>-kihHliwPN|D_+>xT zUEXn#&dWxYeSon-dgJDltBP2EjbVym23c=ty_ISg; zK<5fnh92dHCyomF*Txj!3g*A@=ZvE&!X>R}&~kC}Trm^^{{&1Z%mxsMB=(709yhhI z=o9#Q(8onE?%y{spFvZ(KY-&sm53;6FLkW#BD{7mKe_~M8qZIh6BMJS`C9RDBI&M8Q=AX?93 z+qP}nwmoykw&#p(+qP}nwrzVR=O%ebQukJ+DtX%7FI~N=yY^oDU#q_V1SqFJCZ5&5 zP~xifGMLv3uL`c+(u5aRdQ*kfh-K|c)jqbM8%%Uf6p3b|Qo~vZEBvD@suc6OdERRX zKz*Zf--mmnQdfd8_ufE#gL=Dpd@Vvg!s>J>B?HZ@JtebA9T+vd%}K_nCW4m}pBdUS zix!x*Vw>D75i&r0=v{Xoqh()8RH$&Mj7)JR0;*}~>|tp(a%njO?b-Rn(gC}fLH*jC zW$dkrtRtZYgJCoa5)qv8-U~`9@9x>LD|D(usSF@x!zAlUhe3rYFSg*u!$8yT-4HQpa2fsgQTz> zTLvA5i+vIs>PR=qJFu7|hRMixujg>awgFC}tFA z(qjvo3+k;P9a+wL?of&GB#mU%)RiD|#D_^CTL5idA4rq7%3E{sSo#k$LIfkdU9dej zPG!0^R^^E#dd0Xt`uQkO3Ku;GT5Jl@gJ!9L%v}N2OVSVx;>F&TJ#n_ElMO-g%%{XC zFWrqw-%=KqM5R~*(7GI@Zg60Ia5zM(nBjFY8A~`GCtBNE!Y;0^^jF=s#ds7&kO!1c z@)JXecM9<^#)cK<;bt*J(h`mZ^|_7$cL(YQZw$i2z{PmljoAT-}LbWa5Ty`w}?=&9wf)4NZ^ zDUlWT$MQkDTj>2Us$m!6$E2Mm&uDvD*M0Fp`z!pxpdH50s2kY*a+vYpOo4SiTF);v z*!`>8)P7aSa@4VMRazwLq-U8?O>ANWXNMTqOSOS51?9?z8pEjzuiT%O0T$}C$_n{& zJu7uBeQKMTuXb}6ORBWW!(~Mwg`_xsamZ9fp)UzVAkv7F$A+Hk8HWAA!XS-IDF~Ha zwvo|rq=YhH;rt1nSmsa9ggAC}ofM`>?dc7&%F+oL`acqqq@mlAQ*3@!NHstXF2(XXuZ#mwDI;ekDC_5KUg+}%SXZ3JSb%;!N z$N6tqTEVH8B$Y(K_+hNBf*9q3$ro*G2}~jK{hQR<42~5~ ziO&aU(-qG@i?)tfbr7~X9wIcvnv+a0=+0)kh6z>V=utfM=KM7+bt6GMOce)=ywUrZJsQ zg7of3tX2N}WYLgcv|aZ!W;2i7US$jR+)J6oHA+UV^MM{Yt&zG6><}8$2?a0&;WI=b z#+TI_J3{^$gO#$vV2-4^Hk_*Zpzt)UN({7M-s8$L;ioT1v&R}4aw`%>&$SPW&dB`o z(@CiaF)2=E7|Gx>Q3G)>Wv&!4Nr@)^D=N#6Fk0fk>qQX;U|+N${?ym zO(bqRyyX*HTg%}kTnMY$+AF zvPsbtnaq)i8Qy+`rG|oLHI_V~EaK5s=wTCr;WlMXlx>+S?xzaDc0(~8L2Z^oV0xny z8v2hZTMMbW?hWrTxuuS1^Hhuw)*I!~X*8-wYbT(t>DhxS1-JC}t`f}j z;zxZm&JOXD1E!T$cl6nb9M{UoyDnM>yHS6-I|H?<6=Ox$E>x3H-85cpT;qC<%uv)W zpOGNd$9gEB!g9CZ?eT#v160W)Pb?SwK^U52iv%Z;6=4T<#-XV@(#+Fuih#0`x`by; zQi`CM3InvjCC9}OxksT!@(?C$7#(G{l3Je}&eQhWf}7)jsOzGumt-{=K7xk!6a-Vu zy@?w$LT+GqEDkhc>Y0QpPPfcmt+6i}Wi9h19nlR0m|lA0p9(3w?2sf#$8N;x(>lfX zPdcsJPxEf75|^_6vQ8(cNJ5W=;1+5xj$~M|QW(@4k;`b%^GRb6%n%<2E{^ zZYP45eXdp=0mW{9S%mTrC(rRgvcm&gvYM=JEBnfKN_r-TM{uvTEZMZfN}ekw5e68R z_oL*+LAqLE3^3x9sfh{_k8Hu<@NZPSmrf+mo2q}!^^Kx{_1cn0Z3FB)#F%33Yd&Mc zwi7;Rz!hrb!9~%V;Q?t4Ew4kvc--jROk{Yk9&0aE8r8R#hM`dFzT^Ep?7hn`9swtbEXV8KZ?O~%Nd~iC=8n%MY~M2)?-Ad-eQo}agf^MZH{*-0SPmq>+|#!BykV6 zX}W{TPK!b6e0`}s?#!C;**-q1hva?!6KT_OXDz!*1Qae%;MdKAGIMWm;y0Vp^hU$76tinMsSMcGG>w#L7nBzKiAbCKU__VsyIBiez&FtP=sqXQ03Tkht; z2s$Ub*B4X%|Lmv?NW1n9{x2Ro-! zJWlE8GdVeNOE1^U4L@SL8b-B1W2H=OJ*#Y+RJL@0!cKv-G$doB=D|#%i3lVh3Fj%& z%%bz!&Uwsq?a)~hB)47+teTzk zPS#Ig5^mDWfK*>vdmums>LMGDMP!lg+R#v9ja9(R(~yi(cq^{23~ykb+D=}rImD?v z4YHrFl8P?zz_dw>8sA2*!AqN7Uk7#@ik+p8f>}v>)kURNwVADYgar>eQgr(;Tq=Kk zwUkyZWZETgOlfIWYSX^;6q{emzSwQ`m?6Od8xGA!N30$drS?2Lz|5aSs^LgquujXl z@EFA8R7jHus^tr*`iChJMgN+K3=}jqrh%70%jdi_spPjkY7&UBE1IgspapI{naxHl z5MxWxFI*uoG)7rWjw7dgFM^%S-984c=NWKKx|Mqj{4Fe|bz%f(eB0!$NUMPLR1+S? z1j!0m6*qhD5*{!!@s|s$mmwa-PP;U5Q}@KYlM5HhtAY|xKBZcP&jai zXx*`$QZR^|24%;J0T6Uk5LbL14(8BUW=~SB6EvvPT%%j)>hpYXf1@ICELc~SvIK$8}NHRDbUJNWn3xAW$ z0-i?Xwob`T`i8Co%d_W${w@-86UUSYG%#w8>??6C6GHI1!>iNLalYC*TLE4tITDt1 zA6qr_7~wFLWWRwgW0J4iccPe>A8<^xf1h#<9xC9Sa#nFLpKlSNy*RhZLALZtpqT%EjVr>06oHPO9%`Xqmz<)VUuecC?#@>?oxr57G z5==jK66aGN1OONvx90MA<$si#_5S+1jtzRAL9N}3C1au!g4&^sBkcIyE!Iy!VJr>y zX(C)RsK5)i+jq?aX?p)7Szob7xJvWMpW0AGa#@F+%**wY8JdwtW}77K^CpT5mN9Nz z0-NRpZ=WDCn-z^}1|8kH@nCtBIY7;{hl3oq-I%klyzL#O{K1C&HED5TiylaZQtihM zTU!%GiISqKH|N?SWZE5rvRg4-6A5Gaz$u8~;QyR5>#o#J8L@po2)DXSx5}nOv49hS`EHSaP=UA#XgcXewtdz zNPRe7eJfc zka-iea5B>B=qS~ihWUBUQ0M`PBf^LE&(FFL3L}!{W9qiJBiLWIgFLRPxOQv46t_9X zUhA8RE|sRvt6{14@4fb0TZFB(#_*!rHRSJH2k4Rho77CFJh zpf^zRI8lsaYaTMhF-H`Cn$Sv(ZvS_tsz z(0`N0Hp8!D##Uawb&zUuJDv`^%V`gf!{j-l(t|RaUJ*2OxQB#_5^}ucnUW8;bzY^) zg!)6*rfOe_3Z+^1{`J^A469wF*N2pOX?DO7_iT9@Q`huj{Bj@y7JVfJeVgj5 zlxZh`8)xo5#iR8sLFsxUaIEnz*(mdj-q@@)3I)8riV`~RPfg4{lGt$gh$uy?iZ@4@ zRq*UJUi{#L{9q6sp$SJ5#uy z4_^5sw;{-%gY zdTDrj(AhQrlTLCzT?V(#tq^YzgHwTIF?gWvAu`nv1mLl=x5`>#z8FMG(V0;NZ&0QQ zN5l-W@RDV-s<0mJ`=Nu$sSCZe2H2UMz#_4OdN^tij#`5kw7Our##kMB*r2^8$x0F# zgLBu&MhzOE#F|~QXy)L$V|LUPXW^dcF-xvQ*axFtY)%*(0C!TWuY~i#k0sLha4QrX zUcL5gF;;RlEerfyEmN4Rji6;ia(L+aPmRa!7Bj@mrI56v_?yT;$^!>t#)%lfd#by9 zNGB0aVLvV10vlRPp|CYWqJ6jR??_({w$cyms5%!#XUhjEgdDC(!pff7oDZ%F#w`b9 zL}9S!TMnT5xI2do6~Jq7)pprGATw_G!%_5rE>BS8Z?L>>4EF?F!k)>PgY^>HBRll?@(f<|c zO-MJ^%u|HYhk*3tw4XS@?A7-3ocaABwvIUK8SEfj3G%egZzvt3we-^1qxw4yg2uTv`RdrDcU_kA6zagwJfEV z=hq!WWOUkzm|+d6f{GhNsfAKY=p+)>X|N!T!qnL1nlz{LTVdT>KKswP2k9x418(7| zWtnb9jf*8>;d9*6Te3i5+>AQ4T83d-juA+=6{nA64?MDh4O0TPS0&Q|nQ6V++1^Q| zNAB9L)w&rl(=X>KsqToHyfnR0i6t!b8XH6<4Y0rAEz<#$bquk$>YQZ)ABwjPG6{Mt zD8UZcm71-a%sY(tLHq$sk7y1>oP?J3q=#cBNT*_kX|3$KnP~S<70|l+KCVr2&|8B2 zlo&S$oEI>A&x#JlG^fNz0DDQ#1du5>h5hW|A*G^<8@V zUHTug7a&M@8HmT2?p&I5w}2k>G5dsMLl;@mA12uAOxkVn2JIsO9kR%PstO{8B`j~y zVOCGdYeP3oH>sFzA^}KLVxl{VG~_28LTwzqiTe>5amP3yajDEJ4$O-qu^Zk?`9dFZ z34k7^GMV+FiN2ND#3TJ${ZLL*Na81gT}SiHNfqth;w3wqLi$s|M6&s;YR-CK+!{?c z{WH8KEQJeMfuu?U^}aizU;-qcqC!#B-~?#MTTPC+7rmMO#c+v_)G<*NA5yb(ujt`O ztIVhLX=#KKtRXZwOljqeEKuYG2?26gSmALjCJd zT#QD^N~)s1)?Ui#=HI8tEvkQlm}aXEL1#Y8Htq8Ft&UZEOK-F6@6Hy6cPad79sMka z$C{@1$i%=6RE@HON+zh!qN?LhYdcQCy+?73YCJs)A25TxJysg)6s?q4UrBBK{M!+v zt-I)DX;-)5I+Ga)Rw1DasUv3hALCMz&?KmZad((xT0nQM0gNh7U*N^vL%HG1V{xGyc2NGSw^iyrV#)j+JDsh;e~^% zfB&_Y*b26SnKMsx1CC}3OEdP+0QTxaT&SZiDmnCfgZ0nOoXDSphbb_Ym&>QwHJ@oz zB9?l-D#}ZIq>*-qod|;k332m0Y@r(Q{OS+O%LL-{r+5-Ju~G`fm3Wd}GzB|Y<)1EB z5qwH)`&eix$MLaM>f#jl>z;tb*Ra*UF6c=jX-RbD#l1FtDL=R%*5OyV-qkV{)XZ69 z>k<2M;wtd7%NIor<=b-F`l^hm)Xbi0#z~7-fn^UD1QlN?NK@l?&TUn{8%AZ_Pf#`; zyp$l|4 zRJSmpe>=_1Z!0x|6QqhSI2fN-FN>V*Dd&@%&)AVY=XW0ahh7v-6a_7Uj68@OIaH7H zR2ZDehRk&}RxWY;pBjJT~r^9qZU%SrsNO6?Uw=E?=>Q`nZ9 zC`#4YlIs=aG}evD^`=vkWqH)kN_5oNFp-~rCQ7`O)=@SrOppO@u#;sW1Vr)FO%~TA zmq!Gn2RX}V9HyiP-m8Wrg)6<9>G0L>N65C1&!37sRSd=$bB-Aapw*n0pJI*e+E=q|Ms(JoQ zPbBDUrh_M+n{XlRHcH(|<;HYlKc-SD7TQkfp&hfpk-?wSIOAl13~Cm{7lln3BXKZ@ z&$vtGKsU8>Y6rTAsx*w7t5z`;W>p7aBk^I-rtQ>5DZ0fmA*TBN+0}AA;z+st+f$IT z4HjA9ZARBcKw(bU_mWHxNJ~LGVw|{bGz-JXtKP7ejP7>3+va=DLC#cJ`N4=IRbYTo z9lVB_m^?e?o)u;g(T53K?(((`mLT|zSA7x~PtF{9lRCT0n?I`g&v++Jp_=LFF{dZL z6y6M9?NDGI;x1nZKsXpc?;DxYRKDCG@l4D4G%P=wmV9SKY_+y0KJiwsyVK}cC5iCl zEX0Bt;~H1%7LWtY>oPYFOIqfT2*00hhQ7;4@lFgivck-O&jsv|&3I~X8Gg|uhI?*# z=Eq3>x_V}cxU6@SQK8(yex~$xj^`LI`lV9W3H!yK`;aTv^{(8ig821>eS68qBJlDSQP^e=mIHUksxhz6GaVcj14ZqZbE_0Ax^Qzcod$h#^7sSF>~?DLJ4m-ehxt25CqU8Bn%R6cb$4%X zY&+5Ic5RP#e?FIOJGF#}>EHGrkDWT>;1#{w-Rrkqr4eVjw&c)ywYPt}JUhScms=Zt z$}UT%>@Y}txl|MeE=It36ynwAl0@=6Hb>4Kd-bl_ZtXfRH(R%n%IzZ2TUR&r-7<02 z2vW8VZgg9NzDcA#eBF9IGA%w>qH!p4BN3{6mMYjMPxnhtiE}M#`G zmhZZJ_souFssMka;PB7nuZO!8|HyD!p|AWL`C{S0`{RC@j_qNl2A|EX)r*m4mZ#vL zHapNsbo+f=(tgg-8>v*yK+!6+VXY8YgD3O)`=}Mq{P;^-uLNH;s)6sOp>yYNzYR%> zW02G9+fSmG;06(tYAjgZoO;O;`DVB7c=wjIt@`$fuG_XxyRHZL=)}>W=(rN!UrXVg z!XCEd!%4>HVo+B2TKtvm3x0NPMKAl`+;&hu&&$<|)fds*uoU8(DbcY3g6M9QeI7ti}E-sM6WLUq;WgY{0! zgryUjm`d#8z8$5;u8Lm`-meC&aO1Dznokdx-#U-R1!-&(oVu=Zm1fzB3xG_sf-ra* zgHY&0bmbF!wb%RB?UNUu*Tr2|_(aTo6S^9^niIPW+ZIH(+c$6nJ4jY0cKlZWlpSd}>!`RR{!}<$-mx?m=CxqgMF93$Oz~M1m&{?N z%!0s8dQx{)3>|p^NbQY{Pt5(HZ z_&nX>lc3++m~Hp^?9694h(z`{?mBJV69~#X-?3PGf*ctqFae5jUpkIdC2FF*Lr+ND z$|1i>5GivKu5G&8k2@`cOPKXNd!R^K6iIWFB80~3(5sH@NU)Bm6l@F3KonTnC8$o*=sFDIrJdD>L& zNzCRu+^#IX?IPIqz9ozGgZ=Bq9=uQ6VOLG^01!kr-_~IG?_B6+NiDqF*7N?yPgyAU zdQJMYTV3Any*+wn`SfS_ZKD1C{y^^a@Q0n=%lRl>7wSU4HF>afW-VmucaUlu4t}DK zai)9{Q>pP3`KVY7;g_azkPEMkl3}aU$2X-|Xj*&la0Mvm#<+LMJfRw&P;%n4cg*zt zKEhiwGjvmdCoFU5v0#`rR};tEsOfd-t4*Yi9L|B=W~*=(8?nd!_@|yXM_pZvD|ZKI zIhGbb4ZL;5aOY<+O+U?zZAUvJ=((3OR3@sU!M<&aUZ2|HBF`N>g20694L}rz zVpxau7QzZ9fcA>ZgO8VSHQIh#(S9kfR?;%-6Gg^9XIMOWWa*D&dT$)HlwS-D=Znvz z^cL3d9)6HWJ_ngh;?UDswPpG765%0Uv-AyS8^eT@JXBYPKN|O(Q@_7p%Hp!m0Xm7l zqaWcvVt83U7tJRPFSn(IPc{tMC2XND+3;M_Wzy!HCj$h{0z1%J z2PWeag9f8nTr5t~IDIu|_gX~94{PiHT8k$?t2FaiZyQY)_D9nsSCx3X$!1B@@E8PX zKp=qk)A}y7LKwko@h;MU%oMPb5JzF|kThMP{Fqm9TP4~|8{Ht@ov{{)&VyPQmv52^rp*G7us|o`_Fm)>5Xkt2qAZzXZG;)v|-L z;VkEyEjA@;Qq&UK`jA3~6WLsd{_H2d8dV_C8tb-Q zH=&}_x(Nso(};_L93Dv8L@D=(g+`lNXhMY#vuvCpw%(`fI*5|SVP+0 z^VtSuBE3`UsuF07i1W44*obk11EC`Xo@{a6LWmpQ|1&*^jdLRM%$_JD)UPDGP%KO^ z#>EPFbQ1BkW`XpAW)asmuBH=HC4nfC!QUXdYb?77CzO(dNybIDK+_mP!dO!kN_j6~ zW6WoAkWt8l)4(wK7dn2vYDGsFB%iH-=QV{UXiIjH$*m|jNSnFzn?53R6#CaA(fc1{S(_nyjL&l)# zzCCyjUqoriRp0|2sk-&-Iz9U^jfq&+KpBeJ-kGzMBL#l!jH%wNqmi6l`}`tZ4^PGh zd~zL(PS4elk%ze{w<&!vRS z1rl7KU@WvD68p#xQ$h=RQ!TNBCPq&sbbR9_LynJOQu>2fPmR-k({W;CP@7nm#sSE9 zdK|>DdRX}zgRE*on6e^9$fmR4G%=v1+SK>lgYyWWv7?{s7*0J$Ty+A>Y!4QZg@IWq zFA7Z>3S3b@;&f^;21l19I)c0i9)6FO9y~5hE^Dk~hq*x+-aPULldTZPp`t;msUR!a zTQTk7T-8=!m6>pkTnKrA&3jg_am4_WqvVcgP4z|mO0`H*n?@#E@G;T^#5@DrI39?n z%q~;2xJ^FGkTN4Si*}uW+a!qqo6Lx03Y-pxhvq~=xk$;h>}aikc})^NN&nJppZY4eh`FM%*T|Wg6WpF3MGM8ol3+4zrVvK?KlJ#+nySX z0ubVOTT7*Fh_^pZeVA)~vkfx5Vsrgds9#y@kSmqzZVDz5yvQ})6u=r?o=sXKh0Pmc z8|hBvlYIOuPQimGiry(WhyJ{B2<5iwo9%pyKYH-Y z0Mue5(3BzCY7K9q2y!q~{icy>lg16$ft1_H{YtYYfG+QA5Rf>bLA)mMhVs5xL?0Ys z2K0sypJ5>*z6w)IyT|Wh&u^yLl_r|HINM@rK+gnFU}b2rzPpDiqdywa90uJT;%-O8 z_b_E%&SQ4;tk#bHlq=xR3;Vs$SSC`MXCzxN*G76Pi@mI9t|2Q1hft9qg+9nAB2qMa zQ#l!w6w-l%w*E-UE_tKfWZ1w2Pm4K@ELov#6jF;)DVJCSLc^&O}%pi79j5#Yc42kYD!bfH0j%v}uthfGRi`iCQeQO*Ht>>Qc#wp0X@ zA6T6-K3sK7D*(^|pmJz7RP`Xy0F`-AbqcV~=r40a0EP1cNtO9QVP8ZpFtr6(RU2j9 zfmvUK2Z|#Wr*YF2%_$GCGBSQ+lJ(m0+2XSk69Z~>un7#ib414 zvk=vVM%zj|P=V$zyDIPp)YM5qk9h?9IbsoRge)cXG(Zi{*9)lEW)5^z$$9fLFrF+g;Fje&_vcC zfw&zV)yilPF3#n$>*}>88owG>MhHgLIT~j0z5y#Bd*BlRnY2E5eKaKiXsgL4Pjy7v z1Hp?>BGMW16&1}783K_T0WzqvNmL<75g(q0jNrUJ6fbu=uKK-x}jtC1m0z<%$2iThFW0_&65FBzj;uK|C@g;`syV!ZScrG^-aL2*mD78lEVF%iz z8lDI>DXqYchOjJ;E1i4ikNFnFR4YM&NM>Pij5N}8IUw>^Zc+@WRs!$Qo|NGUq$`V`f{dX9 zAyv?-G5*h|c%bez(oB|fJQY(mq(Mg}&btSIsD@{}aypxEtT#P|pME@jZW6;l1~!oM zuR8(K$a_k&rE#KRQVJ3(5SWk?jzj(wH$eajwi_}V zQyU`DPuPA4We9@%4l6?H@l;g;HSW4X!Dgo5g?-To0Z3WpK|!DJu&-4dlYeC!{=Fh8 zNcUJxn)N;bbVo77maZHyS&`DR)Zg@g3{wTxND*8igLMDXAuh-O*&F4SHqF!{rJO&# z#v6p$E~W zAHf;*Rx_>x2V+2piujnO;HLkJlzgyX3$^4a3jj!-mHEL-3($dTyX0mgEDb$nKVUkR zY!K_LSD8ER^1M6Yb@IMJxVXCFI(LM9Q#HL*-}6)989oK3wNq@LU1JB%R4SfsfHbR6l58dzwA`g3kwu&%slBQv-1WPl}1@EO<)nB0An%WeeQ$>0t1=S@p7Q!=F zDKnT$fczFif5!s7q%l7R&j&e0mg8!WG3|Zsh-ym1GWom&5h#w23<6`)HzocD2pNFI z14~BuI<)#~V4pXM?Oanw0=@*tFM!hDVakMe+tJQ4vjp>at{0MPnL8F^Vsd)JQ(OFyN{ zZDVcCVJd5jI)twD1q!H-@cP3I1`+IF{7p*)l61Tn1)<`%iLhm$;j40mqJATgB(kI{ zl`;>e-y|d!9xy3Olr;gTh*>GhfBy69LW-8fAUo|@hX1NV#f!?%Llvhe0Y1-kNk)iP zP7L=ILki3Y5T(@KMhqa^5`F5H&wdG3*c)B1z!hm!pbWqiV#k~pExOyuJ?QywNT#KU z7U+RULRm4uuL~?t5tk+2d1#9{4J+#eja>!tYe7{zlq{9zsDpR_WW%gYdc!Yy@JTyn zWl1=wLZTl*NZPT2!=!hZwt0t!0vR3JP@xAt=!CD#FBx@nRU*TILc^%3i6L zU-=|8Wl1H&`Rax|{XQgzfT>JUimmu4v84!NjUpp-b!$R-iiIdCbDl=yQUdlc44yNt zSu_rS7b9oJoRp$Af4$AZYRm?3^Tw<|GYP4bjfy$!JrrIgDAB;Q6=LPg0{xOuhx{w< zLXyT@u{Lzv!xX3JmI+x~KqHKTe1Zq=;#+Mh2K)e>m9i-nW1hkcluaN2>C0n#4%Bt_ z@{;njbj9Ql!i5}&LDO{gc|D8!SZ)hHz-^e|5ix)b(=xvShgA-{SU~PZf(r8bl8mhI zgTEN$s624E{UiUBL>B)c4>NGMm+kgabYKu)5a=)Y!#$+2Xr8Cigs5LG*icF^kT$aJ zo*;?WAnnou1ezp949dvo4IYuM4CC}>svaE#b^^(e5Z)*=AZIyGgmtz?s>Ec~GSuD# zZVw=12fPTzn#cZU*~GobTeSrphLOCj|MRJ>$Rzu+5w#POLos8Ty=0k|?VqA~89Kdv zt%!%@NQ>dmo#?Fi`*ZvNdkK>G9!y?x9&*afLs&Q-HVKbIYqE1Y9z@13Yr+(3%#v;) zmAHP&k}jT*F~w6k{<~8}hC)URk;-I~SW3cLtf{1&L&};?PQse*BkE#E@ix-e2;eHhv((F9&){fK z-D;-6HM#ny`AweuA@k=d)pgvq!w3V zk5TCZ){Q*6KTj_IA4+v`T7kuVtSw}zsiFVZmx+r{Z)fMVUYAd2yzl3&dgrwzq_#&t zd@gNwcE*Bo%1%`%*64i)vh8p$dct zTKl<2o6hxW<@U+9jhoMBi?+}qjoy}?o$t1dtA-!X!|-;eEo7&b+QZMy-^aS1b(e3Y zqyUDigX0Cdl~sIvwO8Gfh&?=wfkA*teV=N>5xg$pD=0Nty!2L{1h8mhC1)F$3$)x{XBp^VNB9(^Ue>PctkpTL+8b4Y4^ zlJt73)}9*Pg_5OB0KM7gY33lu2bcF(pHWs;kSHVL^TCv@4Q`okKG#-2$BKi3yn?zP zh6~PCQ0e65SgL%?X+d}=J?%`Lb-&weSN<1a#5Q%!e-hz;uiI|1+iCsXf# ztoZ-L)ccPm{_Dg1pNGiA&hWn>^`^8YV>ZW7w=bzJB|!@vyDK^RXtG?9-2FiA+W_gU z={L47Y&R^&(KZj?=mWk)e;nnyDH4#%Lrwmeq7`VTs-E`D@QPlHi`tC2$hyDv_UOsw zd>xXKyFH6wTS`k-87^VUCLOBm3oFyXYR;0kf@^#|J3buULP6{A$OYw1VTfY<%&ry} zr(7mzOxjc5ba$Zyxw|yi+}5H+{;mY^=x$Z7EFXRk z&K^1XG*?xQUc7R)YgAp#UcNs)d>`4R{vF>VF`0p=Y~}l=1B~!zenZKSC@lwYOq0OO zUJs(+o?*3~te=C?_8#y=O*cQUizNX=oNN2jVv>wd?Mv-SFTJ?7r`B*)ySgF24)=x_iH^yqqz@F#ew>ADLYh2^uWj8**d<)3Iq-S%iijV}aTfZLw|Gm{eAq-VuX-1&~tvNi$kN};&M z2{oY*!ghIj82Y|8EiSY;i1kPa_K=TTsB~vowZ5nGK6css(ztzsSATXoSm;oZ3AZXg z8tddhg9~Xn6@oJn0>V}*o<|ngXhK}go)B#qS#528-rh|}E!~Wuz5ZrM_cAt77+(ad znnHRPWQ?hfJ#ps@> z0t-_W)-#kFk13U|u|!b;Y2$u7!xW5m&;*4w%c0g%4;{TSR=-pS}OXV%AJ7YES-5JbYv@Kq)oWh>?MqzkyI6wxL)uA10@ACcQ z^?my3`na~wj_9vAEi=)cd}@MIg@;7|uvFci->SjZAgF!p=AaK-ZDl8EyVgz|<$y^< z>15^bYDWbx5ZG0vHdFFkh-l%wB~#{15XJu7unNknIzIlX)xlmx^O&+f^&68i;2#v* z7@aPVrBw7^q4_VUv|C74xj6bD<_GzQ585B+#EWsGI%2c26m=IUXNzcJr0yb(DsqeR z!RhrQL&x2(X~yW_`_hj2NbLxDOTplH;t0DTqg)JEQdZK|zRLX4WGs|HTMdvz_TjDvy;;c~ zF_(fdw6N)im?`wf(08Qk_>BQF3LwL|K8JVf0q^ZbgvVWP5_We*eVw6`@zn%DT`1T- z0zA4&fHrsKA?(Eqm4n_k_xt=tl4Y49dZP{3VUdFY^KE#jKTNp^A~5}j7038%6wbz@ z^1x9qDE!HHqEy>@{L68c&%V1yfa;C1fXyFx_^nXG1C1s~@=ZrpbdBN9RD%3Y+raWh&J zF%LytA)j;F1gk#%9Ll)R5FHErwCgilt>WZJeO1E%cH@@O;gwRiN~MpWYmX!Wf#hld z-aXBpaFMAZ^iI3>p+l2bVd`#PQ;de2h)&^5CUjKot7txs1L&{Cl@+0>$oCw&6ICb@ike=6jl;raJ5*w(ZcBjvg}Z&yo=4bcBFo1{ zp)j=O_hfd)|IqB^e(^G!8~y5JE6->9at`qgFaMFjizO!r4m4_>5mdO7IU#`F%|k)e)dIjtN1xd{qf$#-&en^04R63TJoVr0*! zQ9Jy8HM8V(eOWn_Qi>-2h`s1ii_ywPhf;w;p@_(qhCB`y0v4#)`??;|)@D`vs&xFf4uM_`7#UfZY(H4iQAbcJ(! zcKeyz!B|&_h;^^9?`Z|+y0DS8@QRVs{-iv$}|4d*0G(wb46uT|4)qH+oIxHD0dvEb;*>RYqq@)Se{hMbrOPcD*+2g6XR#Sk)FDzygQDv2_owj#Qgp3jMx@h*MI!|S&K9(R5Rzq_oRgM?;2 z>2kh~<#-BO--v=i&HMb0{B5E4S2nEAL#P?h1rc8&dmk@qa2wEqIr4!%v}k(MDN7-m z5f@V#h#c_m8ig;G2m3QmF`wHjbxJOf1s9v`^(9wnE`oO;ocU@jv5m z+jhndbZzmi=bd4`kClG)trxpYSPk$NY%Fv~^L5t)@r{PP&|W3tVriqJU`82u;-Vg_ zIGhXmBb%eLDBSYKbpdPE{Tnu9s zxJOS~#L8 z!9g4xoWsMz>eYI>y2`wNMqn%~EDRA585tSP$V(H+e-`^=ID9$d;*{#>w z{(ghm+2NCt7KbB~d;i`aPG_?Jn*ag=ipSt^y1i6oWo@-Pokm5$00RRzHZ=I*wR^ui z`uhH6uv(?i>1L#-d))2yhlN2vLr1=}ym-CdoSdHa`o7*=w%SckPp8u9*Ho3!(9z8= z&5ezZx7+Uz)av)HadO1qbFVCIUG3i>qM^N<%@^+N?aAlz*=%=2ho+kKf4x(dQ)aT; z>9yMG{?+@5#%9;i(J`IQ*q)nHP*(?kYN)QRE-O1Ll1vm57Ut#UEtN@cuv)!Yt<^6r zDb7gCXlZJh$>H7H>Hj&NOufH{oXz3AzPPBUsECM(xqrTAWoA!JPUfxi^%WNnjgF3P zXlSUZfkS71{qgyHdVc=5!yc2#m7N_uJUzWXfBx9m{5Rs>Iw-EE?H0vJfIx7E;F=JE z>p*aV6I=!f?!kgifCQI>-~6Iw24Dl%qLNuRWb-CTeP?oSt2P+x;7$P+0Gb7tj$T+1ADf?m*2UC8db3ynOH76>U;d z(#PlkfB#aa(k3_9+U{;rPHI(d?w9OrbHleui5bki%;!goO|&AeZIGMF_KFA8T<(l# zCnqJ9mzKVI^-9wB*i=PjFZ>B@j#Pj#7!2%AvIGS^bar;4KuJwY3krn0FSmH-fFRit zZrSZ&52yicX=%yG%+$=5yuF{uIhd=0b$DN(?nceAzJbBc+Ll=G;opLhR204i1Oz0+ z#p@dy%uG$?6%;r$zUP+wASS0jI@lQL8uGgt&l*YP<1?+!trYWjx>gpAUGD1dTkX0x)g9?sV(X(@nkMAb_%U}C)vxrl^to~)7AB_2nI$^LoYkG3ruTi(sNT=l+2LYgaq{qJW(aa| zaM(@eDfIQRxvjL-G&DTH$9HmY$$Dio{FOz?YGYkeN@{F$jL)<=x2&vZyo;EIrnIcc z&c+5cf~MyBYpz1TZg0gpP&D& zzW#FP8;8`A6uWvx(zkE5Dj6Bw zZbT4uNOxq=(4ce>pO7#@O)DxI5=2Sa{?tdhK5Ea#wH;hv$L}+wKfMR zm`VrTU9NULYz)M!e;1WC&^&o)_5CCC2Q|d{`uc}-bdMiDM(MSv$9nIQ-^F;Al!=}m zIWe&%N7}aiON<5(OhLG^nno#;Dn%3#C5>m4-F0 z%Plu2EA4@|=cpN~vmHai*LqNNyM^DPB*tTN@auktBWhmP*AuZXcKFO%1VJFMq5QkC z451i`=cQ$30Z7C=>dvL5rGLgwN9XSD>fqu2`e^Cb0ZJxrj+Y-$kqretqC*&La?;Yt zDPZq>>mTq5iNM-DcP{sIQ526&&_o59lBz07Qqq9a)sEWQ^Q(h7{FvypwDb_^#Bbj+ zCEU#2-K&d>i$8x>P<2$bQP@K1A%k=v6*2LTsw&vjLMciIlad1Ar)v(=g#|@LBg4a} zc!KI6BgjY1z(DEs>(Gc)B@+`9b-k=Pu~S+3A~&5@*mEU^CdM+*@rl2%1n#SMr_b(i! z@7j}-x`k>UUS242JG(jMh*XQT05W-QMfETUy&Z;}`yS1r9|AXD^%ge2UJfIvnyg)^6`? z_>^rN?Cias3Gx5Wq^*FU0RR6g->2e&D#G#a{H-A>foo&!#b@B~?w{1|%U6Q`6_JM~ z4stWfq`{%@A4PK(JqvyD?Aah%D0AN6+F)q6|1;*?;=!%YcntV?k$C%gyU_>GpjOW@ zwM0v9@gcSILg|-GC0=@^2Ybh*l@wSBk~)v8-{@d8e%Pk?RH0n2qLUaDbnsPP4_1p_>8B1rVH&~nh?E>W4Y$1@(nyc=howyT|myk5iy7x>~$`k*! zSmPpV33KBb#73;%tC-topS5UzrbPNsm8k6OHn2f{#p{^G`|z{B00|X9OnUf4ni1cR z)?=pNi**0tq`VDId<>4WFbmW4j)Z0C!>5V4Ze%|hz#-N>rNQO6Qy(p&(bT7y+354) zVbcSfl0Hl6Hty|>n03BjBeAZ_kmv@8r{lLm%4yLcOoN_ZNB-J%jUd`I3c2Zeh8Zvj zuae^Ekbx11@p(Joer-3fI=RQEw6aYCHRDhUy-4(mT5hAm_ije5=#)FTt#YTgW=N7x z$N5-B`J$RA-{n=5;S2h$3g6pTJL^#0PJTQ<&^;A6{{f3Toj^N2gMI6rXq`Ab{Ro!C z+E;d~-s+2ec1$aoS6w#`@B=oaAuhCWIOg6jM)Nri=gZp{Soyz_T4rZ?rkkv!%$)^z zq%7zLpRH%VC)VzC*is)poWfG}(-+2>_(cpvHFG0Z*zP8E`yQM^Xom5*RC_uFFeGRP zY5!El#i^Y4s3A%Iq_|$sV4#X0KhD|R7-{nF@@BP7XVxV@HEnUsP5+^4_E{gA>%1S& zsRG(gt#IvyzBY)o=h3IMJ@4jxm3BQuVy;!YgIUTj6WNOa>nV)7g1VTYzf8zVu&`(@ zVaTnltJ^estR-tXuHU}(XbkUSTc?oM_={4Mq(xW3Z%8KrlHh~NT9)?OXt*LCk}uJmuHS`saMD;f*!zkh^y__JrrNx1F^mDT*mHJK zW5HQ;tma%AV8eij^S{ac?If98MYEKS9I?U4IWct%#H`nXm+1+3{XU0u)=~!%u2%#m zlhTHXXxTmzrbf6Vh(omLt_go1;JKA2ew%#FvO;_Yn78MB+L>q1a#R>r5NKJ`Kwy?N zAVd=2evEGi_?X+jx=uMy!#TkPz5T1592f>Mi4=`#Dc&*V9X??%FTcI{?io@01wDlm z@!(iksIc%ZTK?v(+;j7vem&%Sp%pbq4<;z%;g(oBm6_DW?BPSL>xi5k zyi$nI6M^UbO&}{|)b>>8+C=Z+K(bGsbG)I_T?E&{7=kUb_Dh9k%ck={PSk@?9NmurI#8Gt_Vv{}>UwcnF!S|UJWWN53YH&z(tLNQW^7oujB z8vU70thamqm0!;mp%4?bnK7&80p!P`zjySRp4&ubzpc4fh(xgUL0aKe1)AS`^z9c6 zZ{RYDcH9>|8CTDVuixq|^kb>9d1Jh&K$@TtlHZx1Pp}-hwyl5vr()H|_ZgqODflIa z?&KR_>ix}slb9J=<7AESf2(XR*{X=aU#Bb5yHt2IW6eSBsM7L!qtEPK7BiM!3BwIW6B_?ew;6GW=5UYbCg}6wlUJOm9KufUx|2r=*s$5< zz0`f7+zZd@44yX>z0i9U!ROPPUXmw|U9_!vWJ@|BO>*tEUszu?KG3KhMz}^jbSQtQ4f+tea?hKZV#@$#YFOCrIZ87R;ij zWl#JzzbZjxl%C9feozfcVuww>Q$TykrK%H(ma8>_X8Pq1^^+j2I8ZzCVlW@Z^voo{ z36tszgF^~VFptkCR)n>y5rs?ck9zb|#ehKX1PRi&41Vu8klszmB#wou7Q5xh;7_kg zc!e8R1k1C|ncOqZ9R^9EJPGLjo7&E2UB&|L{@i z^^XWhf@HKfl3K`)oQw=DDr3>$tMOBp*DuF5!t|468(swe?SU#W7$pD>*zpU`V+9R0 z0C7eAp^BM;aA+lQIz!-H%jg~)BCTDhHA|1X z*Z!6K=ZCs5GC;CmUy5J*fK_t{k2Blh2b~m>`cWp_Eu!O9?o22gD){js;YvD7JY@PU ztxRUm8JPUljF>$d)f4R{Sqh@b`|qBY=Jg}1E&ZuU68Uh=5y{Y2Z3CGxAZPFCrz~-A zoIespFS$hN06C`imNBtt%3m0O?)c<=T@XCyNjrZ$*4a&U7Z&!VNjT)J{1*cdQiYox zA-(UtgoKc&(ihfbXG;(OL4;GnOCpAUKM-j+7N`_#1zhborB;*ynJLI$B~sRhb`w8^ z1{};BbCsboQ2~eqi51!rx^M_;iGB6VD!x5YyNAlB)uhQL<7tUeAM333YCW%ZMiwo0OIbMBkNrX=r}89m<; zEj?7+-iJA#pPsD2dH}aZq|~LNE{&G>v!6wdPC=d_3%etbUm!Tt_}S*t*|(XX*ZLCf zdtZu-(N@o}w-o6%aN2;)J<|+&otWru26xb32o_ z$^ikQE;Ia=yk>={Q{da*t!R7o3m4oE_sv`d{c^b1r={Cvb#It|TkVtDXyXaBJ%IlDyjyY@aodBh8mz@;}G^)s?bVN4Eb0t$cg?5Iv-25nz42im5?L6i_#17?ev6lBvaHIP3}{_6E;Ksw=<$Z z?W#xjY`AajBpCaT)`tf7!sHFbS_k!^}pnHdO*uErUuA%tn5eYkH^I^ zkc`;=l$qdkO^>8Rf5hycnw4!l ziPoggzbtVhK4d=}B(tdDc$4G6VI;fDKJWd6=z*A!?HDb!Gm|YfJ(D!Y33v~vnia^t zIR(lD>+sZQ#!JB%J73=TKG2akGub|E6EKGOR3~4pAmE=tw5^Frt|M%#Ap0h3f)eck zpk3yIOO@T-6Z*gnb`iw^qCQ6-Pe>sEalMPM4-1dHHeU5Mh=vxoHw5=Finof+Q94~!(Q&xit|O9d2E67G`4>pP63Db}3*zlVW>v}#DO0X__8mcNYNh$`F+ zh~oS!?5WMNcLS@SlOn5Ae
?phT$R^L>L=uYmGRtF8jmDKNm`&8{!+0NYm8OdVHA z1T{YL&@eL{JL4PWFyVs3=)VK`>_&TVH$p)G6O#<8hZDu4F$82irQf)kc+>p+0~}B< zoiG+7?YvbjA_?8W?SXZ4-w)3wKl{ald$2+O(9LTiJ8>HG24~(L6Jdb%zC?zQ08LcBQn)s8?>{7-`2R}@$p6j* z{6?~*Nm9p@A$MG$A@gtQ)hUKb z(zC>#6x4lH12{K`PDP=H$A6vo$ntwFlxvpw8#hxe%Jc$MpF`f_Bn1@bcRS^WsPfI1 zeILG=UM2rC(nS58uZl|-1at0(&Wd;s`5$^?Zaady$*0gEAuYz>%y z)7_DNJ5hTjfj5VcJQejLjEtU6z*TyILM2Mdo*2RLI@*|g-U<0~vC};Vx_{{A;?e`I zs3-`r1AEM(SA-qqp27&7b#wwk!iH8sN}Aryb|*6>6DGw@&u-o1qGmfByC73PM^<6L zFp;GJ=c?UdwQV+wzEACHPQ_GV#j@9k|0)Q~(-84CuxiC4B;RrsN~D#oo1EhR7)i=H zCXReS8e}Jgd^xSs_91wStoz8lm&|9Kz!3rnT4-It9;+f>>z#a)0aL+21>+eSa;G_O zCn?wMGO&Th_xgU$gfb?$&F2%#F`nl>w32_rMnU(qRQq=P=7D@3ZG(|D7nC1acnJ_- ztcA4N17l{mW}d0eF5^0c67_toIsddxZrUK^vv9R5hrv`R!32%A2xXOhW(6-9qONSg z`tgY5DU68BuXwZG7ir)>Buy8HOn2Urni3Y$$49!@BzW1kB*w*Nv!74=&3!j7OXN+K zKo~H%>=8~0S(6mH|0{%A4UC8X7;rYNUGdfzUpNSXH0~(2rmEsdxyl^TEFZH4z;?$v zFCa0QVhPYjO|&L#;MxkJ?10*Mq4J(ccu|T1yw<6>3io|GmjXOhks-*&KXQg+x$B(* zkjUo%QzF{=$zc2{$iv@$XewRVy)CZJ;hp{QtH?O)r3N%pU+ zjP%HYPLl5=2z(?qz%>N*3hQ2^$Nl#uY9w{p%@LK%DIc5?fva(z)S8NV8oCO?zO|bR zx%&5Kpounn4OmY{@z5y$fT1B2bIy&+5o|*2MC>fBivJIdg{oEPYMp-%WSwjN*PY?SgVYgaRL_Oixd~ec#6HWa)zP z>NciSuK{P@e*8c~nNH zEFc<+DkA}4)glyl+Jll4AGq|gT2+x(N1HfHxIUkwAh_0l&vG!;0*WoWt@Crxd(6+9 zp0OMv-mnL~fcsvivH`fPX*usp!B5{P-Apqep)rMHFDJxrFWKC~OFr=xXBtJ8VMh9SxsKeS-$KCf^+r#$1u%FRUw$=U(Lb90ScJa z8vgXS* zj_Rr#(z0z%{+1FQIoZr!fmSOhx*xTyyfBnSKn|o6%G&EAa#F)Z#DT!x_M<4-Rk!UB zz;Si6MER7D5mT^G91v(8u|s9VvzgCegcUAy<-v2^elWcev(Gp6%97^+Y$r^^t9tLR=G(u@@&EZw@#P?61Am;@c(MokQAuDy# zv%>-{6=cZ!kUy%Wl!gb!cckqCqmwPzzw?V2v=*PfK!#Lm4m0fdkN}BEleY$0`+6Lj zviy3)YdQQKIyCAI$os8q(fd<@Q@#+0_2y1c`EY}m^?Z(^f3_RW-KA?iQz^nT9b#nF z5J`c!e;%0ii!J$q2?(5z&2NezR6N6klc*pQ_DN|iv`(S$ z_k3#uXqM{`3=S`7koOKyu(s@G&vXhIScRf)XUKN~h3A%wvP` z1)M-@Tp?!8(yg07n}nvJsL-B)nZpEtesPf#h{^dDL5ustWq-bS74o%!sD6Z(coVfT zUn*yN9Kd7&D5vfqIT_r4=BPEM9LON(d&FDdOlMd5lvU7EoioBHd0}}3=yg=aLhGp{ zEEIUNebyZWKzrK&&B#4J0>R=Tm&qmIM2Iohlmvk*e~fljG6>*}mX%21KWzITPZ$Jr z4jvE?9ZjhyW*}Tan#wwB6*6fZrd(+9mh8 zt|oAvyP1wn^plYya25MQVz=LJKxGp`YCj-M&Vkux03^F_D0c27!N1fZ7r;3iu&Zdf z4u)RU&F;^roI*dm>Nl$s>4T@b0%R&tJ^B*4`Upx)j)J+3`W=*Wsl$tEw-Tt<_RsQ+ z-oxhy0{?tU*0E~c`p5|f%dZj1_3Fd`a#LnAz;WMuUV}w_L>)Bbu#EOvHrk5minmRQ zThBAIaMDcWhg_4SLUlwWAU3pWQVO2yeueit9>qS9Ux>NK$bx4=&Z=C`vNh5VIK&eeo~4AQ|XO@4cnbEOa74FkSPszWdM{o+%vv zpbeHW>gz^~KP6QOi-NXHGkbr7bm7-rlkKH%JIqP`)~Uh-%EsAlfv(-?MO3VY`8 z`!&4ULoWHewZKfE>xdtE=N+Ez^8w$9MZZ z-NFSMhls8UdAM`ppEtiGwIi@m3x`LgsgYS|8~Y8$W~ZJh(IPVFA(?;N)`Y z7jUA`Kz4I|BQNCQ@9qv`Qx;MLM=C%qRjzW%D2tqbewFy9^Oi3~El9-gngX%ta~9YI z`E+YHkvq_bl?KU;sj(~z_!$bYUcflv39kSWyJP{?e3#$80j^Owqfia9ddf(SoF_v<>%75mTxrfI z=3J1N-Xr9Z8X)SRL5{#xKL2Qfz6BvVJ$bCsNP(dj3Sqp>d1Fq53UY7u;h&DZp5F2$ zWO@?fBZD>p6w~zJsrl&FI9~wga*&_Q*KeJ~8!>G`wqmGA7U=tZ!24ox ?2^-K} z2TS7^(u*R?#uQxzpi!{cyY|l^t1#7t5aNq_s~UjP5^01D2D{N4kb&`7tQPY!0fH4x*3s~lg ztgHthHlgqLM;c3bHg)h;tgIYC?XycIj}ezoAz}-026O$04JZ~ka2wn>=>49_sp!>9 z?^N@>V-U=8wx{EB43Iwn%EXcm5XFHLX?`mm*QJXKfWU}3;k||7)_dt~v$#IC;wk#I<{JCf4U6#iz9e2?*$8j0>(8sRSg@}TdAIA}7=fN| z{d$hcro5TZJTqU&_tA0O%`D}P?_C+A>Ieu87qkq>AA|<393#IxkAmST>R-Ycar9NI zk~>*m6E}3q?j?hI7P$0;F?@f{nXh87L0ZILRMj1L|JVW7DSy4&XO=XHTR2|q<%X42 z*>TP-Wib^R}`K_yj7?6@}&)y`t{y5lb2f} zkUtEf#cnaH4OCvzdkVXiV5?PC_YGRaUNKrb`&A{pkoGpqmXUS?&t z%#qFwr7X=g?zgO4iNg7GZ{%r0(j)-(m`x`q7F;n`wGCy`VuuZ%0HHn|EI=s@B1W?s zVI99?xrmsKANOl&I~fPc*OsXfDytw(_2h4GkR2K5qYK&AL0mi?2@;<_p9{P<4jp2i zdn{2o5O>JIiMX(=(^Ee#FpORWI4>qL_%P?pT7EL~^-Mm??@`NscZ>iDw%tE@j)jbn zJcC)2fj<)90sGr&f|`W50HfFEO1ck+|1>!A2;YkopyfhP(juw~|7lJ60`>o^9h<+Z z$v}s@Ag-bHeU<>gaca%APR+vTH=Nm3h7;Yzo;1gGa z&@6yu94gpT<$D*L84FPtrSY8Q@)-;THntyf#4&({LMtx!A+xLi#j~rVgBP8Tg@ouR zkk4%&G!U7*uN40NHnBAaK)!Rf0$SoL}B@ixCgz}kN_lGnt?7@t{ak`FO7ejP#1Y0rCfOP0C5rZkJLM!e~d(F@05}7 z@DbECtZ&>^#)eEi8}2r%85I37pt6s4deUS6AxBnfD|mrTyQ*;I(zIa9u9`awX!kJ(on1LZs;WaiOzBA+1?iJ zkuQ%uqU>@8Hh~iYmVDf`s|3np+p7VFN4+PnGHheS1JZ(VH|62664f-`_xU zaA4-7zH5y~X>LN$db|PEvIO0o-(IV?Cwd%9l;woH<#4yR56C!*gp~rd4ccM}<|D02 zCc3=Ol&bh2Gu5(V!`YCU?X`a`#ey1Fp%}x-D^EVb1=uxzZ&A;XRp-^%zX=P3P6**Vjy9fBi(?1`;yu&ZB5sQ@utqBBr3=iz|S&~@AJ zjBo7zOZGTG{$ufKNXGi07w zEKwmiaTxaVc85@%(IGHh6RfdP>vIJKF!4+L8Y;ybA0%8=V zU@F+C4FzFHqqS)%R+uVof{!g2M$1!xj8e_AM95%1(kBzUs}(TF<&+$cL^_JHl~5|+pjX2o zvffM*2@xIT)CA*n+)vL0b2b_0bUkWq)DhZsLi@+osv#!OdFWhMpI~SPIy$%4Z+tL| z+pSO8e!N=!Z?F0#7M+$}KoTS6c4h(h+&1zelx4Z+I`v-{eUlVdv)-gA4cAmNPRagt zYsR_6`>+Gtn@{2Za>AtxqRuWkXqPeB|;^ z^yW8%`fJm87IErJC9G2Ocl5Ko5zhbe!#Uibs4c#WfwRuy9^d{e7~c$j#lJ4V^nJc* zPCHzDf+ZrH35xNGv}zoix8bh&<{R1KGCdU2 zf!d1aUp?NN3W=b|3I4*j7KGd~tj0U}^Y)&2@7{3zk3)CiXU5><2BZEbHM0nh_8uKs zl=n{{1OQSCG?lyU{{NI1eD!}VN&D{-ga6$6znK^m5D*gnKS>PU%FXoC_UGgp$}4b1 zghn&JeU6VUDQb*OMovzq)rDDKoJ*nQWKvpheBy}TQ1LhTekYh?-dQ*klbx-Ob$REa z=aqy2tJ{iS&it=Dhv7lYHhlexabMetE+zdIi|1NY9byO7D?9;mlZt1*9`{|Vty(`f zPs$avrD)~4#7|SkNa|bJP^CAIA7l7slB=top598nIQkap)857%=;>ooBvH3eZJX*Y zA1BpHk)s97fUcl)KGq2mo>gBKi@euazJ4_$5~PZnAduz$4Pp7cX~|q&ME!Tuy;u6M z2w4Kzhxk!~R)-}X)klIVWHRgCXBQG-=Bffm3=?;LwVK6qCu!PRq-DxKktKlgJ}j9H z2VhfN$3GnBHA;{(zPBu%hD0oW*T@}FrbCYxcR4Bir%ljO4CZ}el(lHKkxoQPn6f9c zmy_|*_AV(TOsg>F!K#ST41O6suRvR%7v@svH>6@xH=Th4KUK8gs^y?Kz(k9@d-d7i!g za^OQ?if22x6%zmK52XvhdjOqn9NDoTP1+zEv^3?{JF{2yRH!l}`m>{O2)k zQ(q&`9yRg}+tEuP>N|3P@3nM?vBIA?QkF28igN0H^9twso0t|qDVwH`i)Yi2ssT;; z^c*F;cU21?aJw!cYE?k8*Hys+=-@8rvP_ayakatWLG!cgm{9@_Z?%q+bs>-`%KQVu z-y{3gi`Grp=@_%H0QuvMDYCQ;88LbQQ$M=uR{`cuKYv1cCzL17L86L-`3B`+xWkyc zkfCcZ*Mo2H@-b)Ww81Jnc_jdH&zQDXI4(Z0@06dpI@xEEx&p1E zAwig@Ba6`IFe-nIoc`VlUoTc%&!??xHma0*{~#Z*4{2fT)DG7uTlX1)s6@VyV5$HZ z%cZY`gJTnrF+P|Hq#5_hEvZOSKSj=weW)Ckh3}V$4!b1-W8h6AR3`$|B|dk=t=6R{ zsyfv^!=`XIXG)2U6ANuP=9-dqPWXvP;0PFKQ5kh4xtp8kUhHqs?+Z3C*qiuNkA&35 z2NK-JRx%d@G#5Aay-qI=+L1YrUILVtSV6nbE`Wjsa7mAysR8A;zLBV2-L(l1r6Kcj z6}Cm+vPpnla%7ZhR^qyU$NwVu;C$qaa~M223QlscZt0WzaR6!3t5IXL4X=c(7Nq+h zy8@B>5PbJ$#RJ$;L$u-pUl+>`Lqj3GQ0p{C6I0a`SQtaIM`Y*wf#nHnoLDe^m6>`m zoN5&MI`;Q~np;8PKGQxVqTvy@?LMgZH)KC6TAT4kQ3Jp(A+_QQk(hyKeQX^sj~nY; zh^x%tpbIxW(z1%bz|PJ2{AH!y@yIXUoi29!5=N7pgy}}U3+RX+Chvk!T0}$na8uAy z{!NDCiZMxJZ{%b^;i}>m-$%K%`DN(2rkiX``p74Y2cXmtC^_r%Qo95ZdKunLKY$!m=&k;l0iXo)VWM4aOCZt zb(gwI@f&)HX;U%J=Bl^uEACw|@6aBizkfzHG6!iAI?$w##WMhK%M}>l-z%fjkeWs@ z!6!@i&u5@?U}LA^U;-P@y5%7E{*W}pgrW}euGH_}7L00*&R zLFd>0!tE{E0|-0Yi+VB5sljj;Ncbsb^*U0026!co2K3ZJ@L<_vwwci?^s0exB3O7K z6$(^0!DxnP(OXwA9zdS)l6IGa88dc(1bx<(ub>j(WVp+jJvt&~6gi7&L-sv-&)TWp z5_SM6f7x&6sen{a|2=u=Zt9p~h0f5K=iim92uBk_1#8bWuQg;cuLqpJwIL7e_>^H5 zMIK?$^DrvC1<4m?O@qzB6=09eaX_8=x^nt@R62DIsy|6*FCDObVxjmTwMh2!F7GIZ zJ_1Cn(YE%r3ToPruRZc=IS+Im2(?HZgwR{w9x#-hJKZO``&TBG*1Sk2a?dNZc^wmn z6mqF`90p6+OcGK&uH8IkZ>Md4c*f#}NY1`>WXoRouys;5O1_Ni&p|#G2NGLT^xtGw z!n%SM`xHYQ5?Mw@6qbjo7-7;?5Fn@^J0L6grh~|Od+vM$-@pGm1-KX$m%8snW|`>P z91MTqGQxIV6>-l#S9#C{zRp4mv$7#}QAekUsN~@5!dnopC(e$E^-3aJGvmFzb5uG~ zq<3)P(QXdsAK5}Muql-f zo_Q6TG8*f*xzqe+1>tSUsx7sq#xCi$?}Qc1%aTX?hn4Fme) z1ZN*KZii2m_ZMidE~^?WB(n13|4^MrU&b%R_o`MQ^m8N7^YK=b;F2bXGf*Gusy%wW zz^zLkRrIK(t05Z1MC&S}rrp<<%?V*8!DyA)KfWNfiRfUea{Z)qSk_$!j#APB?sn&&R*Yw_qF_&6$LyTlZl~psjQQQ- zTT45myG8v~(R@YpiE7pU<{Hq}+K#f|%D&T)5lcfa4TB z3);VE=lAbrr~?U4pc6k;AvocC`KKyq-m|HaJv;b9dlW-Mx@bqjIf1O<7*Xu4+X^jF z9;D(=((g3+?Y0{tn}2@m-Vv}Udj7!9Bz;;(z8CR+lB1_nPQZ_-`1d6y$=_7&2jXI@ zrBCCYtCX2Y#uWPv%`3vr@BUfa)o&h?%haSJr2U$=TDJB~WV~P8{Zx;=8QUbbh_iM6 zYODmo{Y6#~8shcL_y97^?6ERRHbi=Hnf=gvlSGKQDU(}?&tJ1(l9f^~h`r0m&d<^%C_~!YP*PZU7 zwBZZ>j321iGCP6l6^ckPKW z{^DePaK;mJDh_QCGcO7fA&t4&&d4tQT+U=RTQiqSZFr<>)2y0);kYU2P1B&fhIoPK z^4Zuv;jb^yo{Zq=t}dbQI1C?j`Vy~9>ZsXP`#Y7~rC5bO1O=_jxcK4IRT*H~kev53 zT(iW=>X{A#*BJ2y=JNABIS?C-rmV7+THn*0v)Jy|%P)8thbJvJFngZ*j<=Xmbl$^` zkgu3!RD!A>T9hZmd&~{UPtNkeKSAS0Mb7>7C!w;gNUnV9s)y+2+af}XVV(dx4c}j# zkp@0ezk4FJcP?RV_%DnD!dShI{qWkQnv_i4LiBxIDSr=s)KEU+GsOD?tgM_|K*I8|IWGnv-;!z&AAExuN56aqAx}N4~(11 zy`1_8WloT4fjp6vD_fQv6KetU)>kExA3B^|Bq}80n>wbcwBAxxr?6nV*>a(P>%$-o zvyy|AlfdBOI@Eribg4RNr`hs`#tp;&e}8yCX}!+N!orUMIQ99TsA$x}Q(uc1OvlX# z@)A=z?fR59tL}hiODSe;evSmB`?vCr>eHp(1d7sYm9lWA03etMZ=frgVt@gBj^7pRW z&BvmNu!!8#-;UP25jI(i*}Ows}XbPklmd3Nr< z-{`k;9-N*+bxptD2zAp0DKKDom#hc2H!oHMGr1R28hLh}wlB4@hC^D~9GWV9{0%2{ z3X5I4#(0yjx(x~Ml0)P14{Pf#L+I{qMN*}8HwMT$Hb2&4xpk4xLP@L{EXv2I2Io&) z4o)E-fj+~_5j{jr-vH1}g|O3TdjQh(JGlFmE3sn*Nd!y64qJu*rrWamRIa!VLCXGa zMCz!>Eo52nCJOLVD7Su$x#u4IYRMvCH1DoYGL^hOZ%6&83J!_;ye>RfCqFghR{?7W zo9iofv=%^U0o(~p?sy52C;&4tvZu4nq<8-VV&_Th&%q+X76l9z8ya+?&d1hvBf`aB z3y0S>yIgk&{ab#!r^Mai*Tt2l3O)~xXcD-_EVP$J-VDj6A>4$)Vep*czsp#nVpZ!Uo^fNv0DBINu}wy`fo7sO5$*(%aYlse_ko3;*8Wr}}# z`HX=eK{M4rsx_)$VtzIaLD>~2jjWQ$;Hi3(2c=(Zn)bL3#eG2H7oFX77pAV?l*N5Z z1-|GzoA(iGOm=nSPP*nTC)L^6-n8s~h!rchf)1m1_`J{0_ckFcCO*Mm1v2eH))972 zKkQu%AU*vCg$j)RS9Wqbm(R`E6`OpdSJV(W(Zho(oOiCZP77PZ_wHufmt=9HS}^xkWr z0-RUPP?bMN{q8Q=UokZtwX(|8#7H#uJs#-jZUhjwt0E7MAE!mY z0`seR{0GePBW?#6Hr&~5RdjMX#o12hTiYGa>B#g>RKu;Ed5Mr7NV#mEBrDkT#I@;D_qnyHT`LKA*F#B*bd0afu5$+4(bqYrs23j~4fbvoc|W9AiBr-;y50_y ze1&EYnVg*N83n5r&iQe0UzvX?8~JPg6y58@#pVh6#q}5e%-=;|g5?Q7a(|m!C9;Oj z3&@B6Qjsr|PkJYkVjIJaDj+{mWKTX`THWNl7Wqwf>?0P0*e*W6mB=d4x2Bt8gZK5x z@B9l;9QTMgz45_onlwiv(P*FQ1I8%YoNB9);ZtDi)29(gS_W>%0{%H@{|vCKBPHgO zqaLBl{HPX&mY_kKbRWc*V^+52|DiBKd=tSKIRr!oMvNu0cIW@X$^I0DO*9aZ(IYla z*{od`@AlG)5e-*iVw5Hvy*(x`7l(mB4a;6uEcJk~a%czRk;n?o2|9wYDzuubY~6+2 z<1V}>Zw<>j{KHLpTI3nY3#Z{exkMm6{w+)3X!=iXY_T38Q&*WkS#PWSsjlBxXnatY zhzbsG0eZzwuE)Ks@#=q{2&`4bnk{yh^@t{HFoTcN_ew&~2IUh>UVr;|V5?4~1z?Lj zvyU5RL4V@)vnxsJo=_!#qx=e)SoY@=i|xb zUmSi_+Eh~u_{4&Bpt0@V;g%k*HKiVYW9qHk1~2NGx!AW^O)p}8{dzK3NW?F^dk!vN zs>?VPA6s1(C8c0JnZ`0sicqn+xpe;GSSBRt8He4cloAGfdesMcbo791fJ|%d`ER3VBNHVHqC72 z6)SD={A&Z!U8hUqh&^tMx%vwN*CqnB4&H6=*y&q+VW%L*fnbf6%p9~cHKZpd@zIQbzb##m)zbA$ z-iUn7{VueF15>MS^Y@)hl?Q%lR^G@Qd|_skq57GJYV_Y=G0Ue5#VG-wU)U2TefIBz zgm)D?{(ASAvt`JFck=voyXVxXTunlrTtoJAC}UU8v{^JTJp2AT&hyfyG&p$94BR>( zY1ZPWu#7zG6vn-q6!}f71nhp^>B5G97rPl9 z@~+eyf4E*u|Eh*rE|^K~a*Xwis~9&$$HyQX~vTqeT#vs>|I`>X;TQb2i17GM4xh;n-s{v&FU zkT`FN_!{JT&lk24^#X8U9ebbe7v=MD2r^zSxs)p152mdSu%8BX3UIEqH*4dOv|S0jNWa|4WuJV-{I_p$ z_i9Vl{{{%!FUh17c;~126fki=*y>T=j}$YDcLMGCin9TKyesnWIp|yf=-w9OiFte{ zfLj_RKe2F~FVqj){!MoV{jENO_2NwTFHZ#&4LLGmD)M{&Q{gz?8Nk;E;LITne0eA{ zfoWL)e-5Z3}^bOC8EKw&VGKI}UMhfv)n_;kZxBRHI( z+QUF7BDL$OI4;l93@I1K^78K<08h_B`7zgeyb|pMK63i{Eh{|78lIfNWfNfi5)k3m zlz6|MF5US7f$Mfm%<%$Xid}t9G_VEw%!uPju?~r+DcS^-hyaD3N){Uh9}p9t4tTi? zMgbLqS@kFD&^rdKn`@sB$5uuJ$oz|j<Z0O0OK->MSK;K zAAzT3JP(x4#SE!{oLZ!hoX+55To{#@_-KJVV! zzx29roH@@G$67P33+BJrO?VX}lkA zc}5KHkbiS7;tBl%6;+akuL{9kwj0>Q*B)#=$eN~j)y3`TpHrwZ@s7o&AbKkG<~gKT zS%JS3mF~Ku*wFa?6x~H>f`bq!7d7uAgSp-1cC5IVmiZ9NhmJjNVugS8pT zxk@^AY&=JCsJ{^^aJh3L%YC^>IP&~m1Yt;Pf_lje0lJE#_AISz{L(WxYyei!N zeHk-UNS)MsSRCB49m2jB^(Fw|Y)oc0a|XYA5SfF%vbBe$bLX~hrs92klz zsOTbiX=DWEBu!j_fFsl-G5gNb^bLD{^2pO2Q-;*yoGN}~J z^-mS}9B!n(U%7H|%k9lhXp;NYa6~9yw|Q!slViev46094GI)U0T>R`_(BnCcIVPB(h<<@F@oM zV)lVeoj6@9BF?)pmC=C+y+Inz7YoT+E??5WS(UK-gZ55FwA=HeaW2iw zvU@(2X9Kl031co|^ZjqcF5?(Es2Fue?3guK)&{LTYBd^|p~Orw1x`dYqI&42tH_ot zg}I8UNjGzyWc6*-qAZ^=XYkG;qQQr$H9DuKr}L7&Fp7>kakCY>3?Bhi2D> z=8h36mHB|N7CDh4*&M+wFwA$!A-A_SI^lV~{M86bok6ylK{)8t(22UH{t#611(TiLSf9h*671 z{6__AmT?!dlSe5o)T25@?WSlroy0;3Mv=#;sdBPcIIXCn+Z*@pNFZ-Sa2E#Z7fTc^ z7$==Iorir}MrWGL=GQS}htz4$@Adww|2`?a!&iLc<;fi;*^V&gy+TSH*CT#;_ZYp4 z=3&1#g~D(zVq-KuH{s&51~mq>eEo2yWez#FaPngTHKV6ey|Apr@dp15g~%~ZyH^7DN`7nmFRxl#%k9tBx%NLNliXuD%loo?x&+`^S^)Twrz@^Su@xtL6?Woc8wpz);kNALF&t-9CK zB^4}`M6VlDdk-5OBT0XzE)y9lZ7A@4oSm3%jw^jVkL(|qg~6=Jh9NEq$TrBynf+b8 zOZP+fCt=5vTHRBUkPd`ll>d|Xx0@{gd2sA?+d>odC*8jvS7yLJz_dk5|@&5@d7Zv}X z0n2a1bX;m+yex+bm3`lsf752@(~ScArqCBI4`?1gE_mDiA$>#RPlVgsmad>zS)FLb9rv#vWQb{k^6S@ z#i0%5qdY@)Vuem6dB*lA%FN^_5nO}BqrgjV`BgB;nI-L&-CrT&E{^0RaH{H4vDNXs}jra5r z4fl9+ot#;w({RQ;iR0&Qaju@>@qfj5DvlvWu8ZsrmkK$X;0~adebduUJzqHMS&j%8 zDSr+VesY5&T=kcnaNODGl+}IW2(SFrRXw?UZRFelwJ| zc+%1C!>s!u?c{inX=CpmaxljC&Jqd6zx>5n{&H}co|_E*j( zRNvh@aM3D|d4ewRZMax=IEes`=6@oKJfBt?f_$o}}!R9NI(=*Q=s{DA-cfL7G%(4xaEO{dxqt}fq5Bib>Nv~ zdb`ZqXs|vpj-M@fAP~t8lD6}2EB6Bo(4#w9zs_Fka##xz%O@y(Xvl$4piW&Ev_ut~v=m!FOr3-4J_+x+pz zQ{I%oHG7uP!s^_!<}&G&w>C~ca6-djU7;FSXSPwNH`-3-{8)DE4pXjJr@EXWLF8km zdrIediDD;<(NYf4Qye;WZ8@py9EqX1R4MIU_1mvC_!Hrq#YeZ^raz@(pQ2$5mz|nr z_jM;*c=M58(q~~X3OW82X!82rYrY5_2&CqnkW)# zxX>@S@hIUeY?2zvok)#l~ta4ob|)Q<*iLHMk?s?{z)#i z)*7otnf3PZSUJbxWNNMV+MRI^RYeZIcMh9eCXWZhZYK$u`Et@w5B$Nao5G`B_^R~q zY`q2FGw(J2u;nU&BJ1i~Tp#!B_&O6zdqcld+h4v*^OKo3(WP@Ukc;e2#g>qZ@z2ul zk=GN7^#$~7Iq{io1a8$m3=+@|{dC6avZ~eX=ZTvSjep&Is{Loqj_vQGgu$a|+@+C9 zbDe!VeX7m&%z16b$X$w(;w#Vl#MEeJ8^VQl9uX|=jf-e{_$<&@)hl))HR-m8cPsYg zCr=q;h$i3-rs(+SYKDF1+n7r#qR4Q=k1x$O$=pbJgrgpOD)9E6c;7|p-!tuLwp-LU zu%aP3==O$^@N-c*xmxNPUrD52FOZdYK0pmzVM+XE?fZhR{vj@PJXU-6qp#yn2Ig?%| zf5^|@nQMCkoY6w#l9`Fx>Xm^)znz6Hz^Vd#6vtiF-CY$ZwkKX2z_v6r)ipIXE=5h& z0rM3=w(s7(12`l+nY&6#O84(~|N50%l`X-bkK79^5xB&7r9Ho^LrU}5s-V^JKI3mJp|zC&!0a5&D!}++DKd5eZ9tqkc2)i zAz`A%=gZr-f3c@MY0`G~_JGOlZt0o)`Ezq~`mV6s4iI@&Q*N&Pcu4~Q_5D}g@*we$$$OxEJAu%yA z9-gS!7dGU?VtD5SaBMglOaAGS|6APA8{+>!I!5^!Ri~tk0{Bo_S-G*HA?xEuph7+{ zctAx<>p$HP>ajAQqoV`7LL8m$w}LFf!hM4+<(Zk8H3j}7Uu}S&xG`CKa=bSBm&PdV z>kgL7O z3is~)SziA7wM@ouU)#(~Rz_xex-q=ka}5xl`DJBg078ZkeE4t*PW9TpjRHT|Hf^0#>Zx zI}-0-{RCt%usU~kwqt0;0RS79no0{nV`*v0!qN!HV7M~{g&ep^fTQm1@B8|l7}xrG z06Z3k=Mone0FDB+*~`U6Nl|fXdfuSQeF@?n0vR4aOH&KDrrO5FuCqU0W@TB(1Y!Y^ z?BeVi2wY5{Yyw^xK$~UXz6HSN3V_i}O-b>a<1t7X8ft2Q&PKg_37_)d<>jpf>TY{P zJ7A#!@~N$(6B-)o<97liQdbwZ@UXD^kQdwY9l+kS&C7%E85tS5aNz>brYF!&W$y8)iJvXgy%JHS_k`jRdaVC(33)^`nxSGm)8Tzq^0AWf4hk78LA@bK}E4v%`$ zBo6?S3e@72l@;|QAvyhfO+7tMfR$y-&W3u|*Wd56zsgA_yaQxafIjo^@IYKxZamzW zUjH>Y$;DgzF7$7p(0>?${?q8^ zhPe3u=+gg(WrBdji^RZS7_u3v+sW}E7YD~ZIR!vPfBE=LN9!(BduTB`J3GL7_4f9;#%uW1xjq=cvC=3k4=1PiO+G$m<{4nY0@r-9 zE})~c^Dpi9;lqbM20rfYodpJ84D<~uD=Oifwg8PDw)}EGR7N?Tm&d**o6>d|^OZ zivf)m`V_pb7zW87^=(OjhFzW81uih)d9he*nxxnHa~B+kK5s#%fTxZQJWUp|RCaM` zgJuT-tf8ax4dCc33ej-g8-Rgt`W=@RV*VqF3ZB7{&k?Yg-4?sFv~>FW`$o}DlbH%J znthtpRaG)5Y)#;47<5;4e0*Tl1ND}hn;W?Gz&ch?U}s^uD-#$9P+urCkr5F>|3yRR z6Z=QPtkA#Fh5pBZ^UrW%$g4r8$w1`DZDYcO&B_XZ?5|(=;f(vK zv$@$4UKkv~@$OO|z~2eZ5I|V4{tKQDMCXo*;#oi;T+Gp|-%CLH7McL3?jL1iUfxIYjvXuCm2KF4*)bTLWstAL*%zVlfRZs4K-HC$Y(cC57#NoC>ZxLa4kKUTzKLmW;!#24 z&?`1glXRjd;pYe5FvKsE{q5D^zkMnYv-t=F6hO8i(yRRzqk)19Jq4~5z}*1>{*jR? zA2Q9EnVB!GPNu(l^(sEz15nBkhF%^XfS7g|uW~rqrvu(Q@XVF{{e#QPV^UL%;nQ{| zCgT8Lb{eZ-;<*01uMcS3pHY)CP`MgDFh3%V{Y!>EI2auoI&=1HRb?f?nKQs1b{a12 z?;OKG59IS@V2SyYp6EPcnGf*#}H=N|0uJK0-F1PKRKo12@f zwl=`D&i@FG6~x8C{yy9F>i`o6+&P3-RZdP$M#eOt(&^Xfp{Igdg27koUr|)T1qB7b ze}~t03YEl+VG=0TyvCnz85$n%7p6cuS_7L|#BLuh8e;Qr3EyfYgg^s;ezn*7Shbg^ z2=BMtN^xoFTF^&mbb81eVMfL&I5Fto5R-86fRP8O82jeU33j$+%e;lpq^`!Qiy9#8 zkcsNh8KEhFo-%)IRa9I|=nC2d8~{>56X#~Q9Pe^Mg{|CK0J64Ia0OB`>y##gk{Q2|No}QQ(b!Sgkp_?}Y0qYHk0{se13P8eX>FDeMMg7ws zYXDkDln|A zDlb2Phz8FAxDU`ASfGzXBY}botr<))d^aY>0frs`ZW?eCaA5@0+fW(chQWse(%!hv z-{7z5L1Q?05cIs0R#Q{y>ghoC*FX(@%MJ^B|LRq3h_obOcyRC?e}6ne_C*kx+dDg8 zDDV&ter;_BjxZ=F2>dpn9CRm(RF{6}1qe9ANS#a_v>G2Q25RCETo{C5VSbLDzV_VW z;sHomh!JS>;1Th+UVyCwv={w~hqu8O0^(?((CCSsUA5a{5hTad)I%a7BB=E5Q83E< z73C)bU7$h%%YS@)9M7%$*G%D-hVx+2ICyn{VybhQ4Xda)gz5#|7;F^4U;#RgjSeac?9PPSq0U$cVIwQ zQ?s~YpT-@B%P=Y~VLtf_R<^hNPWn{_;HK5ELP7{3 z1S;Re$Ak8?d~BPXo{nISzQ9Z=?YsL2CQ~S|wcy}kZT;89gwMEQ6Fgl${rLlO1I7d_ zb|?Hr5&+|SK-j{>0Z8{Tm|==zHon^Q!O(1q4m8o!%*)O@o@*n6I|Z#lE9)5*8n2_F zXbltUEx(kM6e#yFiD57pDE&}(oY%)Hp+*Bg9))b(H8BYQ_P$h&6clCn2SFz;L6AL@ zySLDtlKAc&%%KPjq0r)C9Ol%@1{(&`Dt{kn3~<>nx+9OgI9Dw10 zp04)#$hQ;F3J`NpV_~jOjEl3kae!dt=I4e|_NlnIr>8^Kdvgj(+3VM@VR7+aq4PEE zpF`*07UTcBRR{8Tu{)*wQR5F-8axXPJs zTm%-RE$lJCAt&G=f`v2r>xlpl10@uX`Wr}Lu%1Ap4(|WQ-h^APK+J1@6}%?kIF2DI zA$B zxw*OD+Mt*F#l^(e=vL+A-;wjr~YB6M!#Q)U>;|MSSVf zO(CJLrKP^m+TpRmfC&aC*}y|*2nMLh(8xh*L7}+;(=IIBpv1tG4yqVLD@KJ@SWKmeDf0d1Apyc3w3o3@~4N!gM>9XGcxu=xN{4Z&<-_kNy^IGC=&*j_PtSrFH^x;D$jE^PmOTEz4o<~NW93AnRmDz(o5v(Yx zswALr!c-5r2LiCT;FGql?gR{0un-Ln4h9dZw{Iaxhq}|MSLs%tKCpUh+uqW{KuIZP z)0+jY5(XG>lKHRDIY;)-Rp-C8rv2xJ^&epYO3@z*Bq7OqcxWg%-DKqCJb|hYw*mVL z=tLv1Ux9;zp&5qDa>wz7mD!Z^^o^OBhKBZI5IHa}LCk>{ixi9laBa7QQ4nIV&-<$o zAljgW{QW18^>G;IKp%iwmI;LUwkI8m5bSwi$ukD47g)4GW162?cz4657p9lLAtfyh zw*j$=jiANlxmRP>@cK49sR4BZLMi#{13-qo{yo!ukwM#5(S?z>^}|b?30R$ zqLcG%15N8PGqtqbc0fY^m;H-L$3KV8e{1>s&!$uV5jwCQBcr5z`|8zY8VU+9w*%F@ zUAhgLChj*m0YT{B6)LQ>AfI4cF9UX8@VX|^eqIo5P)6QCM#B06R1s{supo`$ZegRk zeF_%Ci`}rsS^YbqZjAkHDSv-l+V2j??HaK9D2a7%!+?JP@p<6+X zfD8vOoVhcK&S*{J;2)q3B;-^gsKK zAy{1fpV(-@zi*}gzxbA6$_rT?b(-(#N&_6ExsGj`7D^xPy!iB0i7577?sXL=3r@{n z3+!CH$eQGil<;C_CEvl6smg{_I>}R9DJ;JQBTL znSb=ImfPuD!1rJ_`k@WkUR*^h8kI}g)+D(&xON#g6uoHnF2ASk{+^?{`sPge_Wm|KmX7nT5>S>#I{V_%ea@Qu%fsK6L)u3 z{U(|m@zU$3DQZ-!32SwENF`^TmBRJltxDeIQj3$R-_#;GO79j!1^Jz7t|{W;`WP<(X-dLX-$as39%%3KWeDtq zn_}x?ypWvt8s5V__i9u7T+oVyM!DJf&NvS>#_DDsN$xcpc3w7Fss3EFHIsS&=zf+s zPk+ufDb`tU7BL(qo?tv^Ui&}hHkiWpjM zq8%~mj7FsUoR*SRVNUN}yw?b#4ivx7@2qNFdQtTnLUt&|^U~Bc{1s8xVW8-m`EkPq&z-aIx-M=6s++`2MZok-Y|I20x21 zgt!@D59)c&wpl5bpc>(S_P*Svm-%V4F_wV3sw8CJd=T5Z)(c1T)Dhex{wxcyEPmiN~*1Y1uL$&)hoi8%)C45^Fh!2u-(I zH7O4^?j)0%<4tY+C=P8x;o|vqDhpFjYG-6$#@A;eNHXXPR=3mszA&of6-VR0e zDNXkV$VG{|Fzq5)x2aKL>~1%T@lv0BCCe%f7J9gSC9y7L*T`zRyKFo|^7l@1t4&_@ zGzxzQp)2-#7{%R_RsV%S|HNPm5!B69ys7Z9qPsQRh8^)9X0P_D^$t{0(HBgLTwgQz zWBN3)&=rr}Ek3mqhwWSI(G`Pw=T8?S%MKBqBiSgQ&gbE$LZ*V4@2!0^O!v6II||-< zA)(C}S2{9xF*dppr%k;L6*+}4?}eH_<|+>J@qfTHQlNc_k@xs@dGgAFah-}sFbU!D zDv#Y$m8^5dTKAMy%u2M+&TQq z_Kd_?bi8TwyuEoF5`$GARaN`YFkppqiw{B0)NT9_51S15lEP|=*FuXy*hAQUSL02m zH#NCeemUDMD5xW|*)2`D$?(lN=$4VqyH!39IgmrJda>|U@ zA?}owTDs!+=Z7tXsIh9goZ}b%)zi{h!rCFvnWl4}k|^$rEytDqc<(Wl=X}1Tg`4S@ zeMl=Zj!plQru)$=_N5Ajxy0SAs3KBD@H_cQ(6Yon>r2F~+iH~0GsBs(l34Kf^GkLb zGv;;ysVr!!5Na8H4U$De=ZJ{poZL>9Pf7y0v4=BA4iCx4HxV^QbI9H`o?Gt@hq>lf zdhUKmP`4UrK72yt#)!3hbWa8~lc#iT>{o#Zu0-nq9Xf#rCx0%?-<@=yo`!W4`?KO7_uS`Kq#6Ja9fL-sNR|8>(iRzdseZ z%-bw?H2J9f=BKn8NeQGc?~L+>;+xY%`Zt5{k$O!JbDL-G7$*mE3=(t5pd*?wFji0h z6N8)&8akucQ_GiC6ILSIUVpuX5a9|9_<-}6uu8YUw%I;F>r36%)A`Vfz=H+!6(7sT zX~$y=llwv9(JMY-1Go6GWC_iPl>g-&?`um)1TyAXF#k!Km=jAFi;CTPO8)hMGp0yu z&O&l}Jrtv0^y8T%(E>uDEMA;_gu)}US8sK1M4ofSnqwzPPX1&MDVfh}bIJ-mWwU)7zg506iApJW$`!%QYJRVUP=Yu4Ph`6;I6-E?dCOYg*7 zb-2j8%Unu(y`7tv=wtC7Dr4YNs3~SJ-wXX5MKwl0ABMEp>bq|uMx2UTT$PW;X9R|8 z=xevyUXS7!@nZO?u!G6SLBo2_vmcX;of=s|@#brOO{A%lV%3IL+*=rjR6e z{w21NoM}c83r^Z!qIKP|(t^Vjh=>r&I5y^y!h;kXkva=SY-ZM8k=m+#^}MXXglYdC zk~p{Zur@1}>uzBC5pv6KvEn{8^B|sY1!K$mKBA*?`Jv(uFH$i(UN){nf5`6=pIW(9 zl=~=AuaDYzSui2F+Z7{E2$2LC(NMp9ntS{F--xFk9HPd~$)%}a(K9F_2kE{CRi5H8 zxb}@mQbkl&p^X%+$CUu**4x<{yqDauceC;cUH3Ixt_y!eBIDeT3*D}5r{6mpbUO`U zx9DuKNBv6lIb_|QR5J;@l+cJC^O=1!XSVhPzk->M;j0G+acD!|dYoqD(Cr7}G46_I zN|?{H3M*eboI(g|XJ?zn@UUoHZHk*FOzC&(vT|EKWG=_?hksKZd1KNlTg{H)yuu*1 zkJ#NH>%J1$*p)A~SIf*9#Cqv&Eq)hbm-bQR9o}vuvRW&Xh!K^Z6-kNlND3IGPb6ih z_J4QF^d>U2dDkpUJ;nK}pDVreTJp2p^yzJTyeAxDhZ>$6=YvQNWS^5L=m?EFCpbQn zwcFy?u&T*f_TO@9nTZxA3Xz?U*m(D~40Z25J?<`c*L8qw!pEH4pknXk`JM?a+n-mu z8~xHTOb3l;DnCTWw}iL2m^Bb0{x~)j$h*|wmidRx>k*H)%6^J0(BU|Qe2~h0OGX~v z;o_8TT@h1iw!>OK&||7HBvrY+PEg^6@T9HU?@A1Oj`YPcju@S3PiMbfVD1dd!mlK? zyn!-Zi!5?Ul&)G|2ckbZA*p@$Zra4`9O zNrb?w@NzIVdw#C2jtl!h-Xs09T+DBiLG_b*EiX zerNX{w_lXn?vXVcW2>A)wYyet_RJC&u~uMsNyrX$5)QhT4@FDwGZ(VbeGY!}n<+tI zBU4Rtlzrw|mO3Y1hl|Dd^<^h@CicTz6qe*;=_%h4nk7I_!sK_cXz!kW(U?6+ZhZbU zN~@haXffc3y*827k&wjOS6o`-zMIaUsaUGt%ji_NXW93X^~%Qg&GcN>H5S1pe2!Bw-pcf;$0~{FZPhP55EKXln}-4jM4kFCSnB# zqD-1n*eF}jVpG!L$IPT(*}Oc8W3A|<^vx7o%i?)!FoXEF@3Hs|r?c1tO6t#KM$S^=Eje4NcnOkp7_P`u>Pd|=CGs|+V-b?+3gV-4(InZz>j6I0Q}{=* zz8&Y@H?|qJ^LyNIDE82>xx2%_rd}>7)lZDbCva0xNV>VvF?#bgR1m+yaUM7@L|vQe z8o3!FrIewb^K=@mBuPnq>%@%J{(+iD>#98Y&{x6{0Dd2)EZ zL)la6x#X+5_7DYekz>pzqL&uE*CIQrVpA<~WpO|?$d};wz5u+ot4hxzi?X}IapQ|4 zZ4l3-*Ms}ov-@c*enP`z72wn0HCQp1zDIj3R5t1${v)R9rO!e~Vt#xloTOzhLHX$q zC8F2oFMs#ydD%}MP5Q~SXJM-m?X=Z~R6U31)p4oL{rZ}*tKNIeHrut16B^nrhPF*7 z2p+?>Z^nuuO6&YyXD{9IWj%&Gb@S;J>z95F?C~^LyTG{LS zH#nPDZogcXQsp|csrvm+7MH-vFOqhW82J}B8qw2}iW*sJ3dHkt-(!18gE)B$QUo}p z&g0IZ{hnI&xCMBxTo&s&d(emqL&0mF+IM38xOv-nLc(mSk8H&L0y(nh+)L#gG&YRF zS=BFn{;!|H+1r@xUbLu`JH6U1A^2PkpLO_Y+i@HPt4@SS5Ft%0>VV-Y751h56>Lfx z(B$~Xue-0*OWuA{n;wqG=qF#p;d3$e!nf_0tw?vi<9yBZWGmY=st%o2qn>GO4da}i71bc$+5?iQz&aas#tXdqkVOmFAw zp^9ho4qf=K)(|!<{rDpC9*d%1oF#f!&;RbJ`N|`bT^cOpU@-HG`>d(`uOpCOR4YWC zBX@6qj~dM(*etvEVBnzk6+Wd1rda#&MMNIszNz2h)+BZ7ey1k+938R7zzb7n*86x; z(UvC?HS(c*4(}4TMjtq;JH2E0wtF>RJn-+SC~<}*2F_mh@jFj&kq^1scD|yz4l`P6 z6WI5l@Mjo`MMbF~GLTqhREa#td;jN*TjiHMPnoW~$t!Tv>}D zQ}iJeP4G1#5qK2H$RZ!inNxddOpM^6%yXagaI#1=Pmss>iRj}walh%uqWTzW71 z$H(kU4g=$h9NhOK7yB3h)0jiFdR-{YhU#%Uv@hQko>vA$h=JS-IE2 z0Jww2b5`?N5OzwP?MW#Ib8_{=`VXB$$vCq_g+pupC)&q#1@qD$w@Hd9AQuh z$I5ebvW3qhi^07zw$_t(H6^VVPfx~^>__!OD`>_&H+9&<)V%O&?yHn-`JHY*T6wnD z9CA&SPl9-AWZal4`Dm8rd(8NFDq`hn`DrylA~|8qH%qKB|7T{Qp3@Vpc4?tM)aq#T zIVWM}7VHPTl~s|VU+!TKA9{3D>yCt1#`Roy(=d5Ix5*SuZNJxg!d*^Mw%}{2TdSZe zE8=j4dBgM5X7Zr_=Lp#vHRAJBBn{;m@UEvxP6YPM6&G zn+(25ESx+PMnPk8(T!p~3PYnG=E8)`4cys(zZi7)iwu-jeslA_@KP7P3xA}$eouaQ z1D}T7%03#s86v-5E_VG_hlEruvxVZOY;d`lyodh0P-*4IAm0u>JxmLSmpo1ky255t zNnXuN;zRP+7QGGbN+QP*l1TxR+kOtD;d2srm+n3wE5~U#Y*aX;OdG4v$*-WCP%fqr z@_h3}($_{~h~-L=`{Iqv5tRl_#>v{$=KI(j5QD&9!q%p78TV}8{ zQ($0pto=%<`{u4}wy&qw%R?;{OP?^`olR?Tex1ZL3WmF7gFkf4r*pn&P3a_mlj9Am zY#n)lZ#-DH`~Dh0!K+(e~9_Jn};mGVND074d(fnTCs`uEspfu_)s4 zz{$!tU5+x5cpPEqi*v7_^cp(WmDBAt>Z^V>k!4U?$d#>EJd>@)9#}1^+tI$x1XNqQ z&m|vKOXJ975ASi*9Zh}1w!FO3Eh~YOdXE4H$EVtE>AV=T$S(oLn-_%dDet{C7B{|X z_hm6|$V)-oS^6?7_m+{A`)s3@p!54BEuOlwmaBKx*l$;>;hp-%3d~aSB;4rMPV6&BKe5k|aDORo zR^-04)YDVutf0%kk6Kn#iZJ=Gf&5)x+A{RMEA1yJ>8Ta3XU75d{c^H)@Ft3KTz zJ0*7*n5*Q`?iHj&)xU6_sFyvfTTdslFK~_2?r?an)a0n6V%Yb~xxJWW((>>k>gmMg zTuEJ{B--((@11ZF8ytM;JEqU&dK@y=6qeE{ly9{>l$E#hkGcEohpb-n$!0%+7{|5x zkrtUFhF2cTmwyh_6LbbnRXW(uN7}2#P?VWpryw^WlWU&BG za)AA68JX>FY*RhzwJj#l`db#QoRg2O4p*WT`> z3&<^1EU?dfcF<}yad4REwS7CslzilYMSXYXR`y`e#hN*7-^ZBFrdzG3ZwAj;x(hjB zH*(33y)(zRdJv@)Bt}Dlfnnw1w-nBI4eQy{-G)`AZHf6ll6MPw-i^$AYLMrl>!CngwPvUp!b@?YwV(8>_Hk^CA^dRxj5kea9r*>%IM^nA zKKA?;IV5SZDo!yH?AB{|=Uw{|S{!Gcx8wq0du0GF(sRxK^*QIx6y)x!)q)6*rEou0 zbJcjUfvZRkQ@et&cy#|}s0USHc)LTb$!gSfqj@o2HtRLN6hypGilEo^Q%6m&$Bh3H z68&aqVoG#jCk@)q2F{a zM~Mu{5RSfo>p0QTD=#pja~Es(r0qLp^bg#2qv46e$2k*i=>3Nj?&XFwK9A6r0x{qiLR<85H5yA;EXO#`+PXZuj?CgZ<5E zF~UA#8D^2ou~>x`0Um{@;`54Ew^8>7!pd+9TsyD4xkyU(O) zjEhnHtp}CUQ)t^L8MWv(O-H;rk(-`R zKX=8y!gVUAd}lSqemuRm-{eoA*^S$Maqa`&W`*D}TP5iTmm)Kk!O@;4`!T-M#*3qA zXPg2;YpNazmQ$XC@2RKChsZNg`IgLPH`(vIVmf^_;orW>!MhE&pWb&ohiDR6Rk4pL2lG4o8M1sA?!4DN?46e8ql1&+N|@J5TDj4j({XRpEMi08o$33}o?X(9-hH_ijFmjveI2oPcR@hy zDU~+I2pF1{ol^UT5HfruDQ=u$@*=R-m?)A|VXa@KS^CoHEcjzyBwm5smxuuqZb5TC z-Xh`(*UeqZVe8k@;j!?W&XUdfc2*)qmToaL1OG zb8j*9^xKc9x|$kIA0sz5b+6S$CowZFpQX*dT3POkD*y{ zWJUDM&-WY6KYH=iE0*q>ZdVkg;5NVF>kj-WdH5}cW>|H*bN_70mE7#t?2WzR-yU#o~~Z|v3U-gIhem2E(94`R7tV2Z*R zVVt}ej)Gy5j_qngv)@p}B=ToQ&BNFuKkyDEwUV%wjQm6v#nVJ}< zt&Bfe9+rIPXh@!m`in&g?PqciNMeS#Wc=sNxEv>_2OH_ROuz|gU{`=S@LDVj7 z4IFicPB?E}T2N7{0)%{ryc4WcURQkadt{Z)X7T?(_vjvx3t%bQ%lcEl`COTMF}aDT zD`Knj1IGCdi*<`}u9$2x=rTX9nnn|wPKk^(Pu%5~YPLIJcESISlD)wfiKO1boZG28 zk}actR(`iZegTPsHy0Jp^5$e>c2Ep5`5eV2n?0-pbO@v5oopg(`6pJPK|b9^WRb7R z_ma-fu6Vl4)s4&MTW@Ma*dhs#*>8(D_y2^Cmy&Fw0vf@piP7Z#FdJ6fkmnH*V)t-4<+tuMMHIFkmxGW&%@~p-B zqf_4D$f{|H>J%^k0jf%T-i4BA6z>V4%?;XY)fUwDM|E3a?nO)L9Rb~LVcH}nY_ay% zSEQOv7S&~!_$IX61a&lZ>2X(FPk+6ejgUNN4CzEb*CrZUsz&=Z&AP13D7Ai(v3ga& z_`Cojvb+$7-ZmV<|6Lr03Q}HP!J((R+=3*>z0`X9ZT*)+IQA-;?H+?~ed2lbrK0Bs zKYnTEi6$_z!BMJl<;8xD^`fB0NtXOHY$K`_G2e9pBE_@dvdIV=6rio-LXZ)?DUGo7AYw($P^ z?dGG7u75t``Kg95H~TZG6z*eSU*8l_sGn&8pHweCQca1v^y)l(PgI3yY4*e2!g8ViM{3cQI z-1s<%1PQ`*+E=&dt{@mX+jv84qt^EK>}5uP$K`_rU4E=_IDhDrUwcV6uKVUbdw>2> zU>lpns=1tUzwJ-yZ$>y(^jxTTz!6^^9ZnfFa;GI*|D5#)V$KTTcr^}Eo;yYy!cuQy z!kpfYo@gU1r!IG2XQdFGD8qRet1uw6dAEUQo8V5otUh_s1{b9Bk)gBiXR}0ZdWp@l zpAw})fVlI^J?AUuG^$(-tMMEBkkY&ov&IMt6ph-7NXC>ak{zi75enx-p@a8-dQDzG z`%1R3X)hXkp!a1;b6$CS6eN|EqGMMxb&0B6_v`Z4i)x!f_NAbz&#saD2*+nb%2aep zK|jsUAq3-SL*T(nSgMUik&~7Ncy$+wXMf zomOjwx0ccBlAg&ChRybCY|oUpn3gFF|MmaAq&n;aluMEXQPL3vJr#o%@rKQgio$-p zVan+mQlCDr+Z%B-1os9|Bj=0{w=d5ssgd!Mqe}DiACWh!lBW>B#l5cV1~fN4t}*M` zXC*|y)(&?}D7!<49c@FY20cWSk6!{P`d}f~bZm9;Xdu`tI}u-qtsd5aawT9vWvkKW zUvfbYM>L7C*k6FP{3dCt9>pd;`>zEr`Zjw#UbW1}h*bPVQUSD!;erBh=`#BX0#`jO zsfCBiEl~kImn;UI$^j=GHwJ61<>ym=nzc5be-{C73+x<=i{=Vb(`<8?v12+0g^Fqn zrth7#Gje455Fr9&qmO`tT1zj-fs$6e6+}E~2g^K}@VDmi-9B(5%}Ju)6_mQ_5TT!U z1=hU;V^ybO0G20dG`^_6-?;X|a3h4_PgvH#lrJHo{v<7R?a<58?nsH}d@zfG<1 z0B7V{4=rio>n_C9C+a;@z%e{VY53p?$>`G%<9gYG-cURH^dDoz9<>^Ai-1^OjnDn@ z_`An>VG<1d!~ii6+X>^-x_bZi0mC}Zqa?4JXOf`3au;|Edtx4pSlz5*0+^RtE#d&^4gvi! zvh~PoVC~RD-|jHQTAy-Z{2WTjDumK;V|8eR4=_oK0~NIsgn(+HKo?_CXtYYTjmHq6 z1Gi7t08%j{;+*Swb($1FUd+As(SBEslwSGR_0v?Je?JE&VY&aL?NqpI9_5C4;xhX%F98jxeIYtFh}ACG*;z>f5-T zH6+gD9J>NAaQRDb^m`AowgzrwTWB#3?svQ3?*hz&JwK8r>NTUj{R3DMH^;?=XI2BNz|ynBdolefo`soB6k=k|yyiGdlE#gzT&-R1E-=gT08mHfd|7OW2&oS?7bH?L=LbB=7-6e>CU8Gh2>F}_U#;UAiRsqHm0-SGZKg1GfI(SV33m-3w3ziy>AC#L+{?4I2tUfm=_mW)5>kjciVvNB4gyw{d zC)Cf`-jTiYnx5IZjHZeo(2kM7F@l619x(gbkVWn$>#FwjbPN5_*kQN)<#Bf5eWt`{ zFg>yr`7dLNNj8fpd0$vv{5A%2(ik+4U{|Mkbe?o9f znR5|sK#6qrfd>=mWF$BHj?fcs^BKw3g_4T`6#Q>Y2L%5o(}DjJ#rXdeWAeXHj9&}< z{|Pere<;QbJhHciiQM)fwMA-r@2wdo@)%34G@hL(aFX(r89yind{4)rT;chljrnX@IwCiP03K*i2v^X)2)1JFI8EjJl-MLn0W(%0<$wjalsSp zN&z29+-~~|i3jQ{UztbCBb!XtPlk+Ossp(-6ShU3(*0{&U^cTwVZ9%c@;$5O-F(}} ziqF>Ds2jcGO$kHN8y)@_Gn!OeA~jg@AGZ1Chyibb?EttE;TX6R_scrR$dG{9#@ZHr z*5NR^(|PrkF@_oqe@0?xfu7A`D-oC@*kv3+|6TGDiuN@d8_9%vxwBIPw!PbujLFCIgaKQ%ZRI%Y5WSATkDPmi2Kr4kU&`00 zm|`k0MN#pM;EotpJx2-v7EK^f>7@8!iY5k_;_MN8K_t;@Y0f*GnhMb9pc*2uUz~}Q z|9HM-JPGDqhe4AQ(RfTv(rw=CSKuVX{@#cE&TyxL@df$cEBL4(ZBZu&opHYeUx1BX z>z{i5A9eUxoEEz_U;<|`_xHi_djy;^!9Uz z#_#obNQp7W_jd2^Z$*pEUms{nu>IMnG2l5K_MvEq2()Opse_-kQf@E4Ss$w!)N5iI=4$G~8aECkg} zvMl$jq9Cqi7LKdElu$wCC(2}c%MvE7#=X&ZaQaz6I29p6N19Lk^J6YS7dXzN0Pz+H z`P$ZAL!XOxCU?Hex&EekDjYZ|$!dQE9Ab_I@eTs+6jX12{rE`iHgCuT`0&>sE4wmn zOO0{0@Edua;&gZ3T2 zC%M((%ULC$_wnr*SLUAL-!8pPFOp)=KHv(RbLUho$)_C~fhulzD#jZG(!$hkWk+p( z72gZ6IGPoQ(0)vKXa8YXr0bQ@(c@^qBMiGE{91cVA^3v6Iy{JZz~D7MAR5OUk9>>N z*9E0ZpM?sZxlBy%mZ5i}tYb;jcsqR0)MU=WEI>)flN&oaPfje(#A(gC-k8V$rrh}q ziZeYg!7o>r2p!&MlOr8P7#+8S<@d6rX?qDQ(4p)y#85Z74zr(jh;9dEU_Jfm{o}57w>rLBS`|^wfd4e~6m^of@!=3N$fr9k65i8ACyWk@m0Mq-K41DuCNdfo+?Ucd~ zHjVxAZ|*&5;9FXJ9C`o5j(B54m-=-o7fbh)%>uchLpjGLtpB5mqFQ_t_Bxah#VMkQDDP z+1f?3OIMemub9RXK(*z7=-m2 zn07q^0msPi=O7zm=YDEH*zDhGM8-cD*p{uWPY__lyh*NMn~4Xf2T8qUGH@Ko3P-f{ z16;Sg&O0ZTp9pFmHACp0$5il(S~(uDVDErY?r)N+auNE99d_EUM#llq)-ZqzdGdY^ zg9`A6gHTCb&y5M2XdQjl!Ngq^J55%|@)g+FC z{F4t#3f80NThMOB+r9dA^Ir13S+zO=iX)veGA6Eg@cnm%uUuBUzkxGzakuj&FR>dZZ{H|aQ7(C!3(730Gw&Rs8@S4@Oyw)=Wv;4e?XaX^_y~e*vRp^gWkJ;uqJJ_ zwcXl!24ve;-O!vDo2i1o%@(8US;$>BQhg9AhDnA9whI=Sl^oLLNFlM&j-y`(15_pNEtgJK@iX!;4gMT z-z6Cjm)em?Y$8F7%nX-ES4y6AwT#Q2X&|6YuvD5Zh}Rpm%PnX+;UfM-EC?v=L^%G! zl*y8RG!DDk-{IQ?OMb$6qg2q5&KZ!Dp3NGJ!3KPXUMbfq{0)V`)zPWdISW&Pi zVZB1UI4`a2&U0fVv`i8WHm;IRLiYM+P@R@lcDSGia@*zuht2P^-gmpPK4~GM>nevi z*$)%}u+c)2*R{;1O+StE}t1|Yq!i7wo|1<#ecBK6r@5b+C_I{n?FAE>XI$xoO;m(+jxZF2NsHCO{aJ z7d|yTgNHAc-tVxK84AwaHjDzdh3lZvD<#9{TTt(YE51UPw+*Rs!GALnZMZbg<>xec-8xG-m!p4ZGE4 z-Ley>m%nXPIA7EtjU(6w2;Eq{w?IXme&50eCWSrv9gdA~kx4qpMz3|r%w5Fc zi!FP?I}&bIJyC&G%0um!K!#g$y`3}m52opOJIGBx$nllkZ4bbU+d8FzbugbX((M0~ z+T}s#Ym_d4nuO}NCNsF({(J?`2d5OPErs#htR)=%2w(&_P{xb%(B5`RBOI~kZ}xH? zbm24zB}BPmT(E#mhOrzPF&sbBDm=_jyzAg}qnS*+SK8?Pbxd z&+*dIdP!U|E?ub?)b*jW{h|v%kJ}Fh`voA_& zjcw4wpA&-^P*6XBX7&8-JrjSPfp7H~G524o4KsolkC4G-dND)Es9VC9fxyY(AWm1< zR|F7d()!a^WK9h7KH{qU1sp)9-z8KV?oR<^1A1Xui1_d^fMI?=^oUF(FMHtYY|U@h z!rSny2~a%F7!a5PL3hL20m%)xE}tb=&;z+xix`B#pSUVAg(0i(HT1~g8Gb9SPnlTQ z4Gt%`pEz{l1TmEIuP+T>?%@d)=n8WL2j{rioncXn(VP|3*$SGy2IkCAAQ6|xy=3^o z1wDVQC}Qd%Y$bm!VCG*G7uUar=U-Bt*nFa=sW``JN2hu%#0(~Jpwyhrd!uykyTkXI z9XM*x>$dmRO-ll#XjQSVvG$6+xq4%bUZIdZXt|?HFe1%nIbl$aa~mQSpXN3sRg)+;m1}<%K-*x4mQr zZg}<=P1xR4T)AT@?ledXAeI|3pg1RwUaoo()Uy{a!qwnX)`#VyycNH(TnrB{O7lKm zR`oFLUJpO_vi+f_^l~Wrbk2#N9eB7d{mu==DFFc-UwV@d$xTp@Jn{xkHiGrvxS5fe z8|3onFZ7WwU+JyT(z9dH99eV@W-eJ46#wD!O+7}JGk_7=kD-a!!~NtGztw5Qzkcp? z=he+m`%7E2YQ|^E4_0K{Beh!?prAdy>blc5A=yeh)tSt$xP7xxg%&8I{a(BCT#O`> zf%7+cM9Smfw;*EQz;r_wIdV*=i)B36^)$)@E|$mF0yq7TgC`jQsUT)`Q`V9tA^PDI zs#$i@&BeqaZ>rIT-L^3<%BYB-1kD5Hvu^`p5zmIf)YHG2B44G&1FZ6k#NAir9(jE4 z+&>~9-&dl%+Ox2xgK5p$hViIE`rdfDn$zUbcGa4zZSB4CWMIaBvuoOT$uVo!-h$$( zZYbaXh2Bi@4R|=z`Y|yid-l%Pi2{mp_wVt$&w?d?pfF1XWy*!S$Wb*OA4Id^WW&2p zuInTw8zp7AT*HBB#n@HcU|_^YUeY!2OG5#*3uWY|5}t*4iin3LLK%**^ta65X{`4r zYV+@5#`MX6I|1_B?jC5O8~o3(h-C{JCaiwFh<^1|Sxa%fxJ!n#38ui}9Va&Iby4SN zh|hWVEsI-N*J7dejBAp~k|yixbjT=Z$vKJguHn}gB%@dIp)k!}%(6DKn1z9i2+cQ; zK<+)u?do&kP_GiHQ5JIs+%d^91=!R2ux2d0jL|Nr<6fwnV9k_VCgO3#y1{yz9!EL} zGQMmwbGyvCik+1TBrU#|Z#>C@!&P0+0ZFg0hxy-ZvdCz?glEGwm{2)y!|v zVh`U}lLXgRqN?_kaN)@f)rVySp)C@k+a~XN<;cVC(_R5&)-#n1(`fcKri4ZB0_k9WiI{_xs)xIvDb<- zT=^wCUV>~#RkGf=1DFp-rETT`p?D?}#f7~a}2#);PjZ9VbGdFfn<^MDW7sun$- zgzxPFtg0ffKRO|K9sxaQ>^%y?`1#L9CcEz*ZXthwcXS6?h}0Sa!xF79KA?$E%mtN4 z5L4I?LCA$Xt07bA5G?YMMwn#35gQSysI<8o)*BTHTos-hH!Orh`+#i;ga)>ke)Vvo z)7^Gp1|8-m7(L5!KxkG4V-qxLqHBorcnrf`qOAil*~)L~;;=61%QzvyN7)i;v9?mk z%6A=o>!>X3H8p)7c)Nb7~cvTzLI}4(WzAsN*}-t*nNyq2J~=f=!@T1zG9s zoD~e_k{zr0Fe+^IH1CAGhCB0nS2Q~#MhmVXf%woY_a^=Dd`h(PRmU7W+4?5T4iobfl z4d9W$FOBhQ805`zEXQNdG5C~Gpu`_GCFT2KaxWPUDv1k38k$uYpspy+4b3?lQ{&h( zLmbXC)&jEnFcEPvv@}x6B6YJrGR&|f>+?_AwZdTQ@A0rDb9ySkEc1ux&g-K z%i3~X1GQshp~I3wObJw`%(^92^->8em$D{!1+pq`IsGISH_6pgy2Q@x?PcAF1ltXM zB@BMDoKrDfU;adt1)g}9 z%>#QLIC@&iA{2kmSYGtYm9}|=n|$xJSIf>#))qp4zxQ?suV|mjn`I@wTqzeV(sv^s6`Ko3{+bV1qrU{SQ zcP}V4@yV>>Z+oFWkaOq#-D^r*;F@oM>vGtLdk|1E!I&@HkPv|~|?B6+58&*9JRP%h% zCIo)lJ$Q|j((^y{9z_7Y3w1UyotIY&DE}Su@+FXntL{-e9ryy!&9w-k|3o4Ghc>}H zN%Kh#(!gANUUHLwem71se3VbA!EiNf-nLGs-oI2v9 z1F`DS)m;9q7NX2=+ZeoZtG2i*;q{LmtA-Wg4Vpx3#u3+4Zl=2f@$}@iot*iK5}l7B zD*QhOY0`tAUyb0n%en_3+fXbduAulw$TVSOIEsqT$Uc`;X~qji;8&Je8-}Q9i!42J zj?S&jJ+7@(l|}HHWhr;&S+90HgRAriLHlT`@;17JVvp-`WZviO0-=}N=wk!mLk+za zZ#wu{tK!;bCpl8X$9yn9=dy)(eX%W%+SS|@6>-PYS{24%z0fH`lXcev-oV`j;Z<3T z@k*7+&AcvFr!jAlm+WjJ$~{@AYb*%}RK2_v-8YEs7CrEDq=3kCcAOKQBWMuk{XoTG zG@okPK zUaZ(N7Q~=m4}&uo|KBbUM%UkHx3s0-Vj}xp_?kfAjP$ zBS)Ot4eLqXiy8`U^t`XDnMg=Ci*VmLVSPh6iT;sXohlpCG5Ctle3%P3LD`Xi((xVm zYyy~BGaH%jw~Zr4c(lOR{@bNLIUPVZ8I{$qVa9KW)yVpmMw-= zZ42{g5&oNSQ$8tdf36Wk^^`y{uEnDzp;lNBkya6*adY_YKz6=AZ@Y!17sd2_#iD^ zWxfJoi2}NOQz2OMFya^}`8&Mk`HLJFu$2OM?zuR9Xq-l%o7oKLMj)U&IEpMQ0h^gp z3;d|Vnh_3gAdH^B%XjGU&D<`C^7JEw7>!hmd86cRxpIo4*p^13cCzD7x6Q!?Negr$ zcmT0pk_3?4GVxc}Jhb+KTcbMA7@bv3iJ~M$oBjwr%-ByCwax*n9)MKM1WX_*QR1^9t1R{!4~MaZ`)lJ@72{7Fp};@Tx>t-#VZYFs zcGm4o-yVFC>@lF$o9#dd`Y?jqub+JQWyK`bo-J$N>P!T~ee&_yy0quS+uREdny;?v za_N3Mp`=YAwr?0ri2a!&?KQo=Zy$f(g{mq45ah4*yzDE<%d`9OIMEt%Zl^-|5FHYO zUnZ>9fob>ADxPh&c<0J?C9%~sa5pb5e9UpJOsxOrM+}$Gz6~M0`ARemPg!)UvD3Pd z2+^uh^O^%F@5+VO4w8{O-Q-bEZd52=oBV^GE+0J>HJOo*XNX+nsn{IE@GaJOb}DK za4kvd&?OON*sF-oxp_rmhnk`Xmswhml5SJuCvOu{=D5%FhD3v8*t?ip1xwMHk@*{p zp*G>Ze?SMVHYivZ_f$RXl#_o9H8k+z?4E-MMqmpf!l8%v7;*X=V|$5yqJ)8*2y~XN~TPv#FzFAKXeDGiDpa90>;e8L`e-G6)jqe5I`~y!&ZACag%z zUiT^yym-#tuUMvLFYU3S!ZX<1@F-6VSau`hOGo zC#C)?jxIHgZQX)uuGhz**nnq^=uM~d`MCX^(Dsq#2bb0;jWL>e2%2i)x0iHZy2S+! zT!It!ZhdjIC|g&@=Mi(9&;liQ7v65kWRW;sjBSX+wbU5t-;HN`n?UE}zCv-<{-1@Q@hMm=v73C|Ldcb)c&)74b}yg&j?R3W@&#;Q7BBrg zG>=nFw8G`G`aZ9(I{R8?i|4%vrV;8FRp#j^HV?xYG7;uYh zIZZS5Z>+-%1EgPQ!e++~H=qo%$Te&ELUY6`sY~uJDltvZR*2XYQZ=v&9euX9fy}nW zq8d2C#y;*3PC6IIuWU=j`Ao?4M#vBLy=M|6O5x@uF6jg6q|jR9^6Y2;{qUmZo{?{N z-FQ4niC?Y7k;515GM?C-BYdp|T{tq(hG`d^`S!>g_aqV6iyP*f%XFn?2CU;K_O^jE z!=;D%lRY*zz(WXM7sc} z1}oum3zL0^sbQ1Ak6;X-H^U_-trJ1M9kBrS{ie;q{U@%M{ql4GOtF1Pqk9h>oz27B zg7(DGfRJ42z}zZ~4|T9S?wDfZ!uZZ*K#SvK*!7A}V<|)^BbLI8Jd}q*mu+_oi0A`U zHo;BN;D*F|UU=#ij3*1xrOt;S9NE{*AV3ORbuCpk^awhi&NMw)>MbJ$I9xTXoghiT zoRe3|IRL2zN(onxY*V~7qzm@!q#{_L;hhsk+myh|nWHvo?5Df@B9$!8w{VlkGW zI&``sUw`=7#L)wqZyo~GJyNl%7t13?6gJKXxyHPxzD~h+Kt3Mr1!gP&YKZ)L)13$1 zd(XDqC)CBd(x|4~{R*m%?YIGl3U1^gnxr*RkoxY})(v=*tj~^msTR@SNz=o*y8dx) zKxr*!(0JD4!~4P2QMo~I$Jv&TT8pf!wqqJxW@SHZ%lOZpwl2@(-KDdbfiR+~!DuUs zuf?tM2gHy4;PTZo5whXoYP4IuC0!Q@ULAyd?RSIS-~Hl%k4Jmo5V*YRjl4E}8K-Da zh%qmVurhIcX<|{{u4}OXHCLuQklK9@T{*3;RL$($Dqa^gq_@V)m|6U)f)p-^5N?Gv zX*L&%tx)Wt{cfB1cgh#OUmo*)1}QlYcuN9IFqGWlD^T*Odc59Gu8YM=1_-b~7--?@ z^42@q&UWw$FZMq0wUflewN~XZPybImmg`4IjV+Nb?X8{SQm* z;Q_u%F%g1llX@`0d)iNylH@0}sv1uB$M_$OQm@s3Xi&DNaXZtb%E{MSe&bcwz`p)v zY%s+ILm%j@ZfCp@0JDoPCa+xT>3YVOGTe;?>3Fhn4sqMe5BCz5v3GF0zkra2=9eG=}PY5qu_Pz99=ENL-&eu-r=KK(dB%9*wzH? z@(anfGJzueZ)Ohktyl7|+xv@KI0sP=1y?7M+Bn4I*=e(2%*4v?uTEAf&@45UY-k9+ ztru=W9)fHXg?=ER5PWOrNwvyrU>Y^o+aaT^{Js93VSTT0Z{*d0pQ3|#(ci{q6DSP_ z&CGMRTCQ-m?`i&rRp8okUT*Uxi^gnZL3wa$ev8>KalF4K-h$GXhL!OCu5oIxm?p8~ zJK+t`mDN2pKG5Bw`$x(3oL<*-kE$*8y~LHVCP&>P+wd1AiyYc}X(o@w`rE_9+KriHA*Dg;Md{_VG3FvHFFh*pRe*4&Hivi zj;$NAI9~DGEg24H7pzkFwkhoj(fW=h>v;xDI`P?x8Q$b4Iy<3@z4nnI$f2d*UPe=VUhK&C^ton_&^w-#a_Ck_shxiHJ>~u>A9Fj z{F7q*`tVA~C4nzhuFFX;qx4ToFF5k9OXGilCS-s<=#OtQq4ayrg8qizDOZ}Oa8xZ|FOgVV=$Ti`Oi#&i0Qv#Oobs5`X74< zClvUbC6}0{m3*{FG3Gic_8+P2*SVv@S=rEa1=AeUE;ZHbT3u1Aq-&oUv(|xb!14UQ|!d`(dOOb4UnZ<_18ichW~uIq-lLd zkTDB@`C^@(hUW{MP|I(|tGOw7L9LHk#i!MX(s^Z${Cc+BRQKxw@{I5i!TGbku`YN1 zo4g53xMvcxa)jc+=Of|kFswlL<3kLQ4l~4aLd1A8UGZkjy9l58R=1ftOKVGvIfh=1 zX6h~kz0fE)R`H8j!N3o95t1T#pEyxTfdN}-Ms6N6&AR%l@kHg^j*GLav~J_i$W*Tn zYA74eKh8cKITYSM=f!~d;QFF}*5|)gR{h0is>X+6X3~}ZkJ>9#5G#=PSl2~Xt{YCI zgg@8ddKWIYqtb$~wfF}QFewx95vMkcUAm9X9O4tBdL`C6+wWMzdiPKf@a=edcIx#d z6|c-&S=+P4{W_<&VpMQ22QJ~NWMv9#Y5du&@`IV!?*7A15tp~jN4i|*t*?)>;2!A~ zA2?=ELMN8916CKyNV1+F+P!^v=8ASeS)*^M%?!oGASCNj#__3^mT4KLP z5Ffwa#Tag70C=6_7H)SFqw*62ogJKc!hR3ZmjE&`PC=3S!Bgz2J^eASl#VxP&LJ(? zF#T^wNj-tRYTeO~>*fA2LIZbVH<@z$gh5qS8cO$@>7-+w+|B|Spb3W+k~ARL{=BJ7 zK}$D!`^gYYl&w_I^eh+)GQ)d@;`G96-TJui_9pHDkI(-Dsxj4f3_pV6^Gp17=ZH|z z{o_;zbyo8@$n^{Xs@q7Wp6Gb#Cmwmz(D~;}y??G*Wv`G}s=i%VH_>7U zYM_6k*?5ligWHbL;;|OhDn+U16Niza2{gQ`_{M4|yT4t40DHeR9=oiC#h7URWYbi= zc7U=scN6q;=}r>9HooPN=aUz;xeYRgPqcfJBS@rBJ%@k&5PvDE(K)pEDB|PNWBI6B z2r8FDuKfG-nq+fSeg5=QV$s3^i4^X)O~Ze-Uuspi9$UQU?$#EU)0Vi%WzlZ`4I{zd9GH=L^>9TY; zmU|OgH2pQo1;sFdgFChcW744P!Xv|rYT`(ehIZ-nP!n=sI~~K*I?uF3kIBUhRJ}9i z^Q?_F5%J}m=H;2Yb6VNbXN&zq5pEnG9#1mC`*xS$?KE{{w(?{n&^ZlPuyEpsue+Y1CSRG42tx>i@I{N^d zc6reNck@6f#rMw-GAL$cl&I0nZ-U?N^s1c9m0i;*Dj#kFm8T1Q{}w+MIEwuPFkP|{ za}!q-WlYl|ZhaMLLWuuzDgU03ll<>!!T(dF)c=VV{9g{t|5xW>eo^87U(Unf`XrJs z!r5LaYDGmvd}rKYM{~)WEQkoil>PmRO#0o2sJxO0MWWx?w4{%Y&`+!jE}qN0pD{WS zIoLuABV!hI-gQIFCZB9^aGw*dVG!}YbO_@iL5XntNQEgKv`-P9jPjeaW*YmqIhV@3 zhTH{3DWkp#bx!16o5VY0C+5qU4+=#%nJv%e;}XoSQfV8Pi@Q`L3VL{nl!I4dPJ-Ob zg=7k&13PBJ*9N90WXyU3`fE}0DpbRPI)?DPmKVW$60?7INPTS<|W98FEPycg*L z$V*-1Ni%medlCtwzLF(pG~p-Vv^z!oo-c%QR=&-vHGGwP$arFMjy1iG>4p*4+6K-k zQ`%9g)-0UmG$iT*h@SjMWwcDhweg+o^kcJuFU}Rg0tws|ns126kfQG=Hj8~k#;EKl z35Ee2v6`19W)(ykgLZ;hng=THIz@DP@ik0PvMi#&0jeTNi>6!9XK_<9cHgzHKA`y|S0{roN z9cpljPBkf7fk?5k0B4$D+1y4%8(vmFAucDq1NV)IhfD(H0q#1K8gC=DSw3V;4-Vyx zOa1Hi+XHztY8>co=1P=XU0&L1a}<^DA!An1C9>CpY}GsJ>#J0pRbpQa0ZO8d(;)_QaM(H6}t32;ll zMJ-gaqrq7>)+^aW7(4F*twVs+yaGAMF6K@20a~`NX2=>?sO*vnzBf9r6>#_)9*3Lz zvx?nLB6?2_4+-hg*h2p1%-5lgPeWLSt{Zn&F=c^Qy$mRP`{k*&w2_|rusyM+%)N4X z;`&Y&+a=feJ;saYUZqtwo)irbk6>K{3gW5(yh&gqGo4w8~P^^ z@^VH~-;Kcx0B4|8dja$%XF}-YGUwwpM_5L&|9rHA)tlH13RXEZIZUh2&-wu z$v)K1;f`!*Pzj5(5)S300Ay3XbAJ*uthSfUzZb#I68u+QAfXTZwkLkr8z9L*Kz+t< zbtl-pRBtL@@yQ!`jk*tvpu4|7HKS56)g<%iRTc*X+8BRrXnC6wM1D5G#;oemYODdy z(tQRsA7E=eV80GUiG0d0<547zKfvzmmC@4@lwwH`E|4p`7V52#stEP2UIg)$k?q=} zV;|Hmo;{gwIbBaYw~+u9g7=ejI*G2?}^2*#XQ0Y*6QroJwp80PJ6 zd2lCG2uaFI&#mCUeV5ea6FBPhy@m${Wuj(O|7jr=BL2$YuhcvY_^516>}P5Rb+)e9 zdGzm>A(NJWfwa7sj}rd1bkRBV3lmly>}Sm%YF%mRk6J=fMMusjK(&r1&7mr>({m{m zs4sD#GZ3PW+L;Sk+U&UZUD^8?mOt`588kWu7VX+~qCaaS!x;pBnDu`2A)9e_Rd#aiQ@ zddWjinA-m^i9(llSB8>y1z$x$bj{ZcHfj>{)pS!C|88!?Ue7%{=0zHr`EF5f;9tw@ z$@zV~`k9(b7z<2eRJvX$1{`BQz*jy@COne%SQ@R5U8?5P!yBSQ_E4aUC&EQPx4a!r ze{>$zasL3*oaIuz&U&|@vHL;@GsApe^6@tMDJ6$njqgg{TyasS-Bc3zs()6Z*Y+ewf_U+nm?t?el4;X?yFe4kK zAbMZhc(Bk_`~fM+E#};6ENA&Ll+uPOd@*AUOG4qy?W$3tsIagBwLUuw_sLE%16&!) z;#fP~no+I%CAGyUmCCivK*N^yFxq|L&__L-Ws3NSb?!)$#of8}g-``I^Gs#tr}*u( zmVo@VUq5HpuAo(QYc{+S6O)tokc+iq_}t`|It1{&Z+|531Tu}VwXW1d`jYhln^$@N z)!Gn{;1+_p$)|!nKN8%mYEb(0@}e#R>GEl z#r=5R;#4T~8^Zqg+p*h*VujK2gShtx+rJAvgHLRGJ(HGxd&7$}YI%r3g024Rp#CR` zhK9%kmcb?XNAaj34ic3hBOzanlsU*UG^&G4V8ZVqs(m7jwDNUi%}I5YxO`@O!|Zdw zXnDmDN9|xz6QhJ@j{s485mH!;LbY-ZxqdzUw<{3_i113mFE-mWpFz-HUN7S!rp>bq z<4hf~9N>LCfMjz8vn!6ABd%+(rFPlWdz+AZXe%$;m$wc_k$^A%7|_&gV4BIpf77}_ z|CJ8_P;>j!0rFp#Sg9rmaH1GvD6i+suI<_j`jW`P;|6b3VV(T`H$8Nt01yaZ1QJR7 zY;h%8{eJbA7Fd~Fm!CiR3#t$S%$>f&fa9tzhssw#htj)ddd3CLeMk7&B%&I#k8rNj z?ypBTSc*nlLD68|zGKMX67sw+nHccp>jIGG>)>%$v0eY9l$s4^T%{B9is~nO=rj5c zNDwnV)b~bY+(qkF2YI$YA%FC@laYqylVm6U`D5rujn|%bfUlzPLk8(KojC_z-u&_I zNTwXDRM=g-JVoYW;Y@$-`4>&sB(Gx|Qt_yYoY7*zUWkxz-VNbn>c)F8Ujs&4ynTb% z$1x67*$3Z=jfm3e1K}H8<7_c2si`*-%`km$wAE#ptC73oWZ0RJ zb=L2nvEdyn_j{b`v`XHlf+CJjb`_xekz!NayN6%cl8J!B?dCh{Z^7+|n=`(H8A`JQ z^drh@*}HE_-M^xtGs?B#y~feny$s-OuE~9tl=Ci_;!^8nYFs9>CxY5RSO;;&ZZgsZ z8g$$;3MBE~OmBuxbg+jA;oko(_XsLEBis*filHt3XB*&C?40;Pf%?iR=>5bbH>wjg z_vx5EW0o)Kl`FcF<%z|8OV8kQJ{bt!tZvk-SE9@EEwdY?Dqd8Kqaa<#=YI8ThOj#J zET$|$zV0u{;_}E6faU@eA&N7d{gy9K2K;9CG|0e%A;Yj1}=lBbP-3Ic9qx93z)fUp26( zH+9YjwO4ub8oPdc{A;WZNA=6)AoKVb<6q{z{naSSFIRHjr7(-^g!~JYG`$%cVCI#i z`fmm9#K+^fE%-BG_l$l->8;Hld_dQpQtK&zdmH@cl7rf58^S{f44M6+<>XKc(MqZn zSIzzV7`A7-MGpM_b`ZByJ5T*BsvnOM9&}+@Ssvp>9E2;rzN{vva4z|yJTFC|rN@yf>=)?}<-DKht^AIw)~PY#6r*Ee>zufE zgJJ>Wq3^8NNl4?CBS0pj(5orqtnde25cLR|eUcBVg?Z^uBA2Z}Y@5`C>c%kIS2#eQ zsh8Xp6iYU{E#$+6F&{L0&UJm;w8k zTm+8*(@(~%@Ts4dNei|q1GooFh`|4gv9}Crt9`=<0~9Y%N^vXh?o!;{-MzRw1T8Mb zofe8ip=c=*+_i;L3KVzu03m1d{&wd7Wp`%x+nGEkPh`$XuKT_(q1?a}m<~!9oZ~3K zW*nu90@w>Kk6+Va9@6PXXE9Iu{2~^_nC0dzf<*5q|D%CQTLhcB|iT4uzU~h`$bFTBA9HxkIY{@bEj>}&W zEc-!3$9!x5T39y3EQp;QVFPA1rU`*(Cu-~!$vkRKK*apzmQ!Z$L!L-GJ_l4#< zDb~lEbJ0V~BD0s7LlLd9Ax0PQPDm#bMwY!HL}%M{%^3c`!v5 za6SZf=7!tfZ*p?g=yEfb;}p&AoTn|<&T_Lc_7>K0&W>qFzey90Yu7_*l!da8Qdym0Ior9yil{W99w_p%J5x0t=h?D$2acYmwO4mzpU9W& zE;IVqJIvE;TRG^{fMiZRrY!}kBfNZ9)6v`m-+vt3vpW3?!>?{kvg4;bTp_|mZyaHC zMm!9;aJ#J*!S4dNFaRDK!nVL4c0_2oa)Cn|;G_#xW)D?jH{oEWo@)Wm`72NW&A?F{ z@u!||m((8P+9@Aj?_^o9dxT~LR|}{Z=sjM8r5Hb;J{ZEmJQX^~rDIAAITfLRMK%QG z5AAzkoopK*9&?v+f-h5hhoY=nAWWxs!UHLrzIxg}jAm<=m3atOwRD$xcW_1l;kmu}?5!kRNDo1DB5|ZkZ9~LA%?p z;EgznElDSurzHWj@nP02F%PY7{oM=T;DhKrvKbhTk7f7-pn(KS*O z#V7sIm7RYW+6nqeRH@6l&0pfZ58%T-TqFHAQGlxIercG_FC1@Mg2FFP=C5b&Jz8%* z2#j}fGR|!QXOoQ&T!G2xX6K2eK}bB^U(Wfb14iS|-|=cQq~h@ZOUDf)GpzdQyxbTl z^v#+{zDP-2z4$Yi)LLxa)`G2U3idqW3De`19lx6C{8)W0kDrx=0t*XI{F?GTW3&pc8xX1w)xWHnzt_l z2cpRJ*f6por=Lb`as9-%2#wfB1AmGpw-%S+ZRPc6J_JI8IMr87eKn7F?~QpSm61B$G6af4rnasFZBUZ!LfB)2xyM?Z8ZbN0*SOdK zX+PJ?AdwnL*8l1a4i1iK2qM7|f%R2YuNx~WDi8(0&;JU7_wV6tt*!jPe`o!7%AVza z%MVNc)e3Ty!Yw3l$(!4@E?SRRi3X*hXGCI&b!{Ym`(Vro~O z0guh4{{Dps7)Qsj-QlD?7yj7`XL3Y0N%H(NG!36z2twb*x5lnx*op97r|0k;2O~?Z z9$n&nzg&y}QN4ioIz=Zb7b}T5uA}k%YH8L-dF!G)ThoU7=2+7_eyIql$t8sNdp*Vz z=&{2RsZ&=Rq4oexuYgfjy@mmwl4vO5E*M_O(2VUcrDS%wu)a;9+ZvdjihR;g3%uC4 z26hd-22`#+4xvp3fmQF91A~#)%?$T-J&Sboy132Iv}W*Do=;G>C9$mVBo{zKqSvzo zgYr(6%J80c@f9duVnWC#qG>R@6eE>of3|)jnLqqqrmoU{8}sdyn;&kbWcK&kzU&Ky zzl8x?5E6+5TO?QiJqVtE^C;V-w@AmkBr|kivyXtc9~uq4>7SerHT8S=WM*HT;njKpOv&<1szmg=ZnQGyL7?#AoI`!|Ykf=v-r4e9)H>(XXEl&+!& z2r29z_5-k=6A3tcN59Yz08xEXBBqAv29fj-X-h!KaZwzsaf3F$nbPWGJCIes+P(Ht zK+rF3qlm{uq#fKdmK(34D6gXQc#1w-Fnw-r)NT54dLtZDv$M%9vKTGGyUIxEY4_T2l86E42uYP7Cpd_tu+g=sw>~L z_@jx`xZGxhC_X29jtxHogIj^9Rrjf~k@3EX^}f(c$TB-gKTr>QZr_2dz$ham?kywI z2oyG{uqOa%ar!}A_G0qiNonjCSkU;W*ey#OLr^7AXvnnxibr(=+t|RsKWDv@e z+ztY3mhvjsm!PdG(awrdJ92&ig1_%M1>&`m!UAIUAj970ZU{h$)XDpq8vU-BFe~%< zP5^&&R+?e~-tfP}-=(f?!*`l-C!Lf>fR1DF`cd0ur} zzaqmB{n~K>{?&b&8(Xp@rgqPhv@clvCklow^p8w4<_h%m( z&bAo0nfgc+qb0nf)wc+hR6+fV_}00j!7aLC5!6pPpRNJo%S%cqHHvJulk31o03}cG zUXvN#)!#^oxd9pPKK+flV*9qkqCk98m+1wtLpX&XFd{#s=>@6$f_c0RS|IzWAOgZ2 z20VnTGN!~#1Yv+jHXZjH06ls=qzx)W8J^PL3&3If%xMZBfXQvmg&3AQ{t)*HHXCiG z{EZucY(xzH8c|wGeE&$Yu=&D{Wc6+v$Xfo94})l(6(Q?mwhBf#Z^i{LVWz^sv8t@f z(dD~#5%~B@F@_qj^;kwP_6I|l=~Fk)49xO#5U+0m^wPuMzc=Um7SQbaNVEsGn3;&( zg2?-|XN=fHNpeK|NwEK6vKY}w(y#&rvoOXC^-b>p-38zmV{?C8Nsz?fj51c+royU} zG%Y&nI5!A|xla8=FTpxwuGj0JCTAEViboYYYqt+v3hUv|1JZK1@wSClP=O9+n7=f9 zfANbHGd%w<)kWWIb_esJll6cBLH{ym((Ys|@| z^3g>-&|b-VuXKsZ?40QEyaMlQ%L}*w@iFl5E{N$(v12|E52zJ%B%wjohF@oZi>eV4 zcrENm*z7O%hZyKEDv%IWm4o^W?pAB3k3l4m_9*lb+?ikR1JBe`mp*^%4Al%v9->cg zT9Tfp8Y7vTlUJSQ7X>jkEFXhTuK_7lK4@5XL7PBz8gz?#{9S8`yE#9V8K1xXIlWO% zM(lZbO zy>*D3n`XpMYP^U~AjMt?nx|>jHDxj!-xMtie!8Omw;VUvg(CX$g2~Yu0KOkCZ{w)+ z-tL~fu4{@Eq+j30lt83pjJIN08F6}Qb@aAkH{8_lts2aji~ovuw{kXgmb>pmY1&Tv zUcqyGVa#qkw68K(-+=jCv>F-ABspw^jf+A7GSkZd-LH}6M+AN|d$-hF$)~q3vH7Y` zW^i5#Cw{jv{A<)Fm@R}nDzKAy3p@q>_0#eKyu-<%s#N#J<$QZM(eR;XFN~O(*IiKK zU+}5G_OP$$xM!|iy zo%bldccbqlY{Pp)E)(CK5P0D8o?)GX$UBpYG0jk8u~U!MNs9;Qz`SK%!``ONj2`OD z6EMzhLRj}+7++Dg<`8CmtYc)f)6lfy0iJIoc7rO@Mrk^;Uavf5v3u^0-#kBwwwIAwrUOZq;ef?=M=pS{{*L%=*)9R02+r0e%fzWu zE-%<#@FQAn+9v;Qs&@@3awec_6g00ugMN}Ndq|Bw&qe;mpBnf4$$DaV0kTo9R*YCgm+EmNza(0 z!COQPq&lqsgl$o#ABwsmaNaRcrap2~YGk$|vkfpMuG!f}yN8;uq1GIq^>IVj(T`O} z5wH*-K%#Ko+lu$sreOMz+$b4>(r913t}?a-wRD6|hPuGp;CQfK-=xtz&m@sQiPQ1% z{Ypye(HqDzkPYKY+LiP`^_IY1UuCkGf+CRREqFc|RmY1tGVt3Aira|Nu#TI`*czPf z$-2-3uhKvr1okBSge9yJi95I%P(17xP`dX>F7BKdu3EqW3#ga+ZRiTu{BJAm z!U8#L!`2yN{bvuA4KVB9WVhYYiWiN3Dve!rnRU{f<&nyuI^nAZsWVbdOc z0m&uHu>AT`UT5pQ5aL&~mBSq>DfgZ(cMAL{x;{k(d9~jeyube8H&^t0=q`p4A^aU^ zoq+czQs~*s{+1Yvi|u#JfDlN7arI@Hlu#FbVnaA7i-0+=}k2o%@b~rvT{F`2v=Z2 zoQ_UY(Qx{c;f06lCt8sUt`H`ZV-?5sO;6G3d?1`e5AsFC#7*1Z!Fn|T9Kq{#^T01LjMD}5}8f| zMxH9kHwqpF-kg3^aKf#)24j+JN9HaCAbsI&*VXdR+w^5M`}&OHDPt}w^TM4cM~T%# z4wdTTjjW?9E*2i6=6cl~^TimUSwnVQ|I5Ny1V=|C{exUp{5sgOL8&eKtRz8}Eg~d0 z@-EcoxG6Ka`Q1f^2F~GQ1EEfNOi(#brDYx%B$9tGJk)3O9%Dx9?J^=XXCsCW$Y*`k zMGpu6>YzN}f%Lz-v>H$%o0j|XkwxO9zbBT-b=FHW8EEV$Q8-qu;O4L08SKgNoZCA_lUrA|^0Z-Df@hn6M3)Pf+>ITH{a zXXPhJ2Q={T4wReq8Kd80dM3H-#;N5-jh-ZJE~HyUXS!W*yZ1K^%~p6njkUGq!`pL{i9f{IX_1Q>hvcR#+8 z%eNoWjh72UkS|^kstMBK!(ozx5~BodB2UcXqb`Hlv35m2g#z5WBP?$1Hjm8mJ^5i} zysqhI=+s04=QeK`jIii*mfScTQQfbwhrvv!SJsW?n-XojEaTsRQrFI1Wk-00=J7(t zLt}>oC)H^3-sk|(|B1Ys0SMU?6pX{~rYyFqC+dk;KoP*}P=nVT=Jo4RtA{*&zb1Y6)=2=aX&@lWVYUG_OU6bnpBfKf5iFS^!9p&ZDd5B@U2Hof zGK?bcB?7B%P^UJyKQHh@^(!GS>GU*yHy>#ahZS9yCiFf}gn-Nq;P2s*CKt0?P9wDA zcdy%8We#$$es*pGRR!;_05$Z?&AY~Co0eAq|F`rl8+fCRTi69K#E}E6OenfrNI0i9jf73EL=}s@UUT@}Q|_vlGM} z%lw=ut7;AqRPF&&lWcl+BLff-(VDLqJAjBd72!(!-9VQ$(l%-D275<&O1?NM6M+1ep%?GPC|AqEv$A+YwV>8hnN+me`h)~m?Btl2udT3wGu4PayT!GV%j?ZijkQ29#grCMe0g6O^pMBT`D1gITQ5>K|4U&` zQpW|9^JTYw*auEqR(VEv^wJe3cI=^-toa1+DI z_i;DgBb%}UzVhWa@9%zn62IdV3b$a~SVNkp&Ksb7-E~S(;qx}Xmrn7z{`Vh_7|S!= z-z={^8hlZ^%lK`~!I_V@A1U@*q*wNTpjVpoUihNW3JTzUhnE=)%}}8U5AbsS@*N(_ z=T~V=mLP`5SY>vZn7CIP#RC<`MU($zG2pU$A^5PRfdUJv6%<0%kXS{}$Zv?&nPj!i z;)|yb+h7d}s=o^Ch?W}Q_vIXkGgZEp-g3!-V;T@$6f*qvzlD@BNQb$hLIZdlP{~WX zu-qn4$p#z|y*M}rK)BhMYbt=ZDV29T1Y&S+dG)^uzX5zH|Gz%nOF-`su~ zYDwxwAoj=XXzl;Z`Wy3r|I@?!I6`#+F1F>8i~Z9`EGxn+dJY~2haRm<%1y(ta1RH zY!n8iO};be+>>nU9TosekB?1rCjgxsA3ugUI=F$*M|AGd+rydMFhK2FtR;KqEELQ-lXApTxON7s7kBB9N+Q{Q(eS=Q0slQ z*`&d9|DD_w6!{s-B{?+d|EFQNF}`Mr5RlDlogf5s+nUs1!1LL965AM9FiVt4^d*i< z9>56ge4&bYp-#a^QA$e^PB|>W=W^e|E(p}&;4QPYXRN<1K zDY(}-#H}rD56p1|L4VA(I;`&&b;WM#cl`B z+(OpwfZ?#UD{z08IE?y@W{K+jI&IWJ#l_DiDFgO!5>5Q7e@RMkzw2)fRz3_?hM8+b z5PimLG!)$G5dH*Pu^(j>Sn|z=Bt-nG4t3!?Z(MXY{9O zMJv~;_@M%>oy27cNy5+1B%!#YZXOM~FyHRv_UK~bZ)xJb#a}gQbPXobw_X3p?HbT> za=zMZ9&NYK>a-3cDIg8O#%~^otbYAb7-Qp6GXe=jvvrm5|3<#$MKEeTY@Bh##ku~! z$hZHU`u~@F%OfHr#HH(J;~V5@&!y~U?P$-X_urwBrj4_`tuL41dplpJw>;du{1OsA zzTWoMZa7#@|4#nr$@`{nR{b-xaWGZ$d098{`_IG`#o;W396!s_byV1DFbH+B;4AAz zJ`QI+9@k&BYD7x$?q^n)&!0;~d>l%woi20zw2yIYQRI9u-iA)(G1CzVin9CbQVfOq5^siXS$mCVs9qvl_Svd3FDpkeC+XMf zQ&xS4EH>8hv1UKE6>je`??XYZ;cQJI)FbQ9-9+}Lgk9x2c8@mN+No@{LlkJabqmbV zly?s9o}CkmVX>3hg8_(avW6SA2anuI{e%uGzO+&9?yp(Z5xGq(**f;^jRoYH^rG#f zT>6z@YPo&q`fuLy4AoM-Yz*`8*IY^8(0F0lZL+lC(iyQ2plT&gNinIXNxAlfo!uxE38nTGa;Z{}h{ zs8cGEFx?rv+>yuPGq+V{?KZo)>gVBlp@NL!!IkSd6(o(GxHB&Lm4`G**^kg?GGgQN z&Z$cCD8b)?bDW^ayU82z{_iq|Hb`4K%vRKY^*HxyzxSXO4zC$_Eh%_W9vUOroI;)j+0PbUOGBMWXEi!M zK5k2VpV~H1$X_|^eL{2XxUCyv52ITZN_M-D3ip&Ml|!QV-Gn}A98ppozEWqb49_%( z1REkUtS5H?nkchO8r5KWt%jPtK8I9Mb?PZl-}YlS69pkEcV6b@8`rhh<}u{j$a9W* zt3GN*?4|*R0@t|W28XC$NCko-#>lwRr-CCb+9E-NlaE7&w5*d7%=dM*f=G7dWsy&d z`b&`#E?dB>lX5v(Xy;O5GMA6{2YJ>&bIW&A0_A(PN8zYeGrvbL`s!-Qq_yym;qBE) zF+kyCcif$}8(K-4P-LJ5>YQb!7s!oqFc90bOhV;Oea^z%X9zBn+D#DoG&@vGQr%sk zeWukJA8HmhhUVg-pRIY+!V~d^{hMqaDHm7#s;$DmuKTTERLcmcA@l3I1;=C`ju0f= zpM}vb?ZgF01eL6s9nh*=wwH1I!e8Ixy}nE!n!vM9x!^MGa)mS5(?b%e$8y(5MsZW1WF>gVB$p`883qd31|QlB+MvK5DP4v>B$?Ob6&H3swnSt# zO*AjRS9HEY@tE@Est};W8Bj^HCHR73GM}f7k{d6ogzCyQgjyWfiOIFo!Z|eW(F~Wt zniIxw%3c>hXIO5UDv-$=o-|zW9$>87#BX4%Yo2|}aA0UxXhPa-|1)BnhZg;ruC@s) zB?KemPuWD&3P1wj?G}m0$zSF=-cb$NU`QEVjdVM6N*Liy`<9-~Li$(rYdjnBPMV?q z9~6!`L-{iI=djE}yZ8^rbqEQKwX6s&aj-z(qXzA8QnkPsX&?=s%wk# zxjMorFijmRwN&{Z9L3bYcDnRA-(V7+Gks|U5gdg2^{=H8d-tx&GN#mH15)oFG>8%d zIz>B)L9R^xhVX5_MLx&hoprijOZ_25@E~DT*n`mJ{ufl6gLkV4Gbp6sQWKaRO3{8H zBf&8^7W~U}2sZggxq3&_l%4Bg^KlEGCaVndQDl)+3|O~k@jg8nOv}$w6ng31f1l-V zT|hwKbHoyk&b)v%Tp%q<>uv%wTn=95G{Wh-<<+wmL_B1IJ01TLHZaQ2ap`>L73??QI&SPpo!)K)nMttTZ;0OpohP zWzU!{_;P~JIEbbp;Jy!(15E;DkRvQk7f5`X2N^^kGNNIWxqvIeAdn=W&}?!Su>EHA zC)&IAJ^$-zC1Lowb|2eX93MC32jJy$M7Y`wOH-~g%|mYLYzu;~l$<`Pum}0DM5U)! zumKqs#HiYk>{Z5xjYh98P!<5zF0Hd{9wQ-QKqb0P&y?eq4w9#JWD>)9S&kG27P93! zWDFc>yo$fKj`}m7o+z`!M5};E-9*^voF zDOWy>jX&9~gSg5upaqXySCGl0CgW9MYlB2W@x8cqecL$1e-fn&MiJ0B7>xTvDLcN< z%O82-yclQwIue%F=cDm$sTqJww4qMCY3%zLoCFvr)*ygzU(%^89EP4YE7l2g;7{2i z$!g9A9ORNjXmTx}T}#SwY{*5z0%~@0m*E|T6dwT=CGFk6P)HdC_qan<$6u9qmD7Mc z^c;b{!AU@z_hDuq%uC>OVStC|h8h!2=hIo$#y%0OjHf}<74BLXJk$otf0k!Fd3B#P zW-1{EAMac}9SVPSaO&v)LpcRGRJ&Cfjlb1;aeEyv_I{CcIA^xiCTYJtdCExz^cJ|0^fce6LK)YQ(@@l0tCXP?};q<6_+93TG z{h!dI)^~>bdc0$&0B2HXiX*oQDAg|KC3BCplKq@zo`1R-At?y&r?|~+szg6iD|IO< zmroCQ46UhDEMnZXuYT|5$;%IjZJ56Q(MN>Fqg~}JP9O5qy}*Tb#;5bE($sN!;%vtZ zJt0PRJbGXNGJo=ynX9{hx)-Mj>wAFAKkiQCxu>$Q&H_i@vu0dIzCp z;vR1dFWJ?XUy)1!_>Z!7bZb7iO9UOf7D4B+^;wtSX7S@u9v(ZbOenE;^YIeS>TX)_kI`-ASd7*R33^zX{ z0C*_f2Zor;xi)^0)R4M=CU7p>xA9l z^Uy%4H`Pk5Ue>L;q_&<0a!jHn28qVT1kYYyYlmuyk4MtfY-#`dV>yOt?8+fY7k$9F ze3$bkbX1W=WC;B22HwI)Hfwmc`(WN3`9_a%nN=uFuynQ8e|GN|d6wz(fz%=9)6aJW z00>_cfYOx1Q*`0KsH!+W-(uybfm>c~qs z&YZt>A6K8BJbb4L27if4_EyY}oi$GtWF;NB?`;hEO)jMA`26}v3kg=0TyxPBy!-U6 zMLM{CA`r*?&)r!YNDVF=&+y#pQLlbBAE?Py^fXmoIw6wWQaFQ2xhwPXioT2Gr}@5$ z>@$rJ`$Xg43Gu5FxUIG3r&Dp!FSL^$sg_h1)Su1W&VwOXC`E7Vc5^Pb9jB#xS9t+_ z)E{>OU`~GTx`t#rOa0ty_>;db+?jcp5{lMdwF#$oc}}J#C?-9U2I8oYpRT)>Y0AH2 zzvHz$hADO(q>uXVA>WRF3T7CNjvIj7p0$uY4BKZ5*criP$A4FJ4D$dc;Z>n&+Lorv z8P^Uf1g%<{dkCTtK=wRgGo)7XxGFCAt#vA`WquYNCHSoXfFOu7qaO8@?lbWkj(3v- z?b`D&7dSw82tntD-R@uIOpSuXO{>tguNxnh%Ip!kg#+W|w?-qeYP-)?rn*XAJ8B}a#uq8ER@dpFdwvZtODx%(oEFv zMdF=xMxtK`!hSpk_J>i#5U&_SVlG%ae{^?~NIEwIy$2V)pk$i?uo^KqW#O-D7hx_u zh+@DSk+zO9c@sqV2OsIXLpo`R$ni11En8@B%Tf42!}&z=J4ln;%p=<2U1Vbb`C8zw z*y&97!Sl1c*+&tbv#fKB-8VG~?7x`95YenXV}Lf@ed4UW1j+3KD~f5@Um*cSp*;`2 z?aXQp<}mDDYCkBkS<#t;kyA zG3HWOslF#bw_Zb=$hCLI)aSDOldo={5WDvQ8E0snW`#>c4f@*o<@QhiQPe7PpS%kl zYJ9=w?r>N{rojebGN}T-xGPhD71l6AlSeu}Km?5*qYb=|p-a7>L;8o=+w~c$xqD$c zp#@Dx7Wq(UD_NkQskaR)mG3waZ`=%oNQ;bl**o!p>ME^`xb&9!7BFC1^$ZTsGb$GA z3^D_6Gse1IlklI@#WWAI7KRL?!(>NHpEHk?iTR7l^R!pE!+4W<7tQ;@{A(GH6Z;2) zWW{YJF+_ zo=HIauBD*)o@Zon0Ux`>A=6c=K_w*N&0hM~L*%miCZGb*-z;#XkzcEL5p2j#{$0Z| z<+Jf6Ag6q)bktiML=;sj`D+*o{||x!VGmTP!Vo9wh!y8u@_CYg+G<&~hb7RRmL9<) zV5x(OzIx^!(W7uDrY);DsehHx+O_6^v`0U(v>J3p{8L8q`&uEAV0;kyhG|sDn~h5S z+&LO-_YN)L6q{SFL@~)V2NyImO`mnpchz09&(1<5vFh8P4wJJCl{|GH51sP2ukAqH z^U!*~8st2Z&=+%u^gQA2>l#A87G5cP^8TRNOODe}Njdvcmb;v5>p72gqYSUH{ni>v z>F9dBOJLlYFFVz~Vn>nRUKME4#?(FN?)h1XcivJu31%1EEYJr8=)KlVIx&s^!o2wk z?Z?{@wLKa-6b@o)eP*m>`Qc6;8{!o{IxNxUREq9;!z1-}MHm>{i-dW!&&9o3>%Dxt zSLHJtIaLf*@aZ|Gm5G(dgEu6IH3(a#0TA)wZ!ItMqd4bks1;J0Yg35(z!OssM?8X5HXQkk5!*EA zara_45!cDm8fd*Hac>9~6qLP5?!KL57cj(!a+1I9t zgS-=ArOX;Fl>;9zj_ioF9@OIwv%zPaD;i8D&2`+u((ZnlAX9fEhBQLSoE z$4lygN8?+-#}gxpj$^;N5Bppnp>94;R(;X~!uI!ydl03t_o9_wsn-On~Th%Fuj=7UEA7D%ZFog&6N8^s`XTY1^Q}KMss!ZIJ zxB;7QCEgZtZtZACyeFYts+}%w`ELP%6Q8#%x;WEE!Y-GkofyDRmB~oDYH`km^JU%X zV?y8=aILX>ZPS7Lq}^6;--&Z^v6CVVLXT73R+phGf1EDZCd%a$NNOJ^bs*jP7Jzax zB4%DEb7Go>yn}iL#@&)-X71Meo2zWEaRMd>Mo<4Kx41&+@PkcrrwPyZ&aA1W^a5udHmApkuh#@ z>GdV|_wDTt3BNDQXkR(H#CU$cAvxXeE_X@5@|CXF4&_TZqn?ayNCATWRPhp$e|`q< z3g6ZY&b^ud0@&gKx+89@9KWk}%hTDK-$dl~>G6P{cRxI}2&KqQLts<%#T0PY8@w2X z0@LzqFjS3n9P$V(0MRgj@k!u zi+*s?(u{wwRKKfe|APASd`aHR_D_!JUq*U3wRBoN$FF~>!QBfV?=H8&$!+W8!VV3(N@2oDkJYvC`y`doV&^HCXbDa2_(?6u53x|(6?2Y;&mUhJz&(|3wy z+p*ryX)Wr?K2$Wy!|&43F_VaNtUf$R(MjTxoKO5|5Ae2?yO4A^RQk-oc|MRy_m1qd z0Ef+^a)poMohEO+5+n$cX>ZA}j6r%Nrye+7Ns9Hn$mX5*MXj@^gR~#EO(cw!KSXRl z5NN8q^N5DG^@*N5686hzGhZf=b+?ba8?pn=F?xkV9dr9E-R_Lcb;a$K-P7Mf(Xp}z zI*kaiY1qmnP+y8lMhcsqn~VGVlg$u_<>|?u@IR@S7r?1|nImV- zfp(e+IqrIlgbr-`5onbFo&v^jgVP*A-5-DD^d(V+pLbDY!PeUA+N!&=nN}EBCv$WR zCvQH=vSx9m-Jg7P#Ae-M^mg8D>0BD6qHcDa76=f)LQ6Hz*G0W@erNeLDC1n+G0*XX z!$0+%F*Vc{V@^}!U9Yql=V^`{=Y*=mlWOeV4-udJ@kYeUYr6xoO?nI%y|0!FuJ$rH z^-Y(H8BKl-?RQK5oj@g4%H85TR9N+IrPB_2aFpl{K!p$8AN5dj201wneSmBLwO-%C zTna;59y|i{LQ+J}yw(!hd(WA_W@RC;y}aINt^*oLUe8LL>E-yJR>${SaeP;q)GrcRfef zWFrTYTl&n8kXWdGn6gigtYr52RwRvV(jG92aGe>zVwX~he_?1?Q#Gv>HEd~?E%dje zmg_w=5Fa>xMe;+y-6a`#$HG#gU(-%ov3GyH-k!F%?)*6K!Eg71!PA@tE3q)&I03#M zhdem8@`hhGfS9v=r^^US@2%d2dK`=? zEV5O9v$O)O7co_?L1~wR%i^d#&*lcb5`-mkDO>|-7m~CjlzHf*)UbM`BPZ!&F8RZJ`o3#lZ{tuC7-Jd$O+AO^UvIz#VAKyaq0t3E+c5ZLC;`v| zD%QX%C>L2vIA)>TX#Kv5%A7I<5yG}|)EZ#8w$z_pI$;%2w3uQOBx46o&KRD?@snrlT-+eytyjXvL{+dBKu0a&CoqzrSd4>9KOQ+J*$pZ03|Gg;T_15 zm8IKjG$@Wd zLRk3*z#4Izc^Pp%P!cc#&SJkHyiwQ#3l-h_bC!ZZdmeOBmC4lvVC4@%d2h)Wp}#4$ z#uf7R(2*;}LObFfRil2qO*oTCOr_i%V>M>y3rRwGV!kLwVfqMINEOqnHVT20KH5>n zXpz0Bi#K%hu0ws(-4~B?A+!2pD)nM4Yb6{(rIaA=?<4N@=(xXnCx1HB$0(w8>bbHCz78Yru;lP!-d|XM;O8hW17mZ+)%oO{0jX;x)jeR2pc#J&p_Yh-qLQ7eL?r z*W)C-1Jv-p?Lc3oi~`JYpaL9)fYEoZmVVoADjS`x6j^=USLR{FZTQLGqMAAuJ}pkf zx|;PSN?G?{FqBbuk=<9m3sMvWP(AB3w+UMGG1_eB>U&c-Ec96qK&D zKB=;2zJTass{ z@iS%E_XJihU(9Ms#>!<`K5xX&vyuwN?IhU%SaZA)VYh|}@6p)+uhf`0g%;wqJrVDb@?|gAQ z$hIs~(h>FL$X>$t@oW|Vz%StYLr*H-gt2DH#!>=LU-Yjg_RzCn*Sy0B%Nz=Xq&mKR8FxAFmT`^1S6!hAZG*Qe8J}COA3a5rrR8Xhxd@k~@68!7$G=c&s69;gLojqm$d;R649wqT3P_qJ zWB|v_tfj?Z-7`cxo$kSr@MqjL@FlzXSDt~xAYCS)cDt|z5xg+eXhuPWYW9T>1g}QI zs!%T_L5@?Q+3<>N{`oaCW;k{R6-*RPjkzL##VxjS%)xSng=9W!NJu?f3eDKV#@5#CluA-AvCFUb^c3<4lVcn zf#natsm`aHD0qYU%o1SXm-%!Im3$%gvVd@M^N|70nA;B~7_&sPKTqfb z2!D;S$bJ~ryJi5!dC&R4PnHg(wJo9%N$t3z)J9Tu#96SDIar83raif9#qK#Two5DJ z@ym_Udx|QeO~^F&FG)T_Rr|dNvTu7M?ku>4_3*+yARx&oczsmpG3J>+=^9K)rk_zn zxF;#1wpKR|8RMBP<>^!1WpRYpF6)bzEOowx``q^dThR}Nx0{d&fjhM0-0zMO@SjB=2CM{W7g85BrRLjL<9%_H=z zI&tF1sN{_>Ry&6x2Sk1+t_ih(;-Zu#z-NLI0QJ!Tq|JR!hn!FHun;N#kisjms}aN0 zCXX_#>2+Y{Z|a&31Jg!ZzvZ=d>WYqtVn~=+*KCwGy;h?8Kblv4Zk5O8qO^t|_FZ0J zwa!8)Xa7lLI%0%eu4_aPbPY>-wIM@uL0_2yKyJpN5j3*B z2Fw8!lOrb}VI7WH*ezC4)usR&-nSc%_aql$H4SIVOxE)$U8PNy*I9D@QfDc1Bpg=9 zx~%p~9osg%aku%Mnan3@(ACGNp5$TBKDj85Zr0~rybZ`e_@fX0cgZXE?Eu^`1}HJZ zh&SIIOa&e*@M8^#hJbjf4CxCiR73j&)hUNx81DXGoV{gG9AES;iUbJ|2oAx5y9bwn z0Kp+aLU4!R?lMS%y9PoaxV!7%?h@SHEy#pn`pxgYFZWg5SM{$uAEv8L_vzEseNOGO z*WP=rz(q>`LFIe}2|4F{oaCsK!N0Vk(&4O7W$yjKea+F^mHTU?Q& zzP)sE+VnsjfjFOZaTE>u^B_UWd^9rKK87K2qUP|?rz9)x5tf+TB?GLhDTVx|K2+7M z%T#`|!II3sbN$g*@v9$oGJgSZJe_ZGfdDDvXcn=t!gSMnGI+ku-2=Ec4zAbyZC>%y z%@F^~+EYp^R>~zOv{^Gk6zao?FAt1{q);ovk9=T7m6z0~YbkpAC45t&BR|AVpm45V zhA^+*f&3@>`>(5!_P3I^3UbaUPD;(hS6RagSI@{A3Yo(B%TtfoIpV>A?5^EDP&I8i z_Qw1P=V8FQL|^+q0A0S|!mdXn;Vw|spwLqsQ^1Qvv{?X=o7li%oJIJ6Eqh!2AFTdA z`Tzew?|D#wT;!2+4hzRZ8%+}2>=cQn22D%p*mGZ#DlvvQP6gtx|=_bFzQ zP5{P}pe3-q@GF`$2@~bfw_suH)%Qg8mX@NzSWkhT7HgU5ja+>-->UiHThUaX;-WV| z*E_z!^#wBK+!qrf2b=nJZLr1Fk<4%Y>>qtQ{~o$*bh(VcNU{GOCOb(YWB&8eI*sp5 zg`#-A-<-NJHupXCTi=>ar87HcS1xK#c0f7}t|QCmXD~Bnz_=h2ux8ws#Mf^B~VoQ!Yh3hAfWlHZtu(cP{ zKgrxM+RW#YF7}LX;@dX9198?8Km8psyZy?$)Zs(>T1ne}VN`YWG;xNwm%$4o7vg4l zUnB#{96^cLfhG-fEmLetNWl9wp~SSWaRR>fjJbasGuLllxWBDlrk=Yp+VgM!8ZS1$ zW_F|X(VdI(-A3d%C?wlI5c6t}aD%GNgZDN~!R=#L+S3l)`89ybi=_XH8?O`+XQz9X>I*PrL;%M#v30TvH{Zd?gkd{%hlw zI9Es@`TY=v;}G|uWs+W+7pZ-C5}6EL7oczZmEP1>ozQ52N&HUNd#Y~*Zzrre;9z{eMMzra8$uNZ}G#*7r~&w zDqa5+2*d8HQS5(ZTk?kp7_{?G)}g-zUOJXCRN{|KXzlxlTn{^JsW!efmK6pz?})dI z|F#(#l(8D)V^+Q&92GQOxj>F+wqGa9?p6QP`z4cU`L%C%2eQ-a{^?``qz1w~Ru^=s zFl|%+4i1u~H6L6DqV9=iK{CPdB*|VEpeWA!jf_2#cysHE2UISNm_DA?;kWsk^?cq^ z5TtXPh#tr(DH!GLub4VfUI6?2t;#R0AT2hm)U75Ycuqoj@lE^+XqG^_iT-KRrME14 z7(m%$p`&vmyVTgnk%PY-rxHXS=H3Hn4U20l*k_NrM(s=?dZ71N+R_{=OHNxa2Po5F zi~3Wkbk8AHa#$+iws|U=-{6zpy0zm5#3#i4J7R4l^TF7H@C8i1oLr1nq486+)~x8z z#lY*FEx?;J5ghc&zn+v@mcyH>(#{Vq;viYEQ^Y_gAOK>j#96i?5UrYX#G-NTgPr1jZb80CFx! zuCqKS_*lKgd$ZX|23Uo9^%cp9ojZIlM*ftpwSi&3_N3hQAguRcaVtheJhB>MST?xhg1wE+u9Ziq5P#wWC5~2`e(qGk8*W~y*XJ-X zzTJ1YiDZjH9n+)R1;xz|#1sFqTRJ=w0jqaQh(Ws*tGRV@)Uwr;+0o9?3!#S>h8`iy zHeH`=Q*Sbi6q#ufD@^btg83tt?AH?mmTcD0~4 z({~Nq3;@rs%V(r`Uqvx6p91ealK<&HHcuUS(cgk-)i)N=ubo819F5%ifrc#QzAIx3 zyQRo0n02p@j}Vx1?REMtqu5vR2@;_nmNg}%+nlR_ApEe9Mp%Lfz*`Z}wv*4BkHpRK zQQ;P^0%n@<7)K(%xCXN^qZ-K`fCIW0;pI>#6ww2-Jx$i{_>a|TQ}rQ_q`>{h-&D;# zR98UA<>L3BfR9*W!&gIZxauokysj_`vo@TuP8{W?@}7sMjO5_cCXTi)%pGv2c**lZ z4p?KobOrZO!fdm>(|g3G>hMbVDj6FuFUFde=scx&Qe--Oa!1b^I`l2|kB( zwJ6W%e`d{q0-!&m=QX_yfmRZ;F0KV7Ih@Jnf4 zy4{EUs=>uqa=`9Pf9Bu1eDb~I+yM}BwA1+E!5^NI`3veSlI8FxI+OiXy2mb$!=E3t zcIJ+rgBBPFS{R#5pSY+a-*7n(i@xV@AN^E;U~Ib|K_p?fp*z=kVFayPyuRO%iJ2<~ z0%HpdbfuOVCOmmZqKLizTrq&P$S1K}#&)ZJ1(H}V?ajDXH1=ea>-?rrW_ng*w#AHx z+#wMGqVV$KW!hsrN?7ilk7PQd9$l+L$JE!s z@To78yrQC-g69B#;fn)*rHh!3_v=5QpZZk`HtnSu;W0FS?q?42oU*D4 zfew=V`a#`}!etdhKigl&7M(Aq!ta~Brw^}|qCoJ;$8Wkq`rhn4x3N6Je4OYFo|zE- zsTTqT_5^r@e*9`i4I0M%^VXvR84%eI6;w3hWNoTn_GoAqyK~mJaQKfaQhY^`KnGrq z{UqzR_mj&A2f`Yj4Ge zQj4)#8Q7^$fAw>&=^C;%1kGVR@n9e)r!gF`hwT&T<%y`RvT!JSA8?%0!xU9&R_Snn zNHHv(Z17=TAf^Dm_eXGQp(E>LBg!!Zo4~jxGnKF4mlt4Hf@Bqj8|#~`mHHTs3Vl-9b5)XI_jr{;huHud zr9QIWt+Nfj2Pq9)1mkTt5|&9*`Tr@;{y*mG|6!i}yZ?Efy`T`k!2eB}eYifMGU?!E z52n(UhAc91s`^JMR5R%+!($c}PqZp5C43HPsZY{pQD}@&|26|Pg?_$XDr9K5mBc$c zJ2*r9U`1IOruHH%xaIDcS6ATj3A}5C*TA3gw_NJOZ#Zgai5phd~w=Y97jeiekr5;)s7wESaSa*r$D~Jo)Lg zTE!zZNjZ8?=Q|-c3cd&4HiVAS+L*pL@)Xudc@jTMVa`+3V+U`@!Q{1}Xy4JGS~!Z> z`Qp*h>q~t<@Z?T7D#?ZkdCnN&iUs>+0xXFO-I6Ad3S8V5BEl^2R04ou)^&lFEHzRS z4{mvOg&!U2Pq`2_L=YmX21`~LlO}-+n-T}U3KBjGcG+X6_tsWy!r1OI$J}{bnyGDNpPk8-f8~=e|`MVN9IJ5=E)Oi;Af}DZghBc z(YAq$AShd&{#u=mQ^#^E1S^F?Qq8#G+5fnXxWkMBZv5ZVTE5-N#Ikqaq2Cw;Ja#~` z%r55J8|ADwcrO(!7?PAfsOO2;x^Vl!^*=U#yi65Z@Dtbpv27F_r&^|FW4DlN!kyO9 z;clI!#dmZo7cKmqt8sB^=`gSL{sX_;ZV(q&ce8RL-koa3SajJxMouLvnP%L(Edvhd zW+^(sgQ1+eGPzd^kLr54{eKnPQp~82f9}_L_th0B0=%WK z3Tpi-%OCA_{69a!f}HpOil-2<_HTG#FGes>f}RHg4lez9FIF!YFJicNPm+Pp=v z^eR|?HufAjbDe<=~4g+f^9VJIZN0Kg&&IZ*Zjwq5{ z|6Z(V*G3ri$lahOnB{-cWorKg1!7dp`S!@{k|K+7jkC(59&Ub|h9D$W?HosQ2!WSn zr1|*bu_SOHOLQc};dRxksx5ZHPB)*r50p0*uSg%6;;d^|*5+RM6AY=D<_-M|u!U>? zx)KU_8+YE)|0T8UbEO!A0^!2yk{4S>0of6KP3I|v^K2qOWz_|{Q+a$4ZnofAO$`cU zh9l>^ESQP}&TWfc4P$LMW_x0S?5{tszH+^r&{5I2*umnNL`9Ct^xLVh%n;X4_S~pt zoZd0^%&n8#|52@DC6VqY!XGk|pfK|}>y6){uKB-Gm+!itJDB~?sHAn

1soCzSu@`S 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

WgJwQ11XJtPCS`+84!-5z(B9G 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

    P&Sbs+_9`Cn6xZ`3~_^5X7! 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 oiq<_V_>b!ff6A?!^wf8rdvNABQM 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

    da(ML_B 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%0DE8BSG2Vi@HE3bUnKKn{c5^28 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 N#gvszt Self { + BitMatrix { + bit_vec: BitVec::from_elem(round_up_to_next(row_bits, BITS) * rows, false), + row_bits, + } + } + + /// Returns the number of rows. + #[inline] + fn num_rows(&self) -> usize { + if self.row_bits == 0 { + 0 + } else { + let row_blocks = round_up_to_next(self.row_bits, BITS) / BITS; + self.bit_vec.storage().len() / row_blocks + } + } + + /// Returns the number of columns. + #[inline] + pub fn num_cols(&self) -> usize { + self.row_bits + } + + /// Returns the matrix's size as `(rows, columns)`. + pub fn size(&self) -> (usize, usize) { + (self.num_rows(), self.row_bits) + } + + /// Sets the value of a bit. + /// + /// # Panics + /// + /// Panics if `(row, col)` is out of bounds. + #[inline] + pub fn set(&mut self, row: usize, col: usize, enabled: bool) { + let row_size_in_bits = round_up_to_next(self.row_bits, BITS); + self.bit_vec.set(row * row_size_in_bits + col, enabled); + } + + /// Sets the value of all bits. + #[inline] + pub fn set_all(&mut self, enabled: bool) { + if enabled { + self.bit_vec.set_all(); + } else { + self.bit_vec.clear(); + } + } + + /// Grows the matrix in-place, adding `num_rows` rows filled with `value`. + pub fn grow(&mut self, num_rows: usize, value: bool) { + self.bit_vec + .grow(round_up_to_next(self.row_bits, BITS) * num_rows, value); + } + + /// Truncates the matrix. + pub fn truncate(&mut self, num_rows: usize) { + self.bit_vec + .truncate(round_up_to_next(self.row_bits, BITS) * num_rows); + } + + /// Returns a slice of the matrix's rows. + #[inline] + pub fn sub_matrix>(&self, range: R) -> BitSubMatrix<'_> { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + BitSubMatrix { + slice: &self.bit_vec.storage()[( + range.start_bound().map(|&s| s * row_size), + range.end_bound().map(|&e| e * row_size), + )], + row_bits: self.row_bits, + } + } + + /// Returns a slice of the matrix's rows. + #[inline] + pub fn sub_matrix_mut>(&mut self, range: R) -> BitSubMatrixMut<'_> { + let row_size = self.row_size(); + // Safety: + // + unsafe { + BitSubMatrixMut { + slice: &mut self.bit_vec.storage_mut()[( + range.start_bound().map(|&s| s * row_size), + range.end_bound().map(|&e| e * row_size), + )], + row_bits: self.row_bits, + } + } + } + + fn row_size(&self) -> usize { + round_up_to_next(self.row_bits, BITS) / BITS + } + + /// Given a row's index, returns a slice of all rows above that row, a reference to said row, + /// and a slice of all rows below. + /// + /// Functionally equivalent to `(self.sub_matrix(0..row), &self[row], + /// self.sub_matrix(row..self.num_rows()))`. + #[inline] + pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_>, BitSubMatrix<'_>) { + ( + self.sub_matrix(0..row), + self.sub_matrix(row..self.num_rows()), + ) + } + + /// Given a row's index, returns a slice of all rows above that row, a reference to said row, + /// and a slice of all rows below. + #[inline] + pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_>, BitSubMatrixMut<'_>) { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + let (first, second) = unsafe { self.bit_vec.storage_mut().split_at_mut(row * row_size) }; + ( + BitSubMatrixMut::new(first, self.row_bits), + BitSubMatrixMut::new(second, self.row_bits), + ) + } + + /// Iterate over bits in the specified row. + pub fn iter_row(&self, row: usize) -> impl Iterator + '_ { + BitSlice::new(&self[row].slice).iter_bits(self.row_bits) + } + + /// Computes the transitive closure of the binary relation + /// represented by this square bit matrix. + /// + /// Modifies this matrix in place using Warshall's algorithm. + /// + /// After this operation, the matrix will describe a transitive + /// relation. This means that, for any indices `a`, `b`, `c`, + /// if `M[(a, b)]` and `M[(b, c)]`, then `M[(a, c)]`. + /// + /// # Complexity + /// + /// The time complexity is **O(n^3)**, where `n` is the number + /// of columns and rows. + /// + /// # Panics + /// + /// The matrix must be square for this operation to succeed. + pub fn transitive_closure(&mut self) { + Into::::into(self).transitive_closure(); + } + + /// Determines whether the number of rows equals the number of columns. + /// + /// This means the matrix is square. + pub fn is_square(&self) -> bool { + self.num_rows() == self.row_bits + } + + /// Determines whether the matrix is empty. + pub fn is_empty(&self) -> bool { + self.size() == (0, 0) + } + + /// Computes the reflexive closure of the binary relation represented by + /// this bit matrix. The matrix can be rectangular. + /// + /// The reflexive closure means that for every `x`` that will be within bounds, + /// `M[(x, x)]` is true. + /// + /// In other words, modifies this matrix in-place by making all + /// bits on the diagonal set. + pub fn reflexive_closure(&mut self) { + for i in 0..cmp::min(self.row_bits, self.num_rows()) { + self.set(i, i, true); + } + } +} + +/// Gains immutable access to the matrix's row in the form of a `BitSlice`. +impl Index for BitMatrix { + type Output = BitSlice; + + #[inline] + fn index(&self, row: usize) -> &BitSlice { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + BitSlice::new(&self.bit_vec.storage()[row * row_size..(row + 1) * row_size]) + } +} + +/// Gains mutable access to the matrix's row in the form of a `BitSlice`. +impl IndexMut for BitMatrix { + #[inline] + fn index_mut(&mut self, row: usize) -> &mut BitSlice { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + unsafe { + BitSlice::new_mut(&mut self.bit_vec.storage_mut()[row * row_size..(row + 1) * row_size]) + } + } +} + +/// Returns `true` if a bit is enabled in the matrix, or `false` otherwise. +/// +/// The first index in the tuple is row number, and the second is column +/// number. +impl Index<(usize, usize)> for BitMatrix { + type Output = bool; + + #[inline] + fn index(&self, (row, col): (usize, usize)) -> &bool { + let row_size_in_bits = round_up_to_next(self.row_bits, BITS); + if self.bit_vec.get(row * row_size_in_bits + col).unwrap() { + &TRUE + } else { + &FALSE + } + } +} + +impl<'a> From<&'a mut BitMatrix> for BitSubMatrixMut<'a> { + fn from(value: &'a mut BitMatrix) -> Self { + unsafe { + BitSubMatrixMut::new(value.bit_vec.storage_mut(), value.row_bits) + } + } +} + +// Tests + +#[test] +fn test_empty() { + let mut matrix = BitMatrix::new(0, 0); + for _ in 0..3 { + assert_eq!(matrix.num_rows(), 0); + assert_eq!(matrix.size(), (0, 0)); + assert!(matrix.is_square()); + assert!(matrix.is_empty()); + matrix.transitive_closure(); + } +} diff --git a/matrix/src/row.rs b/matrix/src/row.rs new file mode 100644 index 0000000..1b7d10a --- /dev/null +++ b/matrix/src/row.rs @@ -0,0 +1,95 @@ +//! Implements access to a matrix's individual rows. + +use core::{mem, ops}; + +use super::{FALSE, TRUE}; +use crate::local_prelude::*; +use crate::util::div_rem; + +/// A slice of bit vector's blocks. +pub struct BitSlice { + pub(crate) slice: [Block], +} + +impl BitSlice { + /// Creates a new slice from a slice of blocks. + #[inline] + pub fn new(slice: &[Block]) -> &Self { + unsafe { mem::transmute(slice) } + } + + /// Creates a new slice from a mutable slice of blocks. + #[inline] + pub fn new_mut(slice: &mut [Block]) -> &mut Self { + unsafe { mem::transmute(slice) } + } + + /// Iterates over bits. + #[inline] + pub fn iter_bits(&self, len: usize) -> impl Iterator + '_ { + (0 .. len).map(|i| self[i]) + } + + /// Iterates over the slice's blocks. + pub fn iter_blocks(&self) -> impl Iterator { + self.slice.iter() + } + + /// Iterates over the slice's blocks, yielding mutable references. + pub fn iter_blocks_mut(&mut self) -> impl Iterator { + self.slice.iter_mut() + } + + /// Returns `true` if a bit is enabled in the bit vector slice, or `false` otherwise. + #[inline] + pub fn get(&self, bit: usize) -> bool { + let (block, i) = div_rem(bit, BITS); + match self.slice.get(block) { + None => false, + Some(b) => (b & (1 << i)) != 0, + } + } + + /// Returns a small integer-sized slice of the bit vector slice. + #[inline] + pub fn small_slice_aligned(&self, bit: usize, len: u8) -> u32 { + let (block, i) = div_rem(bit, BITS); + match self.slice.get(block) { + None => 0, + Some(&b) => { + let len_mask = (1 << len) - 1; + (b >> i) & len_mask + } + } + } +} + +/// Returns `true` if a bit is enabled in the bit vector slice, +/// or `false` otherwise. +impl ops::Index for BitSlice { + type Output = bool; + + #[inline] + fn index(&self, bit: usize) -> &bool { + let (block, i) = div_rem(bit, BITS); + match self.slice.get(block) { + None => &FALSE, + Some(b) => { + if (b & (1 << i)) != 0 { + &TRUE + } else { + &FALSE + } + } + } + } +} + +impl ops::BitOrAssign for &mut BitSlice { + fn bitor_assign(&mut self, rhs: Self) { + debug_assert_eq!(self.slice.len(), rhs.slice.len()); + for (dst, src) in self.iter_blocks_mut().zip(rhs.iter_blocks()) { + *dst |= src; + } + } +} diff --git a/matrix/src/submatrix.rs b/matrix/src/submatrix.rs new file mode 100644 index 0000000..9469387 --- /dev/null +++ b/matrix/src/submatrix.rs @@ -0,0 +1,253 @@ +//! Submatrix of bits. + +use core::cmp; +use core::fmt; +use core::mem; +use core::ops::RangeBounds; +use core::ops::{Index, IndexMut}; +use core::slice; + +use crate::local_prelude::*; +use crate::util::{div_rem, round_up_to_next}; + +/// Immutable access to a range of matrix's rows. +pub struct BitSubMatrix<'a> { + pub(crate) slice: &'a [Block], + pub(crate) row_bits: usize, +} + +/// Mutable access to a range of matrix's rows. +pub struct BitSubMatrixMut<'a> { + pub(crate) slice: &'a mut [Block], + pub(crate) row_bits: usize, +} + +impl<'a> BitSubMatrix<'a> { + /// Returns a new BitSubMatrix. + pub fn new(slice: &[Block], row_bits: usize) -> BitSubMatrix<'_> { + BitSubMatrix { + slice, + row_bits, + } + } + + /// Forms a BitSubMatrix from a pointer and dimensions. + /// + /// # Safety + /// + /// Can construct an ill-formed value, thus the function is marked as + /// unsafe. + #[inline] + pub unsafe fn from_raw_parts(ptr: *const Block, rows: usize, row_bits: usize) -> Self { + BitSubMatrix { + slice: slice::from_raw_parts(ptr, round_up_to_next(row_bits, BITS) / BITS * rows), + row_bits, + } + } + + /// Iterates over the matrix's rows in the form of immutable slices. + pub fn iter(&self) -> impl Iterator { + fn f(arg: &[Block]) -> &BitSlice { + unsafe { mem::transmute(arg) } + } + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + self.slice.chunks(row_size).map(f) + } +} + +impl<'a> BitSubMatrixMut<'a> { + /// Returns a new `BitSubMatrixMut`. + pub fn new(slice: &mut [Block], row_bits: usize) -> BitSubMatrixMut<'_> { + BitSubMatrixMut { + slice, + row_bits, + } + } + + /// Forms a `BitSubMatrix` from a pointer and dimensions. + /// + /// # Safety + /// + /// Can construct an ill-formed value, thus the function is unsafe. + #[inline] + pub unsafe fn from_raw_parts(ptr: *mut Block, rows: usize, row_bits: usize) -> Self { + BitSubMatrixMut { + slice: slice::from_raw_parts_mut(ptr, round_up_to_next(row_bits, BITS) / BITS * rows), + row_bits, + } + } + + /// Returns the number of rows. + #[inline] + fn num_rows(&self) -> usize { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + self.slice.len().checked_div(row_size).unwrap_or(0) + } + + /// Returns the number of columns. + #[inline] + pub fn num_cols(&self) -> usize { + self.row_bits + } + + /// Sets the value of a bit. The first argument is the row number. + /// + /// # Panics + /// + /// Panics if `(row, col)` is out of bounds. + #[inline] + pub fn set(&mut self, row: usize, col: usize, enabled: bool) { + let row_size_in_bits = round_up_to_next(self.row_bits, BITS); + let bit = row * row_size_in_bits + col; + let (block, i) = div_rem(bit, BITS); + assert!(block < self.slice.len() && col < self.row_bits); + unsafe { + let elt = self.slice.get_unchecked_mut(block); + if enabled { + *elt |= 1 << i; + } else { + *elt &= !(1 << i); + } + } + } + + /// Returns a slice of the matrix's rows. + pub fn sub_matrix>(&self, range: R) -> BitSubMatrix<'_> { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + BitSubMatrix { + slice: &self.slice[( + range.start_bound().map(|&s| s * row_size), + range.end_bound().map(|&e| e * row_size), + )], + row_bits: self.row_bits, + } + } + + /// Given a row's index, returns a slice of all rows above that row, a reference to said row, + /// and a slice of all rows below. + /// + /// Functionally equivalent to `(self.sub_matrix(0..row), &self[row], + /// self.sub_matrix(row..self.num_rows()))`. + #[inline] + pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_>, BitSubMatrix<'_>) { + ( + self.sub_matrix(0..row), + self.sub_matrix(row..self.num_rows()), + ) + } + + /// Given a row's index, returns a slice of all rows above that row, a reference to said row, + /// and a slice of all rows below. + #[inline] + pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_>, BitSubMatrixMut<'_>) { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + let (first, second) = self.slice.split_at_mut(row * row_size); + ( + BitSubMatrixMut::new(first, self.row_bits), + BitSubMatrixMut::new(second, self.row_bits), + ) + } + + /// Computes the transitive closure of the binary relation + /// represented by this square bit matrix. + /// + /// Modifies this matrix in place using Warshall's algorithm. + /// + /// After this operation, the matrix will describe a transitive + /// relation. This means that, for any indices `a`, `b`, `c`, + /// if `M[(a, b)]` and `M[(b, c)]`, then `M[(a, c)]`. + /// + /// # Complexity + /// + /// The time complexity is **O(n^3)**, where `n` is the number + /// of columns and rows. + /// + /// # Panics + /// + /// The matrix must be square for this operation to succeed. + pub fn transitive_closure(&mut self) { + assert!(self.is_square()); + for pos in 0..self.row_bits { + let (mut rows0, mut rows1a) = self.split_at_mut(pos); + let (mut row, mut rows1b) = rows1a.split_at_mut(1); + for mut dst_row in rows0.iter_mut().chain(rows1b.iter_mut()) { + if dst_row[pos] { + dst_row |= &mut row[0]; + } + } + } + } + + /// Determines whether the number of rows equals the number of columns. + /// + /// This means the matrix is square. + fn is_square(&self) -> bool { + self.num_rows() == self.row_bits + } + + /// Computes the reflexive closure of the binary relation represented by + /// this bit matrix. The matrix can be rectangular. + /// + /// The reflexive closure means that for every `x`` that will be within bounds, + /// `M[(x, x)]` is true. + /// + /// In other words, modifies this matrix in-place by making all + /// bits on the diagonal set. + pub fn reflexive_closure(&mut self) { + for i in 0..cmp::min(self.row_bits, self.num_rows()) { + self.set(i, i, true); + } + } + + /// Iterates over the matrix's rows in the form of mutable slices. + pub fn iter_mut(&mut self) -> impl Iterator { + fn f(arg: &mut [Block]) -> &mut BitSlice { + unsafe { mem::transmute(arg) } + } + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + self.slice.chunks_mut(row_size).map(f) + } +} + +/// Returns the matrix's row in the form of a mutable slice. +impl<'a> Index for BitSubMatrixMut<'a> { + type Output = BitSlice; + + #[inline] + fn index(&self, row: usize) -> &BitSlice { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + unsafe { mem::transmute(&self.slice[row * row_size..(row + 1) * row_size]) } + } +} + +/// Returns the matrix's row in the form of a mutable slice. +impl<'a> IndexMut for BitSubMatrixMut<'a> { + #[inline] + fn index_mut(&mut self, row: usize) -> &mut BitSlice { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + unsafe { mem::transmute(&mut self.slice[row * row_size..(row + 1) * row_size]) } + } +} + +/// Returns the matrix's row in the form of a mutable slice. +impl<'a> Index for BitSubMatrix<'a> { + type Output = BitSlice; + + #[inline] + fn index(&self, row: usize) -> &BitSlice { + let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + unsafe { mem::transmute(&self.slice[row * row_size..(row + 1) * row_size]) } + } +} + +impl<'a> fmt::Debug for BitSubMatrix<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + for row in self.iter() { + for bit in row.iter_bits(self.row_bits) { + write!(fmt, "{}", if bit { 1 } else { 0 })?; + } + writeln!(fmt)?; + } + Ok(()) + } +} diff --git a/matrix/src/util.rs b/matrix/src/util.rs new file mode 100644 index 0000000..d60b952 --- /dev/null +++ b/matrix/src/util.rs @@ -0,0 +1,12 @@ +//! Arithmetic functions. + +#[inline] +pub fn div_rem(num: usize, divisor: usize) -> (usize, usize) { + (num / divisor, num % divisor) +} + +#[inline] +pub fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize { + assert!(target_alignment.is_power_of_two()); + (unrounded + target_alignment - 1) & !(target_alignment - 1) +} diff --git a/matrix/tests/serialize_deserialize.rs b/matrix/tests/serialize_deserialize.rs new file mode 100644 index 0000000..fc78256 --- /dev/null +++ b/matrix/tests/serialize_deserialize.rs @@ -0,0 +1,53 @@ +#[cfg(feature = "serde")] +#[test] +fn test_serialize_deserialize_serde() { + use bit_matrix::BitMatrix; + + let mut expected_matrix = BitMatrix::new(4, 4); + let points = &[ + (0, 0), + (0, 1), + (0, 3), + (1, 0), + (1, 2), + (2, 0), + (2, 1), + (3, 1), + (3, 3), + ]; + for &(i, j) in points { + expected_matrix.set(i, j, true); + } + + let serialized = serde_json::to_string(&expected_matrix).unwrap(); + let matrix: BitMatrix = serde_json::from_str(serialized.as_str()).unwrap(); + + assert_eq!(matrix, expected_matrix); +} + +#[cfg(feature = "miniserde")] +#[test] +fn test_serialize_deserialize_miniserde() { + use bit_matrix::BitMatrix; + + let mut expected_matrix = BitMatrix::new(4, 4); + let points = &[ + (0, 0), + (0, 1), + (0, 3), + (1, 0), + (1, 2), + (2, 0), + (2, 1), + (3, 1), + (3, 3), + ]; + for &(i, j) in points { + expected_matrix.set(i, j, true); + } + + let serialized = miniserde::json::to_string(&expected_matrix); + let matrix: BitMatrix = miniserde::json::from_str(serialized.as_str()).unwrap(); + + assert_eq!(matrix, expected_matrix); +} diff --git a/matrix/tests/test_submatrix.rs b/matrix/tests/test_submatrix.rs new file mode 100644 index 0000000..c0e194b --- /dev/null +++ b/matrix/tests/test_submatrix.rs @@ -0,0 +1,26 @@ +use bit_matrix::BitMatrix; + +#[test] +fn test_submatrix() { + let mut matrix = BitMatrix::new(5, 4); + let points = &[ + (0, 0), + (0, 1), + (0, 3), + (1, 0), + (1, 2), + (2, 0), + (2, 1), + (3, 1), + (3, 3), + (4, 3), + ]; + for &(i, j) in points { + matrix.set(i, j, true); + } + let submatrix = matrix.sub_matrix(1..=3); + let mut iter = submatrix.iter(); + assert!(iter.next().unwrap().get(0)); + assert!(!iter.next().unwrap().get(2)); + assert_eq!(iter.next().unwrap().small_slice_aligned(1, 3), 0b101); +} diff --git a/matrix/tests/transitive_closure.rs b/matrix/tests/transitive_closure.rs new file mode 100644 index 0000000..0d344eb --- /dev/null +++ b/matrix/tests/transitive_closure.rs @@ -0,0 +1,30 @@ +use bit_matrix::BitMatrix; + +#[test] +fn test_transitive_closure() { + let mut matrix = BitMatrix::new(4, 4); + let points = &[ + (0, 0), + (0, 1), + (0, 3), + (1, 0), + (1, 2), + (2, 0), + (2, 1), + (3, 1), + (3, 3), + ]; + for &(i, j) in points { + matrix.set(i, j, true); + } + matrix.transitive_closure(); + + let mut expected_matrix = BitMatrix::new(4, 4); + for i in 0..4 { + for j in 0..4 { + expected_matrix.set(i, j, true); + } + } + + assert_eq!(matrix, expected_matrix); +} diff --git a/set/Cargo.toml b/set/Cargo.toml new file mode 100644 index 0000000..b00f574 --- /dev/null +++ b/set/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "bit-set" +version = "0.8.0" +authors = ["Alexis Beingessner "] +license = "Apache-2.0 OR MIT" +description = "A set of bits" +repository = "https://github.com/contain-rs/bit-set" +homepage = "https://github.com/contain-rs/bit-set" +documentation = "https://docs.rs/bit-set/" +keywords = ["data-structures", "bitset"] +readme = "README.md" +edition = "2021" +rust-version = "1.63" + +[dependencies] +borsh = { version = "1.5", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +miniserde = { version = "0.1", optional = true } +nanoserde = { version = "0.1", optional = true } + +[dependencies.bit-vec] +version = "0.8.0" +default-features = false + +[dev-dependencies] +rand = "0.9" +serde_json = "1.0" + +[features] +default = ["std"] +std = ["bit-vec/std"] + +borsh = ["dep:borsh", "bit-vec/borsh"] +serde = ["dep:serde", "bit-vec/serde"] +miniserde = ["dep:miniserde", "bit-vec/miniserde"] +nanoserde = ["dep:nanoserde", "bit-vec/nanoserde"] + +serde_std = ["std", "serde/std"] +serde_no_std = ["serde/alloc"] +borsh_std = ["borsh/std"] + +[package.metadata.docs.rs] +features = ["borsh", "serde", "miniserde", "nanoserde"] diff --git a/set/LICENSE-APACHE b/set/LICENSE-APACHE new file mode 100644 index 0000000..11069ed --- /dev/null +++ b/set/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/set/LICENSE-MIT b/set/LICENSE-MIT new file mode 100644 index 0000000..b41213b --- /dev/null +++ b/set/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2026 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/set/README.md b/set/README.md new file mode 100644 index 0000000..d7e96a9 --- /dev/null +++ b/set/README.md @@ -0,0 +1,133 @@ +

    +

    bit-set

    +

    + A compact set of bits. +

    +

    + +[![crates.io][crates.io shield]][crates.io link] +[![Documentation][docs.rs badge]][docs.rs link] +![Rust CI][github ci badge] +![rustc 1.63+] +![borsh: rustc 1.67+] +![nanoserde: rustc 1.67+] +
    +
    +[![Dependency Status][deps.rs status]][deps.rs link] +[![Download Status][shields.io download count]][crates.io link] + +

    +
    + +[crates.io shield]: https://img.shields.io/crates/v/bit-set?label=latest +[crates.io link]: https://crates.io/crates/bit-set +[docs.rs badge]: https://docs.rs/bit-set/badge.svg?version=0.8.0 +[docs.rs link]: https://docs.rs/bit-set/0.8.0/bit_set/ +[github ci badge]: https://github.com/contain-rs/bit-set/workflows/Rust/badge.svg?branch=master +[rustc 1.63+]: https://img.shields.io/badge/rustc-1.63%2B-blue.svg +[borsh: rustc 1.67+]: https://img.shields.io/badge/borsh:%20rustc-1.67%2B-blue.svg +[nanoserde: rustc 1.67+]: https://img.shields.io/badge/nanoserde:%20rustc-1.67%2B-blue.svg +[deps.rs status]: https://deps.rs/crate/bit-set/0.8.0/status.svg +[deps.rs link]: https://deps.rs/crate/bit-set/0.8.0 +[shields.io download count]: https://img.shields.io/crates/d/bit-set.svg + +## Usage + +Add this to your Cargo.toml: + +```toml +[dependencies] +bit-set = "0.8" +``` + +Since Rust 2018, `extern crate` is no longer mandatory. If your edition is old (Rust 2015), +add this to your crate root: + +```rust +extern crate bit_set; +``` + +If you want to use `serde`, enable it with the `serde` feature: + +```toml +[dependencies] +bit-set = { version = "0.8", features = ["serde"] } +``` + +If you want to use bit-set in a program that has `#![no_std]`, just drop default features: + +```toml +[dependencies] +bit-set = { version = "0.8", default-features = false } +``` + +If you want to use serde with the alloc crate instead of std, just use the `serde_no_std` feature: + +```toml +[dependencies] +bit-set = { version = "0.8", default-features = false, features = ["serde", "serde_no_std"] } +``` + +If you want [borsh-rs](https://github.com/near/borsh-rs) support, include it like this: + +```toml +[dependencies] +bit-set = { version = "0.8", features = ["borsh"] } +``` + +Other available serialization libraries can be enabled with the +[`miniserde`](https://github.com/dtolnay/miniserde) and +[`nanoserde`](https://github.com/not-fl3/nanoserde) features. + + + + +### Description + +An implementation of a set using a bit vector as an underlying +representation for holding unsigned numerical elements. + +It should also be noted that the amount of storage necessary for holding a +set of objects is proportional to the maximum of the objects when viewed +as a `usize`. + +### Examples + +```rust +use bit_set::BitSet; + +// It's a regular set +let mut s = BitSet::new(); +s.insert(0); +s.insert(3); +s.insert(7); + +s.remove(7); + +if !s.contains(7) { + println!("There is no 7"); +} + +// Can initialize from a `BitVec` +let other = BitSet::from_bytes(&[0b11010000]); + +s.union_with(&other); + +// Print 0, 1, 3 in some order +for x in s.iter() { + println!("{}", x); +} + +// Can convert back to a `BitVec` +let bv = s.into_bit_vec(); +assert!(bv[3]); +``` + + + +## License + +Dual-licensed for compatibility with the Rust project. + +Licensed under the Apache License Version 2.0: http://www.apache.org/licenses/LICENSE-2.0, +or the MIT license: http://opensource.org/licenses/MIT, at your option. diff --git a/set/RELEASES.md b/set/RELEASES.md new file mode 100644 index 0000000..4e24136 --- /dev/null +++ b/set/RELEASES.md @@ -0,0 +1,10 @@ +Version 0.7.0 (not yet released) (ZERO BREAKING CHANGES) +======================================================== + +
    + +- `serde::Serialize`, `Deserialize` is derived under the `serde` optional feature +- `impl Display` is implemented +- `impl Debug` has different output (we do not promise stable `Debug` output) +- `fn truncate` is implemented +- `fn get_mut` is implemented diff --git a/set/benches/bench.rs b/set/benches/bench.rs new file mode 100644 index 0000000..44e5df4 --- /dev/null +++ b/set/benches/bench.rs @@ -0,0 +1,58 @@ +// Copyright 2012-2024 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate test; + +use bit_set::BitSet; +use bit_vec::BitVec; + +use rand::RngCore; +use test::{black_box, Bencher}; + +const BENCH_BITS: usize = 1 << 14; +const BITS: usize = 32; + +#[bench] +fn bench_bit_vecset_small(b: &mut Bencher) { + let mut r = rand::rng(); + let mut bit_vec = BitSet::new(); + b.iter(|| { + for _ in 0..100 { + bit_vec.insert((r.next_u32() as usize) % BITS); + } + black_box(&bit_vec); + }); +} + +#[bench] +fn bench_bit_vecset_big(b: &mut Bencher) { + let mut r = rand::rng(); + let mut bit_vec = BitSet::new(); + b.iter(|| { + for _ in 0..100 { + bit_vec.insert((r.next_u32() as usize) % BENCH_BITS); + } + black_box(&bit_vec); + }); +} + +#[bench] +fn bench_bit_vecset_iter(b: &mut Bencher) { + let bit_vec = BitSet::from_bit_vec(BitVec::from_fn(BENCH_BITS, |idx| idx % 3 == 0)); + b.iter(|| { + let mut sum = 0; + for idx in &bit_vec { + sum += idx; + } + sum + }) +} diff --git a/set/src/lib.rs b/set/src/lib.rs new file mode 100644 index 0000000..abd7dec --- /dev/null +++ b/set/src/lib.rs @@ -0,0 +1,1778 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Description +//! +//! An implementation of a set using a bit vector as an underlying +//! representation for holding unsigned numerical elements. +//! +//! It should also be noted that the amount of storage necessary for holding a +//! set of objects is proportional to the maximum of the objects when viewed +//! as a `usize`. +//! +//! # Examples +//! +//! ``` +//! use bit_set::BitSet; +//! +//! // It's a regular set +//! let mut s = BitSet::new(); +//! s.insert(0); +//! s.insert(3); +//! s.insert(7); +//! +//! s.remove(7); +//! +//! if !s.contains(7) { +//! println!("There is no 7"); +//! } +//! +//! // Can initialize from a `BitVec` +//! let other = BitSet::from_bytes(&[0b11010000]); +//! +//! s.union_with(&other); +//! +//! // Print 0, 1, 3 in some order +//! for x in s.iter() { +//! println!("{}", x); +//! } +//! +//! // Can convert back to a `BitVec` +//! let bv = s.into_bit_vec(); +//! assert!(bv[3]); +//! ``` +#![doc(html_root_url = "https://docs.rs/bit-set/0.8.0")] +#![deny(clippy::shadow_reuse)] +#![deny(clippy::shadow_same)] +#![deny(clippy::shadow_unrelated)] +#![no_std] + +#[cfg(any(test, feature = "std"))] +extern crate std; + +use bit_vec::{BitBlock, BitVec, Blocks}; +use core::cmp; +use core::cmp::Ordering; +use core::fmt; +use core::hash; +use core::iter::{self, Chain, Enumerate, FromIterator, Repeat, Skip, Take}; + +#[cfg(feature = "nanoserde")] +extern crate alloc; +#[cfg(feature = "nanoserde")] +use alloc::vec::Vec; +#[cfg(feature = "nanoserde")] +use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; + +type MatchWords<'a, B> = Chain>, Skip>>>>; + +/// Computes how many blocks are needed to store that many bits +fn blocks_for_bits(bits: usize) -> usize { + // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we + // reserve enough. But if we want exactly a multiple of 32, this will actually allocate + // one too many. So we need to check if that's the case. We can do that by computing if + // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically + // superior modulo operator on a power of two to this. + // + // Note that we can technically avoid this branch with the expression + // `(nbits + BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. + if bits % B::bits() == 0 { + bits / B::bits() + } else { + bits / B::bits() + 1 + } +} + +#[allow(clippy::iter_skip_zero)] +// Take two BitVec's, and return iterators of their words, where the shorter one +// has been padded with 0's +fn match_words<'a, 'b, B: BitBlock>( + a: &'a BitVec, + b: &'b BitVec, +) -> (MatchWords<'a, B>, MatchWords<'b, B>) { + let a_len = a.storage().len(); + let b_len = b.storage().len(); + + // have to uselessly pretend to pad the longer one for type matching + if a_len < b_len { + ( + a.blocks() + .enumerate() + .chain(iter::repeat(B::zero()).enumerate().take(b_len).skip(a_len)), + b.blocks() + .enumerate() + .chain(iter::repeat(B::zero()).enumerate().take(0).skip(0)), + ) + } else { + ( + a.blocks() + .enumerate() + .chain(iter::repeat(B::zero()).enumerate().take(0).skip(0)), + b.blocks() + .enumerate() + .chain(iter::repeat(B::zero()).enumerate().take(a_len).skip(b_len)), + ) + } +} + +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshDeserialize, borsh::BorshSerialize) +)] +#[cfg_attr( + feature = "miniserde", + derive(miniserde::Deserialize, miniserde::Serialize) +)] +#[cfg_attr( + feature = "nanoserde", + derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) +)] +pub struct BitSet { + bit_vec: BitVec, +} + +impl Clone for BitSet { + fn clone(&self) -> Self { + BitSet { + bit_vec: self.bit_vec.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.bit_vec.clone_from(&other.bit_vec); + } +} + +impl Default for BitSet { + #[inline] + fn default() -> Self { + BitSet { + bit_vec: Default::default(), + } + } +} + +impl FromIterator for BitSet { + fn from_iter>(iter: I) -> Self { + let mut ret = Self::default(); + ret.extend(iter); + ret + } +} + +impl Extend for BitSet { + #[inline] + fn extend>(&mut self, iter: I) { + for i in iter { + self.insert(i); + } + } +} + +impl PartialOrd for BitSet { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for BitSet { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +impl PartialEq for BitSet { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.iter().eq(other) + } +} + +impl Eq for BitSet {} + +impl BitSet { + /// Creates a new empty `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// ``` + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Creates a new `BitSet` with initially no contents, able to + /// hold `nbits` elements without resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn with_capacity(nbits: usize) -> Self { + let bit_vec = BitVec::from_elem(nbits, false); + Self::from_bit_vec(bit_vec) + } + + /// Creates a new `BitSet` from the given bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// use bit_set::BitSet; + /// + /// let bv = BitVec::from_bytes(&[0b01100000]); + /// let s = BitSet::from_bit_vec(bv); + /// + /// // Print 1, 2 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn from_bit_vec(bit_vec: BitVec) -> Self { + BitSet { bit_vec } + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + BitSet { + bit_vec: BitVec::from_bytes(bytes), + } + } +} + +impl BitSet { + /// Returns the capacity in bits for this bit vector. Inserting any + /// element less than this amount will not trigger a resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.bit_vec.capacity() + } + + /// Reserves capacity for the given `BitSet` to contain `len` distinct elements. In the case + /// of `BitSet` this means reallocations will not occur as long as all inserted elements + /// are less than `len`. + /// + /// The collection may reserve more space to avoid frequent reallocations. + /// + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.reserve_len(10); + /// assert!(s.capacity() >= 10); + /// ``` + pub fn reserve_len(&mut self, len: usize) { + let cur_len = self.bit_vec.len(); + if len >= cur_len { + self.bit_vec.reserve(len - cur_len); + } + } + + /// Reserves the minimum capacity for the given `BitSet` to contain `len` distinct elements. + /// In the case of `BitSet` this means reallocations will not occur as long as all inserted + /// elements are less than `len`. + /// + /// Note that the allocator may give the collection more space than it requests. Therefore + /// capacity can not be relied upon to be precisely minimal. Prefer `reserve_len` if future + /// insertions are expected. + /// + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.reserve_len_exact(10); + /// assert!(s.capacity() >= 10); + /// ``` + pub fn reserve_len_exact(&mut self, len: usize) { + let cur_len = self.bit_vec.len(); + if len >= cur_len { + self.bit_vec.reserve_exact(len - cur_len); + } + } + + /// Consumes this set to return the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.insert(0); + /// s.insert(3); + /// + /// let bv = s.into_bit_vec(); + /// assert!(bv[0]); + /// assert!(bv[3]); + /// ``` + #[inline] + pub fn into_bit_vec(self) -> BitVec { + self.bit_vec + } + + /// Returns a reference to the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut set = BitSet::new(); + /// set.insert(0); + /// + /// let bv = set.get_ref(); + /// assert_eq!(bv[0], true); + /// ``` + #[inline] + pub fn get_ref(&self) -> &BitVec { + &self.bit_vec + } + + /// Returns a mutable reference to the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut set = BitSet::new(); + /// set.insert(0); + /// set.insert(3); + /// + /// { + /// let bv = set.get_mut(); + /// bv.set(1, true); + /// } + /// + /// assert!(set.contains(0)); + /// assert!(set.contains(1)); + /// assert!(set.contains(3)); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut BitVec { + &mut self.bit_vec + } + + #[inline] + fn other_op(&mut self, other: &Self, mut f: F) + where + F: FnMut(B, B) -> B, + { + // Unwrap BitVecs + let self_bit_vec = &mut self.bit_vec; + let other_bit_vec = &other.bit_vec; + + let self_len = self_bit_vec.len(); + let other_len = other_bit_vec.len(); + + // Expand the vector if necessary + if self_len < other_len { + self_bit_vec.grow(other_len - self_len, false); + } + + // virtually pad other with 0's for equal lengths + let other_words = { + let (_, result) = match_words(self_bit_vec, other_bit_vec); + result + }; + + // Apply values found in other + for (i, w) in other_words { + let old = self_bit_vec.storage()[i]; + let new = f(old, w); + unsafe { + self_bit_vec.storage_mut()[i] = new; + } + } + } + + /// Truncates the underlying vector to the least length required. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.insert(3231); + /// s.remove(3231); + /// + /// // Internal storage will probably be bigger than necessary + /// println!("old capacity: {}", s.capacity()); + /// assert!(s.capacity() >= 3231); + /// + /// // Now should be smaller + /// s.shrink_to_fit(); + /// println!("new capacity: {}", s.capacity()); + /// ``` + #[inline] + pub fn shrink_to_fit(&mut self) { + let bit_vec = &mut self.bit_vec; + // Obtain original length + let old_len = bit_vec.storage().len(); + // Obtain coarse trailing zero length + let n = bit_vec + .storage() + .iter() + .rev() + .take_while(|&&n| n == B::zero()) + .count(); + // Truncate away all empty trailing blocks, then shrink_to_fit + let trunc_len = old_len - n; + unsafe { + bit_vec.storage_mut().truncate(trunc_len); + bit_vec.set_len(trunc_len * B::bits()); + } + bit_vec.shrink_to_fit(); + } + + /// Iterator over each usize stored in the `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let s = BitSet::from_bytes(&[0b01001010]); + /// + /// // Print 1, 4, 6 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn iter(&self) -> Iter<'_, B> { + Iter(BlockIter::from_blocks(self.bit_vec.blocks())) + } + + /// Iterator over each usize stored in `self` union `other`. + /// See [`union_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 0, 1, 2, 4 in arbitrary order + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`union_with`]: Self::union_with + #[inline] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, B> { + fn or(w1: B, w2: B) -> B { + w1 | w2 + } + + Union(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: or, + })) + } + + /// Iterator over each usize stored in `self` intersect `other`. + /// See [`intersect_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 2 + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`intersect_with`]: Self::intersect_with + #[inline] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, B> { + fn bitand(w1: B, w2: B) -> B { + w1 & w2 + } + let min = cmp::min(self.bit_vec.len(), other.bit_vec.len()); + + Intersection { + iter: BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: bitand, + }), + n: min, + } + } + + /// Iterator over each usize stored in the `self` setminus `other`. + /// See [`difference_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 1, 4 in arbitrary order + /// for x in a.difference(&b) { + /// println!("{}", x); + /// } + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else. + /// // This prints 0 + /// for x in b.difference(&a) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`difference_with`]: Self::difference_with + #[inline] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, B> { + fn diff(w1: B, w2: B) -> B { + w1 & !w2 + } + + Difference(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: diff, + })) + } + + /// Iterator over each usize stored in the symmetric difference of `self` and `other`. + /// See [`symmetric_difference_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 0, 1, 4 in arbitrary order + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`symmetric_difference_with`]: Self::symmetric_difference_with + #[inline] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, B> { + fn bitxor(w1: B, w2: B) -> B { + w1 ^ w2 + } + + SymmetricDifference(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: bitxor, + })) + } + + /// Unions in-place with the specified other bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11101000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.union_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn union_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 | w2); + } + + /// Intersects in-place with the specified other bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b00100000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.intersect_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn intersect_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 & w2); + } + + /// Makes this bit vector the difference with the specified other bit vector + /// in-place. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let a_b = 0b01001000; // a - b + /// let b_a = 0b10000000; // b - a + /// + /// let mut bva = BitSet::from_bytes(&[a]); + /// let bvb = BitSet::from_bytes(&[b]); + /// let bva_b = BitSet::from_bytes(&[a_b]); + /// let bvb_a = BitSet::from_bytes(&[b_a]); + /// + /// bva.difference_with(&bvb); + /// assert_eq!(bva, bva_b); + /// + /// let bva = BitSet::from_bytes(&[a]); + /// let mut bvb = BitSet::from_bytes(&[b]); + /// + /// bvb.difference_with(&bva); + /// assert_eq!(bvb, bvb_a); + /// ``` + #[inline] + pub fn difference_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 & !w2); + } + + /// Makes this bit vector the symmetric difference with the specified other + /// bit vector in-place. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11001000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.symmetric_difference_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn symmetric_difference_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 ^ w2); + } + + /* + /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// + /// let mut b = BitSet::new(); + /// b.insert(1); + /// b.insert(3); + /// b.insert(6); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 4); + /// assert_eq!(b.len(), 0); + /// assert_eq!(a, BitSet::from_bytes(&[0b01110010])); + /// ``` + pub fn append(&mut self, other: &mut Self) { + self.union_with(other); + other.clear(); + } + + /// Splits the `BitSet` into two at the given key including the key. + /// Retains the first part in-place while returning the second part. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// a.insert(1); + /// a.insert(3); + /// + /// let b = a.split_off(3); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 2); + /// assert_eq!(a, BitSet::from_bytes(&[0b01100000])); + /// assert_eq!(b, BitSet::from_bytes(&[0b00010010])); + /// ``` + pub fn split_off(&mut self, at: usize) -> Self { + let mut other = BitSet::new(); + + if at == 0 { + swap(self, &mut other); + return other; + } else if at >= self.bit_vec.len() { + return other; + } + + // Calculate block and bit at which to split + let w = at / BITS; + let b = at % BITS; + + // Pad `other` with `w` zero blocks, + // append `self`'s blocks in the range from `w` to the end to `other` + other.bit_vec.storage_mut().extend(repeat(0u32).take(w) + .chain(self.bit_vec.storage()[w..].iter().cloned())); + other.bit_vec.nbits = self.bit_vec.nbits; + + if b > 0 { + other.bit_vec.storage_mut()[w] &= !0 << b; + } + + // Sets `bit_vec.len()` and fixes the last block as well + self.bit_vec.truncate(at); + + other + } + */ + + /// Counts the number of set bits in this set. + /// + /// Note that this function scans the set to calculate the number. + #[inline] + pub fn count(&self) -> usize { + self.bit_vec.blocks().fold(0, |acc, n| acc + n.count_ones()) + } + + /// Counts the number of set bits in this set. + /// + /// Note that this function scans the set to calculate the number. + #[inline] + #[deprecated = "use BitVec::count() instead"] + pub fn len(&self) -> usize { + self.count() + } + + /// Returns whether there are no bits set in this set + #[inline] + pub fn is_empty(&self) -> bool { + self.bit_vec.none() + } + + /// Clears all bits in this set + #[inline] + pub fn clear(&mut self) { + self.bit_vec.clear(); + } + + /// Returns `true` if this set contains the specified integer. + #[inline] + pub fn contains(&self, value: usize) -> bool { + let bit_vec = &self.bit_vec; + value < bit_vec.len() && bit_vec[value] + } + + /// Returns `true` if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + #[inline] + pub fn is_disjoint(&self, other: &Self) -> bool { + self.intersection(other).next().is_none() + } + + /// Returns `true` if the set is a subset of another. + #[inline] + pub fn is_subset(&self, other: &Self) -> bool { + let self_bit_vec = &self.bit_vec; + let other_bit_vec = &other.bit_vec; + let other_blocks = blocks_for_bits::(other_bit_vec.len()); + + // Check that `self` intersect `other` is self + self_bit_vec.blocks().zip(other_bit_vec.blocks()).all(|(w1, w2)| w1 & w2 == w1) && + // Make sure if `self` has any more blocks than `other`, they're all 0 + self_bit_vec.blocks().skip(other_blocks).all(|w| w == B::zero()) + } + + /// Returns `true` if the set is a superset of another. + #[inline] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. Returns `true` if the value was not already + /// present in the set. + pub fn insert(&mut self, value: usize) -> bool { + if self.contains(value) { + return false; + } + + // Ensure we have enough space to hold the new element + let len = self.bit_vec.len(); + if value >= len { + self.bit_vec.grow(value - len + 1, false); + } + + self.bit_vec.set(value, true); + true + } + + /// Removes a value from the set. Returns `true` if the value was + /// present in the set. + pub fn remove(&mut self, value: usize) -> bool { + if !self.contains(value) { + return false; + } + + self.bit_vec.set(value, false); + + true + } + + /// Excludes `element` and all greater elements from the `BitSet`. + pub fn truncate(&mut self, element: usize) { + self.bit_vec.truncate(element); + } +} + +impl fmt::Debug for BitSet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BitSet") + .field("bit_vec", &self.bit_vec) + .finish() + } +} + +impl fmt::Display for BitSet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set().entries(self).finish() + } +} + +impl hash::Hash for BitSet { + fn hash(&self, state: &mut H) { + for pos in self { + pos.hash(state); + } + } +} + +#[derive(Clone)] +struct BlockIter { + head: B, + head_offset: usize, + tail: T, +} + +impl BlockIter +where + T: Iterator, +{ + fn from_blocks(mut blocks: T) -> BlockIter { + let h = blocks.next().unwrap_or_else(B::zero); + BlockIter { + tail: blocks, + head: h, + head_offset: 0, + } + } +} + +/// An iterator combining two `BitSet` iterators. +#[derive(Clone)] +struct TwoBitPositions<'a, B: 'a> { + set: Blocks<'a, B>, + other: Blocks<'a, B>, + merge: fn(B, B) -> B, +} + +/// An iterator for `BitSet`. +#[derive(Clone)] +pub struct Iter<'a, B: 'a>(BlockIter, B>); +#[derive(Clone)] +pub struct Union<'a, B: 'a>(BlockIter, B>); +#[derive(Clone)] +pub struct Intersection<'a, B: 'a> { + iter: BlockIter, B>, + // as an optimization, we compute the maximum possible + // number of elements in the intersection, and count it + // down as we return elements. If we reach zero, we can + // stop. + n: usize, +} +#[derive(Clone)] +pub struct Difference<'a, B: 'a>(BlockIter, B>); +#[derive(Clone)] +pub struct SymmetricDifference<'a, B: 'a>(BlockIter, B>); + +impl Iterator for BlockIter +where + T: Iterator, +{ + type Item = usize; + + fn next(&mut self) -> Option { + while self.head == B::zero() { + match self.tail.next() { + Some(w) => self.head = w, + None => return None, + } + self.head_offset += B::bits(); + } + + // from the current block, isolate the + // LSB and subtract 1, producing k: + // a block with a number of set bits + // equal to the index of the LSB + let k = (self.head & (!self.head + B::one())) - B::one(); + // update block, removing the LSB + self.head = self.head & (self.head - B::one()); + // return offset + (index of LSB) + Some(self.head_offset + (B::count_ones(k))) + } + + fn count(self) -> usize { + self.head.count_ones() + self.tail.map(|block| block.count_ones()).sum::() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + match self.tail.size_hint() { + (_, Some(h)) => (0, Some((1 + h) * B::bits())), + _ => (0, None), + } + } +} + +impl Iterator for TwoBitPositions<'_, B> { + type Item = B; + + fn next(&mut self) -> Option { + match (self.set.next(), self.other.next()) { + (Some(a), Some(b)) => Some((self.merge)(a, b)), + (Some(a), None) => Some((self.merge)(a, B::zero())), + (None, Some(b)) => Some((self.merge)(B::zero(), b)), + _ => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (first_lower_bound, first_upper_bound) = self.set.size_hint(); + let (second_lower_bound, second_upper_bound) = self.other.size_hint(); + + let upper_bound = first_upper_bound.zip(second_upper_bound); + + let get_max = |(a, b)| cmp::max(a, b); + ( + cmp::max(first_lower_bound, second_lower_bound), + upper_bound.map(get_max), + ) + } +} + +impl Iterator for Iter<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl Iterator for Union<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl Iterator for Intersection<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + if self.n != 0 { + self.n -= 1; + self.iter.next() + } else { + None + } + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + // We could invoke self.iter.size_hint() and incorporate that into the hint. + // In practice, that does not seem worthwhile because the lower bound will + // always be zero and the upper bound could only possibly less then n in a + // partially iterated iterator. However, it makes little sense ask for size_hint + // in a partially iterated iterator, so it did not seem worthwhile. + (0, Some(self.n)) + } + #[inline] + fn count(self) -> usize { + self.iter.count() + } +} + +impl Iterator for Difference<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl Iterator for SymmetricDifference<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl<'a, B: BitBlock> IntoIterator for &'a BitSet { + type Item = usize; + type IntoIter = Iter<'a, B>; + + fn into_iter(self) -> Iter<'a, B> { + self.iter() + } +} + +#[cfg(test)] +mod tests { + #![allow(clippy::shadow_reuse)] + #![allow(clippy::shadow_same)] + #![allow(clippy::shadow_unrelated)] + + use super::BitSet; + use bit_vec::BitVec; + use std::cmp::Ordering::{Equal, Greater, Less}; + use std::vec::Vec; + use std::{format, vec}; + + #[test] + fn test_bit_set_display() { + let mut s = BitSet::new(); + s.insert(1); + s.insert(10); + s.insert(50); + s.insert(2); + assert_eq!("{1, 2, 10, 50}", format!("{}", s)); + } + + #[test] + fn test_bit_set_debug() { + let mut s = BitSet::new(); + s.insert(1); + s.insert(10); + s.insert(50); + s.insert(2); + let expected = "BitSet { bit_vec: BitVec { storage: \ + \"01100000001000000000000000000000 \ + 0000000000000000001\", nbits: 51 } }"; + let actual = format!("{:?}", s); + assert_eq!(expected, actual); + } + + #[test] + fn test_bit_set_from_usizes() { + let usizes = vec![0, 2, 2, 3]; + let a: BitSet = usizes.into_iter().collect(); + let mut b = BitSet::new(); + b.insert(0); + b.insert(2); + b.insert(3); + assert_eq!(a, b); + } + + #[test] + fn test_bit_set_iterator() { + let usizes = vec![0, 2, 2, 3]; + let bit_vec: BitSet = usizes.into_iter().collect(); + + let idxs: Vec<_> = bit_vec.iter().collect(); + assert_eq!(idxs, [0, 2, 3]); + assert_eq!(bit_vec.iter().count(), 3); + + let long: BitSet = (0..10000).filter(|&n| n % 2 == 0).collect(); + let real: Vec<_> = (0..10000 / 2).map(|x| x * 2).collect(); + + let idxs: Vec<_> = long.iter().collect(); + assert_eq!(idxs, real); + assert_eq!(long.iter().count(), real.len()); + } + + #[test] + fn test_bit_set_frombit_vec_init() { + let bools = [true, false]; + let lengths = [10, 64, 100]; + for &b in &bools { + for &l in &lengths { + let bitset = BitSet::from_bit_vec(BitVec::from_elem(l, b)); + assert_eq!(bitset.contains(1), b); + assert_eq!(bitset.contains(l - 1), b); + assert!(!bitset.contains(l)); + } + } + } + + #[test] + fn test_bit_vec_masking() { + let b = BitVec::from_elem(140, true); + let mut bs = BitSet::from_bit_vec(b); + assert!(bs.contains(139)); + assert!(!bs.contains(140)); + assert!(bs.insert(150)); + assert!(!bs.contains(140)); + assert!(!bs.contains(149)); + assert!(bs.contains(150)); + assert!(!bs.contains(151)); + } + + #[test] + fn test_bit_set_basic() { + let mut b = BitSet::new(); + assert!(b.insert(3)); + assert!(!b.insert(3)); + assert!(b.contains(3)); + assert!(b.insert(4)); + assert!(!b.insert(4)); + assert!(b.contains(3)); + assert!(b.insert(400)); + assert!(!b.insert(400)); + assert!(b.contains(400)); + assert_eq!(b.count(), 3); + } + + #[test] + fn test_bit_set_intersection() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let actual: Vec<_> = a.intersection(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.intersection(&b).count(), expected.len()); + } + + #[test] + fn test_bit_set_difference() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(200)); + assert!(a.insert(500)); + + assert!(b.insert(3)); + assert!(b.insert(200)); + + let expected = [1, 5, 500]; + let actual: Vec<_> = a.difference(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.difference(&b).count(), expected.len()); + } + + #[test] + fn test_bit_set_symmetric_difference() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(220)); + + let expected = [1, 5, 11, 14, 220]; + let actual: Vec<_> = a.symmetric_difference(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.symmetric_difference(&b).count(), expected.len()); + } + + #[test] + fn test_bit_set_union() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(160)); + assert!(a.insert(19)); + assert!(a.insert(24)); + assert!(a.insert(200)); + + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [1, 3, 5, 9, 11, 13, 19, 24, 160, 200]; + let actual: Vec<_> = a.union(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.union(&b).count(), expected.len()); + } + + #[test] + fn test_bit_set_subset() { + let mut set1 = BitSet::new(); + let mut set2 = BitSet::new(); + + assert!(set1.is_subset(&set2)); // {} {} + set2.insert(100); + assert!(set1.is_subset(&set2)); // {} { 1 } + set2.insert(200); + assert!(set1.is_subset(&set2)); // {} { 1, 2 } + set1.insert(200); + assert!(set1.is_subset(&set2)); // { 2 } { 1, 2 } + set1.insert(300); + assert!(!set1.is_subset(&set2)); // { 2, 3 } { 1, 2 } + set2.insert(300); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3 } + set2.insert(400); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3, 4 } + set2.remove(100); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 2, 3, 4 } + set2.remove(300); + assert!(!set1.is_subset(&set2)); // { 2, 3 } { 2, 4 } + set1.remove(300); + assert!(set1.is_subset(&set2)); // { 2 } { 2, 4 } + } + + #[test] + fn test_bit_set_is_disjoint() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b01000000]); + let c = BitSet::new(); + let d = BitSet::from_bytes(&[0b00110000]); + + assert!(!a.is_disjoint(&d)); + assert!(!d.is_disjoint(&a)); + + assert!(a.is_disjoint(&b)); + assert!(a.is_disjoint(&c)); + assert!(b.is_disjoint(&a)); + assert!(b.is_disjoint(&c)); + assert!(c.is_disjoint(&a)); + assert!(c.is_disjoint(&b)); + } + + #[test] + fn test_bit_set_union_with() { + //a should grow to include larger elements + let mut a = BitSet::new(); + a.insert(0); + let mut b = BitSet::new(); + b.insert(5); + let expected = BitSet::from_bytes(&[0b10000100]); + a.union_with(&b); + assert_eq!(a, expected); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.union_with(&b); + b.union_with(&c); + assert_eq!(a.count(), 4); + assert_eq!(b.count(), 4); + } + + #[test] + fn test_bit_set_intersect_with() { + // Explicitly 0'ed bits + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b00000000]); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert!(a.is_empty()); + assert!(b.is_empty()); + + // Uninitialized bits should behave like 0's + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::new(); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert!(a.is_empty()); + assert!(b.is_empty()); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert_eq!(a.count(), 2); + assert_eq!(b.count(), 2); + } + + #[test] + fn test_bit_set_difference_with() { + // Explicitly 0'ed bits + let mut a = BitSet::from_bytes(&[0b00000000]); + let b = BitSet::from_bytes(&[0b10100010]); + a.difference_with(&b); + assert!(a.is_empty()); + + // Uninitialized bits should behave like 0's + let mut a = BitSet::new(); + let b = BitSet::from_bytes(&[0b11111111]); + a.difference_with(&b); + assert!(a.is_empty()); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.difference_with(&b); + b.difference_with(&c); + assert_eq!(a.count(), 1); + assert_eq!(b.count(), 1); + } + + #[test] + fn test_bit_set_symmetric_difference_with() { + //a should grow to include larger elements + let mut a = BitSet::new(); + a.insert(0); + a.insert(1); + let mut b = BitSet::new(); + b.insert(1); + b.insert(5); + let expected = BitSet::from_bytes(&[0b10000100]); + a.symmetric_difference_with(&b); + assert_eq!(a, expected); + + let mut a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::new(); + let c = a.clone(); + a.symmetric_difference_with(&b); + assert_eq!(a, c); + + // Standard + let mut a = BitSet::from_bytes(&[0b11100010]); + let mut b = BitSet::from_bytes(&[0b01101010]); + let c = a.clone(); + a.symmetric_difference_with(&b); + b.symmetric_difference_with(&c); + assert_eq!(a.count(), 2); + assert_eq!(b.count(), 2); + } + + #[test] + fn test_bit_set_eq() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b00000000]); + let c = BitSet::new(); + + assert!(a == a); + assert!(a != b); + assert!(a != c); + assert!(b == b); + assert!(b == c); + assert!(c == c); + } + + #[test] + fn test_bit_set_cmp() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b00000000]); + let c = BitSet::new(); + + assert_eq!(a.cmp(&b), Greater); + assert_eq!(a.cmp(&c), Greater); + assert_eq!(b.cmp(&a), Less); + assert_eq!(b.cmp(&c), Equal); + assert_eq!(c.cmp(&a), Less); + assert_eq!(c.cmp(&b), Equal); + } + + #[test] + fn test_bit_set_shrink_to_fit_new() { + // There was a strange bug where we refused to truncate to 0 + // and this would end up actually growing the array in a way + // that (safely corrupted the state). + let mut a = BitSet::new(); + assert_eq!(a.count(), 0); + assert_eq!(a.capacity(), 0); + a.shrink_to_fit(); + assert_eq!(a.count(), 0); + assert_eq!(a.capacity(), 0); + assert!(!a.contains(1)); + a.insert(3); + assert!(a.contains(3)); + assert_eq!(a.count(), 1); + assert!(a.capacity() > 0); + a.shrink_to_fit(); + assert!(a.contains(3)); + assert_eq!(a.count(), 1); + assert!(a.capacity() > 0); + } + + #[test] + fn test_bit_set_shrink_to_fit() { + let mut a = BitSet::new(); + assert_eq!(a.count(), 0); + assert_eq!(a.capacity(), 0); + a.insert(259); + a.insert(98); + a.insert(3); + assert_eq!(a.count(), 3); + assert!(a.capacity() > 0); + assert!(!a.contains(1)); + assert!(a.contains(259)); + assert!(a.contains(98)); + assert!(a.contains(3)); + + a.shrink_to_fit(); + assert!(!a.contains(1)); + assert!(a.contains(259)); + assert!(a.contains(98)); + assert!(a.contains(3)); + assert_eq!(a.count(), 3); + assert!(a.capacity() > 0); + + let old_cap = a.capacity(); + assert!(a.remove(259)); + a.shrink_to_fit(); + assert!(a.capacity() < old_cap, "{} {}", a.capacity(), old_cap); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(a.contains(98)); + assert!(a.contains(3)); + assert_eq!(a.count(), 2); + + let old_cap2 = a.capacity(); + a.clear(); + assert_eq!(a.capacity(), old_cap2); + assert_eq!(a.count(), 0); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(!a.contains(98)); + assert!(!a.contains(3)); + + a.insert(512); + assert!(a.capacity() > 0); + assert_eq!(a.count(), 1); + assert!(a.contains(512)); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(!a.contains(98)); + assert!(!a.contains(3)); + + a.remove(512); + a.shrink_to_fit(); + assert_eq!(a.capacity(), 0); + assert_eq!(a.count(), 0); + assert!(!a.contains(512)); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(!a.contains(98)); + assert!(!a.contains(3)); + assert!(!a.contains(0)); + } + + #[test] + fn test_bit_vec_remove() { + let mut a = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.remove(1)); + + assert!(a.insert(100)); + assert!(a.remove(100)); + + assert!(a.insert(1000)); + assert!(a.remove(1000)); + a.shrink_to_fit(); + } + + #[test] + fn test_bit_vec_clone() { + let mut a = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(100)); + assert!(a.insert(1000)); + + let mut b = a.clone(); + + assert!(a == b); + + assert!(b.remove(1)); + assert!(a.contains(1)); + + assert!(a.remove(1000)); + assert!(b.contains(1000)); + } + + #[test] + fn test_truncate() { + let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; + + let mut s = BitSet::from_bytes(&bytes); + s.truncate(5 * 8); + + assert_eq!(s, BitSet::from_bytes(&bytes[..5])); + assert_eq!(s.count(), 5 * 8); + s.truncate(4 * 8); + assert_eq!(s, BitSet::from_bytes(&bytes[..4])); + assert_eq!(s.count(), 4 * 8); + // Truncating to a size > s.len() should be a noop + s.truncate(5 * 8); + assert_eq!(s, BitSet::from_bytes(&bytes[..4])); + assert_eq!(s.count(), 4 * 8); + s.truncate(8); + assert_eq!(s, BitSet::from_bytes(&bytes[..1])); + assert_eq!(s.count(), 8); + s.truncate(0); + assert_eq!(s, BitSet::from_bytes(&[])); + assert_eq!(s.count(), 0); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serialization() { + let bset: BitSet = BitSet::new(); + let serialized = serde_json::to_string(&bset).unwrap(); + let unserialized: BitSet = serde_json::from_str(&serialized).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = serde_json::to_string(&bset).unwrap(); + let unserialized = serde_json::from_str(&serialized).unwrap(); + assert_eq!(bset, unserialized); + } + + #[cfg(feature = "miniserde")] + #[test] + fn test_miniserde_serialization() { + let bset: BitSet = BitSet::new(); + let serialized = miniserde::json::to_string(&bset); + let unserialized: BitSet = miniserde::json::from_str(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = miniserde::json::to_string(&bset); + let unserialized = miniserde::json::from_str(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + } + + #[cfg(feature = "nanoserde")] + #[test] + fn test_nanoserde_json_serialization() { + use nanoserde::{DeJson, SerJson}; + + let bset: BitSet = BitSet::new(); + let serialized = bset.serialize_json(); + let unserialized: BitSet = BitSet::deserialize_json(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = bset.serialize_json(); + let unserialized = BitSet::deserialize_json(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + } + + #[cfg(feature = "borsh")] + #[test] + fn test_borsh_serialization() { + let bset: BitSet = BitSet::new(); + let serialized = borsh::to_vec(&bset).unwrap(); + let unserialized: BitSet = borsh::from_slice(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = borsh::to_vec(&bset).unwrap(); + let unserialized = borsh::from_slice(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + } + + /* + #[test] + fn test_bit_set_append() { + let mut a = BitSet::new(); + a.insert(2); + a.insert(6); + + let mut b = BitSet::new(); + b.insert(1); + b.insert(3); + b.insert(6); + + a.append(&mut b); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 6); + + assert_eq!(a, BitSet::from_bytes(&[0b01110010])); + } + + #[test] + fn test_bit_set_split_off() { + // Split at 0 + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 21); + + assert_eq!(b, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + // Split behind last element + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(50); + + assert_eq!(a.len(), 21); + assert_eq!(b.len(), 0); + + assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101])); + + // Split at arbitrary element + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(34); + + assert_eq!(a.len(), 12); + assert_eq!(b.len(), 9); + + assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01000000])); + assert_eq!(b, BitSet::from_bytes(&[0, 0, 0, 0, + 0b00101011, 0b10101101])); + } + */ +} diff --git a/vec/Cargo.toml b/vec/Cargo.toml new file mode 100644 index 0000000..e9863c0 --- /dev/null +++ b/vec/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "bit-vec" +version = "0.9.0" +authors = ["Alexis Beingessner "] +license = "Apache-2.0 OR MIT" +description = "A vector of bits" +repository = "https://github.com/contain-rs/bit-vec" +homepage = "https://github.com/contain-rs/bit-vec" +documentation = "https://docs.rs/bit-vec/" +keywords = ["data-structures", "bitvec", "bitmask", "bitmap", "bit"] +readme = "README.md" +edition = "2021" +rust-version = "1.82" + +[dependencies] +borsh = { version = "1.5.7", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +miniserde = { version = "0.1", optional = true } +nanoserde = { version = "0.2", optional = true } +smallvec = { version = "1.15", optional = true } + +[dev-dependencies] +serde_json = "1.0" +rand = "0.10" +rand_xorshift = "0.5" +generic-tests = "0.1" + +[features] +default = ["std"] +serde_std = ["std", "serde/std"] +serde_no_std = ["serde/alloc"] +borsh_std = ["borsh/std"] +std = [] +allocator_api = [] + +[package.metadata.docs.rs] +features = ["borsh", "serde", "miniserde", "nanoserde"] diff --git a/benches/bench.rs b/vec/benches/bench.rs similarity index 100% rename from benches/bench.rs rename to vec/benches/bench.rs diff --git a/docs/README.md b/vec/docs/README.md similarity index 100% rename from docs/README.md rename to vec/docs/README.md diff --git a/src/lib.rs b/vec/src/lib.rs similarity index 98% rename from src/lib.rs rename to vec/src/lib.rs index 4c4c360..a77b47b 100644 --- a/src/lib.rs +++ b/vec/src/lib.rs @@ -107,8 +107,6 @@ use std::vec::Vec; #[cfg(feature = "serde")] extern crate serde; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; #[cfg(feature = "borsh")] extern crate borsh; #[cfg(feature = "miniserde")] @@ -177,7 +175,11 @@ pub trait BitBlock: } pub trait BitBlockOrStore { + #[cfg(not(feature = "nanoserde"))] type Store: BitStore; + #[cfg(feature = "nanoserde")] + type Store: BitStore + DeBin + DeJson + DeRon + SerBin + SerJson + SerRon; + const BITS: usize = ::Block::BITS_; const BYTES: usize = ::Block::BYTES_; const ONE: ::Block = ::Block::ONE_; @@ -365,11 +367,17 @@ where } } +#[cfg(not(feature = "nanoserde"))] impl BitBlockOrStore for Vec { type Store = Self; } -#[cfg(feature = "smallvec")] +#[cfg(feature = "nanoserde")] +impl BitBlockOrStore for Vec { + type Store = Self; +} + +#[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] impl BitBlockOrStore for smallvec::SmallVec where A::Item: BitBlock, @@ -449,11 +457,11 @@ where self.clear(); } - fn new_in(alloc: ()) -> Self { + fn new_in(_alloc: ()) -> Self { smallvec::SmallVec::new() } - fn with_capacity_in(capacity: usize, alloc: ()) -> Self { + fn with_capacity_in(capacity: usize, _alloc: ()) -> Self { smallvec::SmallVec::with_capacity(capacity) } } @@ -527,6 +535,10 @@ type B = u32; /// println!("{:?}", bv); /// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); /// ``` +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize) +)] #[cfg_attr( feature = "borsh", derive(borsh::BorshDeserialize, borsh::BorshSerialize) @@ -3541,10 +3553,10 @@ mod tests { #[cfg(feature = "serde")] #[test] - fn test_serialization() { - let bit_vec: BitVec = BitVec::::new_general(); + fn test_serialization() where S::Store: serde::Serialize + for<'a> serde::Deserialize<'a> { + let bit_vec: BitVec = BitVec::::new_general(); let serialized = serde_json::to_string(&bit_vec).unwrap(); - let unserialized: BitVec = serde_json::from_str(&serialized).unwrap(); + let unserialized: BitVec = serde_json::from_str(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); let bools = vec![true, false, true, true]; @@ -3571,16 +3583,16 @@ mod tests { #[cfg(feature = "nanoserde")] #[test] - fn test_nanoserde_json_serialization() { + fn test_nanoserde_json_serialization() { use nanoserde::{DeJson, SerJson}; - let bit_vec: BitVec = BitVec::::new_general(); + let bit_vec = BitVec::::new_general(); let serialized = bit_vec.serialize_json(); - let unserialized: BitVec = BitVec::::deserialize_json(&serialized[..]).unwrap(); + let unserialized = BitVec::::deserialize_json(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); let bools = vec![true, false, true, true]; - let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); let serialized = bit_vec.serialize_json(); let unserialized = BitVec::::deserialize_json(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); @@ -3924,11 +3936,11 @@ mod tests { #[instantiate_tests(>)] mod vec32 {} - #[cfg(feature = "smallvec")] + #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] #[instantiate_tests(>)] mod smallvec32x8 {} - #[cfg(feature = "smallvec")] + #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] #[instantiate_tests(>)] mod smallvec64x8 {} From 26144665d86bb9a7d0e049a4033eeb63f1cbe0b6 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 6 Mar 2026 10:43:07 +0100 Subject: [PATCH 05/24] Fix workspace code --- fuzz/Cargo.toml | 1 + fuzz/fuzz_targets/bitvec_ops.rs | 7 +- matrix/Cargo.toml | 2 +- set/Cargo.toml | 6 +- set/benches/bench.rs | 2 +- set/src/lib.rs | 124 ++++++++++++++++---------------- vec/Cargo.toml | 2 +- vec/src/lib.rs | 24 +++++-- 8 files changed, 93 insertions(+), 75 deletions(-) diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index f733eba..336a9ea 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -11,6 +11,7 @@ cargo-fuzz = true [features] afl_fuzz = ["afl"] honggfuzz_fuzz = ["honggfuzz"] +nanoserde = ["bit-vec/nanoserde"] [dependencies] honggfuzz = { version = "0.5", optional = true } diff --git a/fuzz/fuzz_targets/bitvec_ops.rs b/fuzz/fuzz_targets/bitvec_ops.rs index ddde46f..844cc20 100644 --- a/fuzz/fuzz_targets/bitvec_ops.rs +++ b/fuzz/fuzz_targets/bitvec_ops.rs @@ -1,5 +1,6 @@ //! Simple fuzzer testing all available `SmallVec` operations -use bit_vec::{BitVec, BitBlockOrStore}; +use bit_vec::{BitBlockOrStore, BitVec}; +#[cfg(not(feature = "nanoserde"))] use smallvec::SmallVec; // There's no point growing too much, so try not to grow @@ -39,8 +40,7 @@ fn do_test(data: &[u8]) -> BitVec { 2 => { v = BitVec::from_bytes_general(&v.to_bytes()[..]); } - 3 => { - } + 3 => {} 4 => { if v.len() < CAP_GROWTH { v.push(next_u8!(bytes) < 128) @@ -122,6 +122,7 @@ fn do_test_all(data: &[u8]) { do_test::(data); do_test::(data); do_test::(data); + #[cfg(not(feature = "nanoserde"))] do_test::>(data); do_test::>(data); } diff --git a/matrix/Cargo.toml b/matrix/Cargo.toml index f12c8c4..d1f6883 100644 --- a/matrix/Cargo.toml +++ b/matrix/Cargo.toml @@ -17,7 +17,7 @@ name = "bit_matrix" [dependencies] serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } miniserde = { version = "0.1", optional = true } -bit-vec = { version = "0.8", default-features = false } +bit-vec = { path = "../vec/", default-features = false } [dev-dependencies] serde_json = "1.0" diff --git a/set/Cargo.toml b/set/Cargo.toml index b00f574..fba430b 100644 --- a/set/Cargo.toml +++ b/set/Cargo.toml @@ -16,14 +16,14 @@ rust-version = "1.63" borsh = { version = "1.5", default-features = false, features = ["derive"], optional = true } serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } miniserde = { version = "0.1", optional = true } -nanoserde = { version = "0.1", optional = true } +nanoserde = { git = "https://github.com/not-fl3/nanoserde.git", optional = true } [dependencies.bit-vec] -version = "0.8.0" +path = "../vec/" default-features = false [dev-dependencies] -rand = "0.9" +rand = "0.10" serde_json = "1.0" [features] diff --git a/set/benches/bench.rs b/set/benches/bench.rs index 44e5df4..b7152b5 100644 --- a/set/benches/bench.rs +++ b/set/benches/bench.rs @@ -15,7 +15,7 @@ extern crate test; use bit_set::BitSet; use bit_vec::BitVec; -use rand::RngCore; +use rand::Rng; use test::{black_box, Bencher}; const BENCH_BITS: usize = 1 << 14; diff --git a/set/src/lib.rs b/set/src/lib.rs index abd7dec..d388302 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -57,6 +57,7 @@ #[cfg(any(test, feature = "std"))] extern crate std; +use bit_vec::{BitBlockOrStore, BitStore}; use bit_vec::{BitBlock, BitVec, Blocks}; use core::cmp; use core::cmp::Ordering; @@ -71,10 +72,11 @@ use alloc::vec::Vec; #[cfg(feature = "nanoserde")] use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; -type MatchWords<'a, B> = Chain>, Skip>>>>; +type Block = ::Block; +type MatchWords<'a, B: BitBlockOrStore> = Chain>, Skip>>>>>; /// Computes how many blocks are needed to store that many bits -fn blocks_for_bits(bits: usize) -> usize { +fn blocks_for_bits(bits: usize) -> usize { // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we // reserve enough. But if we want exactly a multiple of 32, this will actually allocate // one too many. So we need to check if that's the case. We can do that by computing if @@ -83,17 +85,17 @@ fn blocks_for_bits(bits: usize) -> usize { // // Note that we can technically avoid this branch with the expression // `(nbits + BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. - if bits % B::bits() == 0 { - bits / B::bits() + if bits % B::BITS == 0 { + bits / B::BITS } else { - bits / B::bits() + 1 + bits / B::BITS + 1 } } #[allow(clippy::iter_skip_zero)] // Take two BitVec's, and return iterators of their words, where the shorter one // has been padded with 0's -fn match_words<'a, 'b, B: BitBlock>( +fn match_words<'a, 'b, B: BitBlockOrStore>( a: &'a BitVec, b: &'b BitVec, ) -> (MatchWords<'a, B>, MatchWords<'b, B>) { @@ -105,19 +107,19 @@ fn match_words<'a, 'b, B: BitBlock>( ( a.blocks() .enumerate() - .chain(iter::repeat(B::zero()).enumerate().take(b_len).skip(a_len)), + .chain(iter::repeat(B::ZERO).enumerate().take(b_len).skip(a_len)), b.blocks() .enumerate() - .chain(iter::repeat(B::zero()).enumerate().take(0).skip(0)), + .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), ) } else { ( a.blocks() .enumerate() - .chain(iter::repeat(B::zero()).enumerate().take(0).skip(0)), + .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), b.blocks() .enumerate() - .chain(iter::repeat(B::zero()).enumerate().take(a_len).skip(b_len)), + .chain(iter::repeat(B::ZERO).enumerate().take(a_len).skip(b_len)), ) } } @@ -135,11 +137,11 @@ fn match_words<'a, 'b, B: BitBlock>( feature = "nanoserde", derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) )] -pub struct BitSet { +pub struct BitSet { bit_vec: BitVec, } -impl Clone for BitSet { +impl Clone for BitSet { fn clone(&self) -> Self { BitSet { bit_vec: self.bit_vec.clone(), @@ -151,7 +153,7 @@ impl Clone for BitSet { } } -impl Default for BitSet { +impl Default for BitSet { #[inline] fn default() -> Self { BitSet { @@ -160,7 +162,7 @@ impl Default for BitSet { } } -impl FromIterator for BitSet { +impl FromIterator for BitSet { fn from_iter>(iter: I) -> Self { let mut ret = Self::default(); ret.extend(iter); @@ -168,7 +170,7 @@ impl FromIterator for BitSet { } } -impl Extend for BitSet { +impl Extend for BitSet { #[inline] fn extend>(&mut self, iter: I) { for i in iter { @@ -177,28 +179,28 @@ impl Extend for BitSet { } } -impl PartialOrd for BitSet { +impl PartialOrd for BitSet { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for BitSet { +impl Ord for BitSet { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other) } } -impl PartialEq for BitSet { +impl PartialEq for BitSet { #[inline] fn eq(&self, other: &Self) -> bool { self.iter().eq(other) } } -impl Eq for BitSet {} +impl Eq for BitSet {} impl BitSet { /// Creates a new empty `BitSet`. @@ -260,7 +262,7 @@ impl BitSet { } } -impl BitSet { +impl BitSet { /// Returns the capacity in bits for this bit vector. Inserting any /// element less than this amount will not trigger a resizing. /// @@ -391,7 +393,7 @@ impl BitSet { #[inline] fn other_op(&mut self, other: &Self, mut f: F) where - F: FnMut(B, B) -> B, + F: FnMut(Block, Block) -> Block, { // Unwrap BitVecs let self_bit_vec = &mut self.bit_vec; @@ -416,7 +418,7 @@ impl BitSet { let old = self_bit_vec.storage()[i]; let new = f(old, w); unsafe { - self_bit_vec.storage_mut()[i] = new; + self_bit_vec.storage_mut().slice_mut()[i] = new; } } } @@ -450,13 +452,13 @@ impl BitSet { .storage() .iter() .rev() - .take_while(|&&n| n == B::zero()) + .take_while(|&&n| n == B::ZERO) .count(); // Truncate away all empty trailing blocks, then shrink_to_fit let trunc_len = old_len - n; unsafe { bit_vec.storage_mut().truncate(trunc_len); - bit_vec.set_len(trunc_len * B::bits()); + bit_vec.set_len(trunc_len * B::BITS); } bit_vec.shrink_to_fit(); } @@ -850,7 +852,7 @@ impl BitSet { // Check that `self` intersect `other` is self self_bit_vec.blocks().zip(other_bit_vec.blocks()).all(|(w1, w2)| w1 & w2 == w1) && // Make sure if `self` has any more blocks than `other`, they're all 0 - self_bit_vec.blocks().skip(other_blocks).all(|w| w == B::zero()) + self_bit_vec.blocks().skip(other_blocks).all(|w| w == B::ZERO) } /// Returns `true` if the set is a superset of another. @@ -894,7 +896,7 @@ impl BitSet { } } -impl fmt::Debug for BitSet { +impl fmt::Debug for BitSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("BitSet") .field("bit_vec", &self.bit_vec) @@ -902,13 +904,13 @@ impl fmt::Debug for BitSet { } } -impl fmt::Display for BitSet { +impl fmt::Display for BitSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_set().entries(self).finish() } } -impl hash::Hash for BitSet { +impl hash::Hash for BitSet { fn hash(&self, state: &mut H) { for pos in self { pos.hash(state); @@ -917,18 +919,18 @@ impl hash::Hash for BitSet { } #[derive(Clone)] -struct BlockIter { - head: B, +struct BlockIter { + head: Block, head_offset: usize, tail: T, } -impl BlockIter +impl BlockIter where - T: Iterator, + T: Iterator>, { - fn from_blocks(mut blocks: T) -> BlockIter { - let h = blocks.next().unwrap_or_else(B::zero); + fn from_blocks(mut blocks: T) -> Self { + let h = blocks.next().unwrap_or(B::ZERO); BlockIter { tail: blocks, head: h, @@ -939,19 +941,19 @@ where /// An iterator combining two `BitSet` iterators. #[derive(Clone)] -struct TwoBitPositions<'a, B: 'a> { +struct TwoBitPositions<'a, B: 'a + BitBlockOrStore> { set: Blocks<'a, B>, other: Blocks<'a, B>, - merge: fn(B, B) -> B, + merge: fn(Block, Block) -> Block, } /// An iterator for `BitSet`. #[derive(Clone)] -pub struct Iter<'a, B: 'a>(BlockIter, B>); +pub struct Iter<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); #[derive(Clone)] -pub struct Union<'a, B: 'a>(BlockIter, B>); +pub struct Union<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); #[derive(Clone)] -pub struct Intersection<'a, B: 'a> { +pub struct Intersection<'a, B: 'a + BitBlockOrStore> { iter: BlockIter, B>, // as an optimization, we compute the maximum possible // number of elements in the intersection, and count it @@ -960,34 +962,34 @@ pub struct Intersection<'a, B: 'a> { n: usize, } #[derive(Clone)] -pub struct Difference<'a, B: 'a>(BlockIter, B>); +pub struct Difference<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); #[derive(Clone)] -pub struct SymmetricDifference<'a, B: 'a>(BlockIter, B>); +pub struct SymmetricDifference<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); -impl Iterator for BlockIter +impl Iterator for BlockIter where - T: Iterator, + T: Iterator>, { type Item = usize; - fn next(&mut self) -> Option { - while self.head == B::zero() { + fn next(&mut self) -> Option { + while self.head == B::ZERO { match self.tail.next() { Some(w) => self.head = w, None => return None, } - self.head_offset += B::bits(); + self.head_offset += B::BITS; } // from the current block, isolate the // LSB and subtract 1, producing k: // a block with a number of set bits // equal to the index of the LSB - let k = (self.head & (!self.head + B::one())) - B::one(); + let k = (self.head & (!self.head + B::ONE)) - B::ONE; // update block, removing the LSB - self.head = self.head & (self.head - B::one()); + self.head = self.head & (self.head - B::ONE); // return offset + (index of LSB) - Some(self.head_offset + (B::count_ones(k))) + Some(self.head_offset + (::Block::count_ones(k))) } fn count(self) -> usize { @@ -997,20 +999,20 @@ where #[inline] fn size_hint(&self) -> (usize, Option) { match self.tail.size_hint() { - (_, Some(h)) => (0, Some((1 + h) * B::bits())), + (_, Some(h)) => (0, Some((1 + h) * B::BITS)), _ => (0, None), } } } -impl Iterator for TwoBitPositions<'_, B> { - type Item = B; +impl Iterator for TwoBitPositions<'_, B> { + type Item = Block; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { match (self.set.next(), self.other.next()) { (Some(a), Some(b)) => Some((self.merge)(a, b)), - (Some(a), None) => Some((self.merge)(a, B::zero())), - (None, Some(b)) => Some((self.merge)(B::zero(), b)), + (Some(a), None) => Some((self.merge)(a, B::ZERO)), + (None, Some(b)) => Some((self.merge)(B::ZERO, b)), _ => None, } } @@ -1030,7 +1032,7 @@ impl Iterator for TwoBitPositions<'_, B> { } } -impl Iterator for Iter<'_, B> { +impl Iterator for Iter<'_, B> { type Item = usize; #[inline] @@ -1047,7 +1049,7 @@ impl Iterator for Iter<'_, B> { } } -impl Iterator for Union<'_, B> { +impl Iterator for Union<'_, B> { type Item = usize; #[inline] @@ -1064,7 +1066,7 @@ impl Iterator for Union<'_, B> { } } -impl Iterator for Intersection<'_, B> { +impl Iterator for Intersection<'_, B> { type Item = usize; #[inline] @@ -1091,7 +1093,7 @@ impl Iterator for Intersection<'_, B> { } } -impl Iterator for Difference<'_, B> { +impl Iterator for Difference<'_, B> { type Item = usize; #[inline] @@ -1108,7 +1110,7 @@ impl Iterator for Difference<'_, B> { } } -impl Iterator for SymmetricDifference<'_, B> { +impl Iterator for SymmetricDifference<'_, B> { type Item = usize; #[inline] @@ -1125,7 +1127,7 @@ impl Iterator for SymmetricDifference<'_, B> { } } -impl<'a, B: BitBlock> IntoIterator for &'a BitSet { +impl<'a, B: BitBlockOrStore> IntoIterator for &'a BitSet { type Item = usize; type IntoIter = Iter<'a, B>; diff --git a/vec/Cargo.toml b/vec/Cargo.toml index e9863c0..84ca563 100644 --- a/vec/Cargo.toml +++ b/vec/Cargo.toml @@ -16,7 +16,7 @@ rust-version = "1.82" borsh = { version = "1.5.7", default-features = false, features = ["derive"], optional = true } serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } miniserde = { version = "0.1", optional = true } -nanoserde = { version = "0.2", optional = true } +nanoserde = { git = "https://github.com/not-fl3/nanoserde.git", version = "0.2.2", optional = true } smallvec = { version = "1.15", optional = true } [dev-dependencies] diff --git a/vec/src/lib.rs b/vec/src/lib.rs index a77b47b..2806f37 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -175,10 +175,14 @@ pub trait BitBlock: } pub trait BitBlockOrStore { - #[cfg(not(feature = "nanoserde"))] - type Store: BitStore; - #[cfg(feature = "nanoserde")] + #[cfg(all(feature = "nanoserde", not(feature = "serde")))] type Store: BitStore + DeBin + DeJson + DeRon + SerBin + SerJson + SerRon; + #[cfg(all(not(feature = "nanoserde"), feature = "serde"))] + type Store: BitStore + serde::Serialize + for<'a> serde::Deserialize<'a>; + #[cfg(all(feature = "nanoserde", feature = "serde"))] + type Store: BitStore + DeBin + DeJson + DeRon + SerBin + SerJson + SerRon + serde::Serialize + for<'a> serde::Deserialize<'a>; + #[cfg(all(not(feature = "nanoserde"), not(feature = "serde")))] + type Store: BitStore; const BITS: usize = ::Block::BITS_; const BYTES: usize = ::Block::BYTES_; @@ -367,16 +371,26 @@ where } } -#[cfg(not(feature = "nanoserde"))] +#[cfg(all(not(feature = "serde"), not(feature = "nanoserde")))] impl BitBlockOrStore for Vec { type Store = Self; } -#[cfg(feature = "nanoserde")] +#[cfg(all(feature = "serde", not(feature = "nanoserde")))] +impl serde::Deserialize<'a> + serde::Serialize> BitBlockOrStore for Vec { + type Store = Self; +} + +#[cfg(all(not(feature = "serde"), feature = "nanoserde"))] impl BitBlockOrStore for Vec { type Store = Self; } +#[cfg(all(feature = "serde", feature = "nanoserde"))] +impl serde::Deserialize<'a> + serde::Serialize> BitBlockOrStore for Vec { + type Store = Self; +} + #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] impl BitBlockOrStore for smallvec::SmallVec where From f2314f97286fa1e639dd0f75f856448e67e2acf4 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 6 Mar 2026 11:07:26 +0100 Subject: [PATCH 06/24] Formatting --- matrix/src/block.rs | 2 +- matrix/src/matrix.rs | 34 +++++++++++++-------------- matrix/src/row.rs | 2 +- matrix/src/submatrix.rs | 32 +++++++++++-------------- set/src/lib.rs | 5 ++-- vec/src/lib.rs | 52 ++++++++++++++++++++++++++++++----------- 6 files changed, 73 insertions(+), 54 deletions(-) diff --git a/matrix/src/block.rs b/matrix/src/block.rs index 0bdea39..3b40e56 100644 --- a/matrix/src/block.rs +++ b/matrix/src/block.rs @@ -1,5 +1,5 @@ //! Defines a building block for the bit slice. -//! +//! //! Bits are stored in blocks. When the last block //! is not full with bits, we waste some space. diff --git a/matrix/src/matrix.rs b/matrix/src/matrix.rs index 28163c6..f367111 100644 --- a/matrix/src/matrix.rs +++ b/matrix/src/matrix.rs @@ -1,24 +1,24 @@ //! Matrix of bits. -//! +//! //! # Examples -//! +//! //! Gets a mutable reference to the square bit matrix within this //! rectangular matrix, then performs a transitive closure. -//! +//! //! ```rust //! use bit_matrix::BitMatrix; -//! +//! //! let mut matrix = BitMatrix::new(7, 5); //! matrix.set(1, 2, true); //! matrix.set(2, 3, true); //! matrix.set(3, 4, true); -//! +//! //! { //! let mut sub_matrix = matrix.sub_matrix_mut(1 .. 6); //! sub_matrix.transitive_closure(); //! } //! assert!(matrix[(1, 4)]); -//! +//! //! matrix.reflexive_closure(); //! assert!(matrix[(0, 0)]); //! assert!(matrix[(1, 1)]); @@ -131,7 +131,7 @@ impl BitMatrix { pub fn sub_matrix_mut>(&mut self, range: R) -> BitSubMatrixMut<'_> { let row_size = self.row_size(); // Safety: - // + // unsafe { BitSubMatrixMut { slice: &mut self.bit_vec.storage_mut()[( @@ -181,25 +181,25 @@ impl BitMatrix { /// represented by this square bit matrix. /// /// Modifies this matrix in place using Warshall's algorithm. - /// + /// /// After this operation, the matrix will describe a transitive /// relation. This means that, for any indices `a`, `b`, `c`, /// if `M[(a, b)]` and `M[(b, c)]`, then `M[(a, c)]`. - /// + /// /// # Complexity - /// + /// /// The time complexity is **O(n^3)**, where `n` is the number /// of columns and rows. - /// + /// /// # Panics - /// + /// /// The matrix must be square for this operation to succeed. pub fn transitive_closure(&mut self) { Into::::into(self).transitive_closure(); } /// Determines whether the number of rows equals the number of columns. - /// + /// /// This means the matrix is square. pub fn is_square(&self) -> bool { self.num_rows() == self.row_bits @@ -212,7 +212,7 @@ impl BitMatrix { /// Computes the reflexive closure of the binary relation represented by /// this bit matrix. The matrix can be rectangular. - /// + /// /// The reflexive closure means that for every `x`` that will be within bounds, /// `M[(x, x)]` is true. /// @@ -248,7 +248,7 @@ impl IndexMut for BitMatrix { } /// Returns `true` if a bit is enabled in the matrix, or `false` otherwise. -/// +/// /// The first index in the tuple is row number, and the second is column /// number. impl Index<(usize, usize)> for BitMatrix { @@ -267,9 +267,7 @@ impl Index<(usize, usize)> for BitMatrix { impl<'a> From<&'a mut BitMatrix> for BitSubMatrixMut<'a> { fn from(value: &'a mut BitMatrix) -> Self { - unsafe { - BitSubMatrixMut::new(value.bit_vec.storage_mut(), value.row_bits) - } + unsafe { BitSubMatrixMut::new(value.bit_vec.storage_mut(), value.row_bits) } } } diff --git a/matrix/src/row.rs b/matrix/src/row.rs index 1b7d10a..d04c956 100644 --- a/matrix/src/row.rs +++ b/matrix/src/row.rs @@ -27,7 +27,7 @@ impl BitSlice { /// Iterates over bits. #[inline] pub fn iter_bits(&self, len: usize) -> impl Iterator + '_ { - (0 .. len).map(|i| self[i]) + (0..len).map(|i| self[i]) } /// Iterates over the slice's blocks. diff --git a/matrix/src/submatrix.rs b/matrix/src/submatrix.rs index 9469387..192bad5 100644 --- a/matrix/src/submatrix.rs +++ b/matrix/src/submatrix.rs @@ -25,16 +25,13 @@ pub struct BitSubMatrixMut<'a> { impl<'a> BitSubMatrix<'a> { /// Returns a new BitSubMatrix. pub fn new(slice: &[Block], row_bits: usize) -> BitSubMatrix<'_> { - BitSubMatrix { - slice, - row_bits, - } + BitSubMatrix { slice, row_bits } } /// Forms a BitSubMatrix from a pointer and dimensions. - /// + /// /// # Safety - /// + /// /// Can construct an ill-formed value, thus the function is marked as /// unsafe. #[inline] @@ -58,16 +55,13 @@ impl<'a> BitSubMatrix<'a> { impl<'a> BitSubMatrixMut<'a> { /// Returns a new `BitSubMatrixMut`. pub fn new(slice: &mut [Block], row_bits: usize) -> BitSubMatrixMut<'_> { - BitSubMatrixMut { - slice, - row_bits, - } + BitSubMatrixMut { slice, row_bits } } /// Forms a `BitSubMatrix` from a pointer and dimensions. - /// + /// /// # Safety - /// + /// /// Can construct an ill-formed value, thus the function is unsafe. #[inline] pub unsafe fn from_raw_parts(ptr: *mut Block, rows: usize, row_bits: usize) -> Self { @@ -152,18 +146,18 @@ impl<'a> BitSubMatrixMut<'a> { /// represented by this square bit matrix. /// /// Modifies this matrix in place using Warshall's algorithm. - /// + /// /// After this operation, the matrix will describe a transitive /// relation. This means that, for any indices `a`, `b`, `c`, /// if `M[(a, b)]` and `M[(b, c)]`, then `M[(a, c)]`. - /// + /// /// # Complexity - /// + /// /// The time complexity is **O(n^3)**, where `n` is the number /// of columns and rows. - /// + /// /// # Panics - /// + /// /// The matrix must be square for this operation to succeed. pub fn transitive_closure(&mut self) { assert!(self.is_square()); @@ -179,7 +173,7 @@ impl<'a> BitSubMatrixMut<'a> { } /// Determines whether the number of rows equals the number of columns. - /// + /// /// This means the matrix is square. fn is_square(&self) -> bool { self.num_rows() == self.row_bits @@ -187,7 +181,7 @@ impl<'a> BitSubMatrixMut<'a> { /// Computes the reflexive closure of the binary relation represented by /// this bit matrix. The matrix can be rectangular. - /// + /// /// The reflexive closure means that for every `x`` that will be within bounds, /// `M[(x, x)]` is true. /// diff --git a/set/src/lib.rs b/set/src/lib.rs index d388302..8c6eefe 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -57,8 +57,8 @@ #[cfg(any(test, feature = "std"))] extern crate std; -use bit_vec::{BitBlockOrStore, BitStore}; use bit_vec::{BitBlock, BitVec, Blocks}; +use bit_vec::{BitBlockOrStore, BitStore}; use core::cmp; use core::cmp::Ordering; use core::fmt; @@ -73,7 +73,8 @@ use alloc::vec::Vec; use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; type Block = ::Block; -type MatchWords<'a, B: BitBlockOrStore> = Chain>, Skip>>>>>; +type MatchWords<'a, B: BitBlockOrStore> = + Chain>, Skip>>>>>; /// Computes how many blocks are needed to store that many bits fn blocks_for_bits(bits: usize) -> usize { diff --git a/vec/src/lib.rs b/vec/src/lib.rs index 2806f37..371b0b4 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -92,7 +92,6 @@ #![warn(clippy::single_match)] #![warn(clippy::missing_safety_doc)] #![allow(type_alias_bounds)] - #![cfg_attr(feature = "allocator_api", feature(allocator_api))] #[cfg(any(test, feature = "std"))] @@ -105,14 +104,14 @@ use std::string::String; #[cfg(feature = "std")] use std::vec::Vec; -#[cfg(feature = "serde")] -extern crate serde; #[cfg(feature = "borsh")] extern crate borsh; #[cfg(feature = "miniserde")] extern crate miniserde; #[cfg(feature = "nanoserde")] extern crate nanoserde; +#[cfg(feature = "serde")] +extern crate serde; #[cfg(feature = "nanoserde")] use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; @@ -175,12 +174,20 @@ pub trait BitBlock: } pub trait BitBlockOrStore { - #[cfg(all(feature = "nanoserde", not(feature = "serde")))] + #[cfg(all(feature = "nanoserde", not(feature = "serde")))] type Store: BitStore + DeBin + DeJson + DeRon + SerBin + SerJson + SerRon; - #[cfg(all(not(feature = "nanoserde"), feature = "serde"))] + #[cfg(all(not(feature = "nanoserde"), feature = "serde"))] type Store: BitStore + serde::Serialize + for<'a> serde::Deserialize<'a>; #[cfg(all(feature = "nanoserde", feature = "serde"))] - type Store: BitStore + DeBin + DeJson + DeRon + SerBin + SerJson + SerRon + serde::Serialize + for<'a> serde::Deserialize<'a>; + type Store: BitStore + + DeBin + + DeJson + + DeRon + + SerBin + + SerJson + + SerRon + + serde::Serialize + + for<'a> serde::Deserialize<'a>; #[cfg(all(not(feature = "nanoserde"), not(feature = "serde")))] type Store: BitStore; @@ -387,7 +394,18 @@ impl BitBlockO } #[cfg(all(feature = "serde", feature = "nanoserde"))] -impl serde::Deserialize<'a> + serde::Serialize> BitBlockOrStore for Vec { +impl< + T: BitBlock + + DeBin + + DeJson + + DeRon + + SerBin + + SerJson + + SerRon + + for<'a> serde::Deserialize<'a> + + serde::Serialize, + > BitBlockOrStore for Vec +{ type Store = Self; } @@ -549,10 +567,7 @@ type B = u32; /// println!("{:?}", bv); /// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); /// ``` -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize) -)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr( feature = "borsh", derive(borsh::BorshDeserialize, borsh::BorshSerialize) @@ -3567,7 +3582,10 @@ mod tests { #[cfg(feature = "serde")] #[test] - fn test_serialization() where S::Store: serde::Serialize + for<'a> serde::Deserialize<'a> { + fn test_serialization() + where + S::Store: serde::Serialize + for<'a> serde::Deserialize<'a>, + { let bit_vec: BitVec = BitVec::::new_general(); let serialized = serde_json::to_string(&bit_vec).unwrap(); let unserialized: BitVec = serde_json::from_str(&serialized[..]).unwrap(); @@ -3597,7 +3615,15 @@ mod tests { #[cfg(feature = "nanoserde")] #[test] - fn test_nanoserde_json_serialization() { + fn test_nanoserde_json_serialization< + S: BitBlockOrStore + + nanoserde::DeBin + + nanoserde::DeJson + + nanoserde::DeRon + + nanoserde::SerBin + + nanoserde::SerJson + + nanoserde::SerRon, + >() { use nanoserde::{DeJson, SerJson}; let bit_vec = BitVec::::new_general(); From 6399e27f76a1ddc0ddac18c7b8e9cba918713c4a Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 6 Mar 2026 11:10:14 +0100 Subject: [PATCH 07/24] Fix --- Cargo.toml | 3 +++ set/src/lib.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index c0c462f..fd78975 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,9 @@ members = [ "vec", "set", "matrix", +] + +exclude = [ "fuzz", ] diff --git a/set/src/lib.rs b/set/src/lib.rs index 8c6eefe..9652931 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -72,7 +72,9 @@ use alloc::vec::Vec; #[cfg(feature = "nanoserde")] use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; +#[allow(type_alias_bounds)] type Block = ::Block; +#[allow(type_alias_bounds)] type MatchWords<'a, B: BitBlockOrStore> = Chain>, Skip>>>>>; From b162700412d7863ced1fa27482bb49ded93852d1 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 6 Mar 2026 12:40:46 +0100 Subject: [PATCH 08/24] Implement bound combinations with macros --- .github/workflows/rust.yml | 1 + vec/src/lib.rs | 135 +++++++++++++++++++++++-------------- 2 files changed, 84 insertions(+), 52 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d1c4fde..a26b671 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -67,6 +67,7 @@ jobs: - run: cargo test --features nanoserde - run: cargo test --features miniserde - run: cargo test --features borsh + - run: cargo test --features borsh,serde,nanoserde clippy: runs-on: ubuntu-latest diff --git a/vec/src/lib.rs b/vec/src/lib.rs index 371b0b4..f93493e 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -173,23 +173,44 @@ pub trait BitBlock: const ONE_: Self; } +macro_rules! bound_combination { + ( + type $T:ident: [$($B:tt)*]; + $cfg0:tt => [$($Bounds0:tt)*]; + $( + $cfg:tt => [$($Bounds:tt)*]; + )* + ) => { + #[cfg(not(feature = $cfg0))] + bound_combination!( + type $T: [$($B)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + #[cfg(feature = $cfg0)] + bound_combination!( + type $T: [$($B)* + $($Bounds0)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + }; + ( + type $T:ident: [$($B:tt)*]; + ) => { + type $T: $($B)*; + } +} + pub trait BitBlockOrStore { - #[cfg(all(feature = "nanoserde", not(feature = "serde")))] - type Store: BitStore + DeBin + DeJson + DeRon + SerBin + SerJson + SerRon; - #[cfg(all(not(feature = "nanoserde"), feature = "serde"))] - type Store: BitStore + serde::Serialize + for<'a> serde::Deserialize<'a>; - #[cfg(all(feature = "nanoserde", feature = "serde"))] - type Store: BitStore - + DeBin - + DeJson - + DeRon - + SerBin - + SerJson - + SerRon - + serde::Serialize - + for<'a> serde::Deserialize<'a>; - #[cfg(all(not(feature = "nanoserde"), not(feature = "serde")))] - type Store: BitStore; + bound_combination!( + type Store: [BitStore]; + "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; + "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; + "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; + "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; + ); const BITS: usize = ::Block::BITS_; const BYTES: usize = ::Block::BYTES_; @@ -197,6 +218,47 @@ pub trait BitBlockOrStore { const ZERO: ::Block = ::Block::ZERO_; } + +macro_rules! impl_combination { + ( + type $T:ty: [$($B:tt)*]; + $cfg0:tt => [$($Bounds0:tt)*]; + $( + $cfg:tt => [$($Bounds:tt)*]; + )* + ) => { + #[cfg(not(feature = $cfg0))] + impl_combination!( + type $T: [$($B)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + #[cfg(feature = $cfg0)] + impl_combination!( + type $T: [$($B)* + $($Bounds0)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + }; + ( + type $T:ty: [$($B:tt)*]; + ) => { + impl BitBlockOrStore for Vec { + type Store = Self; + } + } +} + +impl_combination!( + type Vec: [BitBlock]; + "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; + "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; + "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; + "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; +); + #[allow(clippy::len_without_is_empty)] pub trait BitStore: Clone { type Block: BitBlock; @@ -378,37 +440,6 @@ where } } -#[cfg(all(not(feature = "serde"), not(feature = "nanoserde")))] -impl BitBlockOrStore for Vec { - type Store = Self; -} - -#[cfg(all(feature = "serde", not(feature = "nanoserde")))] -impl serde::Deserialize<'a> + serde::Serialize> BitBlockOrStore for Vec { - type Store = Self; -} - -#[cfg(all(not(feature = "serde"), feature = "nanoserde"))] -impl BitBlockOrStore for Vec { - type Store = Self; -} - -#[cfg(all(feature = "serde", feature = "nanoserde"))] -impl< - T: BitBlock - + DeBin - + DeJson - + DeRon - + SerBin - + SerJson - + SerRon - + for<'a> serde::Deserialize<'a> - + serde::Serialize, - > BitBlockOrStore for Vec -{ - type Store = Self; -} - #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] impl BitBlockOrStore for smallvec::SmallVec where @@ -3600,10 +3631,10 @@ mod tests { #[cfg(feature = "miniserde")] #[test] - fn test_miniserde_serialization() { - let bit_vec: BitVec = BitVec::::new_general(); + fn test_miniserde_serialization() { + let bit_vec = BitVec::::new_general(); let serialized = miniserde::json::to_string(&bit_vec); - let unserialized: BitVec = miniserde::json::from_str(&serialized[..]).unwrap(); + let unserialized: BitVec = miniserde::json::from_str(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); let bools = vec![true, false, true, true]; @@ -3641,9 +3672,9 @@ mod tests { #[cfg(feature = "borsh")] #[test] fn test_borsh_serialization() { - let bit_vec: BitVec = BitVec::::new_general(); + let bit_vec = BitVec::::new_general(); let serialized = borsh::to_vec(&bit_vec).unwrap(); - let unserialized: BitVec = borsh::from_slice(&serialized[..]).unwrap(); + let unserialized: BitVec = borsh::from_slice(&serialized[..]).unwrap(); assert_eq!(bit_vec, unserialized); let bools = vec![true, false, true, true]; From a7ada9796756820de25c147be366aaba8e73d6cc Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 6 Mar 2026 13:01:45 +0100 Subject: [PATCH 09/24] Update MSRV to 1.85; formatting --- .github/workflows/rust.yml | 2 +- set/Cargo.toml | 2 +- vec/Cargo.toml | 2 +- vec/src/lib.rs | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a26b671..26acdf4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -54,7 +54,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [1.82.0, 1.83.0] + rust: [1.85.0, 1.86.0] timeout-minutes: 45 steps: - uses: actions/checkout@v5 diff --git a/set/Cargo.toml b/set/Cargo.toml index fba430b..438d501 100644 --- a/set/Cargo.toml +++ b/set/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://docs.rs/bit-set/" keywords = ["data-structures", "bitset"] readme = "README.md" edition = "2021" -rust-version = "1.63" +rust-version = "1.85" [dependencies] borsh = { version = "1.5", default-features = false, features = ["derive"], optional = true } diff --git a/vec/Cargo.toml b/vec/Cargo.toml index 84ca563..f0e3b76 100644 --- a/vec/Cargo.toml +++ b/vec/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://docs.rs/bit-vec/" keywords = ["data-structures", "bitvec", "bitmask", "bitmap", "bit"] readme = "README.md" edition = "2021" -rust-version = "1.82" +rust-version = "1.85" [dependencies] borsh = { version = "1.5.7", default-features = false, features = ["derive"], optional = true } diff --git a/vec/src/lib.rs b/vec/src/lib.rs index f93493e..3ec931d 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -218,7 +218,6 @@ pub trait BitBlockOrStore { const ZERO: ::Block = ::Block::ZERO_; } - macro_rules! impl_combination { ( type $T:ty: [$($B:tt)*]; @@ -3631,7 +3630,9 @@ mod tests { #[cfg(feature = "miniserde")] #[test] - fn test_miniserde_serialization() { + fn test_miniserde_serialization< + S: BitBlockOrStore + miniserde::Serialize + miniserde::Deserialize, + >() { let bit_vec = BitVec::::new_general(); let serialized = miniserde::json::to_string(&bit_vec); let unserialized: BitVec = miniserde::json::from_str(&serialized[..]).unwrap(); From fabbc682dc46f65cda06df50f5c9e868bad85c15 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Tue, 10 Mar 2026 15:45:39 +0100 Subject: [PATCH 10/24] Update for recent changes in BitVec --- fuzz/Cargo.toml | 4 ++- matrix/src/matrix.rs | 6 +--- set/Cargo.toml | 3 ++ set/src/lib.rs | 81 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 87 insertions(+), 7 deletions(-) diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 336a9ea..2bac526 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bit-vec-fuzz" +name = "bit-fuzz" version = "0.1.0" authors = ["Dawid Ciężarkiewicz ", "Peter Blackson "] edition = "2021" @@ -17,6 +17,8 @@ nanoserde = ["bit-vec/nanoserde"] honggfuzz = { version = "0.5", optional = true } afl = { version = "0.17", optional = true } bit-vec = { path = "../vec/", features = ["smallvec"] } +bit-set = { path = "../set/", features = ["smallvec"] } +bit-matrix = { path = "../matrix/" } smallvec = "1.15" [[bin]] diff --git a/matrix/src/matrix.rs b/matrix/src/matrix.rs index f367111..0ff15e0 100644 --- a/matrix/src/matrix.rs +++ b/matrix/src/matrix.rs @@ -94,11 +94,7 @@ impl BitMatrix { /// Sets the value of all bits. #[inline] pub fn set_all(&mut self, enabled: bool) { - if enabled { - self.bit_vec.set_all(); - } else { - self.bit_vec.clear(); - } + self.bit_vec.fill(enabled); } /// Grows the matrix in-place, adding `num_rows` rows filled with `value`. diff --git a/set/Cargo.toml b/set/Cargo.toml index 438d501..32e0e5c 100644 --- a/set/Cargo.toml +++ b/set/Cargo.toml @@ -17,6 +17,7 @@ borsh = { version = "1.5", default-features = false, features = ["derive"], opti serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } miniserde = { version = "0.1", optional = true } nanoserde = { git = "https://github.com/not-fl3/nanoserde.git", optional = true } +smallvec = { version = "1.15", optional = true } [dependencies.bit-vec] path = "../vec/" @@ -30,6 +31,8 @@ serde_json = "1.0" default = ["std"] std = ["bit-vec/std"] +smallvec = ["dep:smallvec", "bit-vec/smallvec"] + borsh = ["dep:borsh", "bit-vec/borsh"] serde = ["dep:serde", "bit-vec/serde"] miniserde = ["dep:miniserde", "bit-vec/miniserde"] diff --git a/set/src/lib.rs b/set/src/lib.rs index 9652931..3c977f0 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -266,6 +266,64 @@ impl BitSet { } impl BitSet { + /// Creates a new empty `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = ::new_general(); + /// ``` + #[inline] + pub fn new_general() -> Self { + Self::default() + } + + /// Creates a new `BitSet` with initially no contents, able to + /// hold `nbits` elements without resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = ::with_capacity_general(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn with_capacity_general(nbits: usize) -> Self { + let bit_vec = BitVec::from_elem_general(nbits, false); + Self::from_bit_vec_general(bit_vec) + } + + /// Creates a new `BitSet` from the given bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// use bit_set::BitSet; + /// + /// let bv: BitVec = BitVec::from_bytes_general(&[0b01100000]); + /// let s = BitSet::from_bit_vec_general(bv); + /// + /// // Print 1, 2 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn from_bit_vec_general(bit_vec: BitVec) -> Self { + BitSet { bit_vec } + } + + pub fn from_bytes_general(bytes: &[u8]) -> Self { + BitSet { + bit_vec: BitVec::from_bytes_general(bytes), + } + } + /// Returns the capacity in bits for this bit vector. Inserting any /// element less than this amount will not trigger a resizing. /// @@ -825,10 +883,31 @@ impl BitSet { self.bit_vec.none() } + /// Removes all elements of this set. + /// + /// Different from [`reset`] only in that the capacity is preserved. + /// + /// [`reset`]: Self::reset + #[inline] + pub fn make_empty(&mut self) { + self.bit_vec.fill(false); + } + + /// Resets this set to an empty state. + /// + /// Different from [`make_empty`] only in that the capacity may NOT be preserved. + /// + /// [`make_empty`]: Self::make_empty + #[inline] + pub fn reset(&mut self) { + self.bit_vec.remove_all(); + } + /// Clears all bits in this set + #[deprecated(since = "0.9.0", note = "please use `fn make_empty` instead")] #[inline] pub fn clear(&mut self) { - self.bit_vec.clear(); + self.make_empty(); } /// Returns `true` if this set contains the specified integer. From bc8b16239e5c8491e96e0894e20133563de6b718 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Tue, 10 Mar 2026 16:15:58 +0100 Subject: [PATCH 11/24] Update for changes to BitVec --- set/src/lib.rs | 2 +- vec/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/set/src/lib.rs b/set/src/lib.rs index 3c977f0..748459d 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -1648,7 +1648,7 @@ mod tests { assert_eq!(a.count(), 2); let old_cap2 = a.capacity(); - a.clear(); + a.make_empty(); assert_eq!(a.capacity(), old_cap2); assert_eq!(a.count(), 0); assert!(!a.contains(1)); diff --git a/vec/src/lib.rs b/vec/src/lib.rs index 3ec931d..91cc5fe 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -568,6 +568,7 @@ static TRUE: bool = true; static FALSE: bool = false; #[cfg(feature = "nanoserde")] +#[allow(dead_code)] type B = u32; /// The bitvector type. @@ -3990,7 +3991,7 @@ mod tests { assert_eq!(v.len(), 1025); assert_eq!(v.remove(1024), 1024 % 11 < 7); assert_eq!(v.len(), 1024); - assert_eq!(v.storage().len(), 1024 / 32); + assert_eq!(v.storage().len(), 1024 / S::BITS); } #[test] From bea93d4c2cfa3c06d43c7720527c818b49a60ee9 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Tue, 10 Mar 2026 16:16:24 +0100 Subject: [PATCH 12/24] Develop fuzzing for BitSet --- fuzz/Cargo.toml | 5 +- fuzz/README.md | 4 +- .../{bitvec_ops.rs => bit_ops.rs} | 99 ++++++++++++++++++- 3 files changed, 101 insertions(+), 7 deletions(-) rename fuzz/fuzz_targets/{bitvec_ops.rs => bit_ops.rs} (64%) diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 2bac526..368f1f9 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -9,6 +9,7 @@ publish = false cargo-fuzz = true [features] +default = ["afl"] afl_fuzz = ["afl"] honggfuzz_fuzz = ["honggfuzz"] nanoserde = ["bit-vec/nanoserde"] @@ -22,5 +23,5 @@ bit-matrix = { path = "../matrix/" } smallvec = "1.15" [[bin]] -name = "bitvec_ops" -path = "fuzz_targets/bitvec_ops.rs" +name = "bit_ops" +path = "fuzz_targets/bit_ops.rs" diff --git a/fuzz/README.md b/fuzz/README.md index 694faf6..a31515a 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -1,9 +1,9 @@ -# fuzzer for bit-vec +# fuzzer for bit-vec, bit-set and bit-matrix Based on fuzzing in `smallvec`. # fuzzing ```sh -cargo afl build --release --bin bitvec_ops --features afl && cargo afl fuzz -i in -o out target/release/bitvec_ops +cargo afl build --release --bin bit_ops --features afl && cargo afl fuzz -i in -o out target/release/bit_ops ``` diff --git a/fuzz/fuzz_targets/bitvec_ops.rs b/fuzz/fuzz_targets/bit_ops.rs similarity index 64% rename from fuzz/fuzz_targets/bitvec_ops.rs rename to fuzz/fuzz_targets/bit_ops.rs index 844cc20..32cf975 100644 --- a/fuzz/fuzz_targets/bitvec_ops.rs +++ b/fuzz/fuzz_targets/bit_ops.rs @@ -1,5 +1,6 @@ -//! Simple fuzzer testing all available `SmallVec` operations +//! Simple fuzzer testing all available `BitVec`, `BitSet` and `BitMatrix` operations use bit_vec::{BitBlockOrStore, BitVec}; +use bit_set::BitSet; #[cfg(not(feature = "nanoserde"))] use smallvec::SmallVec; @@ -24,13 +25,18 @@ fn black_box_bit_vec(s: &BitVec) { print!("{}", s); } +fn black_box_bit_set(s: &BitSet) { + // print to work as a black_box + print!("{}", s); +} + fn do_test(data: &[u8]) -> BitVec { let mut v = BitVec::::new_general(); let mut bytes = data.iter().copied(); while let Some(op) = bytes.next() { - match op % 22 { + match op % 23 { 0 => { v = BitVec::new_general(); } @@ -69,7 +75,7 @@ fn do_test(data: &[u8]) -> BitVec { } } 13 => { - v.clear(); + v.fill(false); } 14 => { if !v.is_empty() { @@ -111,6 +117,85 @@ fn do_test(data: &[u8]) -> BitVec { let slice = vec![next_u8!(bytes); next_usize!(bytes)]; v = BitVec::::from_bytes_general(&slice[..]); } + 22 => { + v.fill(true); + } + _ => panic!("booo"), + } + } + v +} + +fn do_test_set(data: &[u8]) -> BitSet { + let mut v = BitSet::::new_general(); + + let mut bytes = data.iter().copied(); + + while let Some(op) = bytes.next() { + match op % 17 { + 0 => { + v = BitSet::new_general(); + } + 1 => { + v = BitSet::with_capacity_general(next_usize!(bytes)); + } + 2 => { + v = BitSet::from_bytes_general(&v.get_ref().to_bytes()[..]); + } + 3 => { + if v.get_ref().len() < CAP_GROWTH { + v.reserve_len(next_usize!(bytes)) + } + } + 4 => { + if v.get_ref().len() < CAP_GROWTH { + v.reserve_len_exact(next_usize!(bytes)) + } + } + 5 => v.shrink_to_fit(), + 6 => v.truncate(next_usize!(bytes)), + 7 => black_box_bit_set(&v), + 8 => { + if !v.is_empty() { + v.remove(next_usize!(bytes) % v.len()); + } + } + 9 => { + v.reset(); + } + 10 => { + if !v.is_empty() { + v.remove(next_usize!(bytes) % v.get_ref().len()); + } + } + 11 => { + let insert_pos = next_usize!(bytes) % (v.get_ref().len() + 1); + v.insert(insert_pos); + } + + 12 => { + v = BitSet::from_bytes_general(&v.get_ref().to_bytes()[..]); + } + + 13 => { + v = BitSet::from_bytes_general(data); + } + + 14 => { + if v.get_ref().len() < CAP_GROWTH { + v.reserve_len(next_usize!(bytes)); + } + } + + 15 => { + if v.get_ref().len() < CAP_GROWTH { + v.reserve_len_exact(next_usize!(bytes)); + } + } + 16 => { + let slice = vec![next_u8!(bytes); next_usize!(bytes)]; + v = BitSet::::from_bytes_general(&slice[..]); + } _ => panic!("booo"), } } @@ -125,6 +210,14 @@ fn do_test_all(data: &[u8]) { #[cfg(not(feature = "nanoserde"))] do_test::>(data); do_test::>(data); + + do_test_set::(data); + do_test_set::(data); + do_test_set::(data); + do_test_set::(data); + #[cfg(not(feature = "nanoserde"))] + do_test_set::>(data); + do_test_set::>(data); } #[cfg(feature = "afl")] From 40c14bbf842c3ac56b017d2ef91582ce2da3008e Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Tue, 10 Mar 2026 16:18:17 +0100 Subject: [PATCH 13/24] Develop fuzzing for BitSet --- fuzz/fuzz_targets/bit_ops.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/fuzz/fuzz_targets/bit_ops.rs b/fuzz/fuzz_targets/bit_ops.rs index 32cf975..def607b 100644 --- a/fuzz/fuzz_targets/bit_ops.rs +++ b/fuzz/fuzz_targets/bit_ops.rs @@ -132,7 +132,7 @@ fn do_test_set(data: &[u8]) -> BitSet { let mut bytes = data.iter().copied(); while let Some(op) = bytes.next() { - match op % 17 { + match op % 16 { 0 => { v = BitSet::new_general(); } @@ -157,42 +157,37 @@ fn do_test_set(data: &[u8]) -> BitSet { 7 => black_box_bit_set(&v), 8 => { if !v.is_empty() { - v.remove(next_usize!(bytes) % v.len()); + v.remove(next_usize!(bytes) % v.get_ref().len()); } } 9 => { v.reset(); } 10 => { - if !v.is_empty() { - v.remove(next_usize!(bytes) % v.get_ref().len()); - } - } - 11 => { let insert_pos = next_usize!(bytes) % (v.get_ref().len() + 1); v.insert(insert_pos); } - 12 => { + 11 => { v = BitSet::from_bytes_general(&v.get_ref().to_bytes()[..]); } - 13 => { + 12 => { v = BitSet::from_bytes_general(data); } - 14 => { + 13 => { if v.get_ref().len() < CAP_GROWTH { v.reserve_len(next_usize!(bytes)); } } - 15 => { + 14 => { if v.get_ref().len() < CAP_GROWTH { v.reserve_len_exact(next_usize!(bytes)); } } - 16 => { + 15 => { let slice = vec![next_u8!(bytes); next_usize!(bytes)]; v = BitSet::::from_bytes_general(&slice[..]); } @@ -269,9 +264,9 @@ mod tests { // paste the output of `xxd -p ` here and run `cargo test` extend_vec_from_hex( r#" - 646e21f9f910f90200f9d9f9c7030000def9000010646e2af9f910f90264 - 6e21f9f910f90200f9d9f9c7030000def90000106400f9f9d9f9c7030000 - def90000106400f9d9f9e7f1000000d9f9e7f1000000f9 + 787c4a1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d4a1d1d1d1d1d1d1d + 1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d27271d1d1d1d1d1d2727fffe + 270a610a "#, &mut a, ); From 6f10ea9709d27d469e8cf10fd8d53fd03f384c57 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 12 Mar 2026 11:30:53 +0100 Subject: [PATCH 14/24] Split vec and set into multiple files --- set/RELEASES.md | 23 +- set/src/iter.rs | 376 ++++++ set/src/lib.rs | 1166 +---------------- set/src/set.rs | 727 +++++++++++ set/src/util.rs | 56 + vec/src/block.rs | 61 + vec/src/block_or_store.rs | 110 ++ vec/src/blocks.rs | 41 + vec/src/blocks_mut.rs | 12 + vec/src/into_iter.rs | 38 + vec/src/iter.rs | 70 + vec/src/lib.rs | 2575 +------------------------------------ vec/src/smart_mut.rs | 162 +++ vec/src/store.rs | 263 ++++ vec/src/util.rs | 14 + vec/src/vec.rs | 1761 +++++++++++++++++++++++++ 16 files changed, 3776 insertions(+), 3679 deletions(-) create mode 100644 set/src/iter.rs create mode 100644 set/src/set.rs create mode 100644 set/src/util.rs create mode 100644 vec/src/block.rs create mode 100644 vec/src/block_or_store.rs create mode 100644 vec/src/blocks.rs create mode 100644 vec/src/blocks_mut.rs create mode 100644 vec/src/into_iter.rs create mode 100644 vec/src/iter.rs create mode 100644 vec/src/smart_mut.rs create mode 100644 vec/src/store.rs create mode 100644 vec/src/util.rs create mode 100644 vec/src/vec.rs diff --git a/set/RELEASES.md b/set/RELEASES.md index 4e24136..d50c119 100644 --- a/set/RELEASES.md +++ b/set/RELEASES.md @@ -1,4 +1,25 @@ -Version 0.7.0 (not yet released) (ZERO BREAKING CHANGES) +Version 0.10.0 (not yet released) +======================================================== + + + +Version 0.9.0 +======================================================== + + + +- Minimal Supported Rust Version is 1.82 +- Rust edition 2021 is used +- implemented `fn make_empty` +- implemented `fn reset` +- added general initialization functions: `fn new_general`, `fn from_bit_vec_general`, `fn with_capacity_general`, `fn from_bytes_general` + +Version 0.8.0 +======================================================== + + + +Version 0.7.0 (ZERO BREAKING CHANGES) ======================================================== diff --git a/set/src/iter.rs b/set/src/iter.rs new file mode 100644 index 0000000..2fc094e --- /dev/null +++ b/set/src/iter.rs @@ -0,0 +1,376 @@ +use crate::{local_prelude::*, set::BitSet}; +use crate::util::Block; + +#[derive(Clone)] +struct BlockIter { + head: Block, + head_offset: usize, + tail: T, +} + +impl BlockIter +where + T: Iterator>, +{ + fn from_blocks(mut blocks: T) -> Self { + let h = blocks.next().unwrap_or(B::ZERO); + BlockIter { + tail: blocks, + head: h, + head_offset: 0, + } + } +} + +impl BitSet { + /// Iterator over each usize stored in `self` union `other`. + /// See [`union_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 0, 1, 2, 4 in arbitrary order + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`union_with`]: Self::union_with + #[inline] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, B> { + fn or(w1: B, w2: B) -> B { + w1 | w2 + } + + Union(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: or, + })) + } + + /// Iterator over each usize stored in `self` intersect `other`. + /// See [`intersect_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 2 + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`intersect_with`]: Self::intersect_with + #[inline] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, B> { + fn bitand(w1: B, w2: B) -> B { + w1 & w2 + } + let min = cmp::min(self.bit_vec.len(), other.bit_vec.len()); + + Intersection { + iter: BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: bitand, + }), + n: min, + } + } + + /// Iterator over each usize stored in the `self` setminus `other`. + /// See [`difference_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 1, 4 in arbitrary order + /// for x in a.difference(&b) { + /// println!("{}", x); + /// } + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else. + /// // This prints 0 + /// for x in b.difference(&a) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`difference_with`]: Self::difference_with + #[inline] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, B> { + fn diff(w1: B, w2: B) -> B { + w1 & !w2 + } + + Difference(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: diff, + })) + } + + /// Iterator over each usize stored in the symmetric difference of `self` and `other`. + /// See [`symmetric_difference_with`] for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 0, 1, 4 in arbitrary order + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// ``` + /// + /// [`symmetric_difference_with`]: Self::symmetric_difference_with + #[inline] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, B> { + fn bitxor(w1: B, w2: B) -> B { + w1 ^ w2 + } + + SymmetricDifference(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: bitxor, + })) + } + + /// Iterator over each usize stored in the `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let s = BitSet::from_bytes(&[0b01001010]); + /// + /// // Print 1, 4, 6 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn iter(&self) -> Iter<'_, B> { + Iter(BlockIter::from_blocks(self.bit_vec.blocks())) + } +} + +/// An iterator combining two `BitSet` iterators. +#[derive(Clone)] +struct TwoBitPositions<'a, B: 'a + BitBlockOrStore> { + set: Blocks<'a, B>, + other: Blocks<'a, B>, + merge: fn(Block, Block) -> Block, +} + +/// An iterator for `BitSet`. +#[derive(Clone)] +pub struct Iter<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); +#[derive(Clone)] +pub struct Union<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); +#[derive(Clone)] +pub struct Intersection<'a, B: 'a + BitBlockOrStore> { + iter: BlockIter, B>, + // as an optimization, we compute the maximum possible + // number of elements in the intersection, and count it + // down as we return elements. If we reach zero, we can + // stop. + n: usize, +} +#[derive(Clone)] +pub struct Difference<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); +#[derive(Clone)] +pub struct SymmetricDifference<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); + +impl Iterator for BlockIter +where + T: Iterator>, +{ + type Item = usize; + + fn next(&mut self) -> Option { + while self.head == B::ZERO { + match self.tail.next() { + Some(w) => self.head = w, + None => return None, + } + self.head_offset += B::BITS; + } + + // from the current block, isolate the + // LSB and subtract 1, producing k: + // a block with a number of set bits + // equal to the index of the LSB + let k = (self.head & (!self.head + B::ONE)) - B::ONE; + // update block, removing the LSB + self.head = self.head & (self.head - B::ONE); + // return offset + (index of LSB) + Some(self.head_offset + (::Block::count_ones(k))) + } + + fn count(self) -> usize { + self.head.count_ones() + self.tail.map(|block| block.count_ones()).sum::() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + match self.tail.size_hint() { + (_, Some(h)) => (0, Some((1 + h) * B::BITS)), + _ => (0, None), + } + } +} + +impl Iterator for TwoBitPositions<'_, B> { + type Item = Block; + + fn next(&mut self) -> Option { + match (self.set.next(), self.other.next()) { + (Some(a), Some(b)) => Some((self.merge)(a, b)), + (Some(a), None) => Some((self.merge)(a, B::ZERO)), + (None, Some(b)) => Some((self.merge)(B::ZERO, b)), + _ => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (first_lower_bound, first_upper_bound) = self.set.size_hint(); + let (second_lower_bound, second_upper_bound) = self.other.size_hint(); + + let upper_bound = first_upper_bound.zip(second_upper_bound); + + let get_max = |(a, b)| cmp::max(a, b); + ( + cmp::max(first_lower_bound, second_lower_bound), + upper_bound.map(get_max), + ) + } +} + +impl Iterator for Iter<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl Iterator for Union<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl Iterator for Intersection<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + if self.n != 0 { + self.n -= 1; + self.iter.next() + } else { + None + } + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + // We could invoke self.iter.size_hint() and incorporate that into the hint. + // In practice, that does not seem worthwhile because the lower bound will + // always be zero and the upper bound could only possibly less then n in a + // partially iterated iterator. However, it makes little sense ask for size_hint + // in a partially iterated iterator, so it did not seem worthwhile. + (0, Some(self.n)) + } + #[inline] + fn count(self) -> usize { + self.iter.count() + } +} + +impl Iterator for Difference<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl Iterator for SymmetricDifference<'_, B> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + #[inline] + fn count(self) -> usize { + self.0.count() + } +} + +impl<'a, B: BitBlockOrStore> IntoIterator for &'a BitSet { + type Item = usize; + type IntoIter = Iter<'a, B>; + + fn into_iter(self) -> Iter<'a, B> { + self.iter() + } +} diff --git a/set/src/lib.rs b/set/src/lib.rs index 748459d..5608c6e 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -57,1166 +57,22 @@ #[cfg(any(test, feature = "std"))] extern crate std; -use bit_vec::{BitBlock, BitVec, Blocks}; -use bit_vec::{BitBlockOrStore, BitStore}; -use core::cmp; -use core::cmp::Ordering; -use core::fmt; -use core::hash; -use core::iter::{self, Chain, Enumerate, FromIterator, Repeat, Skip, Take}; - #[cfg(feature = "nanoserde")] extern crate alloc; -#[cfg(feature = "nanoserde")] -use alloc::vec::Vec; -#[cfg(feature = "nanoserde")] -use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; - -#[allow(type_alias_bounds)] -type Block = ::Block; -#[allow(type_alias_bounds)] -type MatchWords<'a, B: BitBlockOrStore> = - Chain>, Skip>>>>>; - -/// Computes how many blocks are needed to store that many bits -fn blocks_for_bits(bits: usize) -> usize { - // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we - // reserve enough. But if we want exactly a multiple of 32, this will actually allocate - // one too many. So we need to check if that's the case. We can do that by computing if - // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically - // superior modulo operator on a power of two to this. - // - // Note that we can technically avoid this branch with the expression - // `(nbits + BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. - if bits % B::BITS == 0 { - bits / B::BITS - } else { - bits / B::BITS + 1 - } -} - -#[allow(clippy::iter_skip_zero)] -// Take two BitVec's, and return iterators of their words, where the shorter one -// has been padded with 0's -fn match_words<'a, 'b, B: BitBlockOrStore>( - a: &'a BitVec, - b: &'b BitVec, -) -> (MatchWords<'a, B>, MatchWords<'b, B>) { - let a_len = a.storage().len(); - let b_len = b.storage().len(); - - // have to uselessly pretend to pad the longer one for type matching - if a_len < b_len { - ( - a.blocks() - .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(b_len).skip(a_len)), - b.blocks() - .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), - ) - } else { - ( - a.blocks() - .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), - b.blocks() - .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(a_len).skip(b_len)), - ) - } -} - -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshDeserialize, borsh::BorshSerialize) -)] -#[cfg_attr( - feature = "miniserde", - derive(miniserde::Deserialize, miniserde::Serialize) -)] -#[cfg_attr( - feature = "nanoserde", - derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) -)] -pub struct BitSet { - bit_vec: BitVec, -} - -impl Clone for BitSet { - fn clone(&self) -> Self { - BitSet { - bit_vec: self.bit_vec.clone(), - } - } - - fn clone_from(&mut self, other: &Self) { - self.bit_vec.clone_from(&other.bit_vec); - } -} - -impl Default for BitSet { - #[inline] - fn default() -> Self { - BitSet { - bit_vec: Default::default(), - } - } -} - -impl FromIterator for BitSet { - fn from_iter>(iter: I) -> Self { - let mut ret = Self::default(); - ret.extend(iter); - ret - } -} - -impl Extend for BitSet { - #[inline] - fn extend>(&mut self, iter: I) { - for i in iter { - self.insert(i); - } - } -} - -impl PartialOrd for BitSet { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for BitSet { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.iter().cmp(other) - } -} - -impl PartialEq for BitSet { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.iter().eq(other) - } -} - -impl Eq for BitSet {} - -impl BitSet { - /// Creates a new empty `BitSet`. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = BitSet::new(); - /// ``` - #[inline] - pub fn new() -> Self { - Self::default() - } - /// Creates a new `BitSet` with initially no contents, able to - /// hold `nbits` elements without resizing. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = BitSet::with_capacity(100); - /// assert!(s.capacity() >= 100); - /// ``` - #[inline] - pub fn with_capacity(nbits: usize) -> Self { - let bit_vec = BitVec::from_elem(nbits, false); - Self::from_bit_vec(bit_vec) - } +mod set; +mod util; +mod iter; - /// Creates a new `BitSet` from the given bit vector. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// use bit_set::BitSet; - /// - /// let bv = BitVec::from_bytes(&[0b01100000]); - /// let s = BitSet::from_bit_vec(bv); - /// - /// // Print 1, 2 in arbitrary order - /// for x in s.iter() { - /// println!("{}", x); - /// } - /// ``` - #[inline] - pub fn from_bit_vec(bit_vec: BitVec) -> Self { - BitSet { bit_vec } - } - - pub fn from_bytes(bytes: &[u8]) -> Self { - BitSet { - bit_vec: BitVec::from_bytes(bytes), - } - } +pub mod local_prelude { + pub use bit_vec::{BitBlock, BitBlockOrStore, BitStore, BitVec, Blocks}; + pub use core::cmp::Ordering; + pub use core::{hash, fmt, cmp}; + pub use core::iter::{self, Chain, Enumerate, FromIterator, Repeat, Skip, Take}; } -impl BitSet { - /// Creates a new empty `BitSet`. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = ::new_general(); - /// ``` - #[inline] - pub fn new_general() -> Self { - Self::default() - } - - /// Creates a new `BitSet` with initially no contents, able to - /// hold `nbits` elements without resizing. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = ::with_capacity_general(100); - /// assert!(s.capacity() >= 100); - /// ``` - #[inline] - pub fn with_capacity_general(nbits: usize) -> Self { - let bit_vec = BitVec::from_elem_general(nbits, false); - Self::from_bit_vec_general(bit_vec) - } - - /// Creates a new `BitSet` from the given bit vector. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// use bit_set::BitSet; - /// - /// let bv: BitVec = BitVec::from_bytes_general(&[0b01100000]); - /// let s = BitSet::from_bit_vec_general(bv); - /// - /// // Print 1, 2 in arbitrary order - /// for x in s.iter() { - /// println!("{}", x); - /// } - /// ``` - #[inline] - pub fn from_bit_vec_general(bit_vec: BitVec) -> Self { - BitSet { bit_vec } - } - - pub fn from_bytes_general(bytes: &[u8]) -> Self { - BitSet { - bit_vec: BitVec::from_bytes_general(bytes), - } - } - - /// Returns the capacity in bits for this bit vector. Inserting any - /// element less than this amount will not trigger a resizing. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = BitSet::with_capacity(100); - /// assert!(s.capacity() >= 100); - /// ``` - #[inline] - pub fn capacity(&self) -> usize { - self.bit_vec.capacity() - } - - /// Reserves capacity for the given `BitSet` to contain `len` distinct elements. In the case - /// of `BitSet` this means reallocations will not occur as long as all inserted elements - /// are less than `len`. - /// - /// The collection may reserve more space to avoid frequent reallocations. - /// - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = BitSet::new(); - /// s.reserve_len(10); - /// assert!(s.capacity() >= 10); - /// ``` - pub fn reserve_len(&mut self, len: usize) { - let cur_len = self.bit_vec.len(); - if len >= cur_len { - self.bit_vec.reserve(len - cur_len); - } - } - - /// Reserves the minimum capacity for the given `BitSet` to contain `len` distinct elements. - /// In the case of `BitSet` this means reallocations will not occur as long as all inserted - /// elements are less than `len`. - /// - /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer `reserve_len` if future - /// insertions are expected. - /// - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = BitSet::new(); - /// s.reserve_len_exact(10); - /// assert!(s.capacity() >= 10); - /// ``` - pub fn reserve_len_exact(&mut self, len: usize) { - let cur_len = self.bit_vec.len(); - if len >= cur_len { - self.bit_vec.reserve_exact(len - cur_len); - } - } - - /// Consumes this set to return the underlying bit vector. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = BitSet::new(); - /// s.insert(0); - /// s.insert(3); - /// - /// let bv = s.into_bit_vec(); - /// assert!(bv[0]); - /// assert!(bv[3]); - /// ``` - #[inline] - pub fn into_bit_vec(self) -> BitVec { - self.bit_vec - } - - /// Returns a reference to the underlying bit vector. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut set = BitSet::new(); - /// set.insert(0); - /// - /// let bv = set.get_ref(); - /// assert_eq!(bv[0], true); - /// ``` - #[inline] - pub fn get_ref(&self) -> &BitVec { - &self.bit_vec - } - - /// Returns a mutable reference to the underlying bit vector. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut set = BitSet::new(); - /// set.insert(0); - /// set.insert(3); - /// - /// { - /// let bv = set.get_mut(); - /// bv.set(1, true); - /// } - /// - /// assert!(set.contains(0)); - /// assert!(set.contains(1)); - /// assert!(set.contains(3)); - /// ``` - #[inline] - pub fn get_mut(&mut self) -> &mut BitVec { - &mut self.bit_vec - } - - #[inline] - fn other_op(&mut self, other: &Self, mut f: F) - where - F: FnMut(Block, Block) -> Block, - { - // Unwrap BitVecs - let self_bit_vec = &mut self.bit_vec; - let other_bit_vec = &other.bit_vec; - - let self_len = self_bit_vec.len(); - let other_len = other_bit_vec.len(); - - // Expand the vector if necessary - if self_len < other_len { - self_bit_vec.grow(other_len - self_len, false); - } - - // virtually pad other with 0's for equal lengths - let other_words = { - let (_, result) = match_words(self_bit_vec, other_bit_vec); - result - }; - - // Apply values found in other - for (i, w) in other_words { - let old = self_bit_vec.storage()[i]; - let new = f(old, w); - unsafe { - self_bit_vec.storage_mut().slice_mut()[i] = new; - } - } - } - - /// Truncates the underlying vector to the least length required. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut s = BitSet::new(); - /// s.insert(3231); - /// s.remove(3231); - /// - /// // Internal storage will probably be bigger than necessary - /// println!("old capacity: {}", s.capacity()); - /// assert!(s.capacity() >= 3231); - /// - /// // Now should be smaller - /// s.shrink_to_fit(); - /// println!("new capacity: {}", s.capacity()); - /// ``` - #[inline] - pub fn shrink_to_fit(&mut self) { - let bit_vec = &mut self.bit_vec; - // Obtain original length - let old_len = bit_vec.storage().len(); - // Obtain coarse trailing zero length - let n = bit_vec - .storage() - .iter() - .rev() - .take_while(|&&n| n == B::ZERO) - .count(); - // Truncate away all empty trailing blocks, then shrink_to_fit - let trunc_len = old_len - n; - unsafe { - bit_vec.storage_mut().truncate(trunc_len); - bit_vec.set_len(trunc_len * B::BITS); - } - bit_vec.shrink_to_fit(); - } - - /// Iterator over each usize stored in the `BitSet`. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let s = BitSet::from_bytes(&[0b01001010]); - /// - /// // Print 1, 4, 6 in arbitrary order - /// for x in s.iter() { - /// println!("{}", x); - /// } - /// ``` - #[inline] - pub fn iter(&self) -> Iter<'_, B> { - Iter(BlockIter::from_blocks(self.bit_vec.blocks())) - } - - /// Iterator over each usize stored in `self` union `other`. - /// See [`union_with`] for an efficient in-place version. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = BitSet::from_bytes(&[0b01101000]); - /// let b = BitSet::from_bytes(&[0b10100000]); - /// - /// // Print 0, 1, 2, 4 in arbitrary order - /// for x in a.union(&b) { - /// println!("{}", x); - /// } - /// ``` - /// - /// [`union_with`]: Self::union_with - #[inline] - pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, B> { - fn or(w1: B, w2: B) -> B { - w1 | w2 - } - - Union(BlockIter::from_blocks(TwoBitPositions { - set: self.bit_vec.blocks(), - other: other.bit_vec.blocks(), - merge: or, - })) - } - - /// Iterator over each usize stored in `self` intersect `other`. - /// See [`intersect_with`] for an efficient in-place version. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = BitSet::from_bytes(&[0b01101000]); - /// let b = BitSet::from_bytes(&[0b10100000]); - /// - /// // Print 2 - /// for x in a.intersection(&b) { - /// println!("{}", x); - /// } - /// ``` - /// - /// [`intersect_with`]: Self::intersect_with - #[inline] - pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, B> { - fn bitand(w1: B, w2: B) -> B { - w1 & w2 - } - let min = cmp::min(self.bit_vec.len(), other.bit_vec.len()); - - Intersection { - iter: BlockIter::from_blocks(TwoBitPositions { - set: self.bit_vec.blocks(), - other: other.bit_vec.blocks(), - merge: bitand, - }), - n: min, - } - } - - /// Iterator over each usize stored in the `self` setminus `other`. - /// See [`difference_with`] for an efficient in-place version. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = BitSet::from_bytes(&[0b01101000]); - /// let b = BitSet::from_bytes(&[0b10100000]); - /// - /// // Print 1, 4 in arbitrary order - /// for x in a.difference(&b) { - /// println!("{}", x); - /// } - /// - /// // Note that difference is not symmetric, - /// // and `b - a` means something else. - /// // This prints 0 - /// for x in b.difference(&a) { - /// println!("{}", x); - /// } - /// ``` - /// - /// [`difference_with`]: Self::difference_with - #[inline] - pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, B> { - fn diff(w1: B, w2: B) -> B { - w1 & !w2 - } - - Difference(BlockIter::from_blocks(TwoBitPositions { - set: self.bit_vec.blocks(), - other: other.bit_vec.blocks(), - merge: diff, - })) - } - - /// Iterator over each usize stored in the symmetric difference of `self` and `other`. - /// See [`symmetric_difference_with`] for an efficient in-place version. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = BitSet::from_bytes(&[0b01101000]); - /// let b = BitSet::from_bytes(&[0b10100000]); - /// - /// // Print 0, 1, 4 in arbitrary order - /// for x in a.symmetric_difference(&b) { - /// println!("{}", x); - /// } - /// ``` - /// - /// [`symmetric_difference_with`]: Self::symmetric_difference_with - #[inline] - pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, B> { - fn bitxor(w1: B, w2: B) -> B { - w1 ^ w2 - } - - SymmetricDifference(BlockIter::from_blocks(TwoBitPositions { - set: self.bit_vec.blocks(), - other: other.bit_vec.blocks(), - merge: bitxor, - })) - } - - /// Unions in-place with the specified other bit vector. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = 0b01101000; - /// let b = 0b10100000; - /// let res = 0b11101000; - /// - /// let mut a = BitSet::from_bytes(&[a]); - /// let b = BitSet::from_bytes(&[b]); - /// let res = BitSet::from_bytes(&[res]); - /// - /// a.union_with(&b); - /// assert_eq!(a, res); - /// ``` - #[inline] - pub fn union_with(&mut self, other: &Self) { - self.other_op(other, |w1, w2| w1 | w2); - } - - /// Intersects in-place with the specified other bit vector. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = 0b01101000; - /// let b = 0b10100000; - /// let res = 0b00100000; - /// - /// let mut a = BitSet::from_bytes(&[a]); - /// let b = BitSet::from_bytes(&[b]); - /// let res = BitSet::from_bytes(&[res]); - /// - /// a.intersect_with(&b); - /// assert_eq!(a, res); - /// ``` - #[inline] - pub fn intersect_with(&mut self, other: &Self) { - self.other_op(other, |w1, w2| w1 & w2); - } - - /// Makes this bit vector the difference with the specified other bit vector - /// in-place. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = 0b01101000; - /// let b = 0b10100000; - /// let a_b = 0b01001000; // a - b - /// let b_a = 0b10000000; // b - a - /// - /// let mut bva = BitSet::from_bytes(&[a]); - /// let bvb = BitSet::from_bytes(&[b]); - /// let bva_b = BitSet::from_bytes(&[a_b]); - /// let bvb_a = BitSet::from_bytes(&[b_a]); - /// - /// bva.difference_with(&bvb); - /// assert_eq!(bva, bva_b); - /// - /// let bva = BitSet::from_bytes(&[a]); - /// let mut bvb = BitSet::from_bytes(&[b]); - /// - /// bvb.difference_with(&bva); - /// assert_eq!(bvb, bvb_a); - /// ``` - #[inline] - pub fn difference_with(&mut self, other: &Self) { - self.other_op(other, |w1, w2| w1 & !w2); - } - - /// Makes this bit vector the symmetric difference with the specified other - /// bit vector in-place. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let a = 0b01101000; - /// let b = 0b10100000; - /// let res = 0b11001000; - /// - /// let mut a = BitSet::from_bytes(&[a]); - /// let b = BitSet::from_bytes(&[b]); - /// let res = BitSet::from_bytes(&[res]); - /// - /// a.symmetric_difference_with(&b); - /// assert_eq!(a, res); - /// ``` - #[inline] - pub fn symmetric_difference_with(&mut self, other: &Self) { - self.other_op(other, |w1, w2| w1 ^ w2); - } - - /* - /// Moves all elements from `other` into `Self`, leaving `other` empty. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut a = BitSet::new(); - /// a.insert(2); - /// a.insert(6); - /// - /// let mut b = BitSet::new(); - /// b.insert(1); - /// b.insert(3); - /// b.insert(6); - /// - /// a.append(&mut b); - /// - /// assert_eq!(a.len(), 4); - /// assert_eq!(b.len(), 0); - /// assert_eq!(a, BitSet::from_bytes(&[0b01110010])); - /// ``` - pub fn append(&mut self, other: &mut Self) { - self.union_with(other); - other.clear(); - } - - /// Splits the `BitSet` into two at the given key including the key. - /// Retains the first part in-place while returning the second part. - /// - /// # Examples - /// - /// ``` - /// use bit_set::BitSet; - /// - /// let mut a = BitSet::new(); - /// a.insert(2); - /// a.insert(6); - /// a.insert(1); - /// a.insert(3); - /// - /// let b = a.split_off(3); - /// - /// assert_eq!(a.len(), 2); - /// assert_eq!(b.len(), 2); - /// assert_eq!(a, BitSet::from_bytes(&[0b01100000])); - /// assert_eq!(b, BitSet::from_bytes(&[0b00010010])); - /// ``` - pub fn split_off(&mut self, at: usize) -> Self { - let mut other = BitSet::new(); - - if at == 0 { - swap(self, &mut other); - return other; - } else if at >= self.bit_vec.len() { - return other; - } - - // Calculate block and bit at which to split - let w = at / BITS; - let b = at % BITS; - - // Pad `other` with `w` zero blocks, - // append `self`'s blocks in the range from `w` to the end to `other` - other.bit_vec.storage_mut().extend(repeat(0u32).take(w) - .chain(self.bit_vec.storage()[w..].iter().cloned())); - other.bit_vec.nbits = self.bit_vec.nbits; - - if b > 0 { - other.bit_vec.storage_mut()[w] &= !0 << b; - } - - // Sets `bit_vec.len()` and fixes the last block as well - self.bit_vec.truncate(at); - - other - } - */ - - /// Counts the number of set bits in this set. - /// - /// Note that this function scans the set to calculate the number. - #[inline] - pub fn count(&self) -> usize { - self.bit_vec.blocks().fold(0, |acc, n| acc + n.count_ones()) - } - - /// Counts the number of set bits in this set. - /// - /// Note that this function scans the set to calculate the number. - #[inline] - #[deprecated = "use BitVec::count() instead"] - pub fn len(&self) -> usize { - self.count() - } - - /// Returns whether there are no bits set in this set - #[inline] - pub fn is_empty(&self) -> bool { - self.bit_vec.none() - } - - /// Removes all elements of this set. - /// - /// Different from [`reset`] only in that the capacity is preserved. - /// - /// [`reset`]: Self::reset - #[inline] - pub fn make_empty(&mut self) { - self.bit_vec.fill(false); - } - - /// Resets this set to an empty state. - /// - /// Different from [`make_empty`] only in that the capacity may NOT be preserved. - /// - /// [`make_empty`]: Self::make_empty - #[inline] - pub fn reset(&mut self) { - self.bit_vec.remove_all(); - } - - /// Clears all bits in this set - #[deprecated(since = "0.9.0", note = "please use `fn make_empty` instead")] - #[inline] - pub fn clear(&mut self) { - self.make_empty(); - } - - /// Returns `true` if this set contains the specified integer. - #[inline] - pub fn contains(&self, value: usize) -> bool { - let bit_vec = &self.bit_vec; - value < bit_vec.len() && bit_vec[value] - } - - /// Returns `true` if the set has no elements in common with `other`. - /// This is equivalent to checking for an empty intersection. - #[inline] - pub fn is_disjoint(&self, other: &Self) -> bool { - self.intersection(other).next().is_none() - } - - /// Returns `true` if the set is a subset of another. - #[inline] - pub fn is_subset(&self, other: &Self) -> bool { - let self_bit_vec = &self.bit_vec; - let other_bit_vec = &other.bit_vec; - let other_blocks = blocks_for_bits::(other_bit_vec.len()); - - // Check that `self` intersect `other` is self - self_bit_vec.blocks().zip(other_bit_vec.blocks()).all(|(w1, w2)| w1 & w2 == w1) && - // Make sure if `self` has any more blocks than `other`, they're all 0 - self_bit_vec.blocks().skip(other_blocks).all(|w| w == B::ZERO) - } - - /// Returns `true` if the set is a superset of another. - #[inline] - pub fn is_superset(&self, other: &Self) -> bool { - other.is_subset(self) - } - - /// Adds a value to the set. Returns `true` if the value was not already - /// present in the set. - pub fn insert(&mut self, value: usize) -> bool { - if self.contains(value) { - return false; - } - - // Ensure we have enough space to hold the new element - let len = self.bit_vec.len(); - if value >= len { - self.bit_vec.grow(value - len + 1, false); - } - - self.bit_vec.set(value, true); - true - } - - /// Removes a value from the set. Returns `true` if the value was - /// present in the set. - pub fn remove(&mut self, value: usize) -> bool { - if !self.contains(value) { - return false; - } - - self.bit_vec.set(value, false); - - true - } - - /// Excludes `element` and all greater elements from the `BitSet`. - pub fn truncate(&mut self, element: usize) { - self.bit_vec.truncate(element); - } -} - -impl fmt::Debug for BitSet { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BitSet") - .field("bit_vec", &self.bit_vec) - .finish() - } -} - -impl fmt::Display for BitSet { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_set().entries(self).finish() - } -} - -impl hash::Hash for BitSet { - fn hash(&self, state: &mut H) { - for pos in self { - pos.hash(state); - } - } -} - -#[derive(Clone)] -struct BlockIter { - head: Block, - head_offset: usize, - tail: T, -} - -impl BlockIter -where - T: Iterator>, -{ - fn from_blocks(mut blocks: T) -> Self { - let h = blocks.next().unwrap_or(B::ZERO); - BlockIter { - tail: blocks, - head: h, - head_offset: 0, - } - } -} - -/// An iterator combining two `BitSet` iterators. -#[derive(Clone)] -struct TwoBitPositions<'a, B: 'a + BitBlockOrStore> { - set: Blocks<'a, B>, - other: Blocks<'a, B>, - merge: fn(Block, Block) -> Block, -} - -/// An iterator for `BitSet`. -#[derive(Clone)] -pub struct Iter<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); -#[derive(Clone)] -pub struct Union<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); -#[derive(Clone)] -pub struct Intersection<'a, B: 'a + BitBlockOrStore> { - iter: BlockIter, B>, - // as an optimization, we compute the maximum possible - // number of elements in the intersection, and count it - // down as we return elements. If we reach zero, we can - // stop. - n: usize, -} -#[derive(Clone)] -pub struct Difference<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); -#[derive(Clone)] -pub struct SymmetricDifference<'a, B: 'a + BitBlockOrStore>(BlockIter, B>); - -impl Iterator for BlockIter -where - T: Iterator>, -{ - type Item = usize; - - fn next(&mut self) -> Option { - while self.head == B::ZERO { - match self.tail.next() { - Some(w) => self.head = w, - None => return None, - } - self.head_offset += B::BITS; - } - - // from the current block, isolate the - // LSB and subtract 1, producing k: - // a block with a number of set bits - // equal to the index of the LSB - let k = (self.head & (!self.head + B::ONE)) - B::ONE; - // update block, removing the LSB - self.head = self.head & (self.head - B::ONE); - // return offset + (index of LSB) - Some(self.head_offset + (::Block::count_ones(k))) - } - - fn count(self) -> usize { - self.head.count_ones() + self.tail.map(|block| block.count_ones()).sum::() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - match self.tail.size_hint() { - (_, Some(h)) => (0, Some((1 + h) * B::BITS)), - _ => (0, None), - } - } -} - -impl Iterator for TwoBitPositions<'_, B> { - type Item = Block; - - fn next(&mut self) -> Option { - match (self.set.next(), self.other.next()) { - (Some(a), Some(b)) => Some((self.merge)(a, b)), - (Some(a), None) => Some((self.merge)(a, B::ZERO)), - (None, Some(b)) => Some((self.merge)(B::ZERO, b)), - _ => None, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (first_lower_bound, first_upper_bound) = self.set.size_hint(); - let (second_lower_bound, second_upper_bound) = self.other.size_hint(); - - let upper_bound = first_upper_bound.zip(second_upper_bound); - - let get_max = |(a, b)| cmp::max(a, b); - ( - cmp::max(first_lower_bound, second_lower_bound), - upper_bound.map(get_max), - ) - } -} - -impl Iterator for Iter<'_, B> { - type Item = usize; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - #[inline] - fn count(self) -> usize { - self.0.count() - } -} - -impl Iterator for Union<'_, B> { - type Item = usize; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - #[inline] - fn count(self) -> usize { - self.0.count() - } -} - -impl Iterator for Intersection<'_, B> { - type Item = usize; - - #[inline] - fn next(&mut self) -> Option { - if self.n != 0 { - self.n -= 1; - self.iter.next() - } else { - None - } - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - // We could invoke self.iter.size_hint() and incorporate that into the hint. - // In practice, that does not seem worthwhile because the lower bound will - // always be zero and the upper bound could only possibly less then n in a - // partially iterated iterator. However, it makes little sense ask for size_hint - // in a partially iterated iterator, so it did not seem worthwhile. - (0, Some(self.n)) - } - #[inline] - fn count(self) -> usize { - self.iter.count() - } -} - -impl Iterator for Difference<'_, B> { - type Item = usize; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - #[inline] - fn count(self) -> usize { - self.0.count() - } -} - -impl Iterator for SymmetricDifference<'_, B> { - type Item = usize; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - #[inline] - fn count(self) -> usize { - self.0.count() - } -} - -impl<'a, B: BitBlockOrStore> IntoIterator for &'a BitSet { - type Item = usize; - type IntoIter = Iter<'a, B>; - - fn into_iter(self) -> Iter<'a, B> { - self.iter() - } -} +pub use set::BitSet; +pub use bit_vec::{BitStore, BitBlockOrStore}; #[cfg(test)] mod tests { @@ -1224,7 +80,7 @@ mod tests { #![allow(clippy::shadow_same)] #![allow(clippy::shadow_unrelated)] - use super::BitSet; + use crate::set::BitSet; use bit_vec::BitVec; use std::cmp::Ordering::{Equal, Greater, Less}; use std::vec::Vec; diff --git a/set/src/set.rs b/set/src/set.rs new file mode 100644 index 0000000..1e42ba7 --- /dev/null +++ b/set/src/set.rs @@ -0,0 +1,727 @@ +use crate::{local_prelude::*, util}; +use crate::util::Block; + +#[cfg(feature = "nanoserde")] +use alloc::vec::Vec; +#[cfg(feature = "nanoserde")] +use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; + +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshDeserialize, borsh::BorshSerialize) +)] +#[cfg_attr( + feature = "miniserde", + derive(miniserde::Deserialize, miniserde::Serialize) +)] +#[cfg_attr( + feature = "nanoserde", + derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) +)] +pub struct BitSet { + pub(crate) bit_vec: BitVec, +} + +impl Clone for BitSet { + fn clone(&self) -> Self { + BitSet { + bit_vec: self.bit_vec.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.bit_vec.clone_from(&other.bit_vec); + } +} + +impl Default for BitSet { + #[inline] + fn default() -> Self { + BitSet { + bit_vec: Default::default(), + } + } +} + +impl FromIterator for BitSet { + fn from_iter>(iter: I) -> Self { + let mut ret = Self::default(); + ret.extend(iter); + ret + } +} + +impl Extend for BitSet { + #[inline] + fn extend>(&mut self, iter: I) { + for i in iter { + self.insert(i); + } + } +} + +impl PartialOrd for BitSet { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for BitSet { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +impl PartialEq for BitSet { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.iter().eq(other) + } +} + +impl Eq for BitSet {} + +impl BitSet { + /// Creates a new empty `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// ``` + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Creates a new `BitSet` with initially no contents, able to + /// hold `nbits` elements without resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn with_capacity(nbits: usize) -> Self { + let bit_vec = BitVec::from_elem(nbits, false); + Self::from_bit_vec(bit_vec) + } + + /// Creates a new `BitSet` from the given bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// use bit_set::BitSet; + /// + /// let bv = BitVec::from_bytes(&[0b01100000]); + /// let s = BitSet::from_bit_vec(bv); + /// + /// // Print 1, 2 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn from_bit_vec(bit_vec: BitVec) -> Self { + BitSet { bit_vec } + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + BitSet { + bit_vec: BitVec::from_bytes(bytes), + } + } +} + +impl BitSet { + /// Creates a new empty `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = ::new_general(); + /// ``` + #[inline] + pub fn new_general() -> Self { + Self::default() + } + + /// Creates a new `BitSet` with initially no contents, able to + /// hold `nbits` elements without resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = ::with_capacity_general(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn with_capacity_general(nbits: usize) -> Self { + let bit_vec = BitVec::from_elem_general(nbits, false); + Self::from_bit_vec_general(bit_vec) + } + + /// Creates a new `BitSet` from the given bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// use bit_set::BitSet; + /// + /// let bv: BitVec = BitVec::from_bytes_general(&[0b01100000]); + /// let s = BitSet::from_bit_vec_general(bv); + /// + /// // Print 1, 2 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn from_bit_vec_general(bit_vec: BitVec) -> Self { + BitSet { bit_vec } + } + + pub fn from_bytes_general(bytes: &[u8]) -> Self { + BitSet { + bit_vec: BitVec::from_bytes_general(bytes), + } + } + + /// Returns the capacity in bits for this bit vector. Inserting any + /// element less than this amount will not trigger a resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.bit_vec.capacity() + } + + /// Reserves capacity for the given `BitSet` to contain `len` distinct elements. In the case + /// of `BitSet` this means reallocations will not occur as long as all inserted elements + /// are less than `len`. + /// + /// The collection may reserve more space to avoid frequent reallocations. + /// + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.reserve_len(10); + /// assert!(s.capacity() >= 10); + /// ``` + pub fn reserve_len(&mut self, len: usize) { + let cur_len = self.bit_vec.len(); + if len >= cur_len { + self.bit_vec.reserve(len - cur_len); + } + } + + /// Reserves the minimum capacity for the given `BitSet` to contain `len` distinct elements. + /// In the case of `BitSet` this means reallocations will not occur as long as all inserted + /// elements are less than `len`. + /// + /// Note that the allocator may give the collection more space than it requests. Therefore + /// capacity can not be relied upon to be precisely minimal. Prefer `reserve_len` if future + /// insertions are expected. + /// + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.reserve_len_exact(10); + /// assert!(s.capacity() >= 10); + /// ``` + pub fn reserve_len_exact(&mut self, len: usize) { + let cur_len = self.bit_vec.len(); + if len >= cur_len { + self.bit_vec.reserve_exact(len - cur_len); + } + } + + /// Consumes this set to return the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.insert(0); + /// s.insert(3); + /// + /// let bv = s.into_bit_vec(); + /// assert!(bv[0]); + /// assert!(bv[3]); + /// ``` + #[inline] + pub fn into_bit_vec(self) -> BitVec { + self.bit_vec + } + + /// Returns a reference to the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut set = BitSet::new(); + /// set.insert(0); + /// + /// let bv = set.get_ref(); + /// assert_eq!(bv[0], true); + /// ``` + #[inline] + pub fn get_ref(&self) -> &BitVec { + &self.bit_vec + } + + /// Returns a mutable reference to the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut set = BitSet::new(); + /// set.insert(0); + /// set.insert(3); + /// + /// { + /// let bv = set.get_mut(); + /// bv.set(1, true); + /// } + /// + /// assert!(set.contains(0)); + /// assert!(set.contains(1)); + /// assert!(set.contains(3)); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut BitVec { + &mut self.bit_vec + } + + #[inline] + fn other_op(&mut self, other: &Self, mut f: F) + where + F: FnMut(Block, Block) -> Block, + { + // Unwrap BitVecs + let self_bit_vec = &mut self.bit_vec; + let other_bit_vec = &other.bit_vec; + + let self_len = self_bit_vec.len(); + let other_len = other_bit_vec.len(); + + // Expand the vector if necessary + if self_len < other_len { + self_bit_vec.grow(other_len - self_len, false); + } + + // virtually pad other with 0's for equal lengths + let other_words = { + let (_, result) = util::match_words(self_bit_vec, other_bit_vec); + result + }; + + // Apply values found in other + for (i, w) in other_words { + let old = self_bit_vec.storage()[i]; + let new = f(old, w); + unsafe { + self_bit_vec.storage_mut().slice_mut()[i] = new; + } + } + } + + /// Truncates the underlying vector to the least length required. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.insert(3231); + /// s.remove(3231); + /// + /// // Internal storage will probably be bigger than necessary + /// println!("old capacity: {}", s.capacity()); + /// assert!(s.capacity() >= 3231); + /// + /// // Now should be smaller + /// s.shrink_to_fit(); + /// println!("new capacity: {}", s.capacity()); + /// ``` + #[inline] + pub fn shrink_to_fit(&mut self) { + let bit_vec = &mut self.bit_vec; + // Obtain original length + let old_len = bit_vec.storage().len(); + // Obtain coarse trailing zero length + let n = bit_vec + .storage() + .iter() + .rev() + .take_while(|&&n| n == B::ZERO) + .count(); + // Truncate away all empty trailing blocks, then shrink_to_fit + let trunc_len = old_len - n; + unsafe { + bit_vec.storage_mut().truncate(trunc_len); + bit_vec.set_len(trunc_len * B::BITS); + } + bit_vec.shrink_to_fit(); + } + + + /// Unions in-place with the specified other bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11101000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.union_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn union_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 | w2); + } + + /// Intersects in-place with the specified other bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b00100000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.intersect_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn intersect_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 & w2); + } + + /// Makes this bit vector the difference with the specified other bit vector + /// in-place. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let a_b = 0b01001000; // a - b + /// let b_a = 0b10000000; // b - a + /// + /// let mut bva = BitSet::from_bytes(&[a]); + /// let bvb = BitSet::from_bytes(&[b]); + /// let bva_b = BitSet::from_bytes(&[a_b]); + /// let bvb_a = BitSet::from_bytes(&[b_a]); + /// + /// bva.difference_with(&bvb); + /// assert_eq!(bva, bva_b); + /// + /// let bva = BitSet::from_bytes(&[a]); + /// let mut bvb = BitSet::from_bytes(&[b]); + /// + /// bvb.difference_with(&bva); + /// assert_eq!(bvb, bvb_a); + /// ``` + #[inline] + pub fn difference_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 & !w2); + } + + /// Makes this bit vector the symmetric difference with the specified other + /// bit vector in-place. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11001000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.symmetric_difference_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn symmetric_difference_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 ^ w2); + } + + /* + /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// + /// let mut b = BitSet::new(); + /// b.insert(1); + /// b.insert(3); + /// b.insert(6); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 4); + /// assert_eq!(b.len(), 0); + /// assert_eq!(a, BitSet::from_bytes(&[0b01110010])); + /// ``` + pub fn append(&mut self, other: &mut Self) { + self.union_with(other); + other.clear(); + } + + /// Splits the `BitSet` into two at the given key including the key. + /// Retains the first part in-place while returning the second part. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// a.insert(1); + /// a.insert(3); + /// + /// let b = a.split_off(3); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 2); + /// assert_eq!(a, BitSet::from_bytes(&[0b01100000])); + /// assert_eq!(b, BitSet::from_bytes(&[0b00010010])); + /// ``` + pub fn split_off(&mut self, at: usize) -> Self { + let mut other = BitSet::new(); + + if at == 0 { + swap(self, &mut other); + return other; + } else if at >= self.bit_vec.len() { + return other; + } + + // Calculate block and bit at which to split + let w = at / BITS; + let b = at % BITS; + + // Pad `other` with `w` zero blocks, + // append `self`'s blocks in the range from `w` to the end to `other` + other.bit_vec.storage_mut().extend(repeat(0u32).take(w) + .chain(self.bit_vec.storage()[w..].iter().cloned())); + other.bit_vec.nbits = self.bit_vec.nbits; + + if b > 0 { + other.bit_vec.storage_mut()[w] &= !0 << b; + } + + // Sets `bit_vec.len()` and fixes the last block as well + self.bit_vec.truncate(at); + + other + } + */ + + /// Counts the number of set bits in this set. + /// + /// Note that this function scans the set to calculate the number. + #[inline] + pub fn count(&self) -> usize { + self.bit_vec.blocks().fold(0, |acc, n| acc + n.count_ones()) + } + + /// Counts the number of set bits in this set. + /// + /// Note that this function scans the set to calculate the number. + #[inline] + #[deprecated = "use BitVec::count() instead"] + pub fn len(&self) -> usize { + self.count() + } + + /// Returns whether there are no bits set in this set + #[inline] + pub fn is_empty(&self) -> bool { + self.bit_vec.none() + } + + /// Removes all elements of this set. + /// + /// Different from [`reset`] only in that the capacity is preserved. + /// + /// [`reset`]: Self::reset + #[inline] + pub fn make_empty(&mut self) { + self.bit_vec.fill(false); + } + + /// Resets this set to an empty state. + /// + /// Different from [`make_empty`] only in that the capacity may NOT be preserved. + /// + /// [`make_empty`]: Self::make_empty + #[inline] + pub fn reset(&mut self) { + self.bit_vec.remove_all(); + } + + /// Clears all bits in this set + #[deprecated(since = "0.9.0", note = "please use `fn make_empty` instead")] + #[inline] + pub fn clear(&mut self) { + self.make_empty(); + } + + /// Returns `true` if this set contains the specified integer. + #[inline] + pub fn contains(&self, value: usize) -> bool { + let bit_vec = &self.bit_vec; + value < bit_vec.len() && bit_vec[value] + } + + /// Returns `true` if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + #[inline] + pub fn is_disjoint(&self, other: &Self) -> bool { + self.intersection(other).next().is_none() + } + + /// Returns `true` if the set is a subset of another. + #[inline] + pub fn is_subset(&self, other: &Self) -> bool { + let self_bit_vec = &self.bit_vec; + let other_bit_vec = &other.bit_vec; + let other_blocks = util::blocks_for_bits::(other_bit_vec.len()); + + // Check that `self` intersect `other` is self + self_bit_vec.blocks().zip(other_bit_vec.blocks()).all(|(w1, w2)| w1 & w2 == w1) && + // Make sure if `self` has any more blocks than `other`, they're all 0 + self_bit_vec.blocks().skip(other_blocks).all(|w| w == B::ZERO) + } + + /// Returns `true` if the set is a superset of another. + #[inline] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. Returns `true` if the value was not already + /// present in the set. + pub fn insert(&mut self, value: usize) -> bool { + if self.contains(value) { + return false; + } + + // Ensure we have enough space to hold the new element + let len = self.bit_vec.len(); + if value >= len { + self.bit_vec.grow(value - len + 1, false); + } + + self.bit_vec.set(value, true); + true + } + + /// Removes a value from the set. Returns `true` if the value was + /// present in the set. + pub fn remove(&mut self, value: usize) -> bool { + if !self.contains(value) { + return false; + } + + self.bit_vec.set(value, false); + + true + } + + /// Excludes `element` and all greater elements from the `BitSet`. + pub fn truncate(&mut self, element: usize) { + self.bit_vec.truncate(element); + } +} + +impl fmt::Debug for BitSet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BitSet") + .field("bit_vec", &self.bit_vec) + .finish() + } +} + +impl fmt::Display for BitSet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set().entries(self).finish() + } +} + +impl hash::Hash for BitSet { + fn hash(&self, state: &mut H) { + for pos in self { + pos.hash(state); + } + } +} \ No newline at end of file diff --git a/set/src/util.rs b/set/src/util.rs new file mode 100644 index 0000000..5f20398 --- /dev/null +++ b/set/src/util.rs @@ -0,0 +1,56 @@ +use crate::local_prelude::*; + +#[allow(type_alias_bounds)] +pub(crate) type Block = ::Block; +#[allow(type_alias_bounds)] +type MatchWords<'a, B: BitBlockOrStore> = + Chain>, Skip>>>>>; + +/// Computes how many blocks are needed to store that many bits +pub(crate) fn blocks_for_bits(bits: usize) -> usize { + // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we + // reserve enough. But if we want exactly a multiple of 32, this will actually allocate + // one too many. So we need to check if that's the case. We can do that by computing if + // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically + // superior modulo operator on a power of two to this. + // + // Note that we can technically avoid this branch with the expression + // `(nbits + BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. + if bits % B::BITS == 0 { + bits / B::BITS + } else { + bits / B::BITS + 1 + } +} + +#[allow(clippy::iter_skip_zero)] +// Take two BitVec's, and return iterators of their words, where the shorter one +// has been padded with 0's +pub(crate) fn match_words<'a, 'b, B: BitBlockOrStore>( + a: &'a BitVec, + b: &'b BitVec, +) -> (MatchWords<'a, B>, MatchWords<'b, B>) { + let a_len = a.storage().len(); + let b_len = b.storage().len(); + + // have to uselessly pretend to pad the longer one for type matching + if a_len < b_len { + ( + a.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).enumerate().take(b_len).skip(a_len)), + b.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), + ) + } else { + ( + a.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), + b.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).enumerate().take(a_len).skip(b_len)), + ) + } +} diff --git a/vec/src/block.rs b/vec/src/block.rs new file mode 100644 index 0000000..91bb2d1 --- /dev/null +++ b/vec/src/block.rs @@ -0,0 +1,61 @@ +use crate::local_prelude::ops::*; +use crate::local_prelude::*; + +/// Abstracts over a pile of bits (basically unsigned primitives) +pub trait BitBlock: + Copy + + Add + + Sub + + Shl + + Shr + + Not + + BitAnd + + BitOr + + BitXor + + Rem + + BitOrAssign + + Eq + + Ord + + hash::Hash +{ + /// How many bits it has + const BITS_: usize; + /// How many bytes it has + const BYTES_: usize = Self::BITS_ / 8; + /// Convert a byte into this type (lowest-order bits set) + fn from_byte(byte: u8) -> Self; + /// Count the number of 1's in the bitwise repr + fn count_ones(self) -> usize; + /// Count the number of 0's in the bitwise repr + fn count_zeros(self) -> usize { + Self::BITS_ - self.count_ones() + } + /// Get `0` + const ZERO_: Self; + /// Get `1` + const ONE_: Self; +} + +macro_rules! bit_block_impl { + ($(($t: ident, $size: expr)),*) => ($( + impl BitBlock for $t { + const BITS_: usize = $size; + #[inline] + fn from_byte(byte: u8) -> Self { $t::from(byte) } + #[inline] + fn count_ones(self) -> usize { self.count_ones() as usize } + #[inline] + fn count_zeros(self) -> usize { self.count_zeros() as usize } + const ONE_: Self = 1; + const ZERO_: Self = 0; + } + )*) +} + +bit_block_impl! { + (u8, 8), + (u16, 16), + (u32, 32), + (u64, 64), + (usize, usize::BITS as usize) +} diff --git a/vec/src/block_or_store.rs b/vec/src/block_or_store.rs new file mode 100644 index 0000000..dc285de --- /dev/null +++ b/vec/src/block_or_store.rs @@ -0,0 +1,110 @@ +use crate::local_prelude::*; + +macro_rules! bound_combination { + ( + type $T:ident: [$($B:tt)*]; + $cfg0:tt => [$($Bounds0:tt)*]; + $( + $cfg:tt => [$($Bounds:tt)*]; + )* + ) => { + #[cfg(not(feature = $cfg0))] + bound_combination!( + type $T: [$($B)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + #[cfg(feature = $cfg0)] + bound_combination!( + type $T: [$($B)* + $($Bounds0)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + }; + ( + type $T:ident: [$($B:tt)*]; + ) => { + type $T: $($B)*; + } +} + +pub trait BitBlockOrStore { + bound_combination!( + type Store: [BitStore]; + "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; + "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; + "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; + "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; + ); + + const BITS: usize = ::Block::BITS_; + const BYTES: usize = ::Block::BYTES_; + const ONE: ::Block = ::Block::ONE_; + const ZERO: ::Block = ::Block::ZERO_; +} + +macro_rules! impl_combination { + ( + type $T:ty: [$($B:tt)*]; + $cfg0:tt => [$($Bounds0:tt)*]; + $( + $cfg:tt => [$($Bounds:tt)*]; + )* + ) => { + #[cfg(not(feature = $cfg0))] + impl_combination!( + type $T: [$($B)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + #[cfg(feature = $cfg0)] + impl_combination!( + type $T: [$($B)* + $($Bounds0)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + }; + ( + type $T:ty: [$($B:tt)*]; + ) => { + impl BitBlockOrStore for Vec { + type Store = Self; + } + } +} + +impl_combination!( + type Vec: [BitBlock]; + "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; + "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; + "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; + "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; +); + +#[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] +impl BitBlockOrStore for smallvec::SmallVec +where + A::Item: BitBlock, +{ + type Store = Self; +} + +macro_rules! bit_block_or_store_impl { + ($($t: ident),*) => ($( + impl BitBlockOrStore for $t { + type Store = Vec; + } + )*) +} + +bit_block_or_store_impl! { + u8, + u16, + u32, + u64, + usize +} diff --git a/vec/src/blocks.rs b/vec/src/blocks.rs new file mode 100644 index 0000000..2834c2a --- /dev/null +++ b/vec/src/blocks.rs @@ -0,0 +1,41 @@ +use crate::{local_prelude::*, vec::BitVec}; + +impl BitVec { + /// Iterator over the underlying blocks of data + #[inline] + pub fn blocks(&self) -> Blocks<'_, B> { + // (2) + Blocks { + iter: self.storage.slice().iter(), + } + } +} + +/// An iterator over the blocks of a `BitVec`. +#[derive(Clone)] +pub struct Blocks<'a, B: 'a + BitBlockOrStore> { + iter: slice::Iter<'a, Block>, +} + +impl Iterator for Blocks<'_, B> { + type Item = Block; + + #[inline] + fn next(&mut self) -> Option> { + self.iter.next().cloned() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl DoubleEndedIterator for Blocks<'_, B> { + #[inline] + fn next_back(&mut self) -> Option> { + self.iter.next_back().cloned() + } +} + +impl ExactSizeIterator for Blocks<'_, B> {} diff --git a/vec/src/blocks_mut.rs b/vec/src/blocks_mut.rs new file mode 100644 index 0000000..6ba641c --- /dev/null +++ b/vec/src/blocks_mut.rs @@ -0,0 +1,12 @@ +use crate::{local_prelude::*, vec::BitVec}; + +impl BitVec { + /// Iterator over mutable refs to the underlying blocks of data. + #[inline] + pub(crate) fn blocks_mut(&mut self) -> BlocksMut<'_, B> { + // (2) + self.storage.slice_mut().iter_mut() + } +} + +pub type BlocksMut<'a, B: BitBlockOrStore> = slice::IterMut<'a, Block>; diff --git a/vec/src/into_iter.rs b/vec/src/into_iter.rs new file mode 100644 index 0000000..1cc8755 --- /dev/null +++ b/vec/src/into_iter.rs @@ -0,0 +1,38 @@ +use crate::{BitVec, local_prelude::*}; + +pub struct IntoIter { + bit_vec: BitVec, + range: ops::Range, +} + +impl Iterator for IntoIter { + type Item = bool; + + #[inline] + fn next(&mut self) -> Option { + self.range.next().map(|i| self.bit_vec.get(i).unwrap()) + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) + } +} + +impl ExactSizeIterator for IntoIter {} + +impl IntoIterator for BitVec { + type Item = bool; + type IntoIter = IntoIter; + + #[inline] + fn into_iter(self) -> IntoIter { + let nbits = self.nbits; + IntoIter { + bit_vec: self, + range: 0..nbits, + } + } +} \ No newline at end of file diff --git a/vec/src/iter.rs b/vec/src/iter.rs new file mode 100644 index 0000000..8becb06 --- /dev/null +++ b/vec/src/iter.rs @@ -0,0 +1,70 @@ +use crate::{local_prelude::*, vec::BitVec}; + +impl BitVec { + /// Returns an iterator over the elements of the vector in order. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]); + /// assert_eq!(bv.iter().filter(|x| *x).count(), 7); + /// ``` + #[inline] + pub fn iter(&self) -> Iter<'_, B> { + self.ensure_invariant(); + Iter { + bit_vec: self, + range: 0..self.nbits, + } + } +} + +/// An iterator for `BitVec`. +#[derive(Clone)] +pub struct Iter<'a, B: 'a + BitBlockOrStore = u32> { + bit_vec: &'a BitVec, + range: ops::Range, +} + +impl Iterator for Iter<'_, B> { + type Item = bool; + + #[inline] + fn next(&mut self) -> Option { + // NB: indexing is slow for extern crates when it has to go through &TRUE or &FALSE + // variables. get is more direct, and unwrap is fine since we're sure of the range. + self.range.next().map(|i| self.bit_vec.get(i).unwrap()) + } + + fn nth(&mut self, n: usize) -> Option { + // This override is used by the compiler to optimize Iterator::skip. + // Without this, the default implementation of Iterator::nth is used, which walks over + // the whole iterator up to n. + self.range.nth(n).and_then(|i| self.bit_vec.get(i)) + } + + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } +} + +impl DoubleEndedIterator for Iter<'_, B> { + #[inline] + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) + } +} + +impl ExactSizeIterator for Iter<'_, B> {} + +impl<'a, B: BitBlockOrStore> IntoIterator for &'a BitVec { + type Item = bool; + type IntoIter = Iter<'a, B>; + + #[inline] + fn into_iter(self) -> Iter<'a, B> { + self.iter() + } +} diff --git a/vec/src/lib.rs b/vec/src/lib.rs index 91cc5fe..72e4d7a 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -97,12 +97,6 @@ #[cfg(any(test, feature = "std"))] #[macro_use] extern crate std; -#[cfg(feature = "std")] -use std::rc::Rc; -#[cfg(feature = "std")] -use std::string::String; -#[cfg(feature = "std")] -use std::vec::Vec; #[cfg(feature = "borsh")] extern crate borsh; @@ -112,2532 +106,68 @@ extern crate miniserde; extern crate nanoserde; #[cfg(feature = "serde")] extern crate serde; -#[cfg(feature = "nanoserde")] -use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; #[cfg(not(feature = "std"))] #[macro_use] extern crate alloc; -#[cfg(not(feature = "std"))] -use alloc::rc::Rc; -#[cfg(not(feature = "std"))] -use alloc::string::String; -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; - -use core::cell::RefCell; -use core::cmp::Ordering; -use core::fmt::{self, Write}; -use core::hash; -use core::iter::FromIterator; -use core::mem; -use core::ops::*; -use core::slice; -use core::{cmp, iter}; - -type BlocksMut<'a, B: BitBlockOrStore> = slice::IterMut<'a, Block>; -type Block = ::Block; - -/// Abstracts over a pile of bits (basically unsigned primitives) -pub trait BitBlock: - Copy - + Add - + Sub - + Shl - + Shr - + Not - + BitAnd - + BitOr - + BitXor - + Rem - + BitOrAssign - + Eq - + Ord - + hash::Hash -{ - /// How many bits it has - const BITS_: usize; - /// How many bytes it has - const BYTES_: usize = Self::BITS_ / 8; - /// Convert a byte into this type (lowest-order bits set) - fn from_byte(byte: u8) -> Self; - /// Count the number of 1's in the bitwise repr - fn count_ones(self) -> usize; - /// Count the number of 0's in the bitwise repr - fn count_zeros(self) -> usize { - Self::BITS_ - self.count_ones() - } - /// Get `0` - const ZERO_: Self; - /// Get `1` - const ONE_: Self; -} - -macro_rules! bound_combination { - ( - type $T:ident: [$($B:tt)*]; - $cfg0:tt => [$($Bounds0:tt)*]; - $( - $cfg:tt => [$($Bounds:tt)*]; - )* - ) => { - #[cfg(not(feature = $cfg0))] - bound_combination!( - type $T: [$($B)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - #[cfg(feature = $cfg0)] - bound_combination!( - type $T: [$($B)* + $($Bounds0)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - }; - ( - type $T:ident: [$($B:tt)*]; - ) => { - type $T: $($B)*; - } -} - -pub trait BitBlockOrStore { - bound_combination!( - type Store: [BitStore]; - "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; - "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; - "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; - "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; - ); - - const BITS: usize = ::Block::BITS_; - const BYTES: usize = ::Block::BYTES_; - const ONE: ::Block = ::Block::ONE_; - const ZERO: ::Block = ::Block::ZERO_; -} - -macro_rules! impl_combination { - ( - type $T:ty: [$($B:tt)*]; - $cfg0:tt => [$($Bounds0:tt)*]; - $( - $cfg:tt => [$($Bounds:tt)*]; - )* - ) => { - #[cfg(not(feature = $cfg0))] - impl_combination!( - type $T: [$($B)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - #[cfg(feature = $cfg0)] - impl_combination!( - type $T: [$($B)* + $($Bounds0)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - }; - ( - type $T:ty: [$($B:tt)*]; - ) => { - impl BitBlockOrStore for Vec { - type Store = Self; - } - } -} - -impl_combination!( - type Vec: [BitBlock]; - "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; - "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; - "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; - "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; -); - -#[allow(clippy::len_without_is_empty)] -pub trait BitStore: Clone { - type Block: BitBlock; - type Alloc: Default; - fn new_in(alloc: Self::Alloc) -> Self; - fn slice(&self) -> &[Self::Block]; - fn slice_mut(&mut self) -> &mut [Self::Block]; - fn len(&self) -> usize { - self.slice().len() - } - fn pop(&mut self) -> Option; - fn drain>(&mut self, range: R) -> impl Iterator; - fn capacity(&self) -> usize; - fn append(&mut self, other: &mut Self); - fn reserve(&mut self, additional: usize); - fn push(&mut self, value: Self::Block); - fn split_off(&mut self, at: usize) -> Self; - fn truncate(&mut self, len: usize); - fn reserve_exact(&mut self, len: usize); - fn shrink_to_fit(&mut self); - fn extend(&mut self, iter: T) - where - T: IntoIterator; - fn with_capacity(capacity: usize) -> Self; - fn clear(&mut self); - fn with_capacity_in(capacity: usize, alloc: Self::Alloc) -> Self; -} - -#[cfg(not(feature = "allocator_api"))] -impl BitStore for Vec { - type Block = T; - type Alloc = (); - - fn new_in(_alloc: Self::Alloc) -> Self { - Vec::new() - } - - fn slice(&self) -> &[Self::Block] { - &self[..] - } - - fn slice_mut(&mut self) -> &mut [Self::Block] { - &mut self[..] - } - - fn pop(&mut self) -> Option { - Vec::pop(self) - } - - fn drain>(&mut self, range: R) -> impl Iterator { - Vec::drain(self, range) - } - - fn capacity(&self) -> usize { - Vec::capacity(self) - } - - fn append(&mut self, other: &mut Self) { - Vec::append(self, other); - } - - fn reserve(&mut self, additional: usize) { - Vec::reserve(self, additional); - } - - fn push(&mut self, value: Self::Block) { - Vec::push(self, value); - } - - fn split_off(&mut self, at: usize) -> Self { - Vec::split_off(self, at) - } - - fn truncate(&mut self, len: usize) { - Vec::truncate(self, len); - } - - fn reserve_exact(&mut self, len: usize) { - Vec::reserve_exact(self, len); - } - - fn shrink_to_fit(&mut self) { - Vec::shrink_to_fit(self); - } - - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - Extend::extend(self, iter); - } - - fn with_capacity_in(capacity: usize, _alloc: Self::Alloc) -> Self { - Vec::with_capacity(capacity) - } - - fn with_capacity(capacity: usize) -> Self { - Vec::with_capacity(capacity) - } - - fn clear(&mut self) { - Vec::clear(self) - } -} - -#[cfg(feature = "allocator_api")] -impl BitStore for Vec -where - A: core::alloc::Allocator + Clone + Default, -{ - type Block = T; - type Alloc = A; - - fn new_in(alloc: Self::Alloc) -> Self { - Vec::new_in(alloc) - } - - fn slice(&self) -> &[Self::Block] { - &self[..] - } - - fn slice_mut(&mut self) -> &mut [Self::Block] { - &mut self[..] - } - - fn pop(&mut self) -> Option { - Vec::pop(self) - } - - fn drain>(&mut self, range: R) -> impl Iterator { - Vec::drain(self, range) - } - - fn capacity(&self) -> usize { - Vec::capacity(self) - } - - fn append(&mut self, other: &mut Self) { - Vec::append(self, other); - } - - fn reserve(&mut self, additional: usize) { - Vec::reserve(self, additional); - } - - fn push(&mut self, value: Self::Block) { - Vec::push(self, value); - } - - fn split_off(&mut self, at: usize) -> Self { - Vec::split_off(self, at) - } - - fn truncate(&mut self, len: usize) { - Vec::truncate(self, len); - } - - fn reserve_exact(&mut self, len: usize) { - Vec::reserve_exact(self, len); - } - - fn shrink_to_fit(&mut self) { - Vec::shrink_to_fit(self); - } - - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - Extend::extend(self, iter); - } - - fn with_capacity_in(capacity: usize, alloc: A) -> Self { - Vec::with_capacity_in(capacity, alloc) - } - - fn with_capacity(capacity: usize) -> Self { - Vec::with_capacity_in(capacity, A::default()) - } -} - -#[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] -impl BitBlockOrStore for smallvec::SmallVec -where - A::Item: BitBlock, -{ - type Store = Self; -} - -#[cfg(feature = "smallvec")] -impl BitStore for smallvec::SmallVec -where - A::Item: BitBlock, -{ - type Block = A::Item; - type Alloc = (); - - fn slice(&self) -> &[Self::Block] { - &self[..] - } - - fn slice_mut(&mut self) -> &mut [Self::Block] { - &mut self[..] - } - - fn pop(&mut self) -> Option { - self.pop() - } - - fn drain>(&mut self, range: R) -> impl Iterator { - self.drain(range) - } - fn capacity(&self) -> usize { - self.capacity() - } - - fn append(&mut self, other: &mut Self) { - self.append(other); - } - - fn reserve(&mut self, additional: usize) { - self.reserve(additional); - } - - fn push(&mut self, value: Self::Block) { - self.push(value); - } - - fn split_off(&mut self, at: usize) -> Self { - // TODO - self.to_vec().split_off(at).into() - } - - fn truncate(&mut self, len: usize) { - self.truncate(len); - } - - fn reserve_exact(&mut self, len: usize) { - self.reserve_exact(len); - } - - fn shrink_to_fit(&mut self) { - self.shrink_to_fit(); - } - - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - iter::Extend::extend(self, iter); - } - - fn with_capacity(capacity: usize) -> Self { - smallvec::SmallVec::with_capacity(capacity) - } - - fn clear(&mut self) { - self.clear(); - } - - fn new_in(_alloc: ()) -> Self { - smallvec::SmallVec::new() - } - - fn with_capacity_in(capacity: usize, _alloc: ()) -> Self { - smallvec::SmallVec::with_capacity(capacity) - } -} - -macro_rules! bit_block_impl { - ($(($t: ident, $size: expr)),*) => ($( - impl BitBlock for $t { - const BITS_: usize = $size; - #[inline] - fn from_byte(byte: u8) -> Self { $t::from(byte) } - #[inline] - fn count_ones(self) -> usize { self.count_ones() as usize } - #[inline] - fn count_zeros(self) -> usize { self.count_zeros() as usize } - const ONE_: Self = 1; - const ZERO_: Self = 0; - } - - impl BitBlockOrStore for $t { - type Store = Vec; - } - )*) -} - -bit_block_impl! { - (u8, 8), - (u16, 16), - (u32, 32), - (u64, 64), - (usize, usize::BITS as usize) -} +mod block; +mod block_or_store; +mod blocks; +mod blocks_mut; +mod into_iter; +mod iter; +mod smart_mut; +mod store; +mod util; +mod vec; + +pub use block::BitBlock; +pub use block_or_store::BitBlockOrStore; +pub use blocks::Blocks; +pub use blocks_mut::BlocksMut; +pub use into_iter::IntoIter; +pub use iter::Iter; +pub use smart_mut::{IterMut, MutBorrowedBit}; +pub use store::BitStore; +pub use vec::BitVec; + +mod local_prelude { + #[cfg(not(feature = "std"))] + pub use alloc::rc::Rc; + #[cfg(not(feature = "std"))] + pub use alloc::string::String; + #[cfg(not(feature = "std"))] + pub use alloc::vec::Vec; + + #[cfg(feature = "std")] + pub use std::rc::Rc; + #[cfg(feature = "std")] + pub use std::string::String; + #[cfg(feature = "std")] + pub use std::vec::Vec; + + pub use core::cell::RefCell; + pub use core::cmp::Ordering; + pub use core::fmt::Write; + pub use core::iter::FromIterator; + pub use core::{cmp, fmt, hash, iter, mem, ops, slice}; -fn reverse_bits(byte: u8) -> u8 { - let mut result = 0; - for i in 0..u8::BITS { - result |= ((byte >> i) & 1) << (u8::BITS - 1 - i); - } - result + #[cfg(feature = "nanoserde")] + pub use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; + + pub use crate::block::BitBlock; + pub use crate::block_or_store::BitBlockOrStore; + #[cfg(test)] + pub use crate::iter::Iter; + pub use crate::store::BitStore; + pub(crate) use crate::util::Block; } -static TRUE: bool = true; -static FALSE: bool = false; - #[cfg(feature = "nanoserde")] #[allow(dead_code)] type B = u32; -/// The bitvector type. -/// -/// # Examples -/// -/// ``` -/// use bit_vec::BitVec; -/// -/// let mut bv = BitVec::from_elem(10, false); -/// -/// // insert all primes less than 10 -/// bv.set(2, true); -/// bv.set(3, true); -/// bv.set(5, true); -/// bv.set(7, true); -/// println!("{:?}", bv); -/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); -/// -/// // flip all values in bitvector, producing non-primes less than 10 -/// bv.negate(); -/// println!("{:?}", bv); -/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); -/// -/// // reset bitvector to empty -/// bv.fill(false); -/// println!("{:?}", bv); -/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); -/// ``` -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshDeserialize, borsh::BorshSerialize) -)] -#[cfg_attr( - feature = "miniserde", - derive(miniserde::Deserialize, miniserde::Serialize) -)] -#[cfg_attr( - feature = "nanoserde", - derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) -)] -pub struct BitVec { - /// Internal representation of the bit vector - storage: B::Store, - /// The number of valid bits in the internal representation - nbits: usize, -} - -// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing) -impl Index for BitVec { - type Output = bool; - - #[inline] - fn index(&self, i: usize) -> &bool { - if self.get(i).expect("index out of bounds") { - &TRUE - } else { - &FALSE - } - } -} - -/// Computes how many blocks are needed to store that many bits -fn blocks_for_bits(bits: usize) -> usize { - // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we - // reserve enough. But if we want exactly a multiple of 32, this will actually allocate - // one too many. So we need to check if that's the case. We can do that by computing if - // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically - // superior modulo operator on a power of two to this. - // - // Note that we can technically avoid this branch with the expression - // `(nbits + U32_BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. - if bits % B::BITS == 0 { - bits / B::BITS - } else { - bits / B::BITS + 1 - } -} - -/// Computes the bitmask for the final word of the vector -fn mask_for_bits(bits: usize) -> Block { - // Note especially that a perfect multiple of U32_BITS should mask all 1s. - (!B::ZERO) >> ((B::BITS - bits % B::BITS) % B::BITS) -} - -impl BitVec { - /// Creates an empty `BitVec`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// let mut bv = BitVec::new(); - /// ``` - #[inline] - pub fn new() -> Self { - Default::default() - } - - /// Creates a `BitVec` that holds `nbits` elements, setting each element - /// to `bit`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(10, false); - /// assert_eq!(bv.len(), 10); - /// for x in bv.iter() { - /// assert_eq!(x, false); - /// } - /// ``` - #[inline] - pub fn from_elem(len: usize, bit: bool) -> Self { - BitVec::::from_elem_general(len, bit) - } - - /// Constructs a new, empty `BitVec` with the specified capacity. - /// - /// The bitvector will be able to hold at least `capacity` bits without - /// reallocating. If `capacity` is 0, it will not allocate. - /// - /// It is important to note that this function does not specify the - /// *length* of the returned bitvector, but only the *capacity*. - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - BitVec::::with_capacity_general(capacity) - } - - /// Transforms a byte-vector into a `BitVec`. Each byte becomes eight bits, - /// with the most significant bits of each byte coming first. Each - /// bit becomes `true` if equal to 1 or `false` if equal to 0. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::from_bytes(&[0b10100000, 0b00010010]); - /// assert!(bv.eq_vec(&[true, false, true, false, - /// false, false, false, false, - /// false, false, false, true, - /// false, false, true, false])); - /// ``` - pub fn from_bytes(bytes: &[u8]) -> Self { - BitVec::::from_bytes_general(bytes) - } - - /// Creates a `BitVec` of the specified length where the value at each index - /// is `f(index)`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::from_fn(5, |i| { i % 2 == 0 }); - /// assert!(bv.eq_vec(&[true, false, true, false, true])); - /// ``` - #[inline] - pub fn from_fn(len: usize, f: F) -> Self - where - F: FnMut(usize) -> bool, - { - BitVec::::from_fn_general(len, f) - } -} - -impl BitVec { - /// Creates an empty `BitVec`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// let mut bv = BitVec::::new_general(); - /// ``` - #[inline] - pub fn new_general() -> Self { - Default::default() - } - - /// Creates an empty `BitVec` using the provided allocator. - #[inline] - pub fn new_general_in(alloc: ::Alloc) -> Self { - Self::with_capacity_general_in(0, alloc) - } - - /// Creates a `BitVec` that holds `nbits` elements, setting each element - /// to `bit`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::::from_elem_general(10, false); - /// assert_eq!(bv.len(), 10); - /// for x in bv.iter() { - /// assert_eq!(x, false); - /// } - /// ``` - #[inline] - pub fn from_elem_general(len: usize, bit: bool) -> Self { - let nblocks = blocks_for_bits::(len); - let mut storage: B::Store = B::Store::with_capacity(nblocks); - storage.extend(iter::repeat_n( - if bit { !B::ZERO } else { B::ZERO }, - nblocks, - )); - let mut bit_vec = BitVec { - storage, - nbits: len, - }; - bit_vec.fix_last_block(); - bit_vec - } - - /// Constructs a new, empty `BitVec` with the specified capacity. - /// - /// The bitvector will be able to hold at least `capacity` bits without - /// reallocating. If `capacity` is 0, it will not allocate. - /// - /// It is important to note that this function does not specify the - /// *length* of the returned bitvector, but only the *capacity*. - #[inline] - pub fn with_capacity_general(capacity: usize) -> Self { - BitVec { - storage: B::Store::with_capacity(blocks_for_bits::(capacity)), - nbits: 0, - } - } - - /// Constructs a new, empty `BitVec` with the specified capacity. - /// - /// The bitvector will be able to hold at least `capacity` bits without - /// reallocating. If `capacity` is 0, it will not allocate. - /// - /// It is important to note that this function does not specify the - /// *length* of the returned bitvector, but only the *capacity*. - #[inline] - pub fn with_capacity_general_in(capacity: usize, alloc: ::Alloc) -> Self { - BitVec { - storage: B::Store::with_capacity_in(blocks_for_bits::(capacity), alloc), - nbits: 0, - } - } - - /// Transforms a byte-vector into a `BitVec`. Each byte becomes eight bits, - /// with the most significant bits of each byte coming first. Each - /// bit becomes `true` if equal to 1 or `false` if equal to 0. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::::from_bytes_general(&[0b10100000, 0b00010010]); - /// assert!(bv.eq_vec(&[true, false, true, false, - /// false, false, false, false, - /// false, false, false, true, - /// false, false, true, false])); - /// ``` - pub fn from_bytes_general(bytes: &[u8]) -> Self { - let len = bytes - .len() - .checked_mul(u8::BITS as usize) - .expect("capacity overflow"); - let mut bit_vec = BitVec::::with_capacity_general(len); - let complete_words = bytes.len() / B::BYTES; - let extra_bytes = bytes.len() % B::BYTES; - - bit_vec.nbits = len; - - for i in 0..complete_words { - let mut accumulator = B::ZERO; - for idx in 0..B::BYTES { - accumulator |= ::Block::from_byte(reverse_bits( - bytes[i * B::BYTES + idx], - )) << (idx * 8) - } - bit_vec.storage.push(accumulator); - } - - if extra_bytes > 0 { - let mut last_word = B::ZERO; - for (i, &byte) in bytes[complete_words * B::BYTES..].iter().enumerate() { - last_word |= - ::Block::from_byte(reverse_bits(byte)) << (i * 8); - } - bit_vec.storage.push(last_word); - } - - bit_vec - } - - /// Creates a `BitVec` of the specified length where the value at each index - /// is `f(index)`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::::from_fn_general(5, |i| { i % 2 == 0 }); - /// assert!(bv.eq_vec(&[true, false, true, false, true])); - /// ``` - #[inline] - pub fn from_fn_general(len: usize, mut f: F) -> Self - where - F: FnMut(usize) -> bool, - { - let mut bit_vec = BitVec::from_elem_general(len, false); - for i in 0..len { - bit_vec.set(i, f(i)); - } - bit_vec - } - - /// Applies the given operation to the blocks of self and other, and sets - /// self to be the result. This relies on the caller not to corrupt the - /// last word. - #[inline] - fn process(&mut self, other: &BitVec, mut op: F) -> bool - where - F: FnMut(Block, Block) -> Block, - { - assert_eq!(self.len(), other.len()); - debug_assert_eq!(self.storage.len(), other.storage.len()); - let mut changed_bits = B::ZERO; - for (a, b) in self.blocks_mut().zip(other.blocks()) { - let w = op(*a, b); - changed_bits |= *a ^ w; - *a = w; - } - changed_bits != B::ZERO - } - - /// Iterator over mutable refs to the underlying blocks of data. - #[inline] - fn blocks_mut(&mut self) -> BlocksMut<'_, B> { - // (2) - self.storage.slice_mut().iter_mut() - } - - /// Iterator over the underlying blocks of data - #[inline] - pub fn blocks(&self) -> Blocks<'_, B> { - // (2) - Blocks { - iter: self.storage.slice().iter(), - } - } - - /// Exposes the raw block storage of this `BitVec`. - /// - /// Only really intended for `BitSet`. - #[inline] - pub fn storage(&self) -> &[Block] { - self.storage.slice() - } - - /// Exposes the raw block storage of this `BitVec`. - /// - /// # Safety - /// - /// Can probably cause unsafety. Only really intended for `BitSet`. - #[inline] - pub unsafe fn storage_mut(&mut self) -> &mut B::Store { - &mut self.storage - } - - /// Helper for procedures involving spare space in the last block. - #[inline] - fn last_block_with_mask(&self) -> Option<(Block, Block)> { - let extra_bits = self.len() % B::BITS; - if extra_bits > 0 { - let mask = (B::ONE << extra_bits) - B::ONE; - let storage_len = self.storage.len(); - Some((self.storage.slice()[storage_len - 1], mask)) - } else { - None - } - } - - /// Helper for procedures involving spare space in the last block. - #[inline] - fn last_block_mut_with_mask(&mut self) -> Option<(&mut Block, Block)> { - let extra_bits = self.len() % B::BITS; - if extra_bits > 0 { - let mask = (B::ONE << extra_bits) - B::ONE; - let storage_len = self.storage.len(); - Some((&mut self.storage.slice_mut()[storage_len - 1], mask)) - } else { - None - } - } - - /// An operation might screw up the unused bits in the last block of the - /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up. - fn fix_last_block(&mut self) { - if let Some((last_block, used_bits)) = self.last_block_mut_with_mask() { - *last_block = *last_block & used_bits; - } - } - - /// Operations such as change detection for xnor, nor and nand are easiest - /// to implement when unused bits are all set to 1s. - fn fix_last_block_with_ones(&mut self) { - if let Some((last_block, used_bits)) = self.last_block_mut_with_mask() { - *last_block |= !used_bits; - } - } - - /// Check whether last block's invariant is fine. - fn is_last_block_fixed(&self) -> bool { - if let Some((last_block, used_bits)) = self.last_block_with_mask() { - last_block & !used_bits == B::ZERO - } else { - true - } - } - - /// Ensure the invariant for the last block. - /// - /// An operation might screw up the unused bits in the last block of the - /// `BitVec`. - /// - /// This method fails in case the last block is not fixed. The check - /// is skipped outside testing. - #[inline] - fn ensure_invariant(&self) { - if cfg!(test) { - debug_assert!(self.is_last_block_fixed()); - } - } - - /// Retrieves the value at index `i`, or `None` if the index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::from_bytes(&[0b01100000]); - /// assert_eq!(bv.get(0), Some(false)); - /// assert_eq!(bv.get(1), Some(true)); - /// assert_eq!(bv.get(100), None); - /// - /// // Can also use array indexing - /// assert_eq!(bv[1], true); - /// ``` - #[inline] - pub fn get(&self, i: usize) -> Option { - self.ensure_invariant(); - if i >= self.nbits { - return None; - } - let w = i / B::BITS; - let b = i % B::BITS; - self.storage - .slice() - .get(w) - .map(|&block| (block & (B::ONE << b)) != B::ZERO) - } - - /// Retrieves the value at index `i`, without doing bounds checking. - /// - /// For a safe alternative, see `get`. - /// - /// # Safety - /// - /// Calling this method with an out-of-bounds index is undefined behavior - /// even if the resulting reference is not used. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::from_bytes(&[0b01100000]); - /// unsafe { - /// assert_eq!(bv.get_unchecked(0), false); - /// assert_eq!(bv.get_unchecked(1), true); - /// } - /// ``` - #[inline] - pub unsafe fn get_unchecked(&self, i: usize) -> bool { - self.ensure_invariant(); - let w = i / B::BITS; - let b = i % B::BITS; - let block = *self.storage.slice().get_unchecked(w); - block & (B::ONE << b) != B::ZERO - } - - /// Retrieves a smart pointer to the value at index `i`, or `None` if the index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_bytes(&[0b01100000]); - /// *bv.get_mut(0).unwrap() = true; - /// *bv.get_mut(1).unwrap() = false; - /// assert!(bv.get_mut(100).is_none()); - /// assert_eq!(bv, BitVec::from_bytes(&[0b10100000])); - /// ``` - #[inline] - pub fn get_mut(&mut self, index: usize) -> Option> { - self.get(index).map(move |value| MutBorrowedBit { - vec: Rc::new(RefCell::new(self)), - index, - #[cfg(debug_assertions)] - old_value: value, - new_value: value, - }) - } - - /// Retrieves a smart pointer to the value at index `i`, without doing bounds checking. - /// - /// # Safety - /// - /// Calling this method with out-of-bounds `index` may cause undefined behavior even when - /// the result is not used. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_bytes(&[0b01100000]); - /// unsafe { - /// *bv.get_unchecked_mut(0) = true; - /// *bv.get_unchecked_mut(1) = false; - /// } - /// assert_eq!(bv, BitVec::from_bytes(&[0b10100000])); - /// ``` - #[inline] - pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> MutBorrowedBit<'_, B> { - let value = self.get_unchecked(index); - MutBorrowedBit { - #[cfg(debug_assertions)] - old_value: value, - new_value: value, - vec: Rc::new(RefCell::new(self)), - index, - } - } - - /// Sets the value of a bit at an index `i`. - /// - /// # Panics - /// - /// Panics if `i` is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(5, false); - /// bv.set(3, true); - /// assert_eq!(bv[3], true); - /// ``` - #[inline] - pub fn set(&mut self, i: usize, x: bool) { - self.ensure_invariant(); - assert!( - i < self.nbits, - "index out of bounds: {:?} >= {:?}", - i, - self.nbits - ); - let w = i / B::BITS; - let b = i % B::BITS; - let flag = B::ONE << b; - let val = if x { - self.storage.slice()[w] | flag - } else { - self.storage.slice()[w] & !flag - }; - self.storage.slice_mut()[w] = val; - } - - /// Sets all bits to 1. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let before = 0b01100000; - /// let after = 0b11111111; - /// - /// let mut bv = BitVec::from_bytes(&[before]); - /// bv.set_all(); - /// assert_eq!(bv, BitVec::from_bytes(&[after])); - /// ``` - #[inline] - #[deprecated(since = "0.9.0", note = "please use `.fill(true)` instead")] - pub fn set_all(&mut self) { - self.ensure_invariant(); - for w in self.storage.slice_mut() { - *w = !B::ZERO; - } - self.fix_last_block(); - } - - /// Flips all bits. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let before = 0b01100000; - /// let after = 0b10011111; - /// - /// let mut bv = BitVec::from_bytes(&[before]); - /// bv.negate(); - /// assert_eq!(bv, BitVec::from_bytes(&[after])); - /// ``` - #[inline] - pub fn negate(&mut self) { - self.ensure_invariant(); - for w in self.storage.slice_mut() { - *w = !*w; - } - self.fix_last_block(); - } - - /// Calculates the union of two bitvectors. This acts like the bitwise `or` - /// function. - /// - /// Sets `self` to the union of `self` and `other`. Both bitvectors must be - /// the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different lengths. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100100; - /// let b = 0b01011010; - /// let res = 0b01111110; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.union(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[deprecated(since = "0.7.0", note = "Please use the 'or' function instead")] - #[inline] - pub fn union(&mut self, other: &Self) -> bool { - self.or(other) - } - - /// Calculates the intersection of two bitvectors. This acts like the - /// bitwise `and` function. - /// - /// Sets `self` to the intersection of `self` and `other`. Both bitvectors - /// must be the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different lengths. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100100; - /// let b = 0b01011010; - /// let res = 0b01000000; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.intersect(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[deprecated(since = "0.7.0", note = "Please use the 'and' function instead")] - #[inline] - pub fn intersect(&mut self, other: &Self) -> bool { - self.and(other) - } - - /// Calculates the bitwise `or` of two bitvectors. - /// - /// Sets `self` to the union of `self` and `other`. Both bitvectors must be - /// the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different lengths. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100100; - /// let b = 0b01011010; - /// let res = 0b01111110; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.or(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[inline] - pub fn or(&mut self, other: &Self) -> bool { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - self.process(other, |w1, w2| w1 | w2) - } - - /// Calculates the bitwise `and` of two bitvectors. - /// - /// Sets `self` to the intersection of `self` and `other`. Both bitvectors - /// must be the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different lengths. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100100; - /// let b = 0b01011010; - /// let res = 0b01000000; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.and(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[inline] - pub fn and(&mut self, other: &Self) -> bool { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - self.process(other, |w1, w2| w1 & w2) - } - - /// Calculates the difference between two bitvectors. - /// - /// Sets each element of `self` to the value of that element minus the - /// element of `other` at the same index. Both bitvectors must be the same - /// length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different length. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100100; - /// let b = 0b01011010; - /// let a_b = 0b00100100; // a - b - /// let b_a = 0b00011010; // b - a - /// - /// let mut bva = BitVec::from_bytes(&[a]); - /// let bvb = BitVec::from_bytes(&[b]); - /// - /// assert!(bva.difference(&bvb)); - /// assert_eq!(bva, BitVec::from_bytes(&[a_b])); - /// - /// let bva = BitVec::from_bytes(&[a]); - /// let mut bvb = BitVec::from_bytes(&[b]); - /// - /// assert!(bvb.difference(&bva)); - /// assert_eq!(bvb, BitVec::from_bytes(&[b_a])); - /// ``` - #[inline] - pub fn difference(&mut self, other: &Self) -> bool { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - self.process(other, |w1, w2| w1 & !w2) - } - - /// Calculates the xor of two bitvectors. - /// - /// Sets `self` to the xor of `self` and `other`. Both bitvectors must be - /// the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different length. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100110; - /// let b = 0b01010100; - /// let res = 0b00110010; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.xor(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[inline] - pub fn xor(&mut self, other: &Self) -> bool { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - self.process(other, |w1, w2| w1 ^ w2) - } - - /// Calculates the nand of two bitvectors. - /// - /// Sets `self` to the nand of `self` and `other`. Both bitvectors must be - /// the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different length. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100110; - /// let b = 0b01010100; - /// let res = 0b10111011; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.nand(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[inline] - pub fn nand(&mut self, other: &Self) -> bool { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - self.fix_last_block_with_ones(); - let result = self.process(other, |w1, w2| !(w1 & w2)); - self.fix_last_block(); - result - } - - /// Calculates the nor of two bitvectors. - /// - /// Sets `self` to the nor of `self` and `other`. Both bitvectors must be - /// the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different length. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100110; - /// let b = 0b01010100; - /// let res = 0b10001001; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.nor(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[inline] - pub fn nor(&mut self, other: &Self) -> bool { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - self.fix_last_block_with_ones(); - let result = self.process(other, |w1, w2| !(w1 | w2)); - self.fix_last_block(); - result - } - - /// Calculates the xnor of two bitvectors. - /// - /// Sets `self` to the xnor of `self` and `other`. Both bitvectors must be - /// the same length. Returns `true` if `self` changed. - /// - /// # Panics - /// - /// Panics if the bitvectors are of different length. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let a = 0b01100110; - /// let b = 0b01010100; - /// let res = 0b11001101; - /// - /// let mut a = BitVec::from_bytes(&[a]); - /// let b = BitVec::from_bytes(&[b]); - /// - /// assert!(a.xnor(&b)); - /// assert_eq!(a, BitVec::from_bytes(&[res])); - /// ``` - #[inline] - pub fn xnor(&mut self, other: &Self) -> bool { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - self.fix_last_block_with_ones(); - let result = self.process(other, |w1, w2| !(w1 ^ w2)); - self.fix_last_block(); - result - } - - /// Returns `true` if all bits are 1. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(5, true); - /// assert_eq!(bv.all(), true); - /// - /// bv.set(1, false); - /// assert_eq!(bv.all(), false); - /// ``` - #[inline] - pub fn all(&self) -> bool { - self.ensure_invariant(); - let mut last_word = !B::ZERO; - // Check that every block but the last is all-ones... - self.blocks().all(|elem| { - let tmp = last_word; - last_word = elem; - tmp == !B::ZERO - // and then check the last one has enough ones - }) && (last_word == mask_for_bits::(self.nbits)) - } - - /// Returns the number of ones in the binary representation. - /// - /// Also known as the - /// [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight). - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(100, true); - /// assert_eq!(bv.count_ones(), 100); - /// - /// bv.set(50, false); - /// assert_eq!(bv.count_ones(), 99); - /// ``` - #[inline] - pub fn count_ones(&self) -> u64 { - self.ensure_invariant(); - // Add the number of ones of each block. - self.blocks().map(|elem| elem.count_ones() as u64).sum() - } - - /// Returns the number of zeros in the binary representation. - /// - /// Also known as the opposite of - /// [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight). - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(100, false); - /// assert_eq!(bv.count_zeros(), 100); - /// - /// bv.set(50, true); - /// assert_eq!(bv.count_zeros(), 99); - /// ``` - #[inline] - pub fn count_zeros(&self) -> u64 { - self.ensure_invariant(); - // Add the number of zeros of each block. - let extra_zeros = (B::BITS - (self.len() % B::BITS)) % B::BITS; - self.blocks() - .map(|elem| elem.count_zeros() as u64) - .sum::() - - extra_zeros as u64 - } - - /// Returns an iterator over the elements of the vector in order. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]); - /// assert_eq!(bv.iter().filter(|x| *x).count(), 7); - /// ``` - #[inline] - pub fn iter(&self) -> Iter<'_, B> { - self.ensure_invariant(); - Iter { - bit_vec: self, - range: 0..self.nbits, - } - } - - /// Returns an iterator over mutable smart pointers to the elements of the vector in order. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut a = BitVec::from_elem(8, false); - /// a.iter_mut().enumerate().for_each(|(index, mut bit)| { - /// *bit = if index % 2 == 1 { true } else { false }; - /// }); - /// assert!(a.eq_vec(&[ - /// false, true, false, true, false, true, false, true - /// ])); - /// ``` - #[inline] - pub fn iter_mut(&mut self) -> IterMut<'_, B> { - self.ensure_invariant(); - let nbits = self.nbits; - IterMut { - vec: Rc::new(RefCell::new(self)), - range: 0..nbits, - } - } - - /// Moves all bits from `other` into `Self`, leaving `other` empty. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut a = BitVec::from_bytes(&[0b10000000]); - /// let mut b = BitVec::from_bytes(&[0b01100001]); - /// - /// a.append(&mut b); - /// - /// assert_eq!(a.len(), 16); - /// assert_eq!(b.len(), 0); - /// assert!(a.eq_vec(&[true, false, false, false, false, false, false, false, - /// false, true, true, false, false, false, false, true])); - /// ``` - pub fn append(&mut self, other: &mut Self) { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - - let b = self.len() % B::BITS; - let o = other.len() % B::BITS; - let will_overflow = (b + o > B::BITS) || (o == 0 && b != 0); - - self.nbits += other.len(); - other.nbits = 0; - - if b == 0 { - self.storage.append(&mut other.storage); - } else { - self.storage.reserve(other.storage.len()); - - for block in other.storage.drain(..) { - { - let last = self.storage.slice_mut().last_mut().unwrap(); - *last |= block << b; - } - self.storage.push(block >> (B::BITS - b)); - } - - // Remove additional block if the last shift did not overflow - if !will_overflow { - self.storage.pop(); - } - } - } - - /// Splits the `BitVec` into two at the given bit, - /// retaining the first half in-place and returning the second one. - /// - /// # Panics - /// - /// Panics if `at` is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// let mut a = BitVec::new(); - /// a.push(true); - /// a.push(false); - /// a.push(false); - /// a.push(true); - /// - /// let b = a.split_off(2); - /// - /// assert_eq!(a.len(), 2); - /// assert_eq!(b.len(), 2); - /// assert!(a.eq_vec(&[true, false])); - /// assert!(b.eq_vec(&[false, true])); - /// ``` - pub fn split_off(&mut self, at: usize) -> Self { - self.ensure_invariant(); - assert!(at <= self.len(), "`at` out of bounds"); - - let mut other = BitVec::::new_general(); - - if at == 0 { - mem::swap(self, &mut other); - return other; - } else if at == self.len() { - return other; - } - - let w = at / B::BITS; - let b = at % B::BITS; - other.nbits = self.nbits - at; - self.nbits = at; - if b == 0 { - // Split at block boundary - other.storage = self.storage.split_off(w); - } else { - other.storage.reserve(self.storage.len() - w); - - { - let mut iter = self.storage.slice()[w..].iter(); - let mut last = *iter.next().unwrap(); - for &cur in iter { - other.storage.push((last >> b) | (cur << (B::BITS - b))); - last = cur; - } - other.storage.push(last >> b); - } - - self.storage.truncate(w + 1); - self.fix_last_block(); - } - - other - } - - /// Returns `true` if all bits are 0. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(10, false); - /// assert_eq!(bv.none(), true); - /// - /// bv.set(3, true); - /// assert_eq!(bv.none(), false); - /// ``` - #[inline] - pub fn none(&self) -> bool { - self.blocks().all(|w| w == B::ZERO) - } - - /// Returns `true` if any bit is 1. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(10, false); - /// assert_eq!(bv.any(), false); - /// - /// bv.set(3, true); - /// assert_eq!(bv.any(), true); - /// ``` - #[inline] - pub fn any(&self) -> bool { - !self.none() - } - - /// Organises the bits into bytes, such that the first bit in the - /// `BitVec` becomes the high-order bit of the first byte. If the - /// size of the `BitVec` is not a multiple of eight then trailing bits - /// will be filled-in with `false`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(3, true); - /// bv.set(1, false); - /// - /// assert_eq!(bv.to_bytes(), [0b10100000]); - /// - /// let mut bv = BitVec::from_elem(9, false); - /// bv.set(2, true); - /// bv.set(8, true); - /// - /// assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); - /// ``` - pub fn to_bytes(&self) -> Vec { - static REVERSE_TABLE: [u8; 256] = { - let mut tbl = [0u8; 256]; - let mut i: u8 = 0; - loop { - tbl[i as usize] = i.reverse_bits(); - if i == 255 { - break; - } - i += 1; - } - tbl - }; - self.ensure_invariant(); - - let len = self.nbits / 8 + if self.nbits % 8 == 0 { 0 } else { 1 }; - let mut result = Vec::with_capacity(len); - - for byte_idx in 0..len { - let mut byte = 0u8; - for bit_idx in 0..8 { - let offset = byte_idx * 8 + bit_idx; - if offset < self.nbits && self[offset] { - byte |= 1 << bit_idx; - } - } - result.push(REVERSE_TABLE[byte as usize]); - } - - result - } - - /// Compares a `BitVec` to a slice of `bool`s. - /// Both the `BitVec` and slice must have the same length. - /// - /// # Panics - /// - /// Panics if the `BitVec` and slice are of different length. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let bv = BitVec::from_bytes(&[0b10100000]); - /// - /// assert!(bv.eq_vec(&[true, false, true, false, - /// false, false, false, false])); - /// ``` - #[inline] - pub fn eq_vec(&self, v: &[bool]) -> bool { - assert_eq!(self.nbits, v.len()); - self.iter().zip(v.iter().cloned()).all(|(b1, b2)| b1 == b2) - } - - /// Shortens a `BitVec`, dropping excess elements. - /// - /// If `len` is greater than the vector's current length, this has no - /// effect. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_bytes(&[0b01001011]); - /// bv.truncate(2); - /// assert!(bv.eq_vec(&[false, true])); - /// ``` - #[inline] - pub fn truncate(&mut self, len: usize) { - self.ensure_invariant(); - if len < self.len() { - self.nbits = len; - // This fixes (2). - self.storage.truncate(blocks_for_bits::(len)); - self.fix_last_block(); - } - } - - /// Reserves capacity for at least `additional` more bits to be inserted in the given - /// `BitVec`. The collection may reserve more space to avoid frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new capacity overflows `usize`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(3, false); - /// bv.reserve(10); - /// assert_eq!(bv.len(), 3); - /// assert!(bv.capacity() >= 13); - /// ``` - #[inline] - pub fn reserve(&mut self, additional: usize) { - let desired_cap = self - .len() - .checked_add(additional) - .expect("capacity overflow"); - let storage_len = self.storage.len(); - if desired_cap > self.capacity() { - self.storage - .reserve(blocks_for_bits::(desired_cap) - storage_len); - } - } - - /// Reserves the minimum capacity for exactly `additional` more bits to be inserted in the - /// given `BitVec`. Does nothing if the capacity is already sufficient. - /// - /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future - /// insertions are expected. - /// - /// # Panics - /// - /// Panics if the new capacity overflows `usize`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_elem(3, false); - /// bv.reserve(10); - /// assert_eq!(bv.len(), 3); - /// assert!(bv.capacity() >= 13); - /// ``` - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - let desired_cap = self - .len() - .checked_add(additional) - .expect("capacity overflow"); - let storage_len = self.storage.len(); - if desired_cap > self.capacity() { - self.storage - .reserve_exact(blocks_for_bits::(desired_cap) - storage_len); - } - } - - /// Returns the capacity in bits for this bit vector. Inserting any - /// element less than this amount will not trigger a resizing. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::new(); - /// bv.reserve(10); - /// assert!(bv.capacity() >= 10); - /// ``` - #[inline] - pub fn capacity(&self) -> usize { - self.storage.capacity().saturating_mul(B::BITS) - } - - /// Grows the `BitVec` in-place, adding `n` copies of `value` to the `BitVec`. - /// - /// # Panics - /// - /// Panics if the new len overflows a `usize`. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_bytes(&[0b01001011]); - /// bv.grow(2, true); - /// assert_eq!(bv.len(), 10); - /// assert_eq!(bv.to_bytes(), [0b01001011, 0b11000000]); - /// ``` - pub fn grow(&mut self, n: usize, value: bool) { - self.ensure_invariant(); - - // Note: we just bulk set all the bits in the last word in this fn in multiple places - // which is technically wrong if not all of these bits are to be used. However, at the end - // of this fn we call `fix_last_block` at the end of this fn, which should fix this. - - let new_nbits = self.nbits.checked_add(n).expect("capacity overflow"); - let new_nblocks = blocks_for_bits::(new_nbits); - let full_value = if value { !B::ZERO } else { B::ZERO }; - - // Correct the old tail word, setting or clearing formerly unused bits - let num_cur_blocks = blocks_for_bits::(self.nbits); - if self.nbits % B::BITS > 0 { - let mask = mask_for_bits::(self.nbits); - if value { - let block = &mut self.storage.slice_mut()[num_cur_blocks - 1]; - *block |= !mask; - } else { - // Extra bits are already zero by invariant. - } - } - - // Fill in words after the old tail word - let stop_idx = cmp::min(self.storage.len(), new_nblocks); - for idx in num_cur_blocks..stop_idx { - self.storage.slice_mut()[idx] = full_value; - } - - // Allocate new words, if needed - if new_nblocks > self.storage.len() { - let to_add = new_nblocks - self.storage.len(); - self.storage.extend(iter::repeat_n(full_value, to_add)); - } - - // Adjust internal bit count - self.nbits = new_nbits; - - self.fix_last_block(); - } - - /// Removes the last bit from the `BitVec`, and returns it. Returns `None` if the `BitVec` is empty. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::from_bytes(&[0b01001001]); - /// assert_eq!(bv.pop(), Some(true)); - /// assert_eq!(bv.pop(), Some(false)); - /// assert_eq!(bv.len(), 6); - /// ``` - #[inline] - pub fn pop(&mut self) -> Option { - self.ensure_invariant(); - - if self.is_empty() { - None - } else { - let i = self.nbits - 1; - let ret = self[i]; - // (3) - self.set(i, false); - self.nbits = i; - if self.nbits % B::BITS == 0 { - // (2) - self.storage.pop(); - } - Some(ret) - } - } - - /// Pushes a `bool` onto the end. - /// - /// # Examples - /// - /// ``` - /// use bit_vec::BitVec; - /// - /// let mut bv = BitVec::new(); - /// bv.push(true); - /// bv.push(false); - /// assert!(bv.eq_vec(&[true, false])); - /// ``` - #[inline] - pub fn push(&mut self, elem: bool) { - if self.nbits % B::BITS == 0 { - self.storage.push(B::ZERO); - } - let insert_pos = self.nbits; - self.nbits = self.nbits.checked_add(1).expect("Capacity overflow"); - self.set(insert_pos, elem); - } - - /// Returns the total number of bits in this vector - #[inline] - pub fn len(&self) -> usize { - self.nbits - } - - /// Sets the number of bits that this `BitVec` considers initialized. - /// - /// # Safety - /// - /// Almost certainly can cause bad stuff. Only really intended for `BitSet`. - #[inline] - pub unsafe fn set_len(&mut self, len: usize) { - self.nbits = len; - } - - /// Returns true if there are no bits in this vector - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Clears all bits in this vector. - #[inline] - #[deprecated(since = "0.9.0", note = "please use `.fill(false)` instead")] - pub fn clear(&mut self) { - self.ensure_invariant(); - for w in self.storage.slice_mut() { - *w = B::ZERO; - } - } - - /// Assigns all bits in this vector to the given boolean value. - /// - /// # Invariants - /// - /// - After a call to `.fill(true)`, the result of [`all`] is `true`. - /// - After a call to `.fill(false)`, the result of [`none`] is `true`. - /// - /// [`all`]: Self::all - /// [`none`]: Self::none - #[inline] - pub fn fill(&mut self, bit: bool) { - self.ensure_invariant(); - let block = if bit { !B::ZERO } else { B::ZERO }; - for w in self.storage.slice_mut() { - *w = block; - } - if bit { - self.fix_last_block(); - } - } - - /// Shrinks the capacity of the underlying storage as much as - /// possible. - /// - /// It will drop down as close as possible to the length but the - /// allocator may still inform the underlying storage that there - /// is space for a few more elements/bits. - pub fn shrink_to_fit(&mut self) { - self.storage.shrink_to_fit(); - } - - /// Inserts a given bit at index `at`, shifting all bits after by one - /// - /// # Panics - /// Panics if `at` is out of bounds for `BitVec`'s length (that is, if `at > BitVec::len()`) - /// - /// # Examples - ///``` - /// use bit_vec::BitVec; - /// - /// let mut b = BitVec::new(); - /// - /// b.push(true); - /// b.push(true); - /// b.insert(1, false); - /// - /// assert!(b.eq_vec(&[true, false, true])); - ///``` - /// - /// # Time complexity - /// Takes O([`len`]) time. All items after the insertion index must be - /// shifted to the right. In the worst case, all elements are shifted when - /// the insertion index is 0. - /// - /// [`len`]: Self::len - pub fn insert(&mut self, at: usize, bit: bool) { - assert!( - at <= self.nbits, - "insertion index (is {at}) should be <= len (is {nbits})", - nbits = self.nbits - ); - self.ensure_invariant(); - - let last_block_bits = self.nbits % B::BITS; - let block_at = at / B::BITS; // needed block - let bit_at = at % B::BITS; // index within the block - - if last_block_bits == 0 { - self.storage.push(B::ZERO); - } - - self.nbits += 1; - - let mut carry = self.storage.slice()[block_at] >> (B::BITS - 1); - let lsbits_mask = (B::ONE << bit_at) - B::ONE; - let set_bit = if bit { B::ONE } else { B::ZERO } << bit_at; - self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) - | ((self.storage.slice()[block_at] & !lsbits_mask) << 1) - | set_bit; - - for block_ref in &mut self.storage.slice_mut()[block_at + 1..] { - let curr_carry = *block_ref >> (B::BITS - 1); - *block_ref = *block_ref << 1 | carry; - carry = curr_carry; - } - } - - /// Remove a bit at index `at`, shifting all bits after by one. - /// - /// # Panics - /// Panics if `at` is out of bounds for `BitVec`'s length (that is, if `at >= BitVec::len()`) - /// - /// # Examples - ///``` - /// use bit_vec::BitVec; - /// - /// let mut b = BitVec::new(); - /// - /// b.push(true); - /// b.push(false); - /// b.push(false); - /// b.push(true); - /// assert!(!b.remove(1)); - /// - /// assert!(b.eq_vec(&[true, false, true])); - ///``` - /// - /// # Time complexity - /// Takes O([`len`]) time. All items after the removal index must be - /// shifted to the left. In the worst case, all elements are shifted when - /// the removal index is 0. - /// - /// [`len`]: Self::len - pub fn remove(&mut self, at: usize) -> bool { - assert!( - at < self.nbits, - "removal index (is {at}) should be < len (is {nbits})", - nbits = self.nbits - ); - self.ensure_invariant(); - - self.nbits -= 1; - - let last_block_bits = self.nbits % B::BITS; - let block_at = at / B::BITS; // needed block - let bit_at = at % B::BITS; // index within the block - - let lsbits_mask = (B::ONE << bit_at) - B::ONE; - - let mut carry = B::ZERO; - - for block_ref in self.storage.slice_mut()[block_at + 1..].iter_mut().rev() { - let curr_carry = *block_ref & B::ONE; - *block_ref = *block_ref >> 1 | (carry << (B::BITS - 1)); - carry = curr_carry; - } - - // Note: this is equivalent to `.get_unchecked(at)`, but we do - // not want to introduce unsafe code here. - let result = (self.storage.slice()[block_at] >> bit_at) & B::ONE == B::ONE; - - self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) - | ((self.storage.slice()[block_at] & (!lsbits_mask << 1)) >> 1) - | carry << (B::BITS - 1); - - if last_block_bits == 0 { - self.storage.pop(); - } - - result - } - - /// Removes all bits in this vector. - /// - /// Note: this method is not named [`clear`] to avoid confusion whenever [`.fill(false)`] - /// is needed. - /// - /// [`clear`]: Self::clear - /// [`.fill(false)`]: Self::fill - pub fn remove_all(&mut self) { - self.storage.clear(); - self.nbits = 0; - } - - /// Appends an element if there is sufficient spare capacity, otherwise an error is returned - /// with the element. - /// - /// Unlike [`push`] this method will not reallocate when there's insufficient capacity. - /// The caller should use [`reserve`] to ensure that there is enough capacity. - /// - /// [`push`]: Self::push - /// [`reserve`]: Self::reserve - /// - /// # Examples - /// ``` - /// use bit_vec::BitVec; - /// - /// let initial_capacity = 64; - /// let mut bitvec = BitVec::with_capacity(64); - /// - /// for _ in 0..initial_capacity - 1 { - /// bitvec.push(false); - /// } - /// - /// assert_eq!(bitvec.len(), initial_capacity - 1); // there is space for only 1 bit - /// - /// assert_eq!(bitvec.push_within_capacity(true), Ok(())); // Successfully push a bit - /// assert_eq!(bitvec.len(), initial_capacity); // So we can't push within capacity anymore - /// - /// assert_eq!(bitvec.push_within_capacity(true), Err(true)); - /// assert_eq!(bitvec.len(), initial_capacity); - /// assert_eq!(bitvec.capacity(), initial_capacity); - /// ``` - /// - /// # Time Complexity - /// Takes *O(1)* time. - pub fn push_within_capacity(&mut self, bit: bool) -> Result<(), bool> { - let len = self.len(); - - if len == self.capacity() { - return Err(bit); - } - - let bits = B::BITS; - - if len % bits == 0 { - self.storage.push(B::ZERO); - } - - let block_at = len / bits; - let bit_at = len % bits; - let flag = if bit { B::ONE << bit_at } else { B::ZERO }; - - self.ensure_invariant(); - - self.nbits += 1; - - self.storage.slice_mut()[block_at] = self.storage.slice()[block_at] | flag; // set the bit - - Ok(()) - } -} - -impl Default for BitVec { - #[inline] - fn default() -> Self { - BitVec { - storage: B::Store::new_in(Default::default()), - nbits: 0, - } - } -} - -impl FromIterator for BitVec { - #[inline] - fn from_iter>(iter: I) -> Self { - let mut ret: Self = Default::default(); - ret.extend(iter); - ret - } -} - -impl Extend for BitVec { - #[inline] - fn extend>(&mut self, iterable: I) { - self.ensure_invariant(); - let iterator = iterable.into_iter(); - let (min, _) = iterator.size_hint(); - self.reserve(min); - for element in iterator { - self.push(element) - } - } -} - -impl Clone for BitVec { - #[inline] - fn clone(&self) -> Self { - self.ensure_invariant(); - BitVec { - storage: self.storage.clone(), - nbits: self.nbits, - } - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - debug_assert!(source.is_last_block_fixed()); - self.nbits = source.nbits; - self.storage.clone_from(&source.storage); - } -} - -impl PartialOrd for BitVec { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for BitVec { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.ensure_invariant(); - debug_assert!(other.is_last_block_fixed()); - let mut a = self.iter(); - let mut b = other.iter(); - loop { - match (a.next(), b.next()) { - (Some(x), Some(y)) => match x.cmp(&y) { - Ordering::Equal => {} - otherwise => return otherwise, - }, - (None, None) => return Ordering::Equal, - (None, _) => return Ordering::Less, - (_, None) => return Ordering::Greater, - } - } - } -} - -impl fmt::Display for BitVec { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.ensure_invariant(); - for bit in self { - fmt.write_char(if bit { '1' } else { '0' })?; - } - Ok(()) - } -} - -impl fmt::Debug for BitVec { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.ensure_invariant(); - let mut storage = String::with_capacity(self.len() + self.len() / B::BITS); - for (i, bit) in self.iter().enumerate() { - if i != 0 && i % B::BITS == 0 { - storage.push(' '); - } - storage.push(if bit { '1' } else { '0' }); - } - fmt.debug_struct("BitVec") - .field("storage", &storage) - .field("nbits", &self.nbits) - .finish() - } -} - -impl hash::Hash for BitVec { - #[inline] - fn hash(&self, state: &mut H) { - self.ensure_invariant(); - self.nbits.hash(state); - for elem in self.blocks() { - elem.hash(state); - } - } -} - -impl cmp::PartialEq for BitVec { - #[inline] - fn eq(&self, other: &Self) -> bool { - if self.nbits != other.nbits { - self.ensure_invariant(); - other.ensure_invariant(); - return false; - } - self.blocks().zip(other.blocks()).all(|(w1, w2)| w1 == w2) - } -} - -impl cmp::Eq for BitVec {} - -/// An iterator for `BitVec`. -#[derive(Clone)] -pub struct Iter<'a, B: 'a + BitBlockOrStore = u32> { - bit_vec: &'a BitVec, - range: Range, -} - -#[derive(Debug)] -pub struct MutBorrowedBit<'a, B: 'a + BitBlockOrStore> { - vec: Rc>>, - index: usize, - #[cfg(debug_assertions)] - old_value: bool, - new_value: bool, -} - -/// An iterator for mutable references to the bits in a `BitVec`. -pub struct IterMut<'a, B: 'a + BitBlockOrStore = u32> { - vec: Rc>>, - range: Range, -} - -impl<'a, B: 'a + BitBlockOrStore> IterMut<'a, B> { - fn get(&mut self, index: Option) -> Option> { - let value = (*self.vec).borrow().get(index?)?; - Some(MutBorrowedBit { - vec: self.vec.clone(), - index: index?, - #[cfg(debug_assertions)] - old_value: value, - new_value: value, - }) - } -} - -impl Deref for MutBorrowedBit<'_, B> { - type Target = bool; - - fn deref(&self) -> &Self::Target { - &self.new_value - } -} - -impl DerefMut for MutBorrowedBit<'_, B> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.new_value - } -} - -impl Drop for MutBorrowedBit<'_, B> { - fn drop(&mut self) { - let mut vec = (*self.vec).borrow_mut(); - #[cfg(debug_assertions)] - debug_assert_eq!( - Some(self.old_value), - vec.get(self.index), - "Mutably-borrowed bit was modified externally!" - ); - vec.set(self.index, self.new_value); - } -} - -impl Iterator for Iter<'_, B> { - type Item = bool; - - #[inline] - fn next(&mut self) -> Option { - // NB: indexing is slow for extern crates when it has to go through &TRUE or &FALSE - // variables. get is more direct, and unwrap is fine since we're sure of the range. - self.range.next().map(|i| self.bit_vec.get(i).unwrap()) - } - - fn nth(&mut self, n: usize) -> Option { - // This override is used by the compiler to optimize Iterator::skip. - // Without this, the default implementation of Iterator::nth is used, which walks over - // the whole iterator up to n. - self.range.nth(n).and_then(|i| self.bit_vec.get(i)) - } - - fn size_hint(&self) -> (usize, Option) { - self.range.size_hint() - } -} - -impl<'a, B: BitBlockOrStore> Iterator for IterMut<'a, B> { - type Item = MutBorrowedBit<'a, B>; - - #[inline] - fn next(&mut self) -> Option { - let index = self.range.next(); - self.get(index) - } - - fn size_hint(&self) -> (usize, Option) { - self.range.size_hint() - } -} - -impl DoubleEndedIterator for Iter<'_, B> { - #[inline] - fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) - } -} - -impl DoubleEndedIterator for IterMut<'_, B> { - #[inline] - fn next_back(&mut self) -> Option { - let index = self.range.next_back(); - self.get(index) - } -} - -impl ExactSizeIterator for Iter<'_, B> {} - -impl ExactSizeIterator for IterMut<'_, B> {} - -impl<'a, B: BitBlockOrStore> IntoIterator for &'a BitVec { - type Item = bool; - type IntoIter = Iter<'a, B>; - - #[inline] - fn into_iter(self) -> Iter<'a, B> { - self.iter() - } -} - -pub struct IntoIter { - bit_vec: BitVec, - range: Range, -} - -impl Iterator for IntoIter { - type Item = bool; - - #[inline] - fn next(&mut self) -> Option { - self.range.next().map(|i| self.bit_vec.get(i).unwrap()) - } -} - -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) - } -} - -impl ExactSizeIterator for IntoIter {} - -impl IntoIterator for BitVec { - type Item = bool; - type IntoIter = IntoIter; - - #[inline] - fn into_iter(self) -> IntoIter { - let nbits = self.nbits; - IntoIter { - bit_vec: self, - range: 0..nbits, - } - } -} - -/// An iterator over the blocks of a `BitVec`. -#[derive(Clone)] -pub struct Blocks<'a, B: 'a + BitBlockOrStore> { - iter: slice::Iter<'a, Block>, -} - -impl Iterator for Blocks<'_, B> { - type Item = Block; - - #[inline] - fn next(&mut self) -> Option> { - self.iter.next().cloned() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl DoubleEndedIterator for Blocks<'_, B> { - #[inline] - fn next_back(&mut self) -> Option> { - self.iter.next_back().cloned() - } -} - -impl ExactSizeIterator for Blocks<'_, B> {} - #[cfg(test)] #[generic_tests::define] mod tests { @@ -2646,9 +176,8 @@ mod tests { #![allow(clippy::shadow_unrelated)] #![allow(clippy::extra_unused_type_parameters)] - use crate::BitBlockOrStore; - - use super::{BitVec, Iter, Vec}; + use super::BitVec; + use crate::local_prelude::*; // This is stupid, but I want to differentiate from a "random" 32 const U32_BITS: usize = 32; diff --git a/vec/src/smart_mut.rs b/vec/src/smart_mut.rs new file mode 100644 index 0000000..5a418a2 --- /dev/null +++ b/vec/src/smart_mut.rs @@ -0,0 +1,162 @@ +use crate::{local_prelude::*, vec::BitVec}; + +/// An iterator for mutable references to the bits in a `BitVec`. +pub struct IterMut<'a, B: 'a + BitBlockOrStore = u32> { + pub(crate) vec: Rc>>, + range: ops::Range, +} + +impl<'a, B: BitBlockOrStore> Iterator for IterMut<'a, B> { + type Item = MutBorrowedBit<'a, B>; + + #[inline] + fn next(&mut self) -> Option { + let index = self.range.next(); + self.get(index) + } + + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } +} + +impl DoubleEndedIterator for IterMut<'_, B> { + #[inline] + fn next_back(&mut self) -> Option { + let index = self.range.next_back(); + self.get(index) + } +} + +impl ExactSizeIterator for IterMut<'_, B> {} + +#[derive(Debug)] +pub struct MutBorrowedBit<'a, B: 'a + BitBlockOrStore> { + vec: Rc>>, + index: usize, + #[cfg(debug_assertions)] + old_value: bool, + new_value: bool, +} + +impl ops::Deref for MutBorrowedBit<'_, B> { + type Target = bool; + + fn deref(&self) -> &Self::Target { + &self.new_value + } +} + +impl ops::DerefMut for MutBorrowedBit<'_, B> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.new_value + } +} + +impl Drop for MutBorrowedBit<'_, B> { + fn drop(&mut self) { + let mut vec = (*self.vec).borrow_mut(); + #[cfg(debug_assertions)] + debug_assert_eq!( + Some(self.old_value), + vec.get(self.index), + "Mutably-borrowed bit was modified externally!" + ); + vec.set(self.index, self.new_value); + } +} + +impl<'a, B: 'a + BitBlockOrStore> IterMut<'a, B> { + fn get(&mut self, index: Option) -> Option> { + let value = (*self.vec).borrow().get(index?)?; + Some(MutBorrowedBit { + vec: self.vec.clone(), + index: index?, + #[cfg(debug_assertions)] + old_value: value, + new_value: value, + }) + } +} + +impl BitVec { + /// Retrieves a smart pointer to the value at index `i`, or `None` if the index is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01100000]); + /// *bv.get_mut(0).unwrap() = true; + /// *bv.get_mut(1).unwrap() = false; + /// assert!(bv.get_mut(100).is_none()); + /// assert_eq!(bv, BitVec::from_bytes(&[0b10100000])); + /// ``` + #[inline] + pub fn get_mut(&mut self, index: usize) -> Option> { + self.get(index).map(move |value| MutBorrowedBit { + vec: Rc::new(RefCell::new(self)), + index, + #[cfg(debug_assertions)] + old_value: value, + new_value: value, + }) + } + + /// Retrieves a smart pointer to the value at index `i`, without doing bounds checking. + /// + /// # Safety + /// + /// Calling this method with out-of-bounds `index` may cause undefined behavior even when + /// the result is not used. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01100000]); + /// unsafe { + /// *bv.get_unchecked_mut(0) = true; + /// *bv.get_unchecked_mut(1) = false; + /// } + /// assert_eq!(bv, BitVec::from_bytes(&[0b10100000])); + /// ``` + #[inline] + pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> MutBorrowedBit<'_, B> { + let value = self.get_unchecked(index); + MutBorrowedBit { + #[cfg(debug_assertions)] + old_value: value, + new_value: value, + vec: Rc::new(RefCell::new(self)), + index, + } + } + + /// Returns an iterator over mutable smart pointers to the elements of the vector in order. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut a = BitVec::from_elem(8, false); + /// a.iter_mut().enumerate().for_each(|(index, mut bit)| { + /// *bit = if index % 2 == 1 { true } else { false }; + /// }); + /// assert!(a.eq_vec(&[ + /// false, true, false, true, false, true, false, true + /// ])); + /// ``` + #[inline] + pub fn iter_mut(&mut self) -> IterMut<'_, B> { + self.ensure_invariant(); + let nbits = self.nbits; + IterMut { + vec: Rc::new(RefCell::new(self)), + range: 0..nbits, + } + } +} diff --git a/vec/src/store.rs b/vec/src/store.rs new file mode 100644 index 0000000..825922f --- /dev/null +++ b/vec/src/store.rs @@ -0,0 +1,263 @@ +use crate::local_prelude::*; + +#[allow(clippy::len_without_is_empty)] +pub trait BitStore: Clone { + type Block: BitBlock; + type Alloc: Default; + fn new_in(alloc: Self::Alloc) -> Self; + fn slice(&self) -> &[Self::Block]; + fn slice_mut(&mut self) -> &mut [Self::Block]; + fn len(&self) -> usize { + self.slice().len() + } + fn pop(&mut self) -> Option; + fn drain>(&mut self, range: R) -> impl Iterator; + fn capacity(&self) -> usize; + fn append(&mut self, other: &mut Self); + fn reserve(&mut self, additional: usize); + fn push(&mut self, value: Self::Block); + fn split_off(&mut self, at: usize) -> Self; + fn truncate(&mut self, len: usize); + fn reserve_exact(&mut self, len: usize); + fn shrink_to_fit(&mut self); + fn extend(&mut self, iter: T) + where + T: IntoIterator; + fn with_capacity(capacity: usize) -> Self; + fn clear(&mut self); + fn with_capacity_in(capacity: usize, alloc: Self::Alloc) -> Self; +} + +#[cfg(not(feature = "allocator_api"))] +impl BitStore for Vec { + type Block = T; + type Alloc = (); + + fn new_in(_alloc: Self::Alloc) -> Self { + Vec::new() + } + + fn slice(&self) -> &[Self::Block] { + &self[..] + } + + fn slice_mut(&mut self) -> &mut [Self::Block] { + &mut self[..] + } + + fn pop(&mut self) -> Option { + Vec::pop(self) + } + + fn drain>(&mut self, range: R) -> impl Iterator { + Vec::drain(self, range) + } + + fn capacity(&self) -> usize { + Vec::capacity(self) + } + + fn append(&mut self, other: &mut Self) { + Vec::append(self, other); + } + + fn reserve(&mut self, additional: usize) { + Vec::reserve(self, additional); + } + + fn push(&mut self, value: Self::Block) { + Vec::push(self, value); + } + + fn split_off(&mut self, at: usize) -> Self { + Vec::split_off(self, at) + } + + fn truncate(&mut self, len: usize) { + Vec::truncate(self, len); + } + + fn reserve_exact(&mut self, len: usize) { + Vec::reserve_exact(self, len); + } + + fn shrink_to_fit(&mut self) { + Vec::shrink_to_fit(self); + } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + Extend::extend(self, iter); + } + + fn with_capacity_in(capacity: usize, _alloc: Self::Alloc) -> Self { + Vec::with_capacity(capacity) + } + + fn with_capacity(capacity: usize) -> Self { + Vec::with_capacity(capacity) + } + + fn clear(&mut self) { + Vec::clear(self) + } +} + +#[cfg(feature = "allocator_api")] +impl BitStore for Vec +where + A: core::alloc::Allocator + Clone + Default, +{ + type Block = T; + type Alloc = A; + + fn new_in(alloc: Self::Alloc) -> Self { + Vec::new_in(alloc) + } + + fn slice(&self) -> &[Self::Block] { + &self[..] + } + + fn slice_mut(&mut self) -> &mut [Self::Block] { + &mut self[..] + } + + fn pop(&mut self) -> Option { + Vec::pop(self) + } + + fn drain>(&mut self, range: R) -> impl Iterator { + Vec::drain(self, range) + } + + fn capacity(&self) -> usize { + Vec::capacity(self) + } + + fn append(&mut self, other: &mut Self) { + Vec::append(self, other); + } + + fn reserve(&mut self, additional: usize) { + Vec::reserve(self, additional); + } + + fn push(&mut self, value: Self::Block) { + Vec::push(self, value); + } + + fn split_off(&mut self, at: usize) -> Self { + Vec::split_off(self, at) + } + + fn truncate(&mut self, len: usize) { + Vec::truncate(self, len); + } + + fn reserve_exact(&mut self, len: usize) { + Vec::reserve_exact(self, len); + } + + fn shrink_to_fit(&mut self) { + Vec::shrink_to_fit(self); + } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + Extend::extend(self, iter); + } + + fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Vec::with_capacity_in(capacity, alloc) + } + + fn with_capacity(capacity: usize) -> Self { + Vec::with_capacity_in(capacity, A::default()) + } +} + +#[cfg(feature = "smallvec")] +impl BitStore for smallvec::SmallVec +where + A::Item: BitBlock, +{ + type Block = A::Item; + type Alloc = (); + + fn slice(&self) -> &[Self::Block] { + &self[..] + } + + fn slice_mut(&mut self) -> &mut [Self::Block] { + &mut self[..] + } + + fn pop(&mut self) -> Option { + self.pop() + } + + fn drain>(&mut self, range: R) -> impl Iterator { + self.drain(range) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn append(&mut self, other: &mut Self) { + self.append(other); + } + + fn reserve(&mut self, additional: usize) { + self.reserve(additional); + } + + fn push(&mut self, value: Self::Block) { + self.push(value); + } + + fn split_off(&mut self, at: usize) -> Self { + // TODO + self.to_vec().split_off(at).into() + } + + fn truncate(&mut self, len: usize) { + self.truncate(len); + } + + fn reserve_exact(&mut self, len: usize) { + self.reserve_exact(len); + } + + fn shrink_to_fit(&mut self) { + self.shrink_to_fit(); + } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + iter::Extend::extend(self, iter); + } + + fn with_capacity(capacity: usize) -> Self { + smallvec::SmallVec::with_capacity(capacity) + } + + fn clear(&mut self) { + self.clear(); + } + + fn new_in(_alloc: ()) -> Self { + smallvec::SmallVec::new() + } + + fn with_capacity_in(capacity: usize, _alloc: ()) -> Self { + smallvec::SmallVec::with_capacity(capacity) + } +} diff --git a/vec/src/util.rs b/vec/src/util.rs new file mode 100644 index 0000000..7b699a9 --- /dev/null +++ b/vec/src/util.rs @@ -0,0 +1,14 @@ +use crate::local_prelude::*; + +pub(crate) type Block = ::Block; + +pub static TRUE: bool = true; +pub static FALSE: bool = false; + +pub fn reverse_bits(byte: u8) -> u8 { + let mut result = 0; + for i in 0..u8::BITS { + result |= ((byte >> i) & 1) << (u8::BITS - 1 - i); + } + result +} diff --git a/vec/src/vec.rs b/vec/src/vec.rs new file mode 100644 index 0000000..d0c6649 --- /dev/null +++ b/vec/src/vec.rs @@ -0,0 +1,1761 @@ +use crate::local_prelude::*; +use crate::util::{self, FALSE, TRUE}; + +/// The bitvector type. +/// +/// # Examples +/// +/// ``` +/// use bit_vec::BitVec; +/// +/// let mut bv = BitVec::from_elem(10, false); +/// +/// // insert all primes less than 10 +/// bv.set(2, true); +/// bv.set(3, true); +/// bv.set(5, true); +/// bv.set(7, true); +/// println!("{:?}", bv); +/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); +/// +/// // flip all values in bitvector, producing non-primes less than 10 +/// bv.negate(); +/// println!("{:?}", bv); +/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); +/// +/// // reset bitvector to empty +/// bv.fill(false); +/// println!("{:?}", bv); +/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); +/// ``` +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshDeserialize, borsh::BorshSerialize) +)] +#[cfg_attr( + feature = "miniserde", + derive(miniserde::Deserialize, miniserde::Serialize) +)] +#[cfg_attr( + feature = "nanoserde", + derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) +)] +pub struct BitVec { + /// Internal representation of the bit vector + pub(crate) storage: B::Store, + /// The number of valid bits in the internal representation + pub(crate) nbits: usize, +} + +// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing) +impl ops::Index for BitVec { + type Output = bool; + + #[inline] + fn index(&self, i: usize) -> &bool { + if self.get(i).expect("index out of bounds") { + &TRUE + } else { + &FALSE + } + } +} + +/// Computes how many blocks are needed to store that many bits +fn blocks_for_bits(bits: usize) -> usize { + // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we + // reserve enough. But if we want exactly a multiple of 32, this will actually allocate + // one too many. So we need to check if that's the case. We can do that by computing if + // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically + // superior modulo operator on a power of two to this. + // + // Note that we can technically avoid this branch with the expression + // `(nbits + U32_BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. + if bits % B::BITS == 0 { + bits / B::BITS + } else { + bits / B::BITS + 1 + } +} + +/// Computes the bitmask for the final word of the vector +fn mask_for_bits(bits: usize) -> Block { + // Note especially that a perfect multiple of U32_BITS should mask all 1s. + (!B::ZERO) >> ((B::BITS - bits % B::BITS) % B::BITS) +} + +impl BitVec { + /// Creates an empty `BitVec`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// let mut bv = BitVec::new(); + /// ``` + #[inline] + pub fn new() -> Self { + Default::default() + } + + /// Creates a `BitVec` that holds `nbits` elements, setting each element + /// to `bit`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(10, false); + /// assert_eq!(bv.len(), 10); + /// for x in bv.iter() { + /// assert_eq!(x, false); + /// } + /// ``` + #[inline] + pub fn from_elem(len: usize, bit: bool) -> Self { + BitVec::::from_elem_general(len, bit) + } + + /// Constructs a new, empty `BitVec` with the specified capacity. + /// + /// The bitvector will be able to hold at least `capacity` bits without + /// reallocating. If `capacity` is 0, it will not allocate. + /// + /// It is important to note that this function does not specify the + /// *length* of the returned bitvector, but only the *capacity*. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + BitVec::::with_capacity_general(capacity) + } + + /// Transforms a byte-vector into a `BitVec`. Each byte becomes eight bits, + /// with the most significant bits of each byte coming first. Each + /// bit becomes `true` if equal to 1 or `false` if equal to 0. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b10100000, 0b00010010]); + /// assert!(bv.eq_vec(&[true, false, true, false, + /// false, false, false, false, + /// false, false, false, true, + /// false, false, true, false])); + /// ``` + pub fn from_bytes(bytes: &[u8]) -> Self { + BitVec::::from_bytes_general(bytes) + } + + /// Creates a `BitVec` of the specified length where the value at each index + /// is `f(index)`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_fn(5, |i| { i % 2 == 0 }); + /// assert!(bv.eq_vec(&[true, false, true, false, true])); + /// ``` + #[inline] + pub fn from_fn(len: usize, f: F) -> Self + where + F: FnMut(usize) -> bool, + { + BitVec::::from_fn_general(len, f) + } +} + +impl BitVec { + /// Creates an empty `BitVec`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// let mut bv = BitVec::::new_general(); + /// ``` + #[inline] + pub fn new_general() -> Self { + Default::default() + } + + /// Creates an empty `BitVec` using the provided allocator. + #[inline] + pub fn new_general_in(alloc: ::Alloc) -> Self { + Self::with_capacity_general_in(0, alloc) + } + + /// Creates a `BitVec` that holds `nbits` elements, setting each element + /// to `bit`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::::from_elem_general(10, false); + /// assert_eq!(bv.len(), 10); + /// for x in bv.iter() { + /// assert_eq!(x, false); + /// } + /// ``` + #[inline] + pub fn from_elem_general(len: usize, bit: bool) -> Self { + let nblocks = blocks_for_bits::(len); + let mut storage: B::Store = B::Store::with_capacity(nblocks); + storage.extend(iter::repeat_n( + if bit { !B::ZERO } else { B::ZERO }, + nblocks, + )); + let mut bit_vec = BitVec { + storage, + nbits: len, + }; + bit_vec.fix_last_block(); + bit_vec + } + + /// Constructs a new, empty `BitVec` with the specified capacity. + /// + /// The bitvector will be able to hold at least `capacity` bits without + /// reallocating. If `capacity` is 0, it will not allocate. + /// + /// It is important to note that this function does not specify the + /// *length* of the returned bitvector, but only the *capacity*. + #[inline] + pub fn with_capacity_general(capacity: usize) -> Self { + BitVec { + storage: B::Store::with_capacity(blocks_for_bits::(capacity)), + nbits: 0, + } + } + + /// Constructs a new, empty `BitVec` with the specified capacity. + /// + /// The bitvector will be able to hold at least `capacity` bits without + /// reallocating. If `capacity` is 0, it will not allocate. + /// + /// It is important to note that this function does not specify the + /// *length* of the returned bitvector, but only the *capacity*. + #[inline] + pub fn with_capacity_general_in(capacity: usize, alloc: ::Alloc) -> Self { + BitVec { + storage: B::Store::with_capacity_in(blocks_for_bits::(capacity), alloc), + nbits: 0, + } + } + + /// Transforms a byte-vector into a `BitVec`. Each byte becomes eight bits, + /// with the most significant bits of each byte coming first. Each + /// bit becomes `true` if equal to 1 or `false` if equal to 0. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::::from_bytes_general(&[0b10100000, 0b00010010]); + /// assert!(bv.eq_vec(&[true, false, true, false, + /// false, false, false, false, + /// false, false, false, true, + /// false, false, true, false])); + /// ``` + pub fn from_bytes_general(bytes: &[u8]) -> Self { + let len = bytes + .len() + .checked_mul(u8::BITS as usize) + .expect("capacity overflow"); + let mut bit_vec = BitVec::::with_capacity_general(len); + let complete_words = bytes.len() / B::BYTES; + let extra_bytes = bytes.len() % B::BYTES; + + bit_vec.nbits = len; + + for i in 0..complete_words { + let mut accumulator = B::ZERO; + for idx in 0..B::BYTES { + accumulator |= ::Block::from_byte(util::reverse_bits( + bytes[i * B::BYTES + idx], + )) << (idx * 8) + } + bit_vec.storage.push(accumulator); + } + + if extra_bytes > 0 { + let mut last_word = B::ZERO; + for (i, &byte) in bytes[complete_words * B::BYTES..].iter().enumerate() { + last_word |= + ::Block::from_byte(util::reverse_bits(byte)) << (i * 8); + } + bit_vec.storage.push(last_word); + } + + bit_vec + } + + /// Creates a `BitVec` of the specified length where the value at each index + /// is `f(index)`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::::from_fn_general(5, |i| { i % 2 == 0 }); + /// assert!(bv.eq_vec(&[true, false, true, false, true])); + /// ``` + #[inline] + pub fn from_fn_general(len: usize, mut f: F) -> Self + where + F: FnMut(usize) -> bool, + { + let mut bit_vec = BitVec::from_elem_general(len, false); + for i in 0..len { + bit_vec.set(i, f(i)); + } + bit_vec + } + + /// Applies the given operation to the blocks of self and other, and sets + /// self to be the result. This relies on the caller not to corrupt the + /// last word. + #[inline] + fn process(&mut self, other: &BitVec, mut op: F) -> bool + where + F: FnMut(Block, Block) -> Block, + { + assert_eq!(self.len(), other.len()); + debug_assert_eq!(self.storage.len(), other.storage.len()); + let mut changed_bits = B::ZERO; + for (a, b) in self.blocks_mut().zip(other.blocks()) { + let w = op(*a, b); + changed_bits |= *a ^ w; + *a = w; + } + changed_bits != B::ZERO + } + + /// Exposes the raw block storage of this `BitVec`. + /// + /// Only really intended for `BitSet`. + #[inline] + pub fn storage(&self) -> &[Block] { + self.storage.slice() + } + + /// Exposes the raw block storage of this `BitVec`. + /// + /// # Safety + /// + /// Can probably cause unsafety. Only really intended for `BitSet`. + #[inline] + pub unsafe fn storage_mut(&mut self) -> &mut B::Store { + &mut self.storage + } + + /// Helper for procedures involving spare space in the last block. + #[inline] + fn last_block_with_mask(&self) -> Option<(Block, Block)> { + let extra_bits = self.len() % B::BITS; + if extra_bits > 0 { + let mask = (B::ONE << extra_bits) - B::ONE; + let storage_len = self.storage.len(); + Some((self.storage.slice()[storage_len - 1], mask)) + } else { + None + } + } + + /// Helper for procedures involving spare space in the last block. + #[inline] + fn last_block_mut_with_mask(&mut self) -> Option<(&mut Block, Block)> { + let extra_bits = self.len() % B::BITS; + if extra_bits > 0 { + let mask = (B::ONE << extra_bits) - B::ONE; + let storage_len = self.storage.len(); + Some((&mut self.storage.slice_mut()[storage_len - 1], mask)) + } else { + None + } + } + + /// An operation might screw up the unused bits in the last block of the + /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up. + fn fix_last_block(&mut self) { + if let Some((last_block, used_bits)) = self.last_block_mut_with_mask() { + *last_block = *last_block & used_bits; + } + } + + /// Operations such as change detection for xnor, nor and nand are easiest + /// to implement when unused bits are all set to 1s. + fn fix_last_block_with_ones(&mut self) { + if let Some((last_block, used_bits)) = self.last_block_mut_with_mask() { + *last_block |= !used_bits; + } + } + + /// Check whether last block's invariant is fine. + fn is_last_block_fixed(&self) -> bool { + if let Some((last_block, used_bits)) = self.last_block_with_mask() { + last_block & !used_bits == B::ZERO + } else { + true + } + } + + /// Ensure the invariant for the last block. + /// + /// An operation might screw up the unused bits in the last block of the + /// `BitVec`. + /// + /// This method fails in case the last block is not fixed. The check + /// is skipped outside testing. + #[inline] + pub(crate) fn ensure_invariant(&self) { + if cfg!(test) { + debug_assert!(self.is_last_block_fixed()); + } + } + + /// Retrieves the value at index `i`, or `None` if the index is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b01100000]); + /// assert_eq!(bv.get(0), Some(false)); + /// assert_eq!(bv.get(1), Some(true)); + /// assert_eq!(bv.get(100), None); + /// + /// // Can also use array indexing + /// assert_eq!(bv[1], true); + /// ``` + #[inline] + pub fn get(&self, i: usize) -> Option { + self.ensure_invariant(); + if i >= self.nbits { + return None; + } + let w = i / B::BITS; + let b = i % B::BITS; + self.storage + .slice() + .get(w) + .map(|&block| (block & (B::ONE << b)) != B::ZERO) + } + + /// Retrieves the value at index `i`, without doing bounds checking. + /// + /// For a safe alternative, see `get`. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is undefined behavior + /// even if the resulting reference is not used. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b01100000]); + /// unsafe { + /// assert_eq!(bv.get_unchecked(0), false); + /// assert_eq!(bv.get_unchecked(1), true); + /// } + /// ``` + #[inline] + pub unsafe fn get_unchecked(&self, i: usize) -> bool { + self.ensure_invariant(); + let w = i / B::BITS; + let b = i % B::BITS; + let block = *self.storage.slice().get_unchecked(w); + block & (B::ONE << b) != B::ZERO + } + + /// Sets the value of a bit at an index `i`. + /// + /// # Panics + /// + /// Panics if `i` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(5, false); + /// bv.set(3, true); + /// assert_eq!(bv[3], true); + /// ``` + #[inline] + pub fn set(&mut self, i: usize, x: bool) { + self.ensure_invariant(); + assert!( + i < self.nbits, + "index out of bounds: {:?} >= {:?}", + i, + self.nbits + ); + let w = i / B::BITS; + let b = i % B::BITS; + let flag = B::ONE << b; + let val = if x { + self.storage.slice()[w] | flag + } else { + self.storage.slice()[w] & !flag + }; + self.storage.slice_mut()[w] = val; + } + + /// Sets all bits to 1. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let before = 0b01100000; + /// let after = 0b11111111; + /// + /// let mut bv = BitVec::from_bytes(&[before]); + /// bv.set_all(); + /// assert_eq!(bv, BitVec::from_bytes(&[after])); + /// ``` + #[inline] + #[deprecated(since = "0.9.0", note = "please use `.fill(true)` instead")] + pub fn set_all(&mut self) { + self.ensure_invariant(); + for w in self.storage.slice_mut() { + *w = !B::ZERO; + } + self.fix_last_block(); + } + + /// Flips all bits. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let before = 0b01100000; + /// let after = 0b10011111; + /// + /// let mut bv = BitVec::from_bytes(&[before]); + /// bv.negate(); + /// assert_eq!(bv, BitVec::from_bytes(&[after])); + /// ``` + #[inline] + pub fn negate(&mut self) { + self.ensure_invariant(); + for w in self.storage.slice_mut() { + *w = !*w; + } + self.fix_last_block(); + } + + /// Calculates the union of two bitvectors. This acts like the bitwise `or` + /// function. + /// + /// Sets `self` to the union of `self` and `other`. Both bitvectors must be + /// the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different lengths. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01111110; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.union(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[deprecated(since = "0.7.0", note = "Please use the 'or' function instead")] + #[inline] + pub fn union(&mut self, other: &Self) -> bool { + self.or(other) + } + + /// Calculates the intersection of two bitvectors. This acts like the + /// bitwise `and` function. + /// + /// Sets `self` to the intersection of `self` and `other`. Both bitvectors + /// must be the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different lengths. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01000000; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.intersect(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[deprecated(since = "0.7.0", note = "Please use the 'and' function instead")] + #[inline] + pub fn intersect(&mut self, other: &Self) -> bool { + self.and(other) + } + + /// Calculates the bitwise `or` of two bitvectors. + /// + /// Sets `self` to the union of `self` and `other`. Both bitvectors must be + /// the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different lengths. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01111110; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.or(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn or(&mut self, other: &Self) -> bool { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + self.process(other, |w1, w2| w1 | w2) + } + + /// Calculates the bitwise `and` of two bitvectors. + /// + /// Sets `self` to the intersection of `self` and `other`. Both bitvectors + /// must be the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different lengths. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01000000; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.and(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn and(&mut self, other: &Self) -> bool { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + self.process(other, |w1, w2| w1 & w2) + } + + /// Calculates the difference between two bitvectors. + /// + /// Sets each element of `self` to the value of that element minus the + /// element of `other` at the same index. Both bitvectors must be the same + /// length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let a_b = 0b00100100; // a - b + /// let b_a = 0b00011010; // b - a + /// + /// let mut bva = BitVec::from_bytes(&[a]); + /// let bvb = BitVec::from_bytes(&[b]); + /// + /// assert!(bva.difference(&bvb)); + /// assert_eq!(bva, BitVec::from_bytes(&[a_b])); + /// + /// let bva = BitVec::from_bytes(&[a]); + /// let mut bvb = BitVec::from_bytes(&[b]); + /// + /// assert!(bvb.difference(&bva)); + /// assert_eq!(bvb, BitVec::from_bytes(&[b_a])); + /// ``` + #[inline] + pub fn difference(&mut self, other: &Self) -> bool { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + self.process(other, |w1, w2| w1 & !w2) + } + + /// Calculates the xor of two bitvectors. + /// + /// Sets `self` to the xor of `self` and `other`. Both bitvectors must be + /// the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100110; + /// let b = 0b01010100; + /// let res = 0b00110010; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.xor(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn xor(&mut self, other: &Self) -> bool { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + self.process(other, |w1, w2| w1 ^ w2) + } + + /// Calculates the nand of two bitvectors. + /// + /// Sets `self` to the nand of `self` and `other`. Both bitvectors must be + /// the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100110; + /// let b = 0b01010100; + /// let res = 0b10111011; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.nand(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn nand(&mut self, other: &Self) -> bool { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + self.fix_last_block_with_ones(); + let result = self.process(other, |w1, w2| !(w1 & w2)); + self.fix_last_block(); + result + } + + /// Calculates the nor of two bitvectors. + /// + /// Sets `self` to the nor of `self` and `other`. Both bitvectors must be + /// the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100110; + /// let b = 0b01010100; + /// let res = 0b10001001; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.nor(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn nor(&mut self, other: &Self) -> bool { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + self.fix_last_block_with_ones(); + let result = self.process(other, |w1, w2| !(w1 | w2)); + self.fix_last_block(); + result + } + + /// Calculates the xnor of two bitvectors. + /// + /// Sets `self` to the xnor of `self` and `other`. Both bitvectors must be + /// the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100110; + /// let b = 0b01010100; + /// let res = 0b11001101; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.xnor(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn xnor(&mut self, other: &Self) -> bool { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + self.fix_last_block_with_ones(); + let result = self.process(other, |w1, w2| !(w1 ^ w2)); + self.fix_last_block(); + result + } + + /// Returns `true` if all bits are 1. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(5, true); + /// assert_eq!(bv.all(), true); + /// + /// bv.set(1, false); + /// assert_eq!(bv.all(), false); + /// ``` + #[inline] + pub fn all(&self) -> bool { + self.ensure_invariant(); + let mut last_word = !B::ZERO; + // Check that every block but the last is all-ones... + self.blocks().all(|elem| { + let tmp = last_word; + last_word = elem; + tmp == !B::ZERO + // and then check the last one has enough ones + }) && (last_word == mask_for_bits::(self.nbits)) + } + + /// Returns the number of ones in the binary representation. + /// + /// Also known as the + /// [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight). + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(100, true); + /// assert_eq!(bv.count_ones(), 100); + /// + /// bv.set(50, false); + /// assert_eq!(bv.count_ones(), 99); + /// ``` + #[inline] + pub fn count_ones(&self) -> u64 { + self.ensure_invariant(); + // Add the number of ones of each block. + self.blocks().map(|elem| elem.count_ones() as u64).sum() + } + + /// Returns the number of zeros in the binary representation. + /// + /// Also known as the opposite of + /// [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight). + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(100, false); + /// assert_eq!(bv.count_zeros(), 100); + /// + /// bv.set(50, true); + /// assert_eq!(bv.count_zeros(), 99); + /// ``` + #[inline] + pub fn count_zeros(&self) -> u64 { + self.ensure_invariant(); + // Add the number of zeros of each block. + let extra_zeros = (B::BITS - (self.len() % B::BITS)) % B::BITS; + self.blocks() + .map(|elem| elem.count_zeros() as u64) + .sum::() + - extra_zeros as u64 + } + + /// Moves all bits from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut a = BitVec::from_bytes(&[0b10000000]); + /// let mut b = BitVec::from_bytes(&[0b01100001]); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 16); + /// assert_eq!(b.len(), 0); + /// assert!(a.eq_vec(&[true, false, false, false, false, false, false, false, + /// false, true, true, false, false, false, false, true])); + /// ``` + pub fn append(&mut self, other: &mut Self) { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + + let b = self.len() % B::BITS; + let o = other.len() % B::BITS; + let will_overflow = (b + o > B::BITS) || (o == 0 && b != 0); + + self.nbits += other.len(); + other.nbits = 0; + + if b == 0 { + self.storage.append(&mut other.storage); + } else { + self.storage.reserve(other.storage.len()); + + for block in other.storage.drain(..) { + { + let last = self.storage.slice_mut().last_mut().unwrap(); + *last |= block << b; + } + self.storage.push(block >> (B::BITS - b)); + } + + // Remove additional block if the last shift did not overflow + if !will_overflow { + self.storage.pop(); + } + } + } + + /// Splits the `BitVec` into two at the given bit, + /// retaining the first half in-place and returning the second one. + /// + /// # Panics + /// + /// Panics if `at` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// let mut a = BitVec::new(); + /// a.push(true); + /// a.push(false); + /// a.push(false); + /// a.push(true); + /// + /// let b = a.split_off(2); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 2); + /// assert!(a.eq_vec(&[true, false])); + /// assert!(b.eq_vec(&[false, true])); + /// ``` + pub fn split_off(&mut self, at: usize) -> Self { + self.ensure_invariant(); + assert!(at <= self.len(), "`at` out of bounds"); + + let mut other = BitVec::::new_general(); + + if at == 0 { + mem::swap(self, &mut other); + return other; + } else if at == self.len() { + return other; + } + + let w = at / B::BITS; + let b = at % B::BITS; + other.nbits = self.nbits - at; + self.nbits = at; + if b == 0 { + // Split at block boundary + other.storage = self.storage.split_off(w); + } else { + other.storage.reserve(self.storage.len() - w); + + { + let mut iter = self.storage.slice()[w..].iter(); + let mut last = *iter.next().unwrap(); + for &cur in iter { + other.storage.push((last >> b) | (cur << (B::BITS - b))); + last = cur; + } + other.storage.push(last >> b); + } + + self.storage.truncate(w + 1); + self.fix_last_block(); + } + + other + } + + /// Returns `true` if all bits are 0. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(10, false); + /// assert_eq!(bv.none(), true); + /// + /// bv.set(3, true); + /// assert_eq!(bv.none(), false); + /// ``` + #[inline] + pub fn none(&self) -> bool { + self.blocks().all(|w| w == B::ZERO) + } + + /// Returns `true` if any bit is 1. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(10, false); + /// assert_eq!(bv.any(), false); + /// + /// bv.set(3, true); + /// assert_eq!(bv.any(), true); + /// ``` + #[inline] + pub fn any(&self) -> bool { + !self.none() + } + + /// Organises the bits into bytes, such that the first bit in the + /// `BitVec` becomes the high-order bit of the first byte. If the + /// size of the `BitVec` is not a multiple of eight then trailing bits + /// will be filled-in with `false`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(3, true); + /// bv.set(1, false); + /// + /// assert_eq!(bv.to_bytes(), [0b10100000]); + /// + /// let mut bv = BitVec::from_elem(9, false); + /// bv.set(2, true); + /// bv.set(8, true); + /// + /// assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); + /// ``` + pub fn to_bytes(&self) -> Vec { + static REVERSE_TABLE: [u8; 256] = { + let mut tbl = [0u8; 256]; + let mut i: u8 = 0; + loop { + tbl[i as usize] = i.reverse_bits(); + if i == 255 { + break; + } + i += 1; + } + tbl + }; + self.ensure_invariant(); + + let len = self.nbits / 8 + if self.nbits % 8 == 0 { 0 } else { 1 }; + let mut result = Vec::with_capacity(len); + + for byte_idx in 0..len { + let mut byte = 0u8; + for bit_idx in 0..8 { + let offset = byte_idx * 8 + bit_idx; + if offset < self.nbits && self[offset] { + byte |= 1 << bit_idx; + } + } + result.push(REVERSE_TABLE[byte as usize]); + } + + result + } + + /// Compares a `BitVec` to a slice of `bool`s. + /// Both the `BitVec` and slice must have the same length. + /// + /// # Panics + /// + /// Panics if the `BitVec` and slice are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b10100000]); + /// + /// assert!(bv.eq_vec(&[true, false, true, false, + /// false, false, false, false])); + /// ``` + #[inline] + pub fn eq_vec(&self, v: &[bool]) -> bool { + assert_eq!(self.nbits, v.len()); + self.iter().zip(v.iter().cloned()).all(|(b1, b2)| b1 == b2) + } + + /// Shortens a `BitVec`, dropping excess elements. + /// + /// If `len` is greater than the vector's current length, this has no + /// effect. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01001011]); + /// bv.truncate(2); + /// assert!(bv.eq_vec(&[false, true])); + /// ``` + #[inline] + pub fn truncate(&mut self, len: usize) { + self.ensure_invariant(); + if len < self.len() { + self.nbits = len; + // This fixes (2). + self.storage.truncate(blocks_for_bits::(len)); + self.fix_last_block(); + } + } + + /// Reserves capacity for at least `additional` more bits to be inserted in the given + /// `BitVec`. The collection may reserve more space to avoid frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(3, false); + /// bv.reserve(10); + /// assert_eq!(bv.len(), 3); + /// assert!(bv.capacity() >= 13); + /// ``` + #[inline] + pub fn reserve(&mut self, additional: usize) { + let desired_cap = self + .len() + .checked_add(additional) + .expect("capacity overflow"); + let storage_len = self.storage.len(); + if desired_cap > self.capacity() { + self.storage + .reserve(blocks_for_bits::(desired_cap) - storage_len); + } + } + + /// Reserves the minimum capacity for exactly `additional` more bits to be inserted in the + /// given `BitVec`. Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it requests. Therefore + /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future + /// insertions are expected. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(3, false); + /// bv.reserve(10); + /// assert_eq!(bv.len(), 3); + /// assert!(bv.capacity() >= 13); + /// ``` + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + let desired_cap = self + .len() + .checked_add(additional) + .expect("capacity overflow"); + let storage_len = self.storage.len(); + if desired_cap > self.capacity() { + self.storage + .reserve_exact(blocks_for_bits::(desired_cap) - storage_len); + } + } + + /// Returns the capacity in bits for this bit vector. Inserting any + /// element less than this amount will not trigger a resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::new(); + /// bv.reserve(10); + /// assert!(bv.capacity() >= 10); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.storage.capacity().saturating_mul(B::BITS) + } + + /// Grows the `BitVec` in-place, adding `n` copies of `value` to the `BitVec`. + /// + /// # Panics + /// + /// Panics if the new len overflows a `usize`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01001011]); + /// bv.grow(2, true); + /// assert_eq!(bv.len(), 10); + /// assert_eq!(bv.to_bytes(), [0b01001011, 0b11000000]); + /// ``` + pub fn grow(&mut self, n: usize, value: bool) { + self.ensure_invariant(); + + // Note: we just bulk set all the bits in the last word in this fn in multiple places + // which is technically wrong if not all of these bits are to be used. However, at the end + // of this fn we call `fix_last_block` at the end of this fn, which should fix this. + + let new_nbits = self.nbits.checked_add(n).expect("capacity overflow"); + let new_nblocks = blocks_for_bits::(new_nbits); + let full_value = if value { !B::ZERO } else { B::ZERO }; + + // Correct the old tail word, setting or clearing formerly unused bits + let num_cur_blocks = blocks_for_bits::(self.nbits); + if self.nbits % B::BITS > 0 { + let mask = mask_for_bits::(self.nbits); + if value { + let block = &mut self.storage.slice_mut()[num_cur_blocks - 1]; + *block |= !mask; + } else { + // Extra bits are already zero by invariant. + } + } + + // Fill in words after the old tail word + let stop_idx = cmp::min(self.storage.len(), new_nblocks); + for idx in num_cur_blocks..stop_idx { + self.storage.slice_mut()[idx] = full_value; + } + + // Allocate new words, if needed + if new_nblocks > self.storage.len() { + let to_add = new_nblocks - self.storage.len(); + self.storage.extend(iter::repeat_n(full_value, to_add)); + } + + // Adjust internal bit count + self.nbits = new_nbits; + + self.fix_last_block(); + } + + /// Removes the last bit from the `BitVec`, and returns it. Returns `None` if the `BitVec` is empty. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01001001]); + /// assert_eq!(bv.pop(), Some(true)); + /// assert_eq!(bv.pop(), Some(false)); + /// assert_eq!(bv.len(), 6); + /// ``` + #[inline] + pub fn pop(&mut self) -> Option { + self.ensure_invariant(); + + if self.is_empty() { + None + } else { + let i = self.nbits - 1; + let ret = self[i]; + // (3) + self.set(i, false); + self.nbits = i; + if self.nbits % B::BITS == 0 { + // (2) + self.storage.pop(); + } + Some(ret) + } + } + + /// Pushes a `bool` onto the end. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::new(); + /// bv.push(true); + /// bv.push(false); + /// assert!(bv.eq_vec(&[true, false])); + /// ``` + #[inline] + pub fn push(&mut self, elem: bool) { + if self.nbits % B::BITS == 0 { + self.storage.push(B::ZERO); + } + let insert_pos = self.nbits; + self.nbits = self.nbits.checked_add(1).expect("Capacity overflow"); + self.set(insert_pos, elem); + } + + /// Returns the total number of bits in this vector + #[inline] + pub fn len(&self) -> usize { + self.nbits + } + + /// Sets the number of bits that this `BitVec` considers initialized. + /// + /// # Safety + /// + /// Almost certainly can cause bad stuff. Only really intended for `BitSet`. + #[inline] + pub unsafe fn set_len(&mut self, len: usize) { + self.nbits = len; + } + + /// Returns true if there are no bits in this vector + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears all bits in this vector. + #[inline] + #[deprecated(since = "0.9.0", note = "please use `.fill(false)` instead")] + pub fn clear(&mut self) { + self.ensure_invariant(); + for w in self.storage.slice_mut() { + *w = B::ZERO; + } + } + + /// Assigns all bits in this vector to the given boolean value. + /// + /// # Invariants + /// + /// - After a call to `.fill(true)`, the result of [`all`] is `true`. + /// - After a call to `.fill(false)`, the result of [`none`] is `true`. + /// + /// [`all`]: Self::all + /// [`none`]: Self::none + #[inline] + pub fn fill(&mut self, bit: bool) { + self.ensure_invariant(); + let block = if bit { !B::ZERO } else { B::ZERO }; + for w in self.storage.slice_mut() { + *w = block; + } + if bit { + self.fix_last_block(); + } + } + + /// Shrinks the capacity of the underlying storage as much as + /// possible. + /// + /// It will drop down as close as possible to the length but the + /// allocator may still inform the underlying storage that there + /// is space for a few more elements/bits. + pub fn shrink_to_fit(&mut self) { + self.storage.shrink_to_fit(); + } + + /// Inserts a given bit at index `at`, shifting all bits after by one + /// + /// # Panics + /// Panics if `at` is out of bounds for `BitVec`'s length (that is, if `at > BitVec::len()`) + /// + /// # Examples + ///``` + /// use bit_vec::BitVec; + /// + /// let mut b = BitVec::new(); + /// + /// b.push(true); + /// b.push(true); + /// b.insert(1, false); + /// + /// assert!(b.eq_vec(&[true, false, true])); + ///``` + /// + /// # Time complexity + /// Takes O([`len`]) time. All items after the insertion index must be + /// shifted to the right. In the worst case, all elements are shifted when + /// the insertion index is 0. + /// + /// [`len`]: Self::len + pub fn insert(&mut self, at: usize, bit: bool) { + assert!( + at <= self.nbits, + "insertion index (is {at}) should be <= len (is {nbits})", + nbits = self.nbits + ); + self.ensure_invariant(); + + let last_block_bits = self.nbits % B::BITS; + let block_at = at / B::BITS; // needed block + let bit_at = at % B::BITS; // index within the block + + if last_block_bits == 0 { + self.storage.push(B::ZERO); + } + + self.nbits += 1; + + let mut carry = self.storage.slice()[block_at] >> (B::BITS - 1); + let lsbits_mask = (B::ONE << bit_at) - B::ONE; + let set_bit = if bit { B::ONE } else { B::ZERO } << bit_at; + self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) + | ((self.storage.slice()[block_at] & !lsbits_mask) << 1) + | set_bit; + + for block_ref in &mut self.storage.slice_mut()[block_at + 1..] { + let curr_carry = *block_ref >> (B::BITS - 1); + *block_ref = *block_ref << 1 | carry; + carry = curr_carry; + } + } + + /// Remove a bit at index `at`, shifting all bits after by one. + /// + /// # Panics + /// Panics if `at` is out of bounds for `BitVec`'s length (that is, if `at >= BitVec::len()`) + /// + /// # Examples + ///``` + /// use bit_vec::BitVec; + /// + /// let mut b = BitVec::new(); + /// + /// b.push(true); + /// b.push(false); + /// b.push(false); + /// b.push(true); + /// assert!(!b.remove(1)); + /// + /// assert!(b.eq_vec(&[true, false, true])); + ///``` + /// + /// # Time complexity + /// Takes O([`len`]) time. All items after the removal index must be + /// shifted to the left. In the worst case, all elements are shifted when + /// the removal index is 0. + /// + /// [`len`]: Self::len + pub fn remove(&mut self, at: usize) -> bool { + assert!( + at < self.nbits, + "removal index (is {at}) should be < len (is {nbits})", + nbits = self.nbits + ); + self.ensure_invariant(); + + self.nbits -= 1; + + let last_block_bits = self.nbits % B::BITS; + let block_at = at / B::BITS; // needed block + let bit_at = at % B::BITS; // index within the block + + let lsbits_mask = (B::ONE << bit_at) - B::ONE; + + let mut carry = B::ZERO; + + for block_ref in self.storage.slice_mut()[block_at + 1..].iter_mut().rev() { + let curr_carry = *block_ref & B::ONE; + *block_ref = *block_ref >> 1 | (carry << (B::BITS - 1)); + carry = curr_carry; + } + + // Note: this is equivalent to `.get_unchecked(at)`, but we do + // not want to introduce unsafe code here. + let result = (self.storage.slice()[block_at] >> bit_at) & B::ONE == B::ONE; + + self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) + | ((self.storage.slice()[block_at] & (!lsbits_mask << 1)) >> 1) + | carry << (B::BITS - 1); + + if last_block_bits == 0 { + self.storage.pop(); + } + + result + } + + /// Removes all bits in this vector. + /// + /// Note: this method is not named [`clear`] to avoid confusion whenever [`.fill(false)`] + /// is needed. + /// + /// [`clear`]: Self::clear + /// [`.fill(false)`]: Self::fill + pub fn remove_all(&mut self) { + self.storage.clear(); + self.nbits = 0; + } + + /// Appends an element if there is sufficient spare capacity, otherwise an error is returned + /// with the element. + /// + /// Unlike [`push`] this method will not reallocate when there's insufficient capacity. + /// The caller should use [`reserve`] to ensure that there is enough capacity. + /// + /// [`push`]: Self::push + /// [`reserve`]: Self::reserve + /// + /// # Examples + /// ``` + /// use bit_vec::BitVec; + /// + /// let initial_capacity = 64; + /// let mut bitvec = BitVec::with_capacity(64); + /// + /// for _ in 0..initial_capacity - 1 { + /// bitvec.push(false); + /// } + /// + /// assert_eq!(bitvec.len(), initial_capacity - 1); // there is space for only 1 bit + /// + /// assert_eq!(bitvec.push_within_capacity(true), Ok(())); // Successfully push a bit + /// assert_eq!(bitvec.len(), initial_capacity); // So we can't push within capacity anymore + /// + /// assert_eq!(bitvec.push_within_capacity(true), Err(true)); + /// assert_eq!(bitvec.len(), initial_capacity); + /// assert_eq!(bitvec.capacity(), initial_capacity); + /// ``` + /// + /// # Time Complexity + /// Takes *O(1)* time. + pub fn push_within_capacity(&mut self, bit: bool) -> Result<(), bool> { + let len = self.len(); + + if len == self.capacity() { + return Err(bit); + } + + let bits = B::BITS; + + if len % bits == 0 { + self.storage.push(B::ZERO); + } + + let block_at = len / bits; + let bit_at = len % bits; + let flag = if bit { B::ONE << bit_at } else { B::ZERO }; + + self.ensure_invariant(); + + self.nbits += 1; + + self.storage.slice_mut()[block_at] = self.storage.slice()[block_at] | flag; // set the bit + + Ok(()) + } +} + +impl Default for BitVec { + #[inline] + fn default() -> Self { + BitVec { + storage: B::Store::new_in(Default::default()), + nbits: 0, + } + } +} + +impl FromIterator for BitVec { + #[inline] + fn from_iter>(iter: I) -> Self { + let mut ret: Self = Default::default(); + ret.extend(iter); + ret + } +} + +impl Extend for BitVec { + #[inline] + fn extend>(&mut self, iterable: I) { + self.ensure_invariant(); + let iterator = iterable.into_iter(); + let (min, _) = iterator.size_hint(); + self.reserve(min); + for element in iterator { + self.push(element) + } + } +} + +impl Clone for BitVec { + #[inline] + fn clone(&self) -> Self { + self.ensure_invariant(); + BitVec { + storage: self.storage.clone(), + nbits: self.nbits, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + debug_assert!(source.is_last_block_fixed()); + self.nbits = source.nbits; + self.storage.clone_from(&source.storage); + } +} + +impl PartialOrd for BitVec { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for BitVec { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.ensure_invariant(); + debug_assert!(other.is_last_block_fixed()); + let mut a = self.iter(); + let mut b = other.iter(); + loop { + match (a.next(), b.next()) { + (Some(x), Some(y)) => match x.cmp(&y) { + Ordering::Equal => {} + otherwise => return otherwise, + }, + (None, None) => return Ordering::Equal, + (None, _) => return Ordering::Less, + (_, None) => return Ordering::Greater, + } + } + } +} + +impl fmt::Display for BitVec { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.ensure_invariant(); + for bit in self { + fmt.write_char(if bit { '1' } else { '0' })?; + } + Ok(()) + } +} + +impl fmt::Debug for BitVec { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.ensure_invariant(); + let mut storage = String::with_capacity(self.len() + self.len() / B::BITS); + for (i, bit) in self.iter().enumerate() { + if i != 0 && i % B::BITS == 0 { + storage.push(' '); + } + storage.push(if bit { '1' } else { '0' }); + } + fmt.debug_struct("BitVec") + .field("storage", &storage) + .field("nbits", &self.nbits) + .finish() + } +} + +impl hash::Hash for BitVec { + #[inline] + fn hash(&self, state: &mut H) { + self.ensure_invariant(); + self.nbits.hash(state); + for elem in self.blocks() { + elem.hash(state); + } + } +} + +impl cmp::PartialEq for BitVec { + #[inline] + fn eq(&self, other: &Self) -> bool { + if self.nbits != other.nbits { + self.ensure_invariant(); + other.ensure_invariant(); + return false; + } + self.blocks().zip(other.blocks()).all(|(w1, w2)| w1 == w2) + } +} + +impl cmp::Eq for BitVec {} From efc1290e34d0e9418f1631eb1332e26999bdbdc4 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 12 Mar 2026 14:01:01 +0100 Subject: [PATCH 15/24] Create a Cargo workspace --- Cargo.toml | 5 + README.md | 138 +--- fuzz/LICENSE-APACHE | 1 + fuzz/LICENSE-MIT | 1 + matrix/Cargo.toml | 5 +- matrix/LICENSE-APACHE | 202 +---- matrix/LICENSE-MIT | 26 +- matrix/README.md | 4 +- set/Cargo.toml | 16 +- set/LICENSE-APACHE | 202 +---- set/LICENSE-MIT | 26 +- set/README.md | 28 +- set/src/lib.rs | 643 ---------------- set/tests/serialization.rs | 64 ++ set/tests/set.rs | 577 +++++++++++++++ vec/Cargo.toml | 15 +- vec/LICENSE-APACHE | 1 + vec/LICENSE-MIT | 1 + vec/README.md | 137 ++++ vec/src/lib.rs | 1418 ------------------------------------ vec/tests/vec.rs | 1409 +++++++++++++++++++++++++++++++++++ 21 files changed, 2229 insertions(+), 2690 deletions(-) mode change 100644 => 120000 README.md create mode 120000 fuzz/LICENSE-APACHE create mode 120000 fuzz/LICENSE-MIT mode change 100644 => 120000 matrix/LICENSE-APACHE mode change 100644 => 120000 matrix/LICENSE-MIT mode change 100644 => 120000 set/LICENSE-APACHE mode change 100644 => 120000 set/LICENSE-MIT create mode 100644 set/tests/serialization.rs create mode 100644 set/tests/set.rs create mode 120000 vec/LICENSE-APACHE create mode 120000 vec/LICENSE-MIT create mode 100644 vec/README.md create mode 100644 vec/tests/vec.rs diff --git a/Cargo.toml b/Cargo.toml index fd78975..87410b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,8 @@ resolver = "2" debug = false [workspace.dependencies] + +[workspace.package] +# shared version of all public crates in the workspace +version = "0.10.0" +rust-version = "1.82.0" diff --git a/README.md b/README.md deleted file mode 100644 index 84780dc..0000000 --- a/README.md +++ /dev/null @@ -1,137 +0,0 @@ -
    -

    bit-vec

    -

    - A compact vector of bits. -

    -

    - -[![crates.io][crates.io shield]][crates.io link] -[![Documentation][docs.rs badge]][docs.rs link] -![Rust CI][github ci badge] -![MSRV][rustc 1.82+] -
    -
    -[![Dependency Status][deps.rs status]][deps.rs link] -[![Download Status][shields.io download count]][crates.io link] - -

    -
    - -[crates.io shield]: https://img.shields.io/crates/v/bit-vec?label=latest -[crates.io link]: https://crates.io/crates/bit-vec -[docs.rs badge]: https://docs.rs/bit-vec/badge.svg?version=0.9.1 -[docs.rs link]: https://docs.rs/bit-vec/0.9.1/bit_vec/ -[github ci badge]: https://github.com/contain-rs/bit-vec/actions/workflows/rust.yml/badge.svg -[rustc 1.82+]: https://img.shields.io/badge/rustc-1.82%2B-blue.svg -[deps.rs status]: https://deps.rs/crate/bit-vec/0.9.1/status.svg -[deps.rs link]: https://deps.rs/crate/bit-vec/0.9.1 -[shields.io download count]: https://img.shields.io/crates/d/bit-vec.svg - -## Usage - -Add this to your Cargo.toml: - -```toml -[dependencies] -bit-vec = "0.9" -``` - -If you want [serde](https://github.com/serde-rs/serde) support, include the feature like this: - -```toml -[dependencies] -bit-vec = { version = "0.9", features = ["serde"] } -``` - -If you want to use bit-vec in a program that has `#![no_std]`, just drop default features: - -```toml -[dependencies] -bit-vec = { version = "0.9", default-features = false } -``` - -If you want to use serde with the alloc crate instead of std, just use the `serde_no_std` feature: - -```toml -[dependencies] -bit-vec = { version = "0.9", default-features = false, features = ["serde", "serde_no_std"] } -``` - -If you want [borsh-rs](https://github.com/near/borsh-rs) support, include it like this: - -```toml -[dependencies] -bit-vec = { version = "0.9", features = ["borsh"] } -``` - -Other available serialization libraries can be enabled with the -[`miniserde`](https://github.com/dtolnay/miniserde) and -[`nanoserde`](https://github.com/not-fl3/nanoserde) features. - - - -### Description - -Dynamic collections implemented with compact bit vectors. - -### Examples - -This is a simple example of the [Sieve of Eratosthenes][sieve] -which calculates prime numbers up to a given limit. - -[sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes - -```rust -use bit_vec::BitVec; - -let max_prime = 10000; - -// Store the primes as a BitVec -let primes = { - // Assume all numbers are prime to begin, and then we - // cross off non-primes progressively - let mut bv = BitVec::from_elem(max_prime, true); - - // Neither 0 nor 1 are prime - bv.set(0, false); - bv.set(1, false); - - for i in 2.. 1 + (max_prime as f64).sqrt() as usize { - // if i is a prime - if bv[i] { - // Mark all multiples of i as non-prime (any multiples below i * i - // will have been marked as non-prime previously) - for j in i.. { - if i * j >= max_prime { - break; - } - bv.set(i * j, false) - } - } - } - bv -}; - -// Simple primality tests below our max bound -let print_primes = 20; -print!("The primes below {} are: ", print_primes); -for x in 0..print_primes { - if primes.get(x).unwrap_or(false) { - print!("{} ", x); - } -} -println!(); - -let num_primes = primes.iter().filter(|x| *x).count(); -println!("There are {} primes below {}", num_primes, max_prime); -assert_eq!(num_primes, 1_229); -``` - - - -## License - -Dual-licensed for compatibility with the Rust project. - -Licensed under the Apache License Version 2.0: http://www.apache.org/licenses/LICENSE-2.0, -or the MIT license: http://opensource.org/licenses/MIT, at your option. diff --git a/README.md b/README.md new file mode 120000 index 0000000..e169d09 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +vec/README.md \ No newline at end of file diff --git a/fuzz/LICENSE-APACHE b/fuzz/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/fuzz/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/fuzz/LICENSE-MIT b/fuzz/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/fuzz/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/matrix/Cargo.toml b/matrix/Cargo.toml index d1f6883..1e5018b 100644 --- a/matrix/Cargo.toml +++ b/matrix/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bit-matrix" -version = "0.9.0" - +version.workspace = true +rust-version.workspace = true authors = [ "Piotr Czarnecki " ] description = "Library for bit matrices and vectors." keywords = ["container", "bit", "bitfield", "algebra"] @@ -9,7 +9,6 @@ documentation = "https://docs.rs/bit-matrix/latest/bit_matrix/" repository = "https://github.com/pczarn/bit-matrix" license = "MIT/Apache-2.0" edition = "2021" -rust-version = "1.77" [lib] name = "bit_matrix" diff --git a/matrix/LICENSE-APACHE b/matrix/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/matrix/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/matrix/LICENSE-APACHE b/matrix/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/matrix/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/matrix/LICENSE-MIT b/matrix/LICENSE-MIT deleted file mode 100644 index 29256f3..0000000 --- a/matrix/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2015-2016 Piotr Czarnecki - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/matrix/LICENSE-MIT b/matrix/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/matrix/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/matrix/README.md b/matrix/README.md index 50e2e4f..e1f0028 100644 --- a/matrix/README.md +++ b/matrix/README.md @@ -8,7 +8,7 @@ [![crates.io][crates.io shield]][crates.io link] [![Documentation][docs.rs badge]][docs.rs link] ![Rust CI][github ci badge] -![MSRV][rustc 1.65+] +![MSRV][rustc 1.82+]

    [![Dependency Status][deps.rs status]][deps.rs link] @@ -22,7 +22,7 @@ [docs.rs badge]: https://docs.rs/bit-matrix/badge.svg?version=0.8.1 [docs.rs link]: https://docs.rs/bit-matrix/0.8.1/bit-matrix/ [github ci badge]: https://github.com/pczarn/bit-matrix/workflows/CI/badge.svg?branch=master -[rustc 1.65+]: https://img.shields.io/badge/rustc-1.65%2B-blue.svg +[rustc 1.82+]: https://img.shields.io/badge/rustc-1.82%2B-blue.svg [deps.rs status]: https://deps.rs/crate/bit-matrix/0.8.1/status.svg [deps.rs link]: https://deps.rs/crate/bit-matrix/0.8.1 [shields.io download count]: https://img.shields.io/crates/d/bit-matrix.svg diff --git a/set/Cargo.toml b/set/Cargo.toml index 32e0e5c..8615ddc 100644 --- a/set/Cargo.toml +++ b/set/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bit-set" -version = "0.8.0" +version.workspace = true +rust-version.workspace = true authors = ["Alexis Beingessner "] license = "Apache-2.0 OR MIT" description = "A set of bits" @@ -10,13 +11,12 @@ documentation = "https://docs.rs/bit-set/" keywords = ["data-structures", "bitset"] readme = "README.md" edition = "2021" -rust-version = "1.85" [dependencies] -borsh = { version = "1.5", default-features = false, features = ["derive"], optional = true } -serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +borsh = { version = "1.6.0", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } miniserde = { version = "0.1", optional = true } -nanoserde = { git = "https://github.com/not-fl3/nanoserde.git", optional = true } +nanoserde = { version = "0.1", optional = true } smallvec = { version = "1.15", optional = true } [dependencies.bit-vec] @@ -38,9 +38,5 @@ serde = ["dep:serde", "bit-vec/serde"] miniserde = ["dep:miniserde", "bit-vec/miniserde"] nanoserde = ["dep:nanoserde", "bit-vec/nanoserde"] -serde_std = ["std", "serde/std"] -serde_no_std = ["serde/alloc"] -borsh_std = ["borsh/std"] - [package.metadata.docs.rs] -features = ["borsh", "serde", "miniserde", "nanoserde"] +features = ["borsh", "serde", "miniserde", "nanoserde", "smallvec"] diff --git a/set/LICENSE-APACHE b/set/LICENSE-APACHE deleted file mode 100644 index 11069ed..0000000 --- a/set/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/set/LICENSE-APACHE b/set/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/set/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/set/LICENSE-MIT b/set/LICENSE-MIT deleted file mode 100644 index b41213b..0000000 --- a/set/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2026 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/set/LICENSE-MIT b/set/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/set/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/set/README.md b/set/README.md index d7e96a9..5621316 100644 --- a/set/README.md +++ b/set/README.md @@ -8,9 +8,7 @@ [![crates.io][crates.io shield]][crates.io link] [![Documentation][docs.rs badge]][docs.rs link] ![Rust CI][github ci badge] -![rustc 1.63+] -![borsh: rustc 1.67+] -![nanoserde: rustc 1.67+] +![rustc 1.82+]

    [![Dependency Status][deps.rs status]][deps.rs link] @@ -21,14 +19,12 @@ [crates.io shield]: https://img.shields.io/crates/v/bit-set?label=latest [crates.io link]: https://crates.io/crates/bit-set -[docs.rs badge]: https://docs.rs/bit-set/badge.svg?version=0.8.0 -[docs.rs link]: https://docs.rs/bit-set/0.8.0/bit_set/ +[docs.rs badge]: https://docs.rs/bit-set/badge.svg?version=0.10.0 +[docs.rs link]: https://docs.rs/bit-set/0.10.0/bit_set/ [github ci badge]: https://github.com/contain-rs/bit-set/workflows/Rust/badge.svg?branch=master -[rustc 1.63+]: https://img.shields.io/badge/rustc-1.63%2B-blue.svg -[borsh: rustc 1.67+]: https://img.shields.io/badge/borsh:%20rustc-1.67%2B-blue.svg -[nanoserde: rustc 1.67+]: https://img.shields.io/badge/nanoserde:%20rustc-1.67%2B-blue.svg -[deps.rs status]: https://deps.rs/crate/bit-set/0.8.0/status.svg -[deps.rs link]: https://deps.rs/crate/bit-set/0.8.0 +[rustc 1.82+]: https://img.shields.io/badge/rustc-1.82%2B-blue.svg +[deps.rs status]: https://deps.rs/crate/bit-set/0.10.0/status.svg +[deps.rs link]: https://deps.rs/crate/bit-set/0.10.0 [shields.io download count]: https://img.shields.io/crates/d/bit-set.svg ## Usage @@ -37,7 +33,7 @@ Add this to your Cargo.toml: ```toml [dependencies] -bit-set = "0.8" +bit-set = "0.10" ``` Since Rust 2018, `extern crate` is no longer mandatory. If your edition is old (Rust 2015), @@ -51,28 +47,28 @@ If you want to use `serde`, enable it with the `serde` feature: ```toml [dependencies] -bit-set = { version = "0.8", features = ["serde"] } +bit-set = { version = "0.10", features = ["serde"] } ``` If you want to use bit-set in a program that has `#![no_std]`, just drop default features: ```toml [dependencies] -bit-set = { version = "0.8", default-features = false } +bit-set = { version = "0.10", default-features = false } ``` -If you want to use serde with the alloc crate instead of std, just use the `serde_no_std` feature: +If you want to use serde with the alloc crate instead of std, use this: ```toml [dependencies] -bit-set = { version = "0.8", default-features = false, features = ["serde", "serde_no_std"] } +bit-set = { version = "0.10", default-features = false, features = ["serde"] } ``` If you want [borsh-rs](https://github.com/near/borsh-rs) support, include it like this: ```toml [dependencies] -bit-set = { version = "0.8", features = ["borsh"] } +bit-set = { version = "0.10", features = ["borsh"] } ``` Other available serialization libraries can be enabled with the diff --git a/set/src/lib.rs b/set/src/lib.rs index 5608c6e..4f97cf1 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -73,646 +73,3 @@ pub mod local_prelude { pub use set::BitSet; pub use bit_vec::{BitStore, BitBlockOrStore}; - -#[cfg(test)] -mod tests { - #![allow(clippy::shadow_reuse)] - #![allow(clippy::shadow_same)] - #![allow(clippy::shadow_unrelated)] - - use crate::set::BitSet; - use bit_vec::BitVec; - use std::cmp::Ordering::{Equal, Greater, Less}; - use std::vec::Vec; - use std::{format, vec}; - - #[test] - fn test_bit_set_display() { - let mut s = BitSet::new(); - s.insert(1); - s.insert(10); - s.insert(50); - s.insert(2); - assert_eq!("{1, 2, 10, 50}", format!("{}", s)); - } - - #[test] - fn test_bit_set_debug() { - let mut s = BitSet::new(); - s.insert(1); - s.insert(10); - s.insert(50); - s.insert(2); - let expected = "BitSet { bit_vec: BitVec { storage: \ - \"01100000001000000000000000000000 \ - 0000000000000000001\", nbits: 51 } }"; - let actual = format!("{:?}", s); - assert_eq!(expected, actual); - } - - #[test] - fn test_bit_set_from_usizes() { - let usizes = vec![0, 2, 2, 3]; - let a: BitSet = usizes.into_iter().collect(); - let mut b = BitSet::new(); - b.insert(0); - b.insert(2); - b.insert(3); - assert_eq!(a, b); - } - - #[test] - fn test_bit_set_iterator() { - let usizes = vec![0, 2, 2, 3]; - let bit_vec: BitSet = usizes.into_iter().collect(); - - let idxs: Vec<_> = bit_vec.iter().collect(); - assert_eq!(idxs, [0, 2, 3]); - assert_eq!(bit_vec.iter().count(), 3); - - let long: BitSet = (0..10000).filter(|&n| n % 2 == 0).collect(); - let real: Vec<_> = (0..10000 / 2).map(|x| x * 2).collect(); - - let idxs: Vec<_> = long.iter().collect(); - assert_eq!(idxs, real); - assert_eq!(long.iter().count(), real.len()); - } - - #[test] - fn test_bit_set_frombit_vec_init() { - let bools = [true, false]; - let lengths = [10, 64, 100]; - for &b in &bools { - for &l in &lengths { - let bitset = BitSet::from_bit_vec(BitVec::from_elem(l, b)); - assert_eq!(bitset.contains(1), b); - assert_eq!(bitset.contains(l - 1), b); - assert!(!bitset.contains(l)); - } - } - } - - #[test] - fn test_bit_vec_masking() { - let b = BitVec::from_elem(140, true); - let mut bs = BitSet::from_bit_vec(b); - assert!(bs.contains(139)); - assert!(!bs.contains(140)); - assert!(bs.insert(150)); - assert!(!bs.contains(140)); - assert!(!bs.contains(149)); - assert!(bs.contains(150)); - assert!(!bs.contains(151)); - } - - #[test] - fn test_bit_set_basic() { - let mut b = BitSet::new(); - assert!(b.insert(3)); - assert!(!b.insert(3)); - assert!(b.contains(3)); - assert!(b.insert(4)); - assert!(!b.insert(4)); - assert!(b.contains(3)); - assert!(b.insert(400)); - assert!(!b.insert(400)); - assert!(b.contains(400)); - assert_eq!(b.count(), 3); - } - - #[test] - fn test_bit_set_intersection() { - let mut a = BitSet::new(); - let mut b = BitSet::new(); - - assert!(a.insert(11)); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(77)); - assert!(a.insert(103)); - assert!(a.insert(5)); - - assert!(b.insert(2)); - assert!(b.insert(11)); - assert!(b.insert(77)); - assert!(b.insert(5)); - assert!(b.insert(3)); - - let expected = [3, 5, 11, 77]; - let actual: Vec<_> = a.intersection(&b).collect(); - assert_eq!(actual, expected); - assert_eq!(a.intersection(&b).count(), expected.len()); - } - - #[test] - fn test_bit_set_difference() { - let mut a = BitSet::new(); - let mut b = BitSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(200)); - assert!(a.insert(500)); - - assert!(b.insert(3)); - assert!(b.insert(200)); - - let expected = [1, 5, 500]; - let actual: Vec<_> = a.difference(&b).collect(); - assert_eq!(actual, expected); - assert_eq!(a.difference(&b).count(), expected.len()); - } - - #[test] - fn test_bit_set_symmetric_difference() { - let mut a = BitSet::new(); - let mut b = BitSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(3)); - assert!(b.insert(9)); - assert!(b.insert(14)); - assert!(b.insert(220)); - - let expected = [1, 5, 11, 14, 220]; - let actual: Vec<_> = a.symmetric_difference(&b).collect(); - assert_eq!(actual, expected); - assert_eq!(a.symmetric_difference(&b).count(), expected.len()); - } - - #[test] - fn test_bit_set_union() { - let mut a = BitSet::new(); - let mut b = BitSet::new(); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - assert!(a.insert(160)); - assert!(a.insert(19)); - assert!(a.insert(24)); - assert!(a.insert(200)); - - assert!(b.insert(1)); - assert!(b.insert(5)); - assert!(b.insert(9)); - assert!(b.insert(13)); - assert!(b.insert(19)); - - let expected = [1, 3, 5, 9, 11, 13, 19, 24, 160, 200]; - let actual: Vec<_> = a.union(&b).collect(); - assert_eq!(actual, expected); - assert_eq!(a.union(&b).count(), expected.len()); - } - - #[test] - fn test_bit_set_subset() { - let mut set1 = BitSet::new(); - let mut set2 = BitSet::new(); - - assert!(set1.is_subset(&set2)); // {} {} - set2.insert(100); - assert!(set1.is_subset(&set2)); // {} { 1 } - set2.insert(200); - assert!(set1.is_subset(&set2)); // {} { 1, 2 } - set1.insert(200); - assert!(set1.is_subset(&set2)); // { 2 } { 1, 2 } - set1.insert(300); - assert!(!set1.is_subset(&set2)); // { 2, 3 } { 1, 2 } - set2.insert(300); - assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3 } - set2.insert(400); - assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3, 4 } - set2.remove(100); - assert!(set1.is_subset(&set2)); // { 2, 3 } { 2, 3, 4 } - set2.remove(300); - assert!(!set1.is_subset(&set2)); // { 2, 3 } { 2, 4 } - set1.remove(300); - assert!(set1.is_subset(&set2)); // { 2 } { 2, 4 } - } - - #[test] - fn test_bit_set_is_disjoint() { - let a = BitSet::from_bytes(&[0b10100010]); - let b = BitSet::from_bytes(&[0b01000000]); - let c = BitSet::new(); - let d = BitSet::from_bytes(&[0b00110000]); - - assert!(!a.is_disjoint(&d)); - assert!(!d.is_disjoint(&a)); - - assert!(a.is_disjoint(&b)); - assert!(a.is_disjoint(&c)); - assert!(b.is_disjoint(&a)); - assert!(b.is_disjoint(&c)); - assert!(c.is_disjoint(&a)); - assert!(c.is_disjoint(&b)); - } - - #[test] - fn test_bit_set_union_with() { - //a should grow to include larger elements - let mut a = BitSet::new(); - a.insert(0); - let mut b = BitSet::new(); - b.insert(5); - let expected = BitSet::from_bytes(&[0b10000100]); - a.union_with(&b); - assert_eq!(a, expected); - - // Standard - let mut a = BitSet::from_bytes(&[0b10100010]); - let mut b = BitSet::from_bytes(&[0b01100010]); - let c = a.clone(); - a.union_with(&b); - b.union_with(&c); - assert_eq!(a.count(), 4); - assert_eq!(b.count(), 4); - } - - #[test] - fn test_bit_set_intersect_with() { - // Explicitly 0'ed bits - let mut a = BitSet::from_bytes(&[0b10100010]); - let mut b = BitSet::from_bytes(&[0b00000000]); - let c = a.clone(); - a.intersect_with(&b); - b.intersect_with(&c); - assert!(a.is_empty()); - assert!(b.is_empty()); - - // Uninitialized bits should behave like 0's - let mut a = BitSet::from_bytes(&[0b10100010]); - let mut b = BitSet::new(); - let c = a.clone(); - a.intersect_with(&b); - b.intersect_with(&c); - assert!(a.is_empty()); - assert!(b.is_empty()); - - // Standard - let mut a = BitSet::from_bytes(&[0b10100010]); - let mut b = BitSet::from_bytes(&[0b01100010]); - let c = a.clone(); - a.intersect_with(&b); - b.intersect_with(&c); - assert_eq!(a.count(), 2); - assert_eq!(b.count(), 2); - } - - #[test] - fn test_bit_set_difference_with() { - // Explicitly 0'ed bits - let mut a = BitSet::from_bytes(&[0b00000000]); - let b = BitSet::from_bytes(&[0b10100010]); - a.difference_with(&b); - assert!(a.is_empty()); - - // Uninitialized bits should behave like 0's - let mut a = BitSet::new(); - let b = BitSet::from_bytes(&[0b11111111]); - a.difference_with(&b); - assert!(a.is_empty()); - - // Standard - let mut a = BitSet::from_bytes(&[0b10100010]); - let mut b = BitSet::from_bytes(&[0b01100010]); - let c = a.clone(); - a.difference_with(&b); - b.difference_with(&c); - assert_eq!(a.count(), 1); - assert_eq!(b.count(), 1); - } - - #[test] - fn test_bit_set_symmetric_difference_with() { - //a should grow to include larger elements - let mut a = BitSet::new(); - a.insert(0); - a.insert(1); - let mut b = BitSet::new(); - b.insert(1); - b.insert(5); - let expected = BitSet::from_bytes(&[0b10000100]); - a.symmetric_difference_with(&b); - assert_eq!(a, expected); - - let mut a = BitSet::from_bytes(&[0b10100010]); - let b = BitSet::new(); - let c = a.clone(); - a.symmetric_difference_with(&b); - assert_eq!(a, c); - - // Standard - let mut a = BitSet::from_bytes(&[0b11100010]); - let mut b = BitSet::from_bytes(&[0b01101010]); - let c = a.clone(); - a.symmetric_difference_with(&b); - b.symmetric_difference_with(&c); - assert_eq!(a.count(), 2); - assert_eq!(b.count(), 2); - } - - #[test] - fn test_bit_set_eq() { - let a = BitSet::from_bytes(&[0b10100010]); - let b = BitSet::from_bytes(&[0b00000000]); - let c = BitSet::new(); - - assert!(a == a); - assert!(a != b); - assert!(a != c); - assert!(b == b); - assert!(b == c); - assert!(c == c); - } - - #[test] - fn test_bit_set_cmp() { - let a = BitSet::from_bytes(&[0b10100010]); - let b = BitSet::from_bytes(&[0b00000000]); - let c = BitSet::new(); - - assert_eq!(a.cmp(&b), Greater); - assert_eq!(a.cmp(&c), Greater); - assert_eq!(b.cmp(&a), Less); - assert_eq!(b.cmp(&c), Equal); - assert_eq!(c.cmp(&a), Less); - assert_eq!(c.cmp(&b), Equal); - } - - #[test] - fn test_bit_set_shrink_to_fit_new() { - // There was a strange bug where we refused to truncate to 0 - // and this would end up actually growing the array in a way - // that (safely corrupted the state). - let mut a = BitSet::new(); - assert_eq!(a.count(), 0); - assert_eq!(a.capacity(), 0); - a.shrink_to_fit(); - assert_eq!(a.count(), 0); - assert_eq!(a.capacity(), 0); - assert!(!a.contains(1)); - a.insert(3); - assert!(a.contains(3)); - assert_eq!(a.count(), 1); - assert!(a.capacity() > 0); - a.shrink_to_fit(); - assert!(a.contains(3)); - assert_eq!(a.count(), 1); - assert!(a.capacity() > 0); - } - - #[test] - fn test_bit_set_shrink_to_fit() { - let mut a = BitSet::new(); - assert_eq!(a.count(), 0); - assert_eq!(a.capacity(), 0); - a.insert(259); - a.insert(98); - a.insert(3); - assert_eq!(a.count(), 3); - assert!(a.capacity() > 0); - assert!(!a.contains(1)); - assert!(a.contains(259)); - assert!(a.contains(98)); - assert!(a.contains(3)); - - a.shrink_to_fit(); - assert!(!a.contains(1)); - assert!(a.contains(259)); - assert!(a.contains(98)); - assert!(a.contains(3)); - assert_eq!(a.count(), 3); - assert!(a.capacity() > 0); - - let old_cap = a.capacity(); - assert!(a.remove(259)); - a.shrink_to_fit(); - assert!(a.capacity() < old_cap, "{} {}", a.capacity(), old_cap); - assert!(!a.contains(1)); - assert!(!a.contains(259)); - assert!(a.contains(98)); - assert!(a.contains(3)); - assert_eq!(a.count(), 2); - - let old_cap2 = a.capacity(); - a.make_empty(); - assert_eq!(a.capacity(), old_cap2); - assert_eq!(a.count(), 0); - assert!(!a.contains(1)); - assert!(!a.contains(259)); - assert!(!a.contains(98)); - assert!(!a.contains(3)); - - a.insert(512); - assert!(a.capacity() > 0); - assert_eq!(a.count(), 1); - assert!(a.contains(512)); - assert!(!a.contains(1)); - assert!(!a.contains(259)); - assert!(!a.contains(98)); - assert!(!a.contains(3)); - - a.remove(512); - a.shrink_to_fit(); - assert_eq!(a.capacity(), 0); - assert_eq!(a.count(), 0); - assert!(!a.contains(512)); - assert!(!a.contains(1)); - assert!(!a.contains(259)); - assert!(!a.contains(98)); - assert!(!a.contains(3)); - assert!(!a.contains(0)); - } - - #[test] - fn test_bit_vec_remove() { - let mut a = BitSet::new(); - - assert!(a.insert(1)); - assert!(a.remove(1)); - - assert!(a.insert(100)); - assert!(a.remove(100)); - - assert!(a.insert(1000)); - assert!(a.remove(1000)); - a.shrink_to_fit(); - } - - #[test] - fn test_bit_vec_clone() { - let mut a = BitSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(100)); - assert!(a.insert(1000)); - - let mut b = a.clone(); - - assert!(a == b); - - assert!(b.remove(1)); - assert!(a.contains(1)); - - assert!(a.remove(1000)); - assert!(b.contains(1000)); - } - - #[test] - fn test_truncate() { - let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; - - let mut s = BitSet::from_bytes(&bytes); - s.truncate(5 * 8); - - assert_eq!(s, BitSet::from_bytes(&bytes[..5])); - assert_eq!(s.count(), 5 * 8); - s.truncate(4 * 8); - assert_eq!(s, BitSet::from_bytes(&bytes[..4])); - assert_eq!(s.count(), 4 * 8); - // Truncating to a size > s.len() should be a noop - s.truncate(5 * 8); - assert_eq!(s, BitSet::from_bytes(&bytes[..4])); - assert_eq!(s.count(), 4 * 8); - s.truncate(8); - assert_eq!(s, BitSet::from_bytes(&bytes[..1])); - assert_eq!(s.count(), 8); - s.truncate(0); - assert_eq!(s, BitSet::from_bytes(&[])); - assert_eq!(s.count(), 0); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serialization() { - let bset: BitSet = BitSet::new(); - let serialized = serde_json::to_string(&bset).unwrap(); - let unserialized: BitSet = serde_json::from_str(&serialized).unwrap(); - assert_eq!(bset, unserialized); - - let elems: Vec = vec![11, 42, 100, 101]; - let bset: BitSet = elems.iter().map(|n| *n).collect(); - let serialized = serde_json::to_string(&bset).unwrap(); - let unserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(bset, unserialized); - } - - #[cfg(feature = "miniserde")] - #[test] - fn test_miniserde_serialization() { - let bset: BitSet = BitSet::new(); - let serialized = miniserde::json::to_string(&bset); - let unserialized: BitSet = miniserde::json::from_str(&serialized[..]).unwrap(); - assert_eq!(bset, unserialized); - - let elems: Vec = vec![11, 42, 100, 101]; - let bset: BitSet = elems.iter().map(|n| *n).collect(); - let serialized = miniserde::json::to_string(&bset); - let unserialized = miniserde::json::from_str(&serialized[..]).unwrap(); - assert_eq!(bset, unserialized); - } - - #[cfg(feature = "nanoserde")] - #[test] - fn test_nanoserde_json_serialization() { - use nanoserde::{DeJson, SerJson}; - - let bset: BitSet = BitSet::new(); - let serialized = bset.serialize_json(); - let unserialized: BitSet = BitSet::deserialize_json(&serialized[..]).unwrap(); - assert_eq!(bset, unserialized); - - let elems: Vec = vec![11, 42, 100, 101]; - let bset: BitSet = elems.iter().map(|n| *n).collect(); - let serialized = bset.serialize_json(); - let unserialized = BitSet::deserialize_json(&serialized[..]).unwrap(); - assert_eq!(bset, unserialized); - } - - #[cfg(feature = "borsh")] - #[test] - fn test_borsh_serialization() { - let bset: BitSet = BitSet::new(); - let serialized = borsh::to_vec(&bset).unwrap(); - let unserialized: BitSet = borsh::from_slice(&serialized[..]).unwrap(); - assert_eq!(bset, unserialized); - - let elems: Vec = vec![11, 42, 100, 101]; - let bset: BitSet = elems.iter().map(|n| *n).collect(); - let serialized = borsh::to_vec(&bset).unwrap(); - let unserialized = borsh::from_slice(&serialized[..]).unwrap(); - assert_eq!(bset, unserialized); - } - - /* - #[test] - fn test_bit_set_append() { - let mut a = BitSet::new(); - a.insert(2); - a.insert(6); - - let mut b = BitSet::new(); - b.insert(1); - b.insert(3); - b.insert(6); - - a.append(&mut b); - - assert_eq!(a.len(), 4); - assert_eq!(b.len(), 0); - assert!(b.capacity() >= 6); - - assert_eq!(a, BitSet::from_bytes(&[0b01110010])); - } - - #[test] - fn test_bit_set_split_off() { - // Split at 0 - let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, - 0b00110011, 0b01101011, 0b10101101]); - - let b = a.split_off(0); - - assert_eq!(a.len(), 0); - assert_eq!(b.len(), 21); - - assert_eq!(b, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, - 0b00110011, 0b01101011, 0b10101101]); - - // Split behind last element - let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, - 0b00110011, 0b01101011, 0b10101101]); - - let b = a.split_off(50); - - assert_eq!(a.len(), 21); - assert_eq!(b.len(), 0); - - assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, - 0b00110011, 0b01101011, 0b10101101])); - - // Split at arbitrary element - let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, - 0b00110011, 0b01101011, 0b10101101]); - - let b = a.split_off(34); - - assert_eq!(a.len(), 12); - assert_eq!(b.len(), 9); - - assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, - 0b00110011, 0b01000000])); - assert_eq!(b, BitSet::from_bytes(&[0, 0, 0, 0, - 0b00101011, 0b10101101])); - } - */ -} diff --git a/set/tests/serialization.rs b/set/tests/serialization.rs new file mode 100644 index 0000000..c536788 --- /dev/null +++ b/set/tests/serialization.rs @@ -0,0 +1,64 @@ +#[allow(unused_imports)] +use bit_set::BitSet; + +#[cfg(feature = "serde")] +#[test] +fn test_serialization() { + let bset: BitSet = BitSet::new(); + let serialized = serde_json::to_string(&bset).unwrap(); + let unserialized: BitSet = serde_json::from_str(&serialized).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = serde_json::to_string(&bset).unwrap(); + let unserialized = serde_json::from_str(&serialized).unwrap(); + assert_eq!(bset, unserialized); +} + +#[cfg(feature = "miniserde")] +#[test] +fn test_miniserde_serialization() { + let bset: BitSet = BitSet::new(); + let serialized = miniserde::json::to_string(&bset); + let unserialized: BitSet = miniserde::json::from_str(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = miniserde::json::to_string(&bset); + let unserialized = miniserde::json::from_str(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); +} + +#[cfg(feature = "nanoserde")] +#[test] +fn test_nanoserde_json_serialization() { + use nanoserde::{DeJson, SerJson}; + + let bset: BitSet = BitSet::new(); + let serialized = bset.serialize_json(); + let unserialized: BitSet = BitSet::deserialize_json(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = bset.serialize_json(); + let unserialized = BitSet::deserialize_json(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); +} + +#[cfg(feature = "borsh")] +#[test] +fn test_borsh_serialization() { + let bset: BitSet = BitSet::new(); + let serialized = borsh::to_vec(&bset).unwrap(); + let unserialized: BitSet = borsh::from_slice(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); + + let elems: Vec = vec![11, 42, 100, 101]; + let bset: BitSet = elems.iter().map(|n| *n).collect(); + let serialized = borsh::to_vec(&bset).unwrap(); + let unserialized = borsh::from_slice(&serialized[..]).unwrap(); + assert_eq!(bset, unserialized); +} diff --git a/set/tests/set.rs b/set/tests/set.rs new file mode 100644 index 0000000..fce9b38 --- /dev/null +++ b/set/tests/set.rs @@ -0,0 +1,577 @@ +#![allow(clippy::shadow_reuse)] +#![allow(clippy::shadow_same)] +#![allow(clippy::shadow_unrelated)] + +use bit_set::BitSet; +use bit_vec::BitVec; +use std::cmp::Ordering::{Equal, Greater, Less}; +use std::vec::Vec; +use std::{format, vec}; + +#[test] +fn test_bit_set_display() { + let mut s = BitSet::new(); + s.insert(1); + s.insert(10); + s.insert(50); + s.insert(2); + assert_eq!("{1, 2, 10, 50}", format!("{}", s)); +} + +#[test] +fn test_bit_set_debug() { + let mut s = BitSet::new(); + s.insert(1); + s.insert(10); + s.insert(50); + s.insert(2); + let expected = "BitSet { bit_vec: BitVec { storage: \ + \"01100000001000000000000000000000 \ + 0000000000000000001\", nbits: 51 } }"; + let actual = format!("{:?}", s); + assert_eq!(expected, actual); +} + +#[test] +fn test_bit_set_from_usizes() { + let usizes = vec![0, 2, 2, 3]; + let a: BitSet = usizes.into_iter().collect(); + let mut b = BitSet::new(); + b.insert(0); + b.insert(2); + b.insert(3); + assert_eq!(a, b); +} + +#[test] +fn test_bit_set_iterator() { + let usizes = vec![0, 2, 2, 3]; + let bit_vec: BitSet = usizes.into_iter().collect(); + + let idxs: Vec<_> = bit_vec.iter().collect(); + assert_eq!(idxs, [0, 2, 3]); + assert_eq!(bit_vec.iter().count(), 3); + + let long: BitSet = (0..10000).filter(|&n| n % 2 == 0).collect(); + let real: Vec<_> = (0..10000 / 2).map(|x| x * 2).collect(); + + let idxs: Vec<_> = long.iter().collect(); + assert_eq!(idxs, real); + assert_eq!(long.iter().count(), real.len()); +} + +#[test] +fn test_bit_set_frombit_vec_init() { + let bools = [true, false]; + let lengths = [10, 64, 100]; + for &b in &bools { + for &l in &lengths { + let bitset = BitSet::from_bit_vec(BitVec::from_elem(l, b)); + assert_eq!(bitset.contains(1), b); + assert_eq!(bitset.contains(l - 1), b); + assert!(!bitset.contains(l)); + } + } +} + +#[test] +fn test_bit_vec_masking() { + let b = BitVec::from_elem(140, true); + let mut bs = BitSet::from_bit_vec(b); + assert!(bs.contains(139)); + assert!(!bs.contains(140)); + assert!(bs.insert(150)); + assert!(!bs.contains(140)); + assert!(!bs.contains(149)); + assert!(bs.contains(150)); + assert!(!bs.contains(151)); +} + +#[test] +fn test_bit_set_basic() { + let mut b = BitSet::new(); + assert!(b.insert(3)); + assert!(!b.insert(3)); + assert!(b.contains(3)); + assert!(b.insert(4)); + assert!(!b.insert(4)); + assert!(b.contains(3)); + assert!(b.insert(400)); + assert!(!b.insert(400)); + assert!(b.contains(400)); + assert_eq!(b.count(), 3); +} + +#[test] +fn test_bit_set_intersection() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let actual: Vec<_> = a.intersection(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.intersection(&b).count(), expected.len()); +} + +#[test] +fn test_bit_set_difference() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(200)); + assert!(a.insert(500)); + + assert!(b.insert(3)); + assert!(b.insert(200)); + + let expected = [1, 5, 500]; + let actual: Vec<_> = a.difference(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.difference(&b).count(), expected.len()); +} + +#[test] +fn test_bit_set_symmetric_difference() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(220)); + + let expected = [1, 5, 11, 14, 220]; + let actual: Vec<_> = a.symmetric_difference(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.symmetric_difference(&b).count(), expected.len()); +} + +#[test] +fn test_bit_set_union() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(160)); + assert!(a.insert(19)); + assert!(a.insert(24)); + assert!(a.insert(200)); + + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [1, 3, 5, 9, 11, 13, 19, 24, 160, 200]; + let actual: Vec<_> = a.union(&b).collect(); + assert_eq!(actual, expected); + assert_eq!(a.union(&b).count(), expected.len()); +} + +#[test] +fn test_bit_set_subset() { + let mut set1 = BitSet::new(); + let mut set2 = BitSet::new(); + + assert!(set1.is_subset(&set2)); // {} {} + set2.insert(100); + assert!(set1.is_subset(&set2)); // {} { 1 } + set2.insert(200); + assert!(set1.is_subset(&set2)); // {} { 1, 2 } + set1.insert(200); + assert!(set1.is_subset(&set2)); // { 2 } { 1, 2 } + set1.insert(300); + assert!(!set1.is_subset(&set2)); // { 2, 3 } { 1, 2 } + set2.insert(300); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3 } + set2.insert(400); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3, 4 } + set2.remove(100); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 2, 3, 4 } + set2.remove(300); + assert!(!set1.is_subset(&set2)); // { 2, 3 } { 2, 4 } + set1.remove(300); + assert!(set1.is_subset(&set2)); // { 2 } { 2, 4 } +} + +#[test] +fn test_bit_set_is_disjoint() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b01000000]); + let c = BitSet::new(); + let d = BitSet::from_bytes(&[0b00110000]); + + assert!(!a.is_disjoint(&d)); + assert!(!d.is_disjoint(&a)); + + assert!(a.is_disjoint(&b)); + assert!(a.is_disjoint(&c)); + assert!(b.is_disjoint(&a)); + assert!(b.is_disjoint(&c)); + assert!(c.is_disjoint(&a)); + assert!(c.is_disjoint(&b)); +} + +#[test] +fn test_bit_set_union_with() { + //a should grow to include larger elements + let mut a = BitSet::new(); + a.insert(0); + let mut b = BitSet::new(); + b.insert(5); + let expected = BitSet::from_bytes(&[0b10000100]); + a.union_with(&b); + assert_eq!(a, expected); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.union_with(&b); + b.union_with(&c); + assert_eq!(a.count(), 4); + assert_eq!(b.count(), 4); +} + +#[test] +fn test_bit_set_intersect_with() { + // Explicitly 0'ed bits + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b00000000]); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert!(a.is_empty()); + assert!(b.is_empty()); + + // Uninitialized bits should behave like 0's + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::new(); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert!(a.is_empty()); + assert!(b.is_empty()); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert_eq!(a.count(), 2); + assert_eq!(b.count(), 2); +} + +#[test] +fn test_bit_set_difference_with() { + // Explicitly 0'ed bits + let mut a = BitSet::from_bytes(&[0b00000000]); + let b = BitSet::from_bytes(&[0b10100010]); + a.difference_with(&b); + assert!(a.is_empty()); + + // Uninitialized bits should behave like 0's + let mut a = BitSet::new(); + let b = BitSet::from_bytes(&[0b11111111]); + a.difference_with(&b); + assert!(a.is_empty()); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.difference_with(&b); + b.difference_with(&c); + assert_eq!(a.count(), 1); + assert_eq!(b.count(), 1); +} + +#[test] +fn test_bit_set_symmetric_difference_with() { + //a should grow to include larger elements + let mut a = BitSet::new(); + a.insert(0); + a.insert(1); + let mut b = BitSet::new(); + b.insert(1); + b.insert(5); + let expected = BitSet::from_bytes(&[0b10000100]); + a.symmetric_difference_with(&b); + assert_eq!(a, expected); + + let mut a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::new(); + let c = a.clone(); + a.symmetric_difference_with(&b); + assert_eq!(a, c); + + // Standard + let mut a = BitSet::from_bytes(&[0b11100010]); + let mut b = BitSet::from_bytes(&[0b01101010]); + let c = a.clone(); + a.symmetric_difference_with(&b); + b.symmetric_difference_with(&c); + assert_eq!(a.count(), 2); + assert_eq!(b.count(), 2); +} + +#[test] +fn test_bit_set_eq() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b00000000]); + let c = BitSet::new(); + + assert!(a == a); + assert!(a != b); + assert!(a != c); + assert!(b == b); + assert!(b == c); + assert!(c == c); +} + +#[test] +fn test_bit_set_cmp() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b00000000]); + let c = BitSet::new(); + + assert_eq!(a.cmp(&b), Greater); + assert_eq!(a.cmp(&c), Greater); + assert_eq!(b.cmp(&a), Less); + assert_eq!(b.cmp(&c), Equal); + assert_eq!(c.cmp(&a), Less); + assert_eq!(c.cmp(&b), Equal); +} + +#[test] +fn test_bit_set_shrink_to_fit_new() { + // There was a strange bug where we refused to truncate to 0 + // and this would end up actually growing the array in a way + // that (safely corrupted the state). + let mut a = BitSet::new(); + assert_eq!(a.count(), 0); + assert_eq!(a.capacity(), 0); + a.shrink_to_fit(); + assert_eq!(a.count(), 0); + assert_eq!(a.capacity(), 0); + assert!(!a.contains(1)); + a.insert(3); + assert!(a.contains(3)); + assert_eq!(a.count(), 1); + assert!(a.capacity() > 0); + a.shrink_to_fit(); + assert!(a.contains(3)); + assert_eq!(a.count(), 1); + assert!(a.capacity() > 0); +} + +#[test] +fn test_bit_set_shrink_to_fit() { + let mut a = BitSet::new(); + assert_eq!(a.count(), 0); + assert_eq!(a.capacity(), 0); + a.insert(259); + a.insert(98); + a.insert(3); + assert_eq!(a.count(), 3); + assert!(a.capacity() > 0); + assert!(!a.contains(1)); + assert!(a.contains(259)); + assert!(a.contains(98)); + assert!(a.contains(3)); + + a.shrink_to_fit(); + assert!(!a.contains(1)); + assert!(a.contains(259)); + assert!(a.contains(98)); + assert!(a.contains(3)); + assert_eq!(a.count(), 3); + assert!(a.capacity() > 0); + + let old_cap = a.capacity(); + assert!(a.remove(259)); + a.shrink_to_fit(); + assert!(a.capacity() < old_cap, "{} {}", a.capacity(), old_cap); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(a.contains(98)); + assert!(a.contains(3)); + assert_eq!(a.count(), 2); + + let old_cap2 = a.capacity(); + a.make_empty(); + assert_eq!(a.capacity(), old_cap2); + assert_eq!(a.count(), 0); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(!a.contains(98)); + assert!(!a.contains(3)); + + a.insert(512); + assert!(a.capacity() > 0); + assert_eq!(a.count(), 1); + assert!(a.contains(512)); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(!a.contains(98)); + assert!(!a.contains(3)); + + a.remove(512); + a.shrink_to_fit(); + assert_eq!(a.capacity(), 0); + assert_eq!(a.count(), 0); + assert!(!a.contains(512)); + assert!(!a.contains(1)); + assert!(!a.contains(259)); + assert!(!a.contains(98)); + assert!(!a.contains(3)); + assert!(!a.contains(0)); +} + +#[test] +fn test_bit_vec_remove() { + let mut a = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.remove(1)); + + assert!(a.insert(100)); + assert!(a.remove(100)); + + assert!(a.insert(1000)); + assert!(a.remove(1000)); + a.shrink_to_fit(); +} + +#[test] +fn test_bit_vec_clone() { + let mut a = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(100)); + assert!(a.insert(1000)); + + let mut b = a.clone(); + + assert!(a == b); + + assert!(b.remove(1)); + assert!(a.contains(1)); + + assert!(a.remove(1000)); + assert!(b.contains(1000)); +} + +#[test] +fn test_truncate() { + let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; + + let mut s = BitSet::from_bytes(&bytes); + s.truncate(5 * 8); + + assert_eq!(s, BitSet::from_bytes(&bytes[..5])); + assert_eq!(s.count(), 5 * 8); + s.truncate(4 * 8); + assert_eq!(s, BitSet::from_bytes(&bytes[..4])); + assert_eq!(s.count(), 4 * 8); + // Truncating to a size > s.len() should be a noop + s.truncate(5 * 8); + assert_eq!(s, BitSet::from_bytes(&bytes[..4])); + assert_eq!(s.count(), 4 * 8); + s.truncate(8); + assert_eq!(s, BitSet::from_bytes(&bytes[..1])); + assert_eq!(s.count(), 8); + s.truncate(0); + assert_eq!(s, BitSet::from_bytes(&[])); + assert_eq!(s.count(), 0); +} + +/* + #[test] + fn test_bit_set_append() { + let mut a = BitSet::new(); + a.insert(2); + a.insert(6); + + let mut b = BitSet::new(); + b.insert(1); + b.insert(3); + b.insert(6); + + a.append(&mut b); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 6); + + assert_eq!(a, BitSet::from_bytes(&[0b01110010])); + } + + #[test] + fn test_bit_set_split_off() { + // Split at 0 + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 21); + + assert_eq!(b, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + // Split behind last element + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(50); + + assert_eq!(a.len(), 21); + assert_eq!(b.len(), 0); + + assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101])); + + // Split at arbitrary element + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(34); + + assert_eq!(a.len(), 12); + assert_eq!(b.len(), 9); + + assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01000000])); + assert_eq!(b, BitSet::from_bytes(&[0, 0, 0, 0, + 0b00101011, 0b10101101])); + } +*/ diff --git a/vec/Cargo.toml b/vec/Cargo.toml index f0e3b76..7934973 100644 --- a/vec/Cargo.toml +++ b/vec/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bit-vec" -version = "0.9.0" +version.workspace = true +rust-version.workspace = true authors = ["Alexis Beingessner "] license = "Apache-2.0 OR MIT" description = "A vector of bits" @@ -10,13 +11,12 @@ documentation = "https://docs.rs/bit-vec/" keywords = ["data-structures", "bitvec", "bitmask", "bitmap", "bit"] readme = "README.md" edition = "2021" -rust-version = "1.85" [dependencies] -borsh = { version = "1.5.7", default-features = false, features = ["derive"], optional = true } -serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +borsh = { version = "1.6.0", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } miniserde = { version = "0.1", optional = true } -nanoserde = { git = "https://github.com/not-fl3/nanoserde.git", version = "0.2.2", optional = true } +nanoserde = { version = "0.1", optional = true } smallvec = { version = "1.15", optional = true } [dev-dependencies] @@ -27,10 +27,7 @@ generic-tests = "0.1" [features] default = ["std"] -serde_std = ["std", "serde/std"] -serde_no_std = ["serde/alloc"] -borsh_std = ["borsh/std"] -std = [] +std = ["serde?/std", "borsh?/std"] allocator_api = [] [package.metadata.docs.rs] diff --git a/vec/LICENSE-APACHE b/vec/LICENSE-APACHE new file mode 120000 index 0000000..965b606 --- /dev/null +++ b/vec/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/vec/LICENSE-MIT b/vec/LICENSE-MIT new file mode 120000 index 0000000..76219eb --- /dev/null +++ b/vec/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/vec/README.md b/vec/README.md new file mode 100644 index 0000000..54f4f5d --- /dev/null +++ b/vec/README.md @@ -0,0 +1,137 @@ +
    +

    bit-vec

    +

    + A compact vector of bits. +

    +

    + +[![crates.io][crates.io shield]][crates.io link] +[![Documentation][docs.rs badge]][docs.rs link] +![Rust CI][github ci badge] +![MSRV][rustc 1.82+] +
    +
    +[![Dependency Status][deps.rs status]][deps.rs link] +[![Download Status][shields.io download count]][crates.io link] + +

    +
    + +[crates.io shield]: https://img.shields.io/crates/v/bit-vec?label=latest +[crates.io link]: https://crates.io/crates/bit-vec +[docs.rs badge]: https://docs.rs/bit-vec/badge.svg?version=0.10.0 +[docs.rs link]: https://docs.rs/bit-vec/0.10.0/bit_vec/ +[github ci badge]: https://github.com/contain-rs/bit-vec/actions/workflows/rust.yml/badge.svg +[rustc 1.82+]: https://img.shields.io/badge/rustc-1.82%2B-blue.svg +[deps.rs status]: https://deps.rs/crate/bit-vec/0.10.0/status.svg +[deps.rs link]: https://deps.rs/crate/bit-vec/0.10.0 +[shields.io download count]: https://img.shields.io/crates/d/bit-vec.svg + +## Usage + +Add this to your Cargo.toml: + +```toml +[dependencies] +bit-vec = "0.10" +``` + +If you want [serde](https://github.com/serde-rs/serde) support, include the feature like this: + +```toml +[dependencies] +bit-vec = { version = "0.10", features = ["serde"] } +``` + +If you want to use bit-vec in a program that has `#![no_std]`, just drop default features: + +```toml +[dependencies] +bit-vec = { version = "0.10", default-features = false } +``` + +If you want to use serde with the alloc crate instead of std, use this: + +```toml +[dependencies] +bit-vec = { version = "0.10", default-features = false, features = ["serde"] } +``` + +If you want [borsh-rs](https://github.com/near/borsh-rs) support, include it like this: + +```toml +[dependencies] +bit-vec = { version = "0.10", features = ["borsh"] } +``` + +Other available serialization libraries can be enabled with the +[`miniserde`](https://github.com/dtolnay/miniserde) and +[`nanoserde`](https://github.com/not-fl3/nanoserde) features. + + + +### Description + +Dynamic collections implemented with compact bit vectors. + +### Examples + +This is a simple example of the [Sieve of Eratosthenes][sieve] +which calculates prime numbers up to a given limit. + +[sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes + +```rust +use bit_vec::BitVec; + +let max_prime = 10000; + +// Store the primes as a BitVec +let primes = { + // Assume all numbers are prime to begin, and then we + // cross off non-primes progressively + let mut bv = BitVec::from_elem(max_prime, true); + + // Neither 0 nor 1 are prime + bv.set(0, false); + bv.set(1, false); + + for i in 2.. 1 + (max_prime as f64).sqrt() as usize { + // if i is a prime + if bv[i] { + // Mark all multiples of i as non-prime (any multiples below i * i + // will have been marked as non-prime previously) + for j in i.. { + if i * j >= max_prime { + break; + } + bv.set(i * j, false) + } + } + } + bv +}; + +// Simple primality tests below our max bound +let print_primes = 20; +print!("The primes below {} are: ", print_primes); +for x in 0..print_primes { + if primes.get(x).unwrap_or(false) { + print!("{} ", x); + } +} +println!(); + +let num_primes = primes.iter().filter(|x| *x).count(); +println!("There are {} primes below {}", num_primes, max_prime); +assert_eq!(num_primes, 1_229); +``` + + + +## License + +Dual-licensed for compatibility with the Rust project. + +Licensed under the Apache License Version 2.0: http://www.apache.org/licenses/LICENSE-2.0, +or the MIT license: http://opensource.org/licenses/MIT, at your option. diff --git a/vec/src/lib.rs b/vec/src/lib.rs index 72e4d7a..29ab121 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -108,7 +108,6 @@ extern crate nanoserde; extern crate serde; #[cfg(not(feature = "std"))] -#[macro_use] extern crate alloc; mod block; @@ -158,1423 +157,6 @@ mod local_prelude { pub use crate::block::BitBlock; pub use crate::block_or_store::BitBlockOrStore; - #[cfg(test)] - pub use crate::iter::Iter; pub use crate::store::BitStore; pub(crate) use crate::util::Block; } - -#[cfg(feature = "nanoserde")] -#[allow(dead_code)] -type B = u32; - -#[cfg(test)] -#[generic_tests::define] -mod tests { - #![allow(clippy::shadow_reuse)] - #![allow(clippy::shadow_same)] - #![allow(clippy::shadow_unrelated)] - #![allow(clippy::extra_unused_type_parameters)] - - use super::BitVec; - use crate::local_prelude::*; - - // This is stupid, but I want to differentiate from a "random" 32 - const U32_BITS: usize = 32; - - #[test] - fn test_display_output() { - assert_eq!(format!("{}", BitVec::::new_general()), ""); - assert_eq!(format!("{}", BitVec::::from_elem_general(1, true)), "1"); - assert_eq!( - format!("{}", BitVec::::from_elem_general(8, false)), - "00000000" - ) - } - - #[test] - fn test_debug_output() { - assert_eq!( - format!("{:?}", BitVec::::new_general()), - "BitVec { storage: \"\", nbits: 0 }" - ); - assert_eq!( - format!("{:?}", BitVec::::from_elem_general(1, true)), - "BitVec { storage: \"1\", nbits: 1 }" - ); - assert_eq!( - format!("{:?}", BitVec::::from_elem_general(8, false)), - "BitVec { storage: \"00000000\", nbits: 8 }" - ); - assert_eq!( - format!("{:?}", BitVec::::from_elem_general(33, true)).replace(" ", ""), - "BitVec{storage:\"111111111111111111111111111111111\",nbits:33}" - ); - assert_eq!( - format!( - "{:?}", - BitVec::::from_bytes_general(&[ - 0b111, 0b000, 0b1110, 0b0001, 0b11111111, 0b00000000 - ]) - ) - .replace(" ", ""), - "BitVec{storage:\"000001110000000000001110000000011111111100000000\",nbits:48}" - ) - } - - #[test] - fn test_0_elements() { - let act = BitVec::::new_general(); - let exp = Vec::new(); - assert!(act.eq_vec(&exp)); - assert!(act.none() && act.all()); - } - - #[test] - fn test_1_element() { - let mut act = BitVec::::from_elem_general(1, false); - assert!(act.eq_vec(&[false])); - assert!(act.none() && !act.all()); - act = BitVec::::from_elem_general(1, true); - assert!(act.eq_vec(&[true])); - assert!(!act.none() && act.all()); - } - - #[test] - fn test_2_elements() { - let mut b = BitVec::::from_elem_general(2, false); - b.set(0, true); - b.set(1, false); - assert_eq!(format!("{}", b), "10"); - assert!(!b.none() && !b.all()); - } - - #[test] - fn test_10_elements() { - // all 0 - - let mut act = BitVec::::from_elem_general(10, false); - assert!( - (act.eq_vec(&[false, false, false, false, false, false, false, false, false, false])) - ); - assert!(act.none() && !act.all()); - // all 1 - - act = BitVec::::from_elem_general(10, true); - assert!((act.eq_vec(&[true, true, true, true, true, true, true, true, true, true]))); - assert!(!act.none() && act.all()); - // mixed - - act = BitVec::::from_elem_general(10, false); - act.set(0, true); - act.set(1, true); - act.set(2, true); - act.set(3, true); - act.set(4, true); - assert!((act.eq_vec(&[true, true, true, true, true, false, false, false, false, false]))); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(10, false); - act.set(5, true); - act.set(6, true); - act.set(7, true); - act.set(8, true); - act.set(9, true); - assert!((act.eq_vec(&[false, false, false, false, false, true, true, true, true, true]))); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(10, false); - act.set(0, true); - act.set(3, true); - act.set(6, true); - act.set(9, true); - assert!((act.eq_vec(&[true, false, false, true, false, false, true, false, false, true]))); - assert!(!act.none() && !act.all()); - } - - #[test] - fn test_31_elements() { - // all 0 - - let mut act = BitVec::::from_elem_general(31, false); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false - ])); - assert!(act.none() && !act.all()); - // all 1 - - act = BitVec::::from_elem_general(31, true); - assert!(act.eq_vec(&[ - true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true - ])); - assert!(!act.none() && act.all()); - // mixed - - act = BitVec::::from_elem_general(31, false); - act.set(0, true); - act.set(1, true); - act.set(2, true); - act.set(3, true); - act.set(4, true); - act.set(5, true); - act.set(6, true); - act.set(7, true); - assert!(act.eq_vec(&[ - true, true, true, true, true, true, true, true, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(31, false); - act.set(16, true); - act.set(17, true); - act.set(18, true); - act.set(19, true); - act.set(20, true); - act.set(21, true); - act.set(22, true); - act.set(23, true); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, true, true, true, true, true, true, true, true, false, - false, false, false, false, false, false - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(31, false); - act.set(24, true); - act.set(25, true); - act.set(26, true); - act.set(27, true); - act.set(28, true); - act.set(29, true); - act.set(30, true); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - true, true, true, true, true, true, true - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(31, false); - act.set(3, true); - act.set(17, true); - act.set(30, true); - assert!(act.eq_vec(&[ - false, false, false, true, false, false, false, false, false, false, false, false, - false, false, false, false, false, true, false, false, false, false, false, false, - false, false, false, false, false, false, true - ])); - assert!(!act.none() && !act.all()); - } - - #[test] - fn test_32_elements() { - // all 0 - - let mut act = BitVec::::from_elem_general(32, false); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false - ])); - assert!(act.none() && !act.all()); - // all 1 - - act = BitVec::::from_elem_general(32, true); - assert!(act.eq_vec(&[ - true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true, true - ])); - assert!(!act.none() && act.all()); - // mixed - - act = BitVec::::from_elem_general(32, false); - act.set(0, true); - act.set(1, true); - act.set(2, true); - act.set(3, true); - act.set(4, true); - act.set(5, true); - act.set(6, true); - act.set(7, true); - assert!(act.eq_vec(&[ - true, true, true, true, true, true, true, true, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(32, false); - act.set(16, true); - act.set(17, true); - act.set(18, true); - act.set(19, true); - act.set(20, true); - act.set(21, true); - act.set(22, true); - act.set(23, true); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, true, true, true, true, true, true, true, true, false, - false, false, false, false, false, false, false - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(32, false); - act.set(24, true); - act.set(25, true); - act.set(26, true); - act.set(27, true); - act.set(28, true); - act.set(29, true); - act.set(30, true); - act.set(31, true); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - true, true, true, true, true, true, true, true - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(32, false); - act.set(3, true); - act.set(17, true); - act.set(30, true); - act.set(31, true); - assert!(act.eq_vec(&[ - false, false, false, true, false, false, false, false, false, false, false, false, - false, false, false, false, false, true, false, false, false, false, false, false, - false, false, false, false, false, false, true, true - ])); - assert!(!act.none() && !act.all()); - } - - #[test] - fn test_33_elements() { - // all 0 - - let mut act = BitVec::::from_elem_general(33, false); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false - ])); - assert!(act.none() && !act.all()); - // all 1 - - act = BitVec::::from_elem_general(33, true); - assert!(act.eq_vec(&[ - true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, true, true, true, true, true, true, - true, true, true, true, true - ])); - assert!(!act.none() && act.all()); - // mixed - - act = BitVec::::from_elem_general(33, false); - act.set(0, true); - act.set(1, true); - act.set(2, true); - act.set(3, true); - act.set(4, true); - act.set(5, true); - act.set(6, true); - act.set(7, true); - assert!(act.eq_vec(&[ - true, true, true, true, true, true, true, true, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(33, false); - act.set(16, true); - act.set(17, true); - act.set(18, true); - act.set(19, true); - act.set(20, true); - act.set(21, true); - act.set(22, true); - act.set(23, true); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, true, true, true, true, true, true, true, true, false, - false, false, false, false, false, false, false, false - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(33, false); - act.set(24, true); - act.set(25, true); - act.set(26, true); - act.set(27, true); - act.set(28, true); - act.set(29, true); - act.set(30, true); - act.set(31, true); - assert!(act.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - true, true, true, true, true, true, true, true, false - ])); - assert!(!act.none() && !act.all()); - // mixed - - act = BitVec::::from_elem_general(33, false); - act.set(3, true); - act.set(17, true); - act.set(30, true); - act.set(31, true); - act.set(32, true); - assert!(act.eq_vec(&[ - false, false, false, true, false, false, false, false, false, false, false, false, - false, false, false, false, false, true, false, false, false, false, false, false, - false, false, false, false, false, false, true, true, true - ])); - assert!(!act.none() && !act.all()); - } - - #[test] - fn test_equal_differing_sizes() { - let v0 = BitVec::::from_elem_general(10, false); - let v1 = BitVec::::from_elem_general(11, false); - assert_ne!(v0, v1); - } - - #[test] - fn test_equal_greatly_differing_sizes() { - let v0 = BitVec::::from_elem_general(10, false); - let v1 = BitVec::::from_elem_general(110, false); - assert_ne!(v0, v1); - } - - #[test] - fn test_equal_sneaky_small() { - let mut a = BitVec::::from_elem_general(1, false); - a.set(0, true); - - let mut b = BitVec::::from_elem_general(1, true); - b.set(0, true); - - assert_eq!(a, b); - } - - #[test] - fn test_equal_sneaky_big() { - let mut a = BitVec::::from_elem_general(100, false); - for i in 0..100 { - a.set(i, true); - } - - let mut b = BitVec::::from_elem_general(100, true); - for i in 0..100 { - b.set(i, true); - } - - assert_eq!(a, b); - } - - #[test] - fn test_from_bytes() { - let bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b11111111]); - let str = concat!("10110110", "00000000", "11111111"); - assert_eq!(format!("{}", bit_vec), str); - } - - #[test] - fn test_to_bytes() { - let mut bv = BitVec::::from_elem_general(3, true); - bv.set(1, false); - assert_eq!(bv.to_bytes(), [0b10100000]); - - let mut bv = BitVec::::from_elem_general(9, false); - bv.set(2, true); - bv.set(8, true); - assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); - } - - #[test] - fn test_from_bools() { - let bools = [true, false, true, true]; - let bit_vec: BitVec = bools.iter().copied().collect(); - assert_eq!(format!("{}", bit_vec), "1011"); - } - - #[test] - fn test_to_bools() { - let bools = vec![false, false, true, false, false, true, true, false]; - assert_eq!( - BitVec::::from_bytes_general(&[0b00100110]) - .iter() - .collect::>(), - bools - ); - } - - #[test] - fn test_bit_vec_iterator() { - let bools = vec![true, false, true, true]; - let bit_vec: BitVec = bools.iter().copied().collect(); - - assert_eq!(bit_vec.iter().collect::>(), bools); - - let long: Vec<_> = (0..10000).map(|i| i % 2 == 0).collect(); - let bit_vec: BitVec = long.iter().copied().collect(); - assert_eq!(bit_vec.iter().collect::>(), long) - } - - #[test] - fn test_small_difference() { - let mut b1 = BitVec::::from_elem_general(3, false); - let mut b2 = BitVec::::from_elem_general(3, false); - b1.set(0, true); - b1.set(1, true); - b2.set(1, true); - b2.set(2, true); - assert!(b1.difference(&b2)); - assert!(b1[0]); - assert!(!b1[1]); - assert!(!b1[2]); - } - - #[test] - fn test_big_difference() { - let mut b1 = BitVec::::from_elem_general(100, false); - let mut b2 = BitVec::::from_elem_general(100, false); - b1.set(0, true); - b1.set(40, true); - b2.set(40, true); - b2.set(80, true); - assert!(b1.difference(&b2)); - assert!(b1[0]); - assert!(!b1[40]); - assert!(!b1[80]); - } - - #[test] - fn test_small_xor() { - let mut a = BitVec::::from_bytes_general(&[0b0011]); - let b = BitVec::::from_bytes_general(&[0b0101]); - let c = BitVec::::from_bytes_general(&[0b0110]); - assert!(a.xor(&b)); - assert_eq!(a, c); - } - - #[test] - fn test_small_xnor() { - let mut a = BitVec::::from_bytes_general(&[0b0011]); - let b = BitVec::::from_bytes_general(&[0b1111_0101]); - let c = BitVec::::from_bytes_general(&[0b1001]); - assert!(a.xnor(&b)); - assert_eq!(a, c); - } - - #[test] - fn test_small_nand() { - let mut a = BitVec::::from_bytes_general(&[0b1111_0011]); - let b = BitVec::::from_bytes_general(&[0b1111_0101]); - let c = BitVec::::from_bytes_general(&[0b1110]); - assert!(a.nand(&b)); - assert_eq!(a, c); - } - - #[test] - fn test_small_nor() { - let mut a = BitVec::::from_bytes_general(&[0b0011]); - let b = BitVec::::from_bytes_general(&[0b1111_0101]); - let c = BitVec::::from_bytes_general(&[0b1000]); - assert!(a.nor(&b)); - assert_eq!(a, c); - } - - #[test] - fn test_big_xor() { - let mut a = BitVec::::from_bytes_general(&[ - // 88 bits - 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, - ]); - let b = BitVec::::from_bytes_general(&[ - // 88 bits - 0, 0, 0b00010100, 0, 0, 0, 0, 0, 0, 0, 0b00110100, - ]); - let c = BitVec::::from_bytes_general(&[ - // 88 bits - 0, 0, 0, 0, 0, 0, 0, 0b00110100, 0, 0, 0b00110100, - ]); - assert!(a.xor(&b)); - assert_eq!(a, c); - } - - #[test] - fn test_big_xnor() { - let mut a = BitVec::::from_bytes_general(&[ - // 88 bits - 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, - ]); - let b = BitVec::::from_bytes_general(&[ - // 88 bits - 0, 0, 0b00010100, 0, 0, 0, 0, 0, 0, 0, 0b00110100, - ]); - let c = BitVec::::from_bytes_general(&[ - // 88 bits - !0, - !0, - !0, - !0, - !0, - !0, - !0, - !0b00110100, - !0, - !0, - !0b00110100, - ]); - assert!(a.xnor(&b)); - assert_eq!(a, c); - } - - #[test] - fn test_small_fill() { - let mut b = BitVec::::from_elem_general(14, true); - assert!(!b.none() && b.all()); - b.fill(false); - assert!(b.none() && !b.all()); - b.fill(true); - assert!(!b.none() && b.all()); - } - - #[test] - fn test_big_fill() { - let mut b = BitVec::::from_elem_general(140, true); - assert!(!b.none() && b.all()); - b.fill(false); - assert!(b.none() && !b.all()); - b.fill(true); - assert!(!b.none() && b.all()); - } - - #[test] - fn test_bit_vec_lt() { - let mut a = BitVec::::from_elem_general(5, false); - let mut b = BitVec::::from_elem_general(5, false); - - assert!(a >= b && b >= a); - b.set(2, true); - assert!(a < b); - a.set(3, true); - assert!(a < b); - a.set(2, true); - assert!(a >= b && b < a); - b.set(0, true); - assert!(a < b); - } - - #[test] - fn test_ord() { - let mut a = BitVec::::from_elem_general(5, false); - let mut b = BitVec::::from_elem_general(5, false); - - assert!(a == b); - a.set(1, true); - assert!(a > b && a >= b); - assert!(b < a && b <= a); - b.set(1, true); - b.set(2, true); - assert!(b > a && b >= a); - assert!(a < b && a <= b); - } - - #[test] - fn test_small_bit_vec_tests() { - let v = BitVec::::from_bytes_general(&[0]); - assert!(!v.all()); - assert!(!v.any()); - assert!(v.none()); - - let v = BitVec::::from_bytes_general(&[0b00010100]); - assert!(!v.all()); - assert!(v.any()); - assert!(!v.none()); - - let v = BitVec::::from_bytes_general(&[0xFF]); - assert!(v.all()); - assert!(v.any()); - assert!(!v.none()); - } - - #[test] - fn test_big_bit_vec_tests() { - let v = BitVec::::from_bytes_general(&[ - // 88 bits - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]); - assert!(!v.all()); - assert!(!v.any()); - assert!(v.none()); - - let v = BitVec::::from_bytes_general(&[ - // 88 bits - 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, - ]); - assert!(!v.all()); - assert!(v.any()); - assert!(!v.none()); - - let v = BitVec::::from_bytes_general(&[ - // 88 bits - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - ]); - assert!(v.all()); - assert!(v.any()); - assert!(!v.none()); - } - - #[test] - fn test_bit_vec_push_pop() { - let mut s = BitVec::::from_elem_general(5 * U32_BITS - 2, false); - assert_eq!(s.len(), 5 * U32_BITS - 2); - assert!(!s[5 * U32_BITS - 3]); - s.push(true); - s.push(true); - assert!(s[5 * U32_BITS - 2]); - assert!(s[5 * U32_BITS - 1]); - // Here the internal vector will need to be extended - s.push(false); - assert!(!s[5 * U32_BITS]); - s.push(false); - assert!(!s[5 * U32_BITS + 1]); - assert_eq!(s.len(), 5 * U32_BITS + 2); - // Pop it all off - assert_eq!(s.pop(), Some(false)); - assert_eq!(s.pop(), Some(false)); - assert_eq!(s.pop(), Some(true)); - assert_eq!(s.pop(), Some(true)); - assert_eq!(s.len(), 5 * U32_BITS - 2); - } - - #[test] - fn test_bit_vec_truncate() { - let mut s = BitVec::::from_elem_general(5 * U32_BITS, true); - - assert_eq!(s, BitVec::::from_elem_general(5 * U32_BITS, true)); - assert_eq!(s.len(), 5 * U32_BITS); - s.truncate(4 * U32_BITS); - assert_eq!(s, BitVec::::from_elem_general(4 * U32_BITS, true)); - assert_eq!(s.len(), 4 * U32_BITS); - // Truncating to a size > s.len() should be a noop - s.truncate(5 * U32_BITS); - assert_eq!(s, BitVec::::from_elem_general(4 * U32_BITS, true)); - assert_eq!(s.len(), 4 * U32_BITS); - s.truncate(3 * U32_BITS - 10); - assert_eq!(s, BitVec::::from_elem_general(3 * U32_BITS - 10, true)); - assert_eq!(s.len(), 3 * U32_BITS - 10); - s.truncate(0); - assert_eq!(s, BitVec::::from_elem_general(0, true)); - assert_eq!(s.len(), 0); - } - - #[test] - fn test_bit_vec_reserve() { - let mut s = BitVec::::from_elem_general(5 * U32_BITS, true); - // Check capacity - assert!(s.capacity() >= 5 * U32_BITS); - s.reserve(2 * U32_BITS); - assert!(s.capacity() >= 7 * U32_BITS); - s.reserve(7 * U32_BITS); - assert!(s.capacity() >= 12 * U32_BITS); - s.reserve_exact(7 * U32_BITS); - assert!(s.capacity() >= 12 * U32_BITS); - s.reserve(7 * U32_BITS + 1); - assert!(s.capacity() > 12 * U32_BITS); - // Check that length hasn't changed - assert_eq!(s.len(), 5 * U32_BITS); - s.push(true); - s.push(false); - s.push(true); - assert!(s[5 * U32_BITS - 1]); - assert!(s[5 * U32_BITS]); - assert!(!s[5 * U32_BITS + 1]); - assert!(s[5 * U32_BITS + 2]); - } - - #[test] - fn test_bit_vec_grow() { - let mut bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b10101010]); - bit_vec.grow(32, true); - assert_eq!( - bit_vec, - BitVec::::from_bytes_general(&[ - 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF - ]) - ); - bit_vec.grow(64, false); - assert_eq!( - bit_vec, - BitVec::::from_bytes_general(&[ - 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0 - ]) - ); - bit_vec.grow(16, true); - assert_eq!( - bit_vec, - BitVec::::from_bytes_general(&[ - 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, - 0xFF, 0xFF - ]) - ); - } - - #[test] - fn test_bit_vec_extend() { - let mut bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b11111111]); - let ext = BitVec::::from_bytes_general(&[0b01001001, 0b10010010, 0b10111101]); - bit_vec.extend(ext.iter()); - assert_eq!( - bit_vec, - BitVec::::from_bytes_general(&[ - 0b10110110, 0b00000000, 0b11111111, 0b01001001, 0b10010010, 0b10111101 - ]) - ); - } - - #[test] - fn test_bit_vec_append() { - // Append to BitVec that holds a multiple of U32_BITS bits - let mut a = - BitVec::::from_bytes_general(&[0b10100000, 0b00010010, 0b10010010, 0b00110011]); - let mut b = BitVec::::new_general(); - b.push(false); - b.push(true); - b.push(true); - - a.append(&mut b); - - assert_eq!(a.len(), 35); - assert_eq!(b.len(), 0); - assert!(b.capacity() >= 3); - - assert!(a.eq_vec(&[ - true, false, true, false, false, false, false, false, false, false, false, true, false, - false, true, false, true, false, false, true, false, false, true, false, false, false, - true, true, false, false, true, true, false, true, true - ])); - - // Append to arbitrary BitVec - let mut a = BitVec::::new_general(); - a.push(true); - a.push(false); - - let mut b = BitVec::::from_bytes_general(&[ - 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, - ]); - - a.append(&mut b); - - assert_eq!(a.len(), 42); - assert_eq!(b.len(), 0); - assert!(b.capacity() >= 40); - - assert!(a.eq_vec(&[ - true, false, true, false, true, false, false, false, false, false, false, false, false, - true, false, false, true, false, true, false, false, true, false, false, true, false, - false, false, true, true, false, false, true, true, true, false, false, true, false, - true, false, true - ])); - - // Append to empty BitVec - let mut a = BitVec::::new_general(); - let mut b = BitVec::::from_bytes_general(&[ - 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, - ]); - - a.append(&mut b); - - assert_eq!(a.len(), 40); - assert_eq!(b.len(), 0); - assert!(b.capacity() >= 40); - - assert!(a.eq_vec(&[ - true, false, true, false, false, false, false, false, false, false, false, true, false, - false, true, false, true, false, false, true, false, false, true, false, false, false, - true, true, false, false, true, true, true, false, false, true, false, true, false, - true - ])); - - // Append empty BitVec - let mut a = BitVec::::from_bytes_general(&[ - 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, - ]); - let mut b = BitVec::::new_general(); - - a.append(&mut b); - - assert_eq!(a.len(), 40); - assert_eq!(b.len(), 0); - - assert!(a.eq_vec(&[ - true, false, true, false, false, false, false, false, false, false, false, true, false, - false, true, false, true, false, false, true, false, false, true, false, false, false, - true, true, false, false, true, true, true, false, false, true, false, true, false, - true - ])); - } - - #[test] - fn test_bit_vec_split_off() { - // Split at 0 - let mut a = BitVec::::new_general(); - a.push(true); - a.push(false); - a.push(false); - a.push(true); - - let b = a.split_off(0); - - assert_eq!(a.len(), 0); - assert_eq!(b.len(), 4); - - assert!(b.eq_vec(&[true, false, false, true])); - - // Split at last bit - a.truncate(0); - a.push(true); - a.push(false); - a.push(false); - a.push(true); - - let b = a.split_off(4); - - assert_eq!(a.len(), 4); - assert_eq!(b.len(), 0); - - assert!(a.eq_vec(&[true, false, false, true])); - - // Split at block boundary - let mut a = BitVec::::from_bytes_general(&[ - 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b11110011, - ]); - - let b = a.split_off(32); - - assert_eq!(a.len(), 32); - assert_eq!(b.len(), 8); - - assert!(a.eq_vec(&[ - true, false, true, false, false, false, false, false, false, false, false, true, false, - false, true, false, true, false, false, true, false, false, true, false, false, false, - true, true, false, false, true, true - ])); - assert!(b.eq_vec(&[true, true, true, true, false, false, true, true])); - - // Don't split at block boundary - let mut a = BitVec::::from_bytes_general(&[ - 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b01101011, 0b10101101, - ]); - - let b = a.split_off(13); - - assert_eq!(a.len(), 13); - assert_eq!(b.len(), 35); - - assert!(a.eq_vec(&[ - true, false, true, false, false, false, false, false, false, false, false, true, false - ])); - assert!(b.eq_vec(&[ - false, true, false, true, false, false, true, false, false, true, false, false, false, - true, true, false, false, true, true, false, true, true, false, true, false, true, - true, true, false, true, false, true, true, false, true - ])); - } - - #[test] - fn test_into_iter() { - let bools = [true, false, true, true]; - let bit_vec: BitVec = bools.iter().copied().collect(); - let mut iter = bit_vec.into_iter(); - assert_eq!(Some(true), iter.next()); - assert_eq!(Some(false), iter.next()); - assert_eq!(Some(true), iter.next()); - assert_eq!(Some(true), iter.next()); - assert_eq!(None, iter.next()); - assert_eq!(None, iter.next()); - - let bit_vec: BitVec = bools.iter().copied().collect(); - let mut iter = bit_vec.into_iter(); - assert_eq!(Some(true), iter.next_back()); - assert_eq!(Some(true), iter.next_back()); - assert_eq!(Some(false), iter.next_back()); - assert_eq!(Some(true), iter.next_back()); - assert_eq!(None, iter.next_back()); - assert_eq!(None, iter.next_back()); - - let bit_vec: BitVec = bools.iter().copied().collect(); - let mut iter = bit_vec.into_iter(); - assert_eq!(Some(true), iter.next_back()); - assert_eq!(Some(true), iter.next()); - assert_eq!(Some(false), iter.next()); - assert_eq!(Some(true), iter.next_back()); - assert_eq!(None, iter.next()); - assert_eq!(None, iter.next_back()); - } - - #[test] - fn test_iter() { - let b = BitVec::::with_capacity_general(10); - let _a: Iter = b.iter(); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serialization() - where - S::Store: serde::Serialize + for<'a> serde::Deserialize<'a>, - { - let bit_vec: BitVec = BitVec::::new_general(); - let serialized = serde_json::to_string(&bit_vec).unwrap(); - let unserialized: BitVec = serde_json::from_str(&serialized[..]).unwrap(); - assert_eq!(bit_vec, unserialized); - - let bools = vec![true, false, true, true]; - let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); - let serialized = serde_json::to_string(&bit_vec).unwrap(); - let unserialized = serde_json::from_str(&serialized).unwrap(); - assert_eq!(bit_vec, unserialized); - } - - #[cfg(feature = "miniserde")] - #[test] - fn test_miniserde_serialization< - S: BitBlockOrStore + miniserde::Serialize + miniserde::Deserialize, - >() { - let bit_vec = BitVec::::new_general(); - let serialized = miniserde::json::to_string(&bit_vec); - let unserialized: BitVec = miniserde::json::from_str(&serialized[..]).unwrap(); - assert_eq!(bit_vec, unserialized); - - let bools = vec![true, false, true, true]; - let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); - let serialized = miniserde::json::to_string(&bit_vec); - let unserialized = miniserde::json::from_str(&serialized[..]).unwrap(); - assert_eq!(bit_vec, unserialized); - } - - #[cfg(feature = "nanoserde")] - #[test] - fn test_nanoserde_json_serialization< - S: BitBlockOrStore - + nanoserde::DeBin - + nanoserde::DeJson - + nanoserde::DeRon - + nanoserde::SerBin - + nanoserde::SerJson - + nanoserde::SerRon, - >() { - use nanoserde::{DeJson, SerJson}; - - let bit_vec = BitVec::::new_general(); - let serialized = bit_vec.serialize_json(); - let unserialized = BitVec::::deserialize_json(&serialized[..]).unwrap(); - assert_eq!(bit_vec, unserialized); - - let bools = vec![true, false, true, true]; - let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); - let serialized = bit_vec.serialize_json(); - let unserialized = BitVec::::deserialize_json(&serialized[..]).unwrap(); - assert_eq!(bit_vec, unserialized); - } - - #[cfg(feature = "borsh")] - #[test] - fn test_borsh_serialization() { - let bit_vec = BitVec::::new_general(); - let serialized = borsh::to_vec(&bit_vec).unwrap(); - let unserialized: BitVec = borsh::from_slice(&serialized[..]).unwrap(); - assert_eq!(bit_vec, unserialized); - - let bools = vec![true, false, true, true]; - let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); - let serialized = borsh::to_vec(&bit_vec).unwrap(); - let unserialized = borsh::from_slice(&serialized[..]).unwrap(); - assert_eq!(bit_vec, unserialized); - } - - #[test] - fn test_bit_vec_unaligned_small_append() { - let mut a = BitVec::::from_elem_general(8, false); - a.set(7, true); - - let mut b = BitVec::::from_elem_general(16, false); - b.set(14, true); - - let mut c = BitVec::::from_elem_general(8, false); - c.set(6, true); - c.set(7, true); - - a.append(&mut b); - a.append(&mut c); - - assert_eq!(&[1, 0, 2, 3][..], &*a.to_bytes()); - } - - #[test] - fn test_bit_vec_unaligned_large_append() { - let mut a = BitVec::::from_elem_general(48, false); - a.set(47, true); - - let mut b = BitVec::::from_elem_general(48, false); - b.set(46, true); - - let mut c = BitVec::::from_elem_general(48, false); - c.set(46, true); - c.set(47, true); - - a.append(&mut b); - a.append(&mut c); - - assert_eq!( - &[ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03 - ][..], - &*a.to_bytes() - ); - } - - #[test] - fn test_bit_vec_append_aligned_to_unaligned() { - let mut a = BitVec::::from_elem_general(2, true); - let mut b = BitVec::::from_elem_general(32, false); - let mut c = BitVec::::from_elem_general(8, true); - a.append(&mut b); - a.append(&mut c); - assert_eq!(&[0xc0, 0x00, 0x00, 0x00, 0x3f, 0xc0][..], &*a.to_bytes()); - } - - #[test] - fn test_count_ones() { - for i in 0..1000 { - let mut t = BitVec::::from_elem_general(i, true); - let mut f = BitVec::::from_elem_general(i, false); - assert_eq!(i as u64, t.count_ones()); - assert_eq!(0_u64, f.count_ones()); - if i > 20 { - t.set(10, false); - t.set(i - 10, false); - assert_eq!(i - 2, t.count_ones() as usize); - f.set(10, true); - f.set(i - 10, true); - assert_eq!(2, f.count_ones()); - } - } - } - - #[test] - fn test_count_zeros() { - for i in 0..1000 { - let mut tbits = BitVec::::from_elem_general(i, true); - let mut fbits = BitVec::::from_elem_general(i, false); - assert_eq!(i as u64, fbits.count_zeros()); - assert_eq!(0_u64, tbits.count_zeros()); - if i > 20 { - fbits.set(10, true); - fbits.set(i - 10, true); - assert_eq!(i - 2, fbits.count_zeros() as usize); - tbits.set(10, false); - tbits.set(i - 10, false); - assert_eq!(2, tbits.count_zeros()); - } - } - } - - #[test] - fn test_get_mut() { - let mut a = BitVec::::from_elem_general(3, false); - let mut a_bit_1 = a.get_mut(1).unwrap(); - assert!(!*a_bit_1); - *a_bit_1 = true; - drop(a_bit_1); - assert!(a.eq_vec(&[false, true, false])); - } - - #[test] - fn test_iter_mut() { - let mut a = BitVec::::from_elem_general(8, false); - a.iter_mut().enumerate().for_each(|(index, mut bit)| { - *bit = index % 2 == 1; - }); - assert!(a.eq_vec(&[false, true, false, true, false, true, false, true])); - } - - #[test] - fn test_insert_at_zero() { - let mut v = BitVec::::new_general(); - - v.insert(0, false); - v.insert(0, true); - v.insert(0, false); - v.insert(0, true); - v.insert(0, false); - v.insert(0, true); - - assert_eq!(v.len(), 6); - assert_eq!(v.storage().len(), 1); - assert!(v.eq_vec(&[true, false, true, false, true, false])); - } - - #[test] - fn test_insert_at_end() { - let mut v = BitVec::::new_general(); - - v.insert(v.len(), true); - v.insert(v.len(), false); - v.insert(v.len(), true); - v.insert(v.len(), false); - v.insert(v.len(), true); - v.insert(v.len(), false); - - assert_eq!(v.storage().len(), 1); - assert_eq!(v.len(), 6); - assert!(v.eq_vec(&[true, false, true, false, true, false])); - } - - #[test] - fn test_insert_at_block_boundaries() { - let mut v = BitVec::::from_elem_general(32, false); - - assert_eq!(v.storage().len(), (4 / S::BYTES).max(1)); - - v.insert(31, true); - - assert_eq!(v.len(), 33); - - assert!(matches!(v.get(31), Some(true))); - assert!(v.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, true, false - ])); - - assert_eq!(v.storage().len(), 1 + 4 / S::BYTES); - } - - #[test] - fn test_insert_at_block_boundaries_1() { - let mut v = BitVec::::from_elem_general(64, false); - - assert_eq!(v.storage().len(), 8 / S::BYTES); - - v.insert(63, true); - - assert_eq!(v.len(), 65); - - assert!(matches!(v.get(63), Some(true))); - assert!(v.eq_vec(&[ - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, true, false - ])); - - assert_eq!(v.storage().len(), 1 + 8 / S::BYTES); - } - - #[test] - fn test_push_within_capacity_with_suffice_cap() { - let mut v = BitVec::::from_elem_general(16, true); - - if S::BYTES > 2 { - assert!(v.push_within_capacity(false).is_ok()); - } - - for i in 0..16 { - assert_eq!(v.get(i), Some(true)); - } - - if S::BYTES > 2 { - assert_eq!(v.get(16), Some(false)); - assert_eq!(v.len(), 17); - } - } - - #[test] - fn test_push_within_capacity_at_brink() { - let mut v = BitVec::::from_elem_general(31, true); - - assert!(v.push_within_capacity(false).is_ok()); - - assert_eq!(v.get(31), Some(false)); - if v.capacity() < 256 { - assert_eq!(if S::BYTES == 8 { 64 } else { v.len() }, v.capacity()); - } - assert_eq!(v.len(), 32); - - if v.capacity() < 256 { - assert_eq!( - v.push_within_capacity(false), - if S::BYTES == 8 { Ok(()) } else { Err(false) } - ); - assert_eq!(v.capacity(), if S::BYTES == 8 { 64 } else { 32 }); - } - - for i in 0..31 { - assert_eq!(v.get(i), Some(true)); - } - assert_eq!(v.get(31), Some(false)); - } - - #[test] - fn test_push_within_capacity_at_brink_with_mul_blocks() { - let mut v = BitVec::::from_elem_general(95, true); - - assert!(v.push_within_capacity(false).is_ok()); - - assert_eq!(v.get(95), Some(false)); - if S::BYTES <= 4 && v.capacity() < 256 { - assert_eq!(v.len(), v.capacity()); - } - assert_eq!(v.len(), 96); - - if S::BYTES == 8 { - assert_eq!(v.push_within_capacity(false), Ok(())); - if v.capacity() < 256 { - assert_eq!(v.capacity(), 128); - } - } else if v.capacity() < 256 { - assert_eq!(v.push_within_capacity(false), Err(false)); - assert_eq!(v.capacity(), 96); - } - - for i in 0..95 { - assert_eq!(v.get(i), Some(true)); - } - assert_eq!(v.get(95), Some(false)); - } - - #[test] - fn test_push_within_capacity_storage_push() { - let mut v = BitVec::::with_capacity_general(64); - - for _ in 0..32 { - v.push(true); - } - - assert_eq!(v.len(), 32); - - assert!(v.push_within_capacity(false).is_ok()); - - assert_eq!(v.len(), 33); - - for i in 0..32 { - assert_eq!(v.get(i), Some(true)); - } - assert_eq!(v.get(32), Some(false)); - } - - #[test] - fn test_insert_remove() { - // two primes for no common divisors with 32 - let mut v = BitVec::::from_fn_general(1024, |i| i % 11 < 7); - for i in 0..1024 { - let result = v.remove(i); - v.insert(i, result); - assert_eq!(result, i % 11 < 7); - } - - for i in 0..1024 { - v.insert(i, false); - v.remove(i); - } - - for i in 0..1024 { - v.insert(i, true); - v.remove(i); - } - - for (i, result) in v.into_iter().enumerate() { - assert_eq!(result, i % 11 < 7); - } - } - - #[test] - fn test_remove_last() { - let mut v = BitVec::::from_fn_general(1025, |i| i % 11 < 7); - assert_eq!(v.len(), 1025); - assert_eq!(v.remove(1024), 1024 % 11 < 7); - assert_eq!(v.len(), 1024); - assert_eq!(v.storage().len(), 1024 / S::BITS); - } - - #[test] - fn test_remove_all() { - let v = BitVec::::from_elem_general(1024, false); - for _ in 0..1024 { - let mut v2 = v.clone(); - v2.remove_all(); - assert_eq!(v2.len(), 0); - assert_eq!(v2.get(0), None); - assert_eq!(v2, BitVec::new_general()); - } - } - - #[instantiate_tests(>)] - mod vec32 {} - - #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] - #[instantiate_tests(>)] - mod smallvec32x8 {} - - #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] - #[instantiate_tests(>)] - mod smallvec64x8 {} - - #[instantiate_tests()] - mod integer32 {} - - #[instantiate_tests()] - mod native {} - - #[instantiate_tests()] - mod integer16 {} - - #[instantiate_tests()] - mod integer8 {} -} - -#[cfg(test)] -#[cfg(feature = "allocator_api")] -mod alloc_tests { - use std::alloc::Global; - use std::vec::Vec; - - use crate::BitVec; - - #[test] - fn test_new_in() { - let alloc = Global; - let mut v: BitVec> = BitVec::new_general_in(alloc); - v.push(true); - v.push(false); - assert_eq!(v.len(), 2); - assert_eq!(v.pop(), Some(false)); - assert_eq!(v.pop(), Some(true)); - } -} diff --git a/vec/tests/vec.rs b/vec/tests/vec.rs new file mode 100644 index 0000000..0721e4a --- /dev/null +++ b/vec/tests/vec.rs @@ -0,0 +1,1409 @@ +#[cfg(test)] +#[generic_tests::define] +mod tests { + #![allow(clippy::shadow_reuse)] + #![allow(clippy::shadow_same)] + #![allow(clippy::shadow_unrelated)] + #![allow(clippy::extra_unused_type_parameters)] + + use bit_vec::{BitVec, BitBlockOrStore, Iter}; + + // This is stupid, but I want to differentiate from a "random" 32 + const U32_BITS: usize = 32; + + #[test] + fn test_display_output() { + assert_eq!(format!("{}", BitVec::::new_general()), ""); + assert_eq!(format!("{}", BitVec::::from_elem_general(1, true)), "1"); + assert_eq!( + format!("{}", BitVec::::from_elem_general(8, false)), + "00000000" + ) + } + + #[test] + fn test_debug_output() { + assert_eq!( + format!("{:?}", BitVec::::new_general()), + "BitVec { storage: \"\", nbits: 0 }" + ); + assert_eq!( + format!("{:?}", BitVec::::from_elem_general(1, true)), + "BitVec { storage: \"1\", nbits: 1 }" + ); + assert_eq!( + format!("{:?}", BitVec::::from_elem_general(8, false)), + "BitVec { storage: \"00000000\", nbits: 8 }" + ); + assert_eq!( + format!("{:?}", BitVec::::from_elem_general(33, true)).replace(" ", ""), + "BitVec{storage:\"111111111111111111111111111111111\",nbits:33}" + ); + assert_eq!( + format!( + "{:?}", + BitVec::::from_bytes_general(&[ + 0b111, 0b000, 0b1110, 0b0001, 0b11111111, 0b00000000 + ]) + ) + .replace(" ", ""), + "BitVec{storage:\"000001110000000000001110000000011111111100000000\",nbits:48}" + ) + } + + #[test] + fn test_0_elements() { + let act = BitVec::::new_general(); + let exp = Vec::new(); + assert!(act.eq_vec(&exp)); + assert!(act.none() && act.all()); + } + + #[test] + fn test_1_element() { + let mut act = BitVec::::from_elem_general(1, false); + assert!(act.eq_vec(&[false])); + assert!(act.none() && !act.all()); + act = BitVec::::from_elem_general(1, true); + assert!(act.eq_vec(&[true])); + assert!(!act.none() && act.all()); + } + + #[test] + fn test_2_elements() { + let mut b = BitVec::::from_elem_general(2, false); + b.set(0, true); + b.set(1, false); + assert_eq!(format!("{}", b), "10"); + assert!(!b.none() && !b.all()); + } + + #[test] + fn test_10_elements() { + // all 0 + + let mut act = BitVec::::from_elem_general(10, false); + assert!( + (act.eq_vec(&[false, false, false, false, false, false, false, false, false, false])) + ); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::::from_elem_general(10, true); + assert!((act.eq_vec(&[true, true, true, true, true, true, true, true, true, true]))); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::::from_elem_general(10, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + assert!((act.eq_vec(&[true, true, true, true, true, false, false, false, false, false]))); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(10, false); + act.set(5, true); + act.set(6, true); + act.set(7, true); + act.set(8, true); + act.set(9, true); + assert!((act.eq_vec(&[false, false, false, false, false, true, true, true, true, true]))); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(10, false); + act.set(0, true); + act.set(3, true); + act.set(6, true); + act.set(9, true); + assert!((act.eq_vec(&[true, false, false, true, false, false, true, false, false, true]))); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_31_elements() { + // all 0 + + let mut act = BitVec::::from_elem_general(31, false); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false + ])); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::::from_elem_general(31, true); + assert!(act.eq_vec(&[ + true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true + ])); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::::from_elem_general(31, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + act.set(5, true); + act.set(6, true); + act.set(7, true); + assert!(act.eq_vec(&[ + true, true, true, true, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(31, false); + act.set(16, true); + act.set(17, true); + act.set(18, true); + act.set(19, true); + act.set(20, true); + act.set(21, true); + act.set(22, true); + act.set(23, true); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, true, true, true, true, true, true, true, true, false, + false, false, false, false, false, false + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(31, false); + act.set(24, true); + act.set(25, true); + act.set(26, true); + act.set(27, true); + act.set(28, true); + act.set(29, true); + act.set(30, true); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + true, true, true, true, true, true, true + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(31, false); + act.set(3, true); + act.set(17, true); + act.set(30, true); + assert!(act.eq_vec(&[ + false, false, false, true, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, false, true + ])); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_32_elements() { + // all 0 + + let mut act = BitVec::::from_elem_general(32, false); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false + ])); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::::from_elem_general(32, true); + assert!(act.eq_vec(&[ + true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true + ])); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::::from_elem_general(32, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + act.set(5, true); + act.set(6, true); + act.set(7, true); + assert!(act.eq_vec(&[ + true, true, true, true, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(32, false); + act.set(16, true); + act.set(17, true); + act.set(18, true); + act.set(19, true); + act.set(20, true); + act.set(21, true); + act.set(22, true); + act.set(23, true); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, true, true, true, true, true, true, true, true, false, + false, false, false, false, false, false, false + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(32, false); + act.set(24, true); + act.set(25, true); + act.set(26, true); + act.set(27, true); + act.set(28, true); + act.set(29, true); + act.set(30, true); + act.set(31, true); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + true, true, true, true, true, true, true, true + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(32, false); + act.set(3, true); + act.set(17, true); + act.set(30, true); + act.set(31, true); + assert!(act.eq_vec(&[ + false, false, false, true, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, false, true, true + ])); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_33_elements() { + // all 0 + + let mut act = BitVec::::from_elem_general(33, false); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false + ])); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::::from_elem_general(33, true); + assert!(act.eq_vec(&[ + true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true + ])); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::::from_elem_general(33, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + act.set(5, true); + act.set(6, true); + act.set(7, true); + assert!(act.eq_vec(&[ + true, true, true, true, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(33, false); + act.set(16, true); + act.set(17, true); + act.set(18, true); + act.set(19, true); + act.set(20, true); + act.set(21, true); + act.set(22, true); + act.set(23, true); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, true, true, true, true, true, true, true, true, false, + false, false, false, false, false, false, false, false + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(33, false); + act.set(24, true); + act.set(25, true); + act.set(26, true); + act.set(27, true); + act.set(28, true); + act.set(29, true); + act.set(30, true); + act.set(31, true); + assert!(act.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + true, true, true, true, true, true, true, true, false + ])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::::from_elem_general(33, false); + act.set(3, true); + act.set(17, true); + act.set(30, true); + act.set(31, true); + act.set(32, true); + assert!(act.eq_vec(&[ + false, false, false, true, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, false, true, true, true + ])); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_equal_differing_sizes() { + let v0 = BitVec::::from_elem_general(10, false); + let v1 = BitVec::::from_elem_general(11, false); + assert_ne!(v0, v1); + } + + #[test] + fn test_equal_greatly_differing_sizes() { + let v0 = BitVec::::from_elem_general(10, false); + let v1 = BitVec::::from_elem_general(110, false); + assert_ne!(v0, v1); + } + + #[test] + fn test_equal_sneaky_small() { + let mut a = BitVec::::from_elem_general(1, false); + a.set(0, true); + + let mut b = BitVec::::from_elem_general(1, true); + b.set(0, true); + + assert_eq!(a, b); + } + + #[test] + fn test_equal_sneaky_big() { + let mut a = BitVec::::from_elem_general(100, false); + for i in 0..100 { + a.set(i, true); + } + + let mut b = BitVec::::from_elem_general(100, true); + for i in 0..100 { + b.set(i, true); + } + + assert_eq!(a, b); + } + + #[test] + fn test_from_bytes() { + let bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b11111111]); + let str = concat!("10110110", "00000000", "11111111"); + assert_eq!(format!("{}", bit_vec), str); + } + + #[test] + fn test_to_bytes() { + let mut bv = BitVec::::from_elem_general(3, true); + bv.set(1, false); + assert_eq!(bv.to_bytes(), [0b10100000]); + + let mut bv = BitVec::::from_elem_general(9, false); + bv.set(2, true); + bv.set(8, true); + assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); + } + + #[test] + fn test_from_bools() { + let bools = [true, false, true, true]; + let bit_vec: BitVec = bools.iter().copied().collect(); + assert_eq!(format!("{}", bit_vec), "1011"); + } + + #[test] + fn test_to_bools() { + let bools = vec![false, false, true, false, false, true, true, false]; + assert_eq!( + BitVec::::from_bytes_general(&[0b00100110]) + .iter() + .collect::>(), + bools + ); + } + + #[test] + fn test_bit_vec_iterator() { + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().copied().collect(); + + assert_eq!(bit_vec.iter().collect::>(), bools); + + let long: Vec<_> = (0..10000).map(|i| i % 2 == 0).collect(); + let bit_vec: BitVec = long.iter().copied().collect(); + assert_eq!(bit_vec.iter().collect::>(), long) + } + + #[test] + fn test_small_difference() { + let mut b1 = BitVec::::from_elem_general(3, false); + let mut b2 = BitVec::::from_elem_general(3, false); + b1.set(0, true); + b1.set(1, true); + b2.set(1, true); + b2.set(2, true); + assert!(b1.difference(&b2)); + assert!(b1[0]); + assert!(!b1[1]); + assert!(!b1[2]); + } + + #[test] + fn test_big_difference() { + let mut b1 = BitVec::::from_elem_general(100, false); + let mut b2 = BitVec::::from_elem_general(100, false); + b1.set(0, true); + b1.set(40, true); + b2.set(40, true); + b2.set(80, true); + assert!(b1.difference(&b2)); + assert!(b1[0]); + assert!(!b1[40]); + assert!(!b1[80]); + } + + #[test] + fn test_small_xor() { + let mut a = BitVec::::from_bytes_general(&[0b0011]); + let b = BitVec::::from_bytes_general(&[0b0101]); + let c = BitVec::::from_bytes_general(&[0b0110]); + assert!(a.xor(&b)); + assert_eq!(a, c); + } + + #[test] + fn test_small_xnor() { + let mut a = BitVec::::from_bytes_general(&[0b0011]); + let b = BitVec::::from_bytes_general(&[0b1111_0101]); + let c = BitVec::::from_bytes_general(&[0b1001]); + assert!(a.xnor(&b)); + assert_eq!(a, c); + } + + #[test] + fn test_small_nand() { + let mut a = BitVec::::from_bytes_general(&[0b1111_0011]); + let b = BitVec::::from_bytes_general(&[0b1111_0101]); + let c = BitVec::::from_bytes_general(&[0b1110]); + assert!(a.nand(&b)); + assert_eq!(a, c); + } + + #[test] + fn test_small_nor() { + let mut a = BitVec::::from_bytes_general(&[0b0011]); + let b = BitVec::::from_bytes_general(&[0b1111_0101]); + let c = BitVec::::from_bytes_general(&[0b1000]); + assert!(a.nor(&b)); + assert_eq!(a, c); + } + + #[test] + fn test_big_xor() { + let mut a = BitVec::::from_bytes_general(&[ + // 88 bits + 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, + ]); + let b = BitVec::::from_bytes_general(&[ + // 88 bits + 0, 0, 0b00010100, 0, 0, 0, 0, 0, 0, 0, 0b00110100, + ]); + let c = BitVec::::from_bytes_general(&[ + // 88 bits + 0, 0, 0, 0, 0, 0, 0, 0b00110100, 0, 0, 0b00110100, + ]); + assert!(a.xor(&b)); + assert_eq!(a, c); + } + + #[test] + fn test_big_xnor() { + let mut a = BitVec::::from_bytes_general(&[ + // 88 bits + 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, + ]); + let b = BitVec::::from_bytes_general(&[ + // 88 bits + 0, 0, 0b00010100, 0, 0, 0, 0, 0, 0, 0, 0b00110100, + ]); + let c = BitVec::::from_bytes_general(&[ + // 88 bits + !0, + !0, + !0, + !0, + !0, + !0, + !0, + !0b00110100, + !0, + !0, + !0b00110100, + ]); + assert!(a.xnor(&b)); + assert_eq!(a, c); + } + + #[test] + fn test_small_fill() { + let mut b = BitVec::::from_elem_general(14, true); + assert!(!b.none() && b.all()); + b.fill(false); + assert!(b.none() && !b.all()); + b.fill(true); + assert!(!b.none() && b.all()); + } + + #[test] + fn test_big_fill() { + let mut b = BitVec::::from_elem_general(140, true); + assert!(!b.none() && b.all()); + b.fill(false); + assert!(b.none() && !b.all()); + b.fill(true); + assert!(!b.none() && b.all()); + } + + #[test] + fn test_bit_vec_lt() { + let mut a = BitVec::::from_elem_general(5, false); + let mut b = BitVec::::from_elem_general(5, false); + + assert!(a >= b && b >= a); + b.set(2, true); + assert!(a < b); + a.set(3, true); + assert!(a < b); + a.set(2, true); + assert!(a >= b && b < a); + b.set(0, true); + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = BitVec::::from_elem_general(5, false); + let mut b = BitVec::::from_elem_general(5, false); + + assert!(a == b); + a.set(1, true); + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b.set(1, true); + b.set(2, true); + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + #[test] + fn test_small_bit_vec_tests() { + let v = BitVec::::from_bytes_general(&[0]); + assert!(!v.all()); + assert!(!v.any()); + assert!(v.none()); + + let v = BitVec::::from_bytes_general(&[0b00010100]); + assert!(!v.all()); + assert!(v.any()); + assert!(!v.none()); + + let v = BitVec::::from_bytes_general(&[0xFF]); + assert!(v.all()); + assert!(v.any()); + assert!(!v.none()); + } + + #[test] + fn test_big_bit_vec_tests() { + let v = BitVec::::from_bytes_general(&[ + // 88 bits + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]); + assert!(!v.all()); + assert!(!v.any()); + assert!(v.none()); + + let v = BitVec::::from_bytes_general(&[ + // 88 bits + 0, 0, 0b00010100, 0, 0, 0, 0, 0b00110100, 0, 0, 0, + ]); + assert!(!v.all()); + assert!(v.any()); + assert!(!v.none()); + + let v = BitVec::::from_bytes_general(&[ + // 88 bits + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ]); + assert!(v.all()); + assert!(v.any()); + assert!(!v.none()); + } + + #[test] + fn test_bit_vec_push_pop() { + let mut s = BitVec::::from_elem_general(5 * U32_BITS - 2, false); + assert_eq!(s.len(), 5 * U32_BITS - 2); + assert!(!s[5 * U32_BITS - 3]); + s.push(true); + s.push(true); + assert!(s[5 * U32_BITS - 2]); + assert!(s[5 * U32_BITS - 1]); + // Here the internal vector will need to be extended + s.push(false); + assert!(!s[5 * U32_BITS]); + s.push(false); + assert!(!s[5 * U32_BITS + 1]); + assert_eq!(s.len(), 5 * U32_BITS + 2); + // Pop it all off + assert_eq!(s.pop(), Some(false)); + assert_eq!(s.pop(), Some(false)); + assert_eq!(s.pop(), Some(true)); + assert_eq!(s.pop(), Some(true)); + assert_eq!(s.len(), 5 * U32_BITS - 2); + } + + #[test] + fn test_bit_vec_truncate() { + let mut s = BitVec::::from_elem_general(5 * U32_BITS, true); + + assert_eq!(s, BitVec::::from_elem_general(5 * U32_BITS, true)); + assert_eq!(s.len(), 5 * U32_BITS); + s.truncate(4 * U32_BITS); + assert_eq!(s, BitVec::::from_elem_general(4 * U32_BITS, true)); + assert_eq!(s.len(), 4 * U32_BITS); + // Truncating to a size > s.len() should be a noop + s.truncate(5 * U32_BITS); + assert_eq!(s, BitVec::::from_elem_general(4 * U32_BITS, true)); + assert_eq!(s.len(), 4 * U32_BITS); + s.truncate(3 * U32_BITS - 10); + assert_eq!(s, BitVec::::from_elem_general(3 * U32_BITS - 10, true)); + assert_eq!(s.len(), 3 * U32_BITS - 10); + s.truncate(0); + assert_eq!(s, BitVec::::from_elem_general(0, true)); + assert_eq!(s.len(), 0); + } + + #[test] + fn test_bit_vec_reserve() { + let mut s = BitVec::::from_elem_general(5 * U32_BITS, true); + // Check capacity + assert!(s.capacity() >= 5 * U32_BITS); + s.reserve(2 * U32_BITS); + assert!(s.capacity() >= 7 * U32_BITS); + s.reserve(7 * U32_BITS); + assert!(s.capacity() >= 12 * U32_BITS); + s.reserve_exact(7 * U32_BITS); + assert!(s.capacity() >= 12 * U32_BITS); + s.reserve(7 * U32_BITS + 1); + assert!(s.capacity() > 12 * U32_BITS); + // Check that length hasn't changed + assert_eq!(s.len(), 5 * U32_BITS); + s.push(true); + s.push(false); + s.push(true); + assert!(s[5 * U32_BITS - 1]); + assert!(s[5 * U32_BITS]); + assert!(!s[5 * U32_BITS + 1]); + assert!(s[5 * U32_BITS + 2]); + } + + #[test] + fn test_bit_vec_grow() { + let mut bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b10101010]); + bit_vec.grow(32, true); + assert_eq!( + bit_vec, + BitVec::::from_bytes_general(&[ + 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF + ]) + ); + bit_vec.grow(64, false); + assert_eq!( + bit_vec, + BitVec::::from_bytes_general(&[ + 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0 + ]) + ); + bit_vec.grow(16, true); + assert_eq!( + bit_vec, + BitVec::::from_bytes_general(&[ + 0b10110110, 0b00000000, 0b10101010, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, + 0xFF, 0xFF + ]) + ); + } + + #[test] + fn test_bit_vec_extend() { + let mut bit_vec = BitVec::::from_bytes_general(&[0b10110110, 0b00000000, 0b11111111]); + let ext = BitVec::::from_bytes_general(&[0b01001001, 0b10010010, 0b10111101]); + bit_vec.extend(ext.iter()); + assert_eq!( + bit_vec, + BitVec::::from_bytes_general(&[ + 0b10110110, 0b00000000, 0b11111111, 0b01001001, 0b10010010, 0b10111101 + ]) + ); + } + + #[test] + fn test_bit_vec_append() { + // Append to BitVec that holds a multiple of U32_BITS bits + let mut a = + BitVec::::from_bytes_general(&[0b10100000, 0b00010010, 0b10010010, 0b00110011]); + let mut b = BitVec::::new_general(); + b.push(false); + b.push(true); + b.push(true); + + a.append(&mut b); + + assert_eq!(a.len(), 35); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 3); + + assert!(a.eq_vec(&[ + true, false, true, false, false, false, false, false, false, false, false, true, false, + false, true, false, true, false, false, true, false, false, true, false, false, false, + true, true, false, false, true, true, false, true, true + ])); + + // Append to arbitrary BitVec + let mut a = BitVec::::new_general(); + a.push(true); + a.push(false); + + let mut b = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, + ]); + + a.append(&mut b); + + assert_eq!(a.len(), 42); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 40); + + assert!(a.eq_vec(&[ + true, false, true, false, true, false, false, false, false, false, false, false, false, + true, false, false, true, false, true, false, false, true, false, false, true, false, + false, false, true, true, false, false, true, true, true, false, false, true, false, + true, false, true + ])); + + // Append to empty BitVec + let mut a = BitVec::::new_general(); + let mut b = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, + ]); + + a.append(&mut b); + + assert_eq!(a.len(), 40); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 40); + + assert!(a.eq_vec(&[ + true, false, true, false, false, false, false, false, false, false, false, true, false, + false, true, false, true, false, false, true, false, false, true, false, false, false, + true, true, false, false, true, true, true, false, false, true, false, true, false, + true + ])); + + // Append empty BitVec + let mut a = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101, + ]); + let mut b = BitVec::::new_general(); + + a.append(&mut b); + + assert_eq!(a.len(), 40); + assert_eq!(b.len(), 0); + + assert!(a.eq_vec(&[ + true, false, true, false, false, false, false, false, false, false, false, true, false, + false, true, false, true, false, false, true, false, false, true, false, false, false, + true, true, false, false, true, true, true, false, false, true, false, true, false, + true + ])); + } + + #[test] + fn test_bit_vec_split_off() { + // Split at 0 + let mut a = BitVec::::new_general(); + a.push(true); + a.push(false); + a.push(false); + a.push(true); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 4); + + assert!(b.eq_vec(&[true, false, false, true])); + + // Split at last bit + a.truncate(0); + a.push(true); + a.push(false); + a.push(false); + a.push(true); + + let b = a.split_off(4); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + + assert!(a.eq_vec(&[true, false, false, true])); + + // Split at block boundary + let mut a = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b11110011, + ]); + + let b = a.split_off(32); + + assert_eq!(a.len(), 32); + assert_eq!(b.len(), 8); + + assert!(a.eq_vec(&[ + true, false, true, false, false, false, false, false, false, false, false, true, false, + false, true, false, true, false, false, true, false, false, true, false, false, false, + true, true, false, false, true, true + ])); + assert!(b.eq_vec(&[true, true, true, true, false, false, true, true])); + + // Don't split at block boundary + let mut a = BitVec::::from_bytes_general(&[ + 0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b01101011, 0b10101101, + ]); + + let b = a.split_off(13); + + assert_eq!(a.len(), 13); + assert_eq!(b.len(), 35); + + assert!(a.eq_vec(&[ + true, false, true, false, false, false, false, false, false, false, false, true, false + ])); + assert!(b.eq_vec(&[ + false, true, false, true, false, false, true, false, false, true, false, false, false, + true, true, false, false, true, true, false, true, true, false, true, false, true, + true, true, false, true, false, true, true, false, true + ])); + } + + #[test] + fn test_into_iter() { + let bools = [true, false, true, true]; + let bit_vec: BitVec = bools.iter().copied().collect(); + let mut iter = bit_vec.into_iter(); + assert_eq!(Some(true), iter.next()); + assert_eq!(Some(false), iter.next()); + assert_eq!(Some(true), iter.next()); + assert_eq!(Some(true), iter.next()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next()); + + let bit_vec: BitVec = bools.iter().copied().collect(); + let mut iter = bit_vec.into_iter(); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(Some(false), iter.next_back()); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(None, iter.next_back()); + assert_eq!(None, iter.next_back()); + + let bit_vec: BitVec = bools.iter().copied().collect(); + let mut iter = bit_vec.into_iter(); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(Some(true), iter.next()); + assert_eq!(Some(false), iter.next()); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next_back()); + } + + #[test] + fn test_iter() { + let b = BitVec::::with_capacity_general(10); + let _a: Iter = b.iter(); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serialization() + where + S::Store: serde::Serialize + for<'a> serde::Deserialize<'a>, + { + let bit_vec: BitVec = BitVec::::new_general(); + let serialized = serde_json::to_string(&bit_vec).unwrap(); + let unserialized: BitVec = serde_json::from_str(&serialized[..]).unwrap(); + assert_eq!(bit_vec, unserialized); + + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let serialized = serde_json::to_string(&bit_vec).unwrap(); + let unserialized = serde_json::from_str(&serialized).unwrap(); + assert_eq!(bit_vec, unserialized); + } + + #[cfg(feature = "miniserde")] + #[test] + fn test_miniserde_serialization< + S: BitBlockOrStore + miniserde::Serialize + miniserde::Deserialize, + >() { + let bit_vec = BitVec::::new_general(); + let serialized = miniserde::json::to_string(&bit_vec); + let unserialized: BitVec = miniserde::json::from_str(&serialized[..]).unwrap(); + assert_eq!(bit_vec, unserialized); + + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let serialized = miniserde::json::to_string(&bit_vec); + let unserialized = miniserde::json::from_str(&serialized[..]).unwrap(); + assert_eq!(bit_vec, unserialized); + } + + #[cfg(feature = "nanoserde")] + #[test] + fn test_nanoserde_json_serialization< + S: BitBlockOrStore + + nanoserde::DeBin + + nanoserde::DeJson + + nanoserde::DeRon + + nanoserde::SerBin + + nanoserde::SerJson + + nanoserde::SerRon, + >() { + use nanoserde::{DeJson, SerJson}; + + let bit_vec = BitVec::::new_general(); + let serialized = bit_vec.serialize_json(); + let unserialized = BitVec::::deserialize_json(&serialized[..]).unwrap(); + assert_eq!(bit_vec, unserialized); + + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let serialized = bit_vec.serialize_json(); + let unserialized = BitVec::::deserialize_json(&serialized[..]).unwrap(); + assert_eq!(bit_vec, unserialized); + } + + #[cfg(feature = "borsh")] + #[test] + fn test_borsh_serialization() { + let bit_vec = BitVec::::new_general(); + let serialized = borsh::to_vec(&bit_vec).unwrap(); + let unserialized: BitVec = borsh::from_slice(&serialized[..]).unwrap(); + assert_eq!(bit_vec, unserialized); + + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let serialized = borsh::to_vec(&bit_vec).unwrap(); + let unserialized = borsh::from_slice(&serialized[..]).unwrap(); + assert_eq!(bit_vec, unserialized); + } + + #[test] + fn test_bit_vec_unaligned_small_append() { + let mut a = BitVec::::from_elem_general(8, false); + a.set(7, true); + + let mut b = BitVec::::from_elem_general(16, false); + b.set(14, true); + + let mut c = BitVec::::from_elem_general(8, false); + c.set(6, true); + c.set(7, true); + + a.append(&mut b); + a.append(&mut c); + + assert_eq!(&[1, 0, 2, 3][..], &*a.to_bytes()); + } + + #[test] + fn test_bit_vec_unaligned_large_append() { + let mut a = BitVec::::from_elem_general(48, false); + a.set(47, true); + + let mut b = BitVec::::from_elem_general(48, false); + b.set(46, true); + + let mut c = BitVec::::from_elem_general(48, false); + c.set(46, true); + c.set(47, true); + + a.append(&mut b); + a.append(&mut c); + + assert_eq!( + &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03 + ][..], + &*a.to_bytes() + ); + } + + #[test] + fn test_bit_vec_append_aligned_to_unaligned() { + let mut a = BitVec::::from_elem_general(2, true); + let mut b = BitVec::::from_elem_general(32, false); + let mut c = BitVec::::from_elem_general(8, true); + a.append(&mut b); + a.append(&mut c); + assert_eq!(&[0xc0, 0x00, 0x00, 0x00, 0x3f, 0xc0][..], &*a.to_bytes()); + } + + #[test] + fn test_count_ones() { + for i in 0..1000 { + let mut t = BitVec::::from_elem_general(i, true); + let mut f = BitVec::::from_elem_general(i, false); + assert_eq!(i as u64, t.count_ones()); + assert_eq!(0_u64, f.count_ones()); + if i > 20 { + t.set(10, false); + t.set(i - 10, false); + assert_eq!(i - 2, t.count_ones() as usize); + f.set(10, true); + f.set(i - 10, true); + assert_eq!(2, f.count_ones()); + } + } + } + + #[test] + fn test_count_zeros() { + for i in 0..1000 { + let mut tbits = BitVec::::from_elem_general(i, true); + let mut fbits = BitVec::::from_elem_general(i, false); + assert_eq!(i as u64, fbits.count_zeros()); + assert_eq!(0_u64, tbits.count_zeros()); + if i > 20 { + fbits.set(10, true); + fbits.set(i - 10, true); + assert_eq!(i - 2, fbits.count_zeros() as usize); + tbits.set(10, false); + tbits.set(i - 10, false); + assert_eq!(2, tbits.count_zeros()); + } + } + } + + #[test] + fn test_get_mut() { + let mut a = BitVec::::from_elem_general(3, false); + let mut a_bit_1 = a.get_mut(1).unwrap(); + assert!(!*a_bit_1); + *a_bit_1 = true; + drop(a_bit_1); + assert!(a.eq_vec(&[false, true, false])); + } + + #[test] + fn test_iter_mut() { + let mut a = BitVec::::from_elem_general(8, false); + a.iter_mut().enumerate().for_each(|(index, mut bit)| { + *bit = index % 2 == 1; + }); + assert!(a.eq_vec(&[false, true, false, true, false, true, false, true])); + } + + #[test] + fn test_insert_at_zero() { + let mut v = BitVec::::new_general(); + + v.insert(0, false); + v.insert(0, true); + v.insert(0, false); + v.insert(0, true); + v.insert(0, false); + v.insert(0, true); + + assert_eq!(v.len(), 6); + assert_eq!(v.storage().len(), 1); + assert!(v.eq_vec(&[true, false, true, false, true, false])); + } + + #[test] + fn test_insert_at_end() { + let mut v = BitVec::::new_general(); + + v.insert(v.len(), true); + v.insert(v.len(), false); + v.insert(v.len(), true); + v.insert(v.len(), false); + v.insert(v.len(), true); + v.insert(v.len(), false); + + assert_eq!(v.storage().len(), 1); + assert_eq!(v.len(), 6); + assert!(v.eq_vec(&[true, false, true, false, true, false])); + } + + #[test] + fn test_insert_at_block_boundaries() { + let mut v = BitVec::::from_elem_general(32, false); + + assert_eq!(v.storage().len(), (4 / S::BYTES).max(1)); + + v.insert(31, true); + + assert_eq!(v.len(), 33); + + assert!(matches!(v.get(31), Some(true))); + assert!(v.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, true, false + ])); + + assert_eq!(v.storage().len(), 1 + 4 / S::BYTES); + } + + #[test] + fn test_insert_at_block_boundaries_1() { + let mut v = BitVec::::from_elem_general(64, false); + + assert_eq!(v.storage().len(), 8 / S::BYTES); + + v.insert(63, true); + + assert_eq!(v.len(), 65); + + assert!(matches!(v.get(63), Some(true))); + assert!(v.eq_vec(&[ + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, true, false + ])); + + assert_eq!(v.storage().len(), 1 + 8 / S::BYTES); + } + + #[test] + fn test_push_within_capacity_with_suffice_cap() { + let mut v = BitVec::::from_elem_general(16, true); + + if S::BYTES > 2 { + assert!(v.push_within_capacity(false).is_ok()); + } + + for i in 0..16 { + assert_eq!(v.get(i), Some(true)); + } + + if S::BYTES > 2 { + assert_eq!(v.get(16), Some(false)); + assert_eq!(v.len(), 17); + } + } + + #[test] + fn test_push_within_capacity_at_brink() { + let mut v = BitVec::::from_elem_general(31, true); + + assert!(v.push_within_capacity(false).is_ok()); + + assert_eq!(v.get(31), Some(false)); + if v.capacity() < 256 { + assert_eq!(if S::BYTES == 8 { 64 } else { v.len() }, v.capacity()); + } + assert_eq!(v.len(), 32); + + if v.capacity() < 256 { + assert_eq!( + v.push_within_capacity(false), + if S::BYTES == 8 { Ok(()) } else { Err(false) } + ); + assert_eq!(v.capacity(), if S::BYTES == 8 { 64 } else { 32 }); + } + + for i in 0..31 { + assert_eq!(v.get(i), Some(true)); + } + assert_eq!(v.get(31), Some(false)); + } + + #[test] + fn test_push_within_capacity_at_brink_with_mul_blocks() { + let mut v = BitVec::::from_elem_general(95, true); + + assert!(v.push_within_capacity(false).is_ok()); + + assert_eq!(v.get(95), Some(false)); + if S::BYTES <= 4 && v.capacity() < 256 { + assert_eq!(v.len(), v.capacity()); + } + assert_eq!(v.len(), 96); + + if S::BYTES == 8 { + assert_eq!(v.push_within_capacity(false), Ok(())); + if v.capacity() < 256 { + assert_eq!(v.capacity(), 128); + } + } else if v.capacity() < 256 { + assert_eq!(v.push_within_capacity(false), Err(false)); + assert_eq!(v.capacity(), 96); + } + + for i in 0..95 { + assert_eq!(v.get(i), Some(true)); + } + assert_eq!(v.get(95), Some(false)); + } + + #[test] + fn test_push_within_capacity_storage_push() { + let mut v = BitVec::::with_capacity_general(64); + + for _ in 0..32 { + v.push(true); + } + + assert_eq!(v.len(), 32); + + assert!(v.push_within_capacity(false).is_ok()); + + assert_eq!(v.len(), 33); + + for i in 0..32 { + assert_eq!(v.get(i), Some(true)); + } + assert_eq!(v.get(32), Some(false)); + } + + #[test] + fn test_insert_remove() { + // two primes for no common divisors with 32 + let mut v = BitVec::::from_fn_general(1024, |i| i % 11 < 7); + for i in 0..1024 { + let result = v.remove(i); + v.insert(i, result); + assert_eq!(result, i % 11 < 7); + } + + for i in 0..1024 { + v.insert(i, false); + v.remove(i); + } + + for i in 0..1024 { + v.insert(i, true); + v.remove(i); + } + + for (i, result) in v.into_iter().enumerate() { + assert_eq!(result, i % 11 < 7); + } + } + + #[test] + fn test_remove_last() { + let mut v = BitVec::::from_fn_general(1025, |i| i % 11 < 7); + assert_eq!(v.len(), 1025); + assert_eq!(v.remove(1024), 1024 % 11 < 7); + assert_eq!(v.len(), 1024); + assert_eq!(v.storage().len(), 1024 / S::BITS); + } + + #[test] + fn test_remove_all() { + let v = BitVec::::from_elem_general(1024, false); + for _ in 0..1024 { + let mut v2 = v.clone(); + v2.remove_all(); + assert_eq!(v2.len(), 0); + assert_eq!(v2.get(0), None); + assert_eq!(v2, BitVec::new_general()); + } + } + + #[instantiate_tests(>)] + mod vec32 {} + + #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] + #[instantiate_tests(>)] + mod smallvec32x8 {} + + #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] + #[instantiate_tests(>)] + mod smallvec64x8 {} + + #[instantiate_tests()] + mod integer32 {} + + #[instantiate_tests()] + mod native {} + + #[instantiate_tests()] + mod integer16 {} + + #[instantiate_tests()] + mod integer8 {} +} + +#[cfg(test)] +#[cfg(feature = "allocator_api")] +mod alloc_tests { + use std::alloc::Global; + use std::vec::Vec; + + use crate::BitVec; + + #[test] + fn test_new_in() { + let alloc = Global; + let mut v: BitVec> = BitVec::new_general_in(alloc); + v.push(true); + v.push(false); + assert_eq!(v.len(), 2); + assert_eq!(v.pop(), Some(false)); + assert_eq!(v.pop(), Some(true)); + } +} From 0aab160adaaf63f96ee28c205e11543284c31386 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 12 Mar 2026 13:52:27 +0100 Subject: [PATCH 16/24] Fix github CI workflow --- .github/workflows/rust.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 26acdf4..5ba479f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,6 +16,14 @@ jobs: - uses: actions/checkout@v5 - name: Build run: cargo build --verbose + - name: Build with serde + run: cargo build --features serde --verbose + - name: Build with miniserde + run: cargo build --features nanoserde --verbose + - name: Build with miniserde + run: cargo build --features miniserde --verbose + - name: Build with borsh + run: cargo build --features borsh --verbose - name: Run tests run: cargo test --verbose - name: Run miniserde tests @@ -62,12 +70,18 @@ jobs: with: toolchain: ${{matrix.rust}} - run: cargo build + - run: cargo build --features serde + - run: cargo build --features serde --no-default-features + - run: cargo build --features nanoserde + - run: cargo build --features miniserde + - run: cargo build --features borsh + - run: cargo build --features borsh,serde,nanoserde + - run: cargo build --features borsh,serde,nanoserde,miniserde + - run: cargo build --features borsh,serde,nanoserde,miniserde --no-default-features - run: cargo test - run: cargo test --features serde - - run: cargo test --features nanoserde - - run: cargo test --features miniserde - - run: cargo test --features borsh - - run: cargo test --features borsh,serde,nanoserde + - run: cargo test --features borsh,serde,nanoserde,miniserde + - run: cargo test --features borsh,serde,nanoserde,miniserde --no-default-features clippy: runs-on: ubuntu-latest From d45599fba647c84a0dca72faa925f35f3b19fa38 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 12 Mar 2026 14:05:05 +0100 Subject: [PATCH 17/24] Formatting for imports --- set/src/iter.rs | 2 +- set/src/lib.rs | 6 +++--- set/src/set.rs | 5 ++--- vec/src/into_iter.rs | 4 ++-- vec/tests/vec.rs | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/set/src/iter.rs b/set/src/iter.rs index 2fc094e..0ace9ff 100644 --- a/set/src/iter.rs +++ b/set/src/iter.rs @@ -1,5 +1,5 @@ -use crate::{local_prelude::*, set::BitSet}; use crate::util::Block; +use crate::{local_prelude::*, set::BitSet}; #[derive(Clone)] struct BlockIter { diff --git a/set/src/lib.rs b/set/src/lib.rs index 4f97cf1..3fbe1d4 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -60,16 +60,16 @@ extern crate std; #[cfg(feature = "nanoserde")] extern crate alloc; +mod iter; mod set; mod util; -mod iter; pub mod local_prelude { pub use bit_vec::{BitBlock, BitBlockOrStore, BitStore, BitVec, Blocks}; pub use core::cmp::Ordering; - pub use core::{hash, fmt, cmp}; pub use core::iter::{self, Chain, Enumerate, FromIterator, Repeat, Skip, Take}; + pub use core::{cmp, fmt, hash}; } +pub use bit_vec::{BitBlockOrStore, BitStore}; pub use set::BitSet; -pub use bit_vec::{BitStore, BitBlockOrStore}; diff --git a/set/src/set.rs b/set/src/set.rs index 1e42ba7..c907151 100644 --- a/set/src/set.rs +++ b/set/src/set.rs @@ -1,5 +1,5 @@ -use crate::{local_prelude::*, util}; use crate::util::Block; +use crate::{local_prelude::*, util}; #[cfg(feature = "nanoserde")] use alloc::vec::Vec; @@ -403,7 +403,6 @@ impl BitSet { bit_vec.shrink_to_fit(); } - /// Unions in-place with the specified other bit vector. /// /// # Examples @@ -724,4 +723,4 @@ impl hash::Hash for BitSet { pos.hash(state); } } -} \ No newline at end of file +} diff --git a/vec/src/into_iter.rs b/vec/src/into_iter.rs index 1cc8755..b4aaa96 100644 --- a/vec/src/into_iter.rs +++ b/vec/src/into_iter.rs @@ -1,4 +1,4 @@ -use crate::{BitVec, local_prelude::*}; +use crate::{local_prelude::*, BitVec}; pub struct IntoIter { bit_vec: BitVec, @@ -35,4 +35,4 @@ impl IntoIterator for BitVec { range: 0..nbits, } } -} \ No newline at end of file +} diff --git a/vec/tests/vec.rs b/vec/tests/vec.rs index 0721e4a..b060442 100644 --- a/vec/tests/vec.rs +++ b/vec/tests/vec.rs @@ -6,7 +6,7 @@ mod tests { #![allow(clippy::shadow_unrelated)] #![allow(clippy::extra_unused_type_parameters)] - use bit_vec::{BitVec, BitBlockOrStore, Iter}; + use bit_vec::{BitBlockOrStore, BitVec, Iter}; // This is stupid, but I want to differentiate from a "random" 32 const U32_BITS: usize = 32; From 522ca05149c22a0c8867b2cc7dcccaa7839ac1d3 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Thu, 12 Mar 2026 17:08:30 +0100 Subject: [PATCH 18/24] Move static REVERSE_BITS table to the `util`s module * use the static table in `fn reverse_bits` --- vec/src/util.rs | 21 +++++++++++++++------ vec/src/vec.rs | 14 +------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/vec/src/util.rs b/vec/src/util.rs index 7b699a9..4e55cbb 100644 --- a/vec/src/util.rs +++ b/vec/src/util.rs @@ -5,10 +5,19 @@ pub(crate) type Block = ::Block; pub static TRUE: bool = true; pub static FALSE: bool = false; -pub fn reverse_bits(byte: u8) -> u8 { - let mut result = 0; - for i in 0..u8::BITS { - result |= ((byte >> i) & 1) << (u8::BITS - 1 - i); - } - result +pub(crate) fn reverse_bits(byte: u8) -> u8 { + REVERSE_TABLE[byte as usize] } + +static REVERSE_TABLE: [u8; 256] = { + let mut tbl = [0u8; 256]; + let mut i: u8 = 0; + loop { + tbl[i as usize] = i.reverse_bits(); + if i == 255 { + break; + } + i += 1; + } + tbl +}; diff --git a/vec/src/vec.rs b/vec/src/vec.rs index d0c6649..948161c 100644 --- a/vec/src/vec.rs +++ b/vec/src/vec.rs @@ -1104,18 +1104,6 @@ impl BitVec { /// assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); /// ``` pub fn to_bytes(&self) -> Vec { - static REVERSE_TABLE: [u8; 256] = { - let mut tbl = [0u8; 256]; - let mut i: u8 = 0; - loop { - tbl[i as usize] = i.reverse_bits(); - if i == 255 { - break; - } - i += 1; - } - tbl - }; self.ensure_invariant(); let len = self.nbits / 8 + if self.nbits % 8 == 0 { 0 } else { 1 }; @@ -1129,7 +1117,7 @@ impl BitVec { byte |= 1 << bit_idx; } } - result.push(REVERSE_TABLE[byte as usize]); + result.push(util::reverse_bits(byte)); } result From a2c388fa82bc0538a460cc494626420693da27a2 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 13 Mar 2026 18:58:47 +0100 Subject: [PATCH 19/24] Permit boxed bit vectors (of immediate size of 2 words) --- vec/src/block_or_store.rs | 8 +++- vec/src/lib.rs | 4 ++ vec/src/store.rs | 77 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/vec/src/block_or_store.rs b/vec/src/block_or_store.rs index dc285de..dd3bef0 100644 --- a/vec/src/block_or_store.rs +++ b/vec/src/block_or_store.rs @@ -69,9 +69,13 @@ macro_rules! impl_combination { ); }; ( - type $T:ty: [$($B:tt)*]; + type $T:ty: [$B0:tt + $($B:tt)*]; ) => { - impl BitBlockOrStore for Vec { + impl BitBlockOrStore for Vec { + type Store = Self; + } + + impl BitBlockOrStore for Box> where Self: $($B)* { type Store = Self; } } diff --git a/vec/src/lib.rs b/vec/src/lib.rs index 29ab121..de5334c 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -138,6 +138,8 @@ mod local_prelude { pub use alloc::string::String; #[cfg(not(feature = "std"))] pub use alloc::vec::Vec; + #[cfg(not(feature = "std"))] + pub use alloc::boxed::Box; #[cfg(feature = "std")] pub use std::rc::Rc; @@ -145,6 +147,8 @@ mod local_prelude { pub use std::string::String; #[cfg(feature = "std")] pub use std::vec::Vec; + #[cfg(feature = "std")] + pub use std::boxed::Box; pub use core::cell::RefCell; pub use core::cmp::Ordering; diff --git a/vec/src/store.rs b/vec/src/store.rs index 825922f..f7c285a 100644 --- a/vec/src/store.rs +++ b/vec/src/store.rs @@ -261,3 +261,80 @@ where smallvec::SmallVec::with_capacity(capacity) } } + +impl BitStore for Box { + type Block = S::Block; + type Alloc = S::Alloc; + + fn slice(&self) -> &[Self::Block] { + (**self).slice() + } + + fn slice_mut(&mut self) -> &mut [Self::Block] { + (**self).slice_mut() + } + + fn pop(&mut self) -> Option { + (**self).pop() + } + + fn drain>(&mut self, range: R) -> impl Iterator { + (**self).drain(range) + } + + fn capacity(&self) -> usize { + (**self).capacity() + } + + fn append(&mut self, other: &mut Self) { + (**self).append(other); + } + + fn reserve(&mut self, additional: usize) { + (**self).reserve(additional); + } + + fn push(&mut self, value: Self::Block) { + (**self).push(value); + } + + fn split_off(&mut self, at: usize) -> Self { + // TODO + Box::new((**self).split_off(at)) + } + + fn truncate(&mut self, len: usize) { + (**self).truncate(len); + } + + fn reserve_exact(&mut self, len: usize) { + (**self).reserve_exact(len); + } + + fn shrink_to_fit(&mut self) { + (**self).shrink_to_fit(); + } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + (**self).extend(iter); + } + + fn with_capacity(capacity: usize) -> Self { + Box::new(S::with_capacity(capacity)) + } + + fn clear(&mut self) { + (**self).clear(); + } + + fn new_in(alloc: Self::Alloc) -> Self { + Box::new(S::new_in(alloc)) + } + + fn with_capacity_in(capacity: usize, alloc: Self::Alloc) -> Self { + Box::new(S::with_capacity_in(capacity, alloc)) + } +} From cb9779281c0fa011af05ad7a64387fa5a8e5d012 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 13 Mar 2026 18:59:10 +0100 Subject: [PATCH 20/24] Add conversion from Vec to BitVec --- vec/src/vec.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vec/src/vec.rs b/vec/src/vec.rs index 948161c..ba56661 100644 --- a/vec/src/vec.rs +++ b/vec/src/vec.rs @@ -1747,3 +1747,10 @@ impl cmp::PartialEq for BitVec { } impl cmp::Eq for BitVec {} + +impl> + BitBlock> From> for BitVec { + fn from(value: Vec) -> Self { + let nbits = value.len() * S::BITS; + BitVec { storage: value, nbits } + } +} From 64e279ac02e68b0725454f261a4dda8fed71925d Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 13 Mar 2026 19:28:25 +0100 Subject: [PATCH 21/24] Fix macro invocation for bounds --- vec/src/block_or_store.rs | 10 +++++----- vec/src/lib.rs | 8 ++++---- vec/src/vec.rs | 5 ++++- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/vec/src/block_or_store.rs b/vec/src/block_or_store.rs index dd3bef0..bb7ee57 100644 --- a/vec/src/block_or_store.rs +++ b/vec/src/block_or_store.rs @@ -47,7 +47,7 @@ pub trait BitBlockOrStore { macro_rules! impl_combination { ( - type $T:ty: [$($B:tt)*]; + type $T:ty: $B0:tt + [$($B:tt)*]; $cfg0:tt => [$($Bounds0:tt)*]; $( $cfg:tt => [$($Bounds:tt)*]; @@ -55,21 +55,21 @@ macro_rules! impl_combination { ) => { #[cfg(not(feature = $cfg0))] impl_combination!( - type $T: [$($B)*]; + type $T: $B0 + [$($B)*]; $( $cfg => [$($Bounds)*]; )* ); #[cfg(feature = $cfg0)] impl_combination!( - type $T: [$($B)* + $($Bounds0)*]; + type $T: $B0 + [$($B)* + $($Bounds0)*]; $( $cfg => [$($Bounds)*]; )* ); }; ( - type $T:ty: [$B0:tt + $($B:tt)*]; + type $T:ty: $B0:tt + [$($B:tt)*]; ) => { impl BitBlockOrStore for Vec { type Store = Self; @@ -82,7 +82,7 @@ macro_rules! impl_combination { } impl_combination!( - type Vec: [BitBlock]; + type Vec: BitBlock + []; "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; diff --git a/vec/src/lib.rs b/vec/src/lib.rs index de5334c..88fd0e0 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -132,23 +132,23 @@ pub use store::BitStore; pub use vec::BitVec; mod local_prelude { + #[cfg(not(feature = "std"))] + pub use alloc::boxed::Box; #[cfg(not(feature = "std"))] pub use alloc::rc::Rc; #[cfg(not(feature = "std"))] pub use alloc::string::String; #[cfg(not(feature = "std"))] pub use alloc::vec::Vec; - #[cfg(not(feature = "std"))] - pub use alloc::boxed::Box; + #[cfg(feature = "std")] + pub use std::boxed::Box; #[cfg(feature = "std")] pub use std::rc::Rc; #[cfg(feature = "std")] pub use std::string::String; #[cfg(feature = "std")] pub use std::vec::Vec; - #[cfg(feature = "std")] - pub use std::boxed::Box; pub use core::cell::RefCell; pub use core::cmp::Ordering; diff --git a/vec/src/vec.rs b/vec/src/vec.rs index ba56661..8163796 100644 --- a/vec/src/vec.rs +++ b/vec/src/vec.rs @@ -1751,6 +1751,9 @@ impl cmp::Eq for BitVec {} impl> + BitBlock> From> for BitVec { fn from(value: Vec) -> Self { let nbits = value.len() * S::BITS; - BitVec { storage: value, nbits } + BitVec { + storage: value, + nbits, + } } } From f7425aff02ead737d1ebff6e667a2c19e85a608f Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 13 Mar 2026 19:40:51 +0100 Subject: [PATCH 22/24] Fix incorrect macro invocation with an empty list --- vec/src/block_or_store.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/vec/src/block_or_store.rs b/vec/src/block_or_store.rs index bb7ee57..2e69ec5 100644 --- a/vec/src/block_or_store.rs +++ b/vec/src/block_or_store.rs @@ -46,6 +46,28 @@ pub trait BitBlockOrStore { } macro_rules! impl_combination { + ( + type $T:ty: $B0:tt + []; + $cfg0:tt => [$($Bounds0:tt)*]; + $( + $cfg:tt => [$($Bounds:tt)*]; + )* + ) => { + #[cfg(not(feature = $cfg0))] + impl_combination!( + type $T: $B0 + []; + $( + $cfg => [$($Bounds)*]; + )* + ); + #[cfg(feature = $cfg0)] + impl_combination!( + type $T: $B0 + [$($Bounds0)*]; + $( + $cfg => [$($Bounds)*]; + )* + ); + }; ( type $T:ty: $B0:tt + [$($B:tt)*]; $cfg0:tt => [$($Bounds0:tt)*]; From 18e49d4b246e4959329d4731a90069612b0beaee Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Sat, 14 Mar 2026 13:01:57 +0100 Subject: [PATCH 23/24] Update BitMatrix --- matrix/Cargo.toml | 11 +-- matrix/README.md | 78 ++++++++++++++------- matrix/src/block.rs | 11 +-- matrix/src/lib.rs | 69 +++++++++++++++++-- matrix/src/matrix.rs | 99 +++++++++++--------------- matrix/src/row.rs | 32 +++++---- matrix/src/submatrix.rs | 107 +++++++++++++++-------------- matrix/tests/test_submatrix.rs | 2 +- matrix/tests/transitive_closure.rs | 2 +- 9 files changed, 242 insertions(+), 169 deletions(-) diff --git a/matrix/Cargo.toml b/matrix/Cargo.toml index 1e5018b..554f132 100644 --- a/matrix/Cargo.toml +++ b/matrix/Cargo.toml @@ -14,8 +14,10 @@ edition = "2021" name = "bit_matrix" [dependencies] -serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true } miniserde = { version = "0.1", optional = true } +nanoserde = { version = "0.1", optional = true } +borsh = { version = "1.6.0", optional = true } bit-vec = { path = "../vec/", default-features = false } [dev-dependencies] @@ -24,9 +26,10 @@ serde_json = "1.0" [features] default = ["std"] -std = ["bit-vec/std"] +std = ["bit-vec/std", "serde?/std"] serde = ["dep:serde", "bit-vec/serde"] -serde_std = ["std", "serde/std"] -serde_no_std = ["serde/alloc"] miniserde = ["dep:miniserde", "bit-vec/miniserde"] +nanoserde = ["dep:nanoserde", "bit-vec/nanoserde"] +borsh = ["dep:borsh", "bit-vec/borsh"] +smallvec = ["bit-vec/smallvec"] diff --git a/matrix/README.md b/matrix/README.md index e1f0028..1240190 100644 --- a/matrix/README.md +++ b/matrix/README.md @@ -32,42 +32,70 @@ Rust library that implements bit matrices. Built on top of [contain-rs/bit-vec](https://github.com/contain-rs/bit-vec/). -## Examples + + +Implements bit matrices. + +# Examples + +Gets a mutable reference to the square bit matrix within this +rectangular matrix, then performs a transitive closure. + +```rust +use bit_matrix::BitMatrix; + +let mut matrix = ::new(7, 5); +matrix.set(1, 2, true); +matrix.set(2, 3, true); +matrix.set(3, 4, true); + +{ + let mut sub_matrix = matrix.sub_matrix_mut(1 .. 6); + sub_matrix.transitive_closure(); +} +assert!(matrix[(1, 4)]); + +matrix.reflexive_closure(); +assert!(matrix[(0, 0)]); +assert!(matrix[(1, 1)]); +assert!(matrix[(2, 2)]); +assert!(matrix[(3, 3)]); +``` This simple example calculates the transitive closure of 4x4 bit matrix. ```rust use bit_matrix::BitMatrix; -fn main() { - let mut matrix = BitMatrix::new(4, 4); - let points = &[ - (0, 0), - (0, 1), - (0, 3), - (1, 0), - (1, 2), - (2, 0), - (2, 1), - (3, 1), - (3, 3), - ]; - for &(i, j) in points { - matrix.set(i, j, true); - } - matrix.transitive_closure(); +let mut matrix = ::new(4, 4); +let points = &[ + (0, 0), + (0, 1), + (0, 3), + (1, 0), + (1, 2), + (2, 0), + (2, 1), + (3, 1), + (3, 3), +]; +for &(i, j) in points { + matrix.set(i, j, true); +} +matrix.transitive_closure(); - let mut expected_matrix = BitMatrix::new(4, 4); - for i in 0..4 { - for j in 0..4 { - expected_matrix.set(i, j, true); - } +let mut expected_matrix = BitMatrix::new(4, 4); +for i in 0..4 { + for j in 0..4 { + expected_matrix.set(i, j, true); } - - assert_eq!(matrix, expected_matrix); } + +assert_eq!(matrix, expected_matrix); ``` + + ## License Dual-licensed for compatibility with the Rust project. diff --git a/matrix/src/block.rs b/matrix/src/block.rs index 3b40e56..e142b93 100644 --- a/matrix/src/block.rs +++ b/matrix/src/block.rs @@ -1,9 +1,4 @@ -//! Defines a building block for the bit slice. -//! -//! Bits are stored in blocks. When the last block -//! is not full with bits, we waste some space. +use bit_vec::{BitBlockOrStore, BitStore}; -/// The number of bits in a block. -pub const BITS: usize = 32; -/// The type used as storage for bits. -pub type Block = u32; +#[allow(type_alias_bounds)] +pub(crate) type Block = ::Block; diff --git a/matrix/src/lib.rs b/matrix/src/lib.rs index 90b44f7..2d2b0ce 100644 --- a/matrix/src/lib.rs +++ b/matrix/src/lib.rs @@ -1,4 +1,62 @@ //! Implements bit matrices. +//! +//! # Examples +//! +//! Gets a mutable reference to the square bit matrix within this +//! rectangular matrix, then performs a transitive closure. +//! +//! ```rust +//! use bit_matrix::BitMatrix; +//! +//! let mut matrix = ::new(7, 5); +//! matrix.set(1, 2, true); +//! matrix.set(2, 3, true); +//! matrix.set(3, 4, true); +//! +//! { +//! let mut sub_matrix = matrix.sub_matrix_mut(1 .. 6); +//! sub_matrix.transitive_closure(); +//! } +//! assert!(matrix[(1, 4)]); +//! +//! matrix.reflexive_closure(); +//! assert!(matrix[(0, 0)]); +//! assert!(matrix[(1, 1)]); +//! assert!(matrix[(2, 2)]); +//! assert!(matrix[(3, 3)]); +//! ``` +//! +//! This simple example calculates the transitive closure of 4x4 bit matrix. +//! +//! ```rust +//! use bit_matrix::BitMatrix; +//! +//! let mut matrix = ::new(4, 4); +//! let points = &[ +//! (0, 0), +//! (0, 1), +//! (0, 3), +//! (1, 0), +//! (1, 2), +//! (2, 0), +//! (2, 1), +//! (3, 1), +//! (3, 3), +//! ]; +//! for &(i, j) in points { +//! matrix.set(i, j, true); +//! } +//! matrix.transitive_closure(); +//! +//! let mut expected_matrix = BitMatrix::new(4, 4); +//! for i in 0..4 { +//! for j in 0..4 { +//! expected_matrix.set(i, j, true); +//! } +//! } +//! +//! assert_eq!(matrix, expected_matrix); +//! ``` #![deny( missing_docs, @@ -11,10 +69,10 @@ #![cfg_attr(test, deny(warnings))] #![no_std] -pub mod block; -pub mod matrix; -pub mod row; -pub mod submatrix; +mod block; +mod matrix; +mod row; +mod submatrix; mod util; pub use matrix::BitMatrix; @@ -25,8 +83,7 @@ pub static TRUE: bool = true; pub static FALSE: bool = false; pub(crate) mod local_prelude { - pub use crate::block::{Block, BITS}; - // pub use crate::matrix::BitMatrix; + pub(crate) use crate::block::Block; pub use crate::row::BitSlice; pub use crate::submatrix::{BitSubMatrix, BitSubMatrixMut}; } diff --git a/matrix/src/matrix.rs b/matrix/src/matrix.rs index 0ff15e0..e050cd1 100644 --- a/matrix/src/matrix.rs +++ b/matrix/src/matrix.rs @@ -1,35 +1,9 @@ //! Matrix of bits. -//! -//! # Examples -//! -//! Gets a mutable reference to the square bit matrix within this -//! rectangular matrix, then performs a transitive closure. -//! -//! ```rust -//! use bit_matrix::BitMatrix; -//! -//! let mut matrix = BitMatrix::new(7, 5); -//! matrix.set(1, 2, true); -//! matrix.set(2, 3, true); -//! matrix.set(3, 4, true); -//! -//! { -//! let mut sub_matrix = matrix.sub_matrix_mut(1 .. 6); -//! sub_matrix.transitive_closure(); -//! } -//! assert!(matrix[(1, 4)]); -//! -//! matrix.reflexive_closure(); -//! assert!(matrix[(0, 0)]); -//! assert!(matrix[(1, 1)]); -//! assert!(matrix[(2, 2)]); -//! assert!(matrix[(3, 3)]); -//! ``` use core::cmp; use core::ops::{Index, IndexMut, RangeBounds}; -use bit_vec::BitVec; +use bit_vec::{BitBlockOrStore, BitStore, BitVec}; use super::{FALSE, TRUE}; use crate::local_prelude::*; @@ -42,18 +16,18 @@ use crate::util::round_up_to_next; derive(miniserde::Serialize, miniserde::Deserialize) )] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BitMatrix { - bit_vec: BitVec, +pub struct BitMatrix { + bit_vec: BitVec, row_bits: usize, } // Matrix -impl BitMatrix { +impl BitMatrix { /// Create a new BitMatrix with specific numbers of bits in columns and rows. pub fn new(rows: usize, row_bits: usize) -> Self { BitMatrix { - bit_vec: BitVec::from_elem(round_up_to_next(row_bits, BITS) * rows, false), + bit_vec: BitVec::from_elem_general(round_up_to_next(row_bits, B::BITS) * rows, false), row_bits, } } @@ -64,7 +38,7 @@ impl BitMatrix { if self.row_bits == 0 { 0 } else { - let row_blocks = round_up_to_next(self.row_bits, BITS) / BITS; + let row_blocks = round_up_to_next(self.row_bits, B::BITS) / B::BITS; self.bit_vec.storage().len() / row_blocks } } @@ -87,7 +61,7 @@ impl BitMatrix { /// Panics if `(row, col)` is out of bounds. #[inline] pub fn set(&mut self, row: usize, col: usize, enabled: bool) { - let row_size_in_bits = round_up_to_next(self.row_bits, BITS); + let row_size_in_bits = round_up_to_next(self.row_bits, B::BITS); self.bit_vec.set(row * row_size_in_bits + col, enabled); } @@ -100,19 +74,19 @@ impl BitMatrix { /// Grows the matrix in-place, adding `num_rows` rows filled with `value`. pub fn grow(&mut self, num_rows: usize, value: bool) { self.bit_vec - .grow(round_up_to_next(self.row_bits, BITS) * num_rows, value); + .grow(round_up_to_next(self.row_bits, B::BITS) * num_rows, value); } /// Truncates the matrix. pub fn truncate(&mut self, num_rows: usize) { self.bit_vec - .truncate(round_up_to_next(self.row_bits, BITS) * num_rows); + .truncate(round_up_to_next(self.row_bits, B::BITS) * num_rows); } /// Returns a slice of the matrix's rows. #[inline] - pub fn sub_matrix>(&self, range: R) -> BitSubMatrix<'_> { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + pub fn sub_matrix>(&self, range: R) -> BitSubMatrix<'_, B> { + let row_size = round_up_to_next(self.row_bits, B::BITS) / B::BITS; BitSubMatrix { slice: &self.bit_vec.storage()[( range.start_bound().map(|&s| s * row_size), @@ -124,13 +98,13 @@ impl BitMatrix { /// Returns a slice of the matrix's rows. #[inline] - pub fn sub_matrix_mut>(&mut self, range: R) -> BitSubMatrixMut<'_> { + pub fn sub_matrix_mut>(&mut self, range: R) -> BitSubMatrixMut<'_, B> { let row_size = self.row_size(); // Safety: // unsafe { BitSubMatrixMut { - slice: &mut self.bit_vec.storage_mut()[( + slice: &mut self.bit_vec.storage_mut().slice_mut()[( range.start_bound().map(|&s| s * row_size), range.end_bound().map(|&e| e * row_size), )], @@ -140,7 +114,7 @@ impl BitMatrix { } fn row_size(&self) -> usize { - round_up_to_next(self.row_bits, BITS) / BITS + round_up_to_next(self.row_bits, B::BITS) / B::BITS } /// Given a row's index, returns a slice of all rows above that row, a reference to said row, @@ -149,7 +123,7 @@ impl BitMatrix { /// Functionally equivalent to `(self.sub_matrix(0..row), &self[row], /// self.sub_matrix(row..self.num_rows()))`. #[inline] - pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_>, BitSubMatrix<'_>) { + pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_, B>, BitSubMatrix<'_, B>) { ( self.sub_matrix(0..row), self.sub_matrix(row..self.num_rows()), @@ -159,9 +133,14 @@ impl BitMatrix { /// Given a row's index, returns a slice of all rows above that row, a reference to said row, /// and a slice of all rows below. #[inline] - pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_>, BitSubMatrixMut<'_>) { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; - let (first, second) = unsafe { self.bit_vec.storage_mut().split_at_mut(row * row_size) }; + pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_, B>, BitSubMatrixMut<'_, B>) { + let row_size = round_up_to_next(self.row_bits, B::BITS) / B::BITS; + let (first, second) = unsafe { + self.bit_vec + .storage_mut() + .slice_mut() + .split_at_mut(row * row_size) + }; ( BitSubMatrixMut::new(first, self.row_bits), BitSubMatrixMut::new(second, self.row_bits), @@ -191,7 +170,7 @@ impl BitMatrix { /// /// The matrix must be square for this operation to succeed. pub fn transitive_closure(&mut self) { - Into::::into(self).transitive_closure(); + Into::>::into(self).transitive_closure(); } /// Determines whether the number of rows equals the number of columns. @@ -222,23 +201,25 @@ impl BitMatrix { } /// Gains immutable access to the matrix's row in the form of a `BitSlice`. -impl Index for BitMatrix { - type Output = BitSlice; +impl Index for BitMatrix { + type Output = BitSlice>; #[inline] - fn index(&self, row: usize) -> &BitSlice { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + fn index(&self, row: usize) -> &Self::Output { + let row_size = round_up_to_next(self.row_bits, B::BITS) / B::BITS; BitSlice::new(&self.bit_vec.storage()[row * row_size..(row + 1) * row_size]) } } /// Gains mutable access to the matrix's row in the form of a `BitSlice`. -impl IndexMut for BitMatrix { +impl IndexMut for BitMatrix { #[inline] - fn index_mut(&mut self, row: usize) -> &mut BitSlice { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + fn index_mut(&mut self, row: usize) -> &mut Self::Output { + let row_size = round_up_to_next(self.row_bits, B::BITS) / B::BITS; unsafe { - BitSlice::new_mut(&mut self.bit_vec.storage_mut()[row * row_size..(row + 1) * row_size]) + BitSlice::new_mut( + &mut self.bit_vec.storage_mut().slice_mut()[row * row_size..(row + 1) * row_size], + ) } } } @@ -247,12 +228,12 @@ impl IndexMut for BitMatrix { /// /// The first index in the tuple is row number, and the second is column /// number. -impl Index<(usize, usize)> for BitMatrix { +impl Index<(usize, usize)> for BitMatrix { type Output = bool; #[inline] fn index(&self, (row, col): (usize, usize)) -> &bool { - let row_size_in_bits = round_up_to_next(self.row_bits, BITS); + let row_size_in_bits = round_up_to_next(self.row_bits, B::BITS); if self.bit_vec.get(row * row_size_in_bits + col).unwrap() { &TRUE } else { @@ -261,9 +242,9 @@ impl Index<(usize, usize)> for BitMatrix { } } -impl<'a> From<&'a mut BitMatrix> for BitSubMatrixMut<'a> { - fn from(value: &'a mut BitMatrix) -> Self { - unsafe { BitSubMatrixMut::new(value.bit_vec.storage_mut(), value.row_bits) } +impl<'a, B: BitBlockOrStore> From<&'a mut BitMatrix> for BitSubMatrixMut<'a, B> { + fn from(value: &'a mut BitMatrix) -> Self { + unsafe { BitSubMatrixMut::new(value.bit_vec.storage_mut().slice_mut(), value.row_bits) } } } @@ -271,7 +252,7 @@ impl<'a> From<&'a mut BitMatrix> for BitSubMatrixMut<'a> { #[test] fn test_empty() { - let mut matrix = BitMatrix::new(0, 0); + let mut matrix = ::new(0, 0); for _ in 0..3 { assert_eq!(matrix.num_rows(), 0); assert_eq!(matrix.size(), (0, 0)); diff --git a/matrix/src/row.rs b/matrix/src/row.rs index d04c956..b70f4f2 100644 --- a/matrix/src/row.rs +++ b/matrix/src/row.rs @@ -2,16 +2,18 @@ use core::{mem, ops}; +use bit_vec::BitBlock; + use super::{FALSE, TRUE}; -use crate::local_prelude::*; +// use crate::local_prelude::*; use crate::util::div_rem; /// A slice of bit vector's blocks. -pub struct BitSlice { +pub struct BitSlice { pub(crate) slice: [Block], } -impl BitSlice { +impl BitSlice { /// Creates a new slice from a slice of blocks. #[inline] pub fn new(slice: &[Block]) -> &Self { @@ -43,21 +45,21 @@ impl BitSlice { /// Returns `true` if a bit is enabled in the bit vector slice, or `false` otherwise. #[inline] pub fn get(&self, bit: usize) -> bool { - let (block, i) = div_rem(bit, BITS); + let (block, i) = div_rem(bit, Block::BITS_); match self.slice.get(block) { None => false, - Some(b) => (b & (1 << i)) != 0, + Some(&b) => (b & (Block::ONE_ << i)) != Block::ZERO_, } } /// Returns a small integer-sized slice of the bit vector slice. #[inline] - pub fn small_slice_aligned(&self, bit: usize, len: u8) -> u32 { - let (block, i) = div_rem(bit, BITS); + pub fn small_slice_aligned(&self, bit: usize, len: u8) -> Block { + let (block, i) = div_rem(bit, Block::BITS_); match self.slice.get(block) { - None => 0, + None => Block::ZERO_, Some(&b) => { - let len_mask = (1 << len) - 1; + let len_mask = (Block::ONE_ << len as usize) - Block::ONE_; (b >> i) & len_mask } } @@ -66,16 +68,16 @@ impl BitSlice { /// Returns `true` if a bit is enabled in the bit vector slice, /// or `false` otherwise. -impl ops::Index for BitSlice { +impl ops::Index for BitSlice { type Output = bool; #[inline] fn index(&self, bit: usize) -> &bool { - let (block, i) = div_rem(bit, BITS); + let (block, i) = div_rem(bit, Block::BITS_); match self.slice.get(block) { None => &FALSE, - Some(b) => { - if (b & (1 << i)) != 0 { + Some(&b) => { + if (b & (Block::ONE_ << i)) != Block::ZERO_ { &TRUE } else { &FALSE @@ -85,11 +87,11 @@ impl ops::Index for BitSlice { } } -impl ops::BitOrAssign for &mut BitSlice { +impl ops::BitOrAssign for &mut BitSlice { fn bitor_assign(&mut self, rhs: Self) { debug_assert_eq!(self.slice.len(), rhs.slice.len()); for (dst, src) in self.iter_blocks_mut().zip(rhs.iter_blocks()) { - *dst |= src; + *dst |= *src; } } } diff --git a/matrix/src/submatrix.rs b/matrix/src/submatrix.rs index 192bad5..60538c6 100644 --- a/matrix/src/submatrix.rs +++ b/matrix/src/submatrix.rs @@ -1,5 +1,6 @@ //! Submatrix of bits. +use bit_vec::BitBlockOrStore; use core::cmp; use core::fmt; use core::mem; @@ -11,22 +12,22 @@ use crate::local_prelude::*; use crate::util::{div_rem, round_up_to_next}; /// Immutable access to a range of matrix's rows. -pub struct BitSubMatrix<'a> { - pub(crate) slice: &'a [Block], +pub struct BitSubMatrix<'a, B: BitBlockOrStore> { + pub(crate) slice: &'a [Block], pub(crate) row_bits: usize, } /// Mutable access to a range of matrix's rows. -pub struct BitSubMatrixMut<'a> { - pub(crate) slice: &'a mut [Block], +pub struct BitSubMatrixMut<'a, B: BitBlockOrStore> { + pub(crate) slice: &'a mut [Block], pub(crate) row_bits: usize, } -impl<'a> BitSubMatrix<'a> { - /// Returns a new BitSubMatrix. - pub fn new(slice: &[Block], row_bits: usize) -> BitSubMatrix<'_> { - BitSubMatrix { slice, row_bits } - } +impl<'a, B: BitBlockOrStore> BitSubMatrix<'a, B> { + // /// Returns a new BitSubMatrix. + // pub(crate) fn new(slice: &[Block], row_bits: usize) -> BitSubMatrix<'_, B> { + // BitSubMatrix { slice, row_bits } + // } /// Forms a BitSubMatrix from a pointer and dimensions. /// @@ -35,26 +36,30 @@ impl<'a> BitSubMatrix<'a> { /// Can construct an ill-formed value, thus the function is marked as /// unsafe. #[inline] - pub unsafe fn from_raw_parts(ptr: *const Block, rows: usize, row_bits: usize) -> Self { + pub unsafe fn from_raw_parts(ptr: *const Block, rows: usize, row_bits: usize) -> Self { BitSubMatrix { - slice: slice::from_raw_parts(ptr, round_up_to_next(row_bits, BITS) / BITS * rows), + slice: slice::from_raw_parts(ptr, round_up_to_next(row_bits, B::BITS) / B::BITS * rows), row_bits, } } /// Iterates over the matrix's rows in the form of immutable slices. - pub fn iter(&self) -> impl Iterator { - fn f(arg: &[Block]) -> &BitSlice { + pub fn iter(&self) -> impl Iterator>> { + fn f(arg: &[Block]) -> &BitSlice> { unsafe { mem::transmute(arg) } } - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; - self.slice.chunks(row_size).map(f) + let row_size = round_up_to_next(self.row_bits, B::BITS) / B::BITS; + self.slice.chunks(row_size).map(f::) + } + + fn row_size(&self) -> usize { + round_up_to_next(self.row_bits, B::BITS) / B::BITS } } -impl<'a> BitSubMatrixMut<'a> { +impl<'a, B: BitBlockOrStore> BitSubMatrixMut<'a, B> { /// Returns a new `BitSubMatrixMut`. - pub fn new(slice: &mut [Block], row_bits: usize) -> BitSubMatrixMut<'_> { + pub(crate) fn new(slice: &mut [Block], row_bits: usize) -> BitSubMatrixMut<'_, B> { BitSubMatrixMut { slice, row_bits } } @@ -64,9 +69,12 @@ impl<'a> BitSubMatrixMut<'a> { /// /// Can construct an ill-formed value, thus the function is unsafe. #[inline] - pub unsafe fn from_raw_parts(ptr: *mut Block, rows: usize, row_bits: usize) -> Self { + pub unsafe fn from_raw_parts(ptr: *mut Block, rows: usize, row_bits: usize) -> Self { BitSubMatrixMut { - slice: slice::from_raw_parts_mut(ptr, round_up_to_next(row_bits, BITS) / BITS * rows), + slice: slice::from_raw_parts_mut( + ptr, + round_up_to_next(row_bits, B::BITS) / B::BITS * rows, + ), row_bits, } } @@ -74,8 +82,7 @@ impl<'a> BitSubMatrixMut<'a> { /// Returns the number of rows. #[inline] fn num_rows(&self) -> usize { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; - self.slice.len().checked_div(row_size).unwrap_or(0) + self.slice.len().checked_div(self.row_size()).unwrap_or(0) } /// Returns the number of columns. @@ -91,27 +98,26 @@ impl<'a> BitSubMatrixMut<'a> { /// Panics if `(row, col)` is out of bounds. #[inline] pub fn set(&mut self, row: usize, col: usize, enabled: bool) { - let row_size_in_bits = round_up_to_next(self.row_bits, BITS); + let row_size_in_bits = round_up_to_next(self.row_bits, B::BITS); let bit = row * row_size_in_bits + col; - let (block, i) = div_rem(bit, BITS); + let (block, i) = div_rem(bit, B::BITS); assert!(block < self.slice.len() && col < self.row_bits); unsafe { let elt = self.slice.get_unchecked_mut(block); if enabled { - *elt |= 1 << i; + *elt |= B::ONE << i; } else { - *elt &= !(1 << i); + *elt = *elt & !(B::ONE << i); } } } /// Returns a slice of the matrix's rows. - pub fn sub_matrix>(&self, range: R) -> BitSubMatrix<'_> { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + pub fn sub_matrix>(&self, range: R) -> BitSubMatrix<'_, B> { BitSubMatrix { slice: &self.slice[( - range.start_bound().map(|&s| s * row_size), - range.end_bound().map(|&e| e * row_size), + range.start_bound().map(|&s| s * self.row_size()), + range.end_bound().map(|&e| e * self.row_size()), )], row_bits: self.row_bits, } @@ -123,7 +129,7 @@ impl<'a> BitSubMatrixMut<'a> { /// Functionally equivalent to `(self.sub_matrix(0..row), &self[row], /// self.sub_matrix(row..self.num_rows()))`. #[inline] - pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_>, BitSubMatrix<'_>) { + pub fn split_at(&self, row: usize) -> (BitSubMatrix<'_, B>, BitSubMatrix<'_, B>) { ( self.sub_matrix(0..row), self.sub_matrix(row..self.num_rows()), @@ -133,9 +139,8 @@ impl<'a> BitSubMatrixMut<'a> { /// Given a row's index, returns a slice of all rows above that row, a reference to said row, /// and a slice of all rows below. #[inline] - pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_>, BitSubMatrixMut<'_>) { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; - let (first, second) = self.slice.split_at_mut(row * row_size); + pub fn split_at_mut(&mut self, row: usize) -> (BitSubMatrixMut<'_, B>, BitSubMatrixMut<'_, B>) { + let (first, second) = self.slice.split_at_mut(row * self.row_size()); ( BitSubMatrixMut::new(first, self.row_bits), BitSubMatrixMut::new(second, self.row_bits), @@ -194,47 +199,49 @@ impl<'a> BitSubMatrixMut<'a> { } /// Iterates over the matrix's rows in the form of mutable slices. - pub fn iter_mut(&mut self) -> impl Iterator { - fn f(arg: &mut [Block]) -> &mut BitSlice { + pub fn iter_mut(&mut self) -> impl Iterator>> { + fn f(arg: &mut [Block]) -> &mut BitSlice> { unsafe { mem::transmute(arg) } } - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; - self.slice.chunks_mut(row_size).map(f) + self.slice.chunks_mut(self.row_size()).map(f::) + } + + fn row_size(&self) -> usize { + round_up_to_next(self.row_bits, B::BITS) / B::BITS } } /// Returns the matrix's row in the form of a mutable slice. -impl<'a> Index for BitSubMatrixMut<'a> { - type Output = BitSlice; +impl<'a, B: BitBlockOrStore> Index for BitSubMatrixMut<'a, B> { + type Output = BitSlice>; #[inline] - fn index(&self, row: usize) -> &BitSlice { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; - unsafe { mem::transmute(&self.slice[row * row_size..(row + 1) * row_size]) } + fn index(&self, row: usize) -> &Self::Output { + unsafe { mem::transmute(&self.slice[row * self.row_size()..(row + 1) * self.row_size()]) } } } /// Returns the matrix's row in the form of a mutable slice. -impl<'a> IndexMut for BitSubMatrixMut<'a> { +impl<'a, B: BitBlockOrStore> IndexMut for BitSubMatrixMut<'a, B> { #[inline] - fn index_mut(&mut self, row: usize) -> &mut BitSlice { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + fn index_mut(&mut self, row: usize) -> &mut Self::Output { + let row_size = self.row_size(); unsafe { mem::transmute(&mut self.slice[row * row_size..(row + 1) * row_size]) } } } /// Returns the matrix's row in the form of a mutable slice. -impl<'a> Index for BitSubMatrix<'a> { - type Output = BitSlice; +impl<'a, B: BitBlockOrStore> Index for BitSubMatrix<'a, B> { + type Output = BitSlice>; #[inline] - fn index(&self, row: usize) -> &BitSlice { - let row_size = round_up_to_next(self.row_bits, BITS) / BITS; + fn index(&self, row: usize) -> &Self::Output { + let row_size = self.row_size(); unsafe { mem::transmute(&self.slice[row * row_size..(row + 1) * row_size]) } } } -impl<'a> fmt::Debug for BitSubMatrix<'a> { +impl<'a, B: BitBlockOrStore> fmt::Debug for BitSubMatrix<'a, B> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { for row in self.iter() { for bit in row.iter_bits(self.row_bits) { diff --git a/matrix/tests/test_submatrix.rs b/matrix/tests/test_submatrix.rs index c0e194b..c6aaa94 100644 --- a/matrix/tests/test_submatrix.rs +++ b/matrix/tests/test_submatrix.rs @@ -2,7 +2,7 @@ use bit_matrix::BitMatrix; #[test] fn test_submatrix() { - let mut matrix = BitMatrix::new(5, 4); + let mut matrix = ::new(5, 4); let points = &[ (0, 0), (0, 1), diff --git a/matrix/tests/transitive_closure.rs b/matrix/tests/transitive_closure.rs index 0d344eb..46f3b79 100644 --- a/matrix/tests/transitive_closure.rs +++ b/matrix/tests/transitive_closure.rs @@ -2,7 +2,7 @@ use bit_matrix::BitMatrix; #[test] fn test_transitive_closure() { - let mut matrix = BitMatrix::new(4, 4); + let mut matrix = ::new(4, 4); let points = &[ (0, 0), (0, 1), From c58799846b834042b1582df66f3dcd9e51453391 Mon Sep 17 00:00:00 2001 From: Peter Blackson Date: Fri, 10 Apr 2026 10:58:44 +0200 Subject: [PATCH 24/24] f --- .vscode/settings.json | 2 +- matrix/src/matrix.rs | 14 +- matrix/src/row.rs | 14 +- matrix/src/submatrix.rs | 5 +- set/src/iter.rs | 10 +- set/src/lib.rs | 7 +- set/src/set.rs | 17 +-- set/src/util copy.rs | 60 ++++++++ set/src/util.rs | 14 +- vec/Cargo.toml | 4 +- vec/src/atomic/block.rs | 39 ++++++ vec/src/atomic/block_or_store.rs | 20 +++ vec/src/atomic/mod.rs | 3 + vec/src/atomic/vec.rs | 80 +++++++++++ vec/src/block.rs | 62 ++++++--- vec/src/block_or_store.rs | 228 +++++++++++++++++-------------- vec/src/blocks.rs | 15 +- vec/src/lib.rs | 12 +- vec/src/store.rs | 5 +- vec/src/vec.rs | 124 ++++++++--------- vec/tests/vec.rs | 4 +- 21 files changed, 503 insertions(+), 236 deletions(-) create mode 100644 set/src/util copy.rs create mode 100644 vec/src/atomic/block.rs create mode 100644 vec/src/atomic/block_or_store.rs create mode 100644 vec/src/atomic/mod.rs create mode 100644 vec/src/atomic/vec.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index ea54d8d..f8aa115 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "rust-analyzer.cargo.features": ["serde", "nanoserde", "smallvec"] + "rust-analyzer.cargo.features": ["serde", "nanoserde", "smallvec", "portable-atomic"] } diff --git a/matrix/src/matrix.rs b/matrix/src/matrix.rs index e050cd1..9a0a221 100644 --- a/matrix/src/matrix.rs +++ b/matrix/src/matrix.rs @@ -3,7 +3,7 @@ use core::cmp; use core::ops::{Index, IndexMut, RangeBounds}; -use bit_vec::{BitBlockOrStore, BitStore, BitVec}; +use bit_vec::{BitStore, BitVec, CloneableBitBlockOrStore}; use super::{FALSE, TRUE}; use crate::local_prelude::*; @@ -16,14 +16,14 @@ use crate::util::round_up_to_next; derive(miniserde::Serialize, miniserde::Deserialize) )] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct BitMatrix { +pub struct BitMatrix { bit_vec: BitVec, row_bits: usize, } // Matrix -impl BitMatrix { +impl BitMatrix { /// Create a new BitMatrix with specific numbers of bits in columns and rows. pub fn new(rows: usize, row_bits: usize) -> Self { BitMatrix { @@ -201,7 +201,7 @@ impl BitMatrix { } /// Gains immutable access to the matrix's row in the form of a `BitSlice`. -impl Index for BitMatrix { +impl Index for BitMatrix { type Output = BitSlice>; #[inline] @@ -212,7 +212,7 @@ impl Index for BitMatrix { } /// Gains mutable access to the matrix's row in the form of a `BitSlice`. -impl IndexMut for BitMatrix { +impl IndexMut for BitMatrix { #[inline] fn index_mut(&mut self, row: usize) -> &mut Self::Output { let row_size = round_up_to_next(self.row_bits, B::BITS) / B::BITS; @@ -228,7 +228,7 @@ impl IndexMut for BitMatrix { /// /// The first index in the tuple is row number, and the second is column /// number. -impl Index<(usize, usize)> for BitMatrix { +impl Index<(usize, usize)> for BitMatrix { type Output = bool; #[inline] @@ -242,7 +242,7 @@ impl Index<(usize, usize)> for BitMatrix { } } -impl<'a, B: BitBlockOrStore> From<&'a mut BitMatrix> for BitSubMatrixMut<'a, B> { +impl<'a, B: CloneableBitBlockOrStore> From<&'a mut BitMatrix> for BitSubMatrixMut<'a, B> { fn from(value: &'a mut BitMatrix) -> Self { unsafe { BitSubMatrixMut::new(value.bit_vec.storage_mut().slice_mut(), value.row_bits) } } diff --git a/matrix/src/row.rs b/matrix/src/row.rs index b70f4f2..3bbcfdd 100644 --- a/matrix/src/row.rs +++ b/matrix/src/row.rs @@ -48,7 +48,7 @@ impl BitSlice { let (block, i) = div_rem(bit, Block::BITS_); match self.slice.get(block) { None => false, - Some(&b) => (b & (Block::ONE_ << i)) != Block::ZERO_, + Some(b) => (b.load() & (Block::ONE_ << i)) != Block::ZERO_, } } @@ -58,11 +58,11 @@ impl BitSlice { let (block, i) = div_rem(bit, Block::BITS_); match self.slice.get(block) { None => Block::ZERO_, - Some(&b) => { + Some(b) => { let len_mask = (Block::ONE_ << len as usize) - Block::ONE_; - (b >> i) & len_mask + (b.load() >> i) & len_mask } - } + }.into() } } @@ -76,8 +76,8 @@ impl ops::Index for BitSlice { let (block, i) = div_rem(bit, Block::BITS_); match self.slice.get(block) { None => &FALSE, - Some(&b) => { - if (b & (Block::ONE_ << i)) != Block::ZERO_ { + Some(b) => { + if (b.load() & (Block::ONE_ << i)) != Block::ZERO_ { &TRUE } else { &FALSE @@ -91,7 +91,7 @@ impl ops::BitOrAssign for &mut BitSlice { fn bitor_assign(&mut self, rhs: Self) { debug_assert_eq!(self.slice.len(), rhs.slice.len()); for (dst, src) in self.iter_blocks_mut().zip(rhs.iter_blocks()) { - *dst |= *src; + *dst.get_mut() |= src.load(); } } } diff --git a/matrix/src/submatrix.rs b/matrix/src/submatrix.rs index 60538c6..8b2f643 100644 --- a/matrix/src/submatrix.rs +++ b/matrix/src/submatrix.rs @@ -1,5 +1,6 @@ //! Submatrix of bits. +use bit_vec::BitBlock; use bit_vec::BitBlockOrStore; use core::cmp; use core::fmt; @@ -105,9 +106,9 @@ impl<'a, B: BitBlockOrStore> BitSubMatrixMut<'a, B> { unsafe { let elt = self.slice.get_unchecked_mut(block); if enabled { - *elt |= B::ONE << i; + *elt.get_mut() |= B::ONE << i; } else { - *elt = *elt & !(B::ONE << i); + *elt.get_mut() = elt.load() & !(B::ONE << i); } } } diff --git a/set/src/iter.rs b/set/src/iter.rs index 0ace9ff..9157ab0 100644 --- a/set/src/iter.rs +++ b/set/src/iter.rs @@ -1,16 +1,18 @@ +use bit_vec::block::Target; + use crate::util::Block; use crate::{local_prelude::*, set::BitSet}; #[derive(Clone)] struct BlockIter { - head: Block, + head: Target, head_offset: usize, tail: T, } impl BlockIter where - T: Iterator>, + T: Iterator>, { fn from_blocks(mut blocks: T) -> Self { let h = blocks.next().unwrap_or(B::ZERO); @@ -43,7 +45,7 @@ impl BitSet { /// [`union_with`]: Self::union_with #[inline] pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, B> { - fn or(w1: B, w2: B) -> B { + fn or(w1: B::Target, w2: B::Target) -> B::Target { w1 | w2 } @@ -183,7 +185,7 @@ impl BitSet { struct TwoBitPositions<'a, B: 'a + BitBlockOrStore> { set: Blocks<'a, B>, other: Blocks<'a, B>, - merge: fn(Block, Block) -> Block, + merge: fn(&Block, &Block) -> Block, } /// An iterator for `BitSet`. diff --git a/set/src/lib.rs b/set/src/lib.rs index 3fbe1d4..12aafc1 100644 --- a/set/src/lib.rs +++ b/set/src/lib.rs @@ -64,12 +64,13 @@ mod iter; mod set; mod util; -pub mod local_prelude { - pub use bit_vec::{BitBlock, BitBlockOrStore, BitStore, BitVec, Blocks}; +mod local_prelude { + pub use bit_vec::{BitBlock, BitBlockOrStore, BitStore, BitVec}; + pub use bit_vec::blocks::{BlockRefs, Blocks}; pub use core::cmp::Ordering; pub use core::iter::{self, Chain, Enumerate, FromIterator, Repeat, Skip, Take}; pub use core::{cmp, fmt, hash}; } -pub use bit_vec::{BitBlockOrStore, BitStore}; +pub use bit_vec::{BitBlockOrStore, CloneableBitBlockOrStore, BitStore}; pub use set::BitSet; diff --git a/set/src/set.rs b/set/src/set.rs index c907151..394605c 100644 --- a/set/src/set.rs +++ b/set/src/set.rs @@ -1,8 +1,9 @@ -use crate::util::Block; use crate::{local_prelude::*, util}; #[cfg(feature = "nanoserde")] use alloc::vec::Vec; +use bit_vec::CloneableBitBlockOrStore; +use bit_vec::block::Target; #[cfg(feature = "nanoserde")] use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; @@ -23,7 +24,7 @@ pub struct BitSet { pub(crate) bit_vec: BitVec, } -impl Clone for BitSet { +impl Clone for BitSet { fn clone(&self) -> Self { BitSet { bit_vec: self.bit_vec.clone(), @@ -333,7 +334,7 @@ impl BitSet { #[inline] fn other_op(&mut self, other: &Self, mut f: F) where - F: FnMut(Block, Block) -> Block, + F: FnMut(Target, Target) -> Target, { // Unwrap BitVecs let self_bit_vec = &mut self.bit_vec; @@ -355,10 +356,10 @@ impl BitSet { // Apply values found in other for (i, w) in other_words { - let old = self_bit_vec.storage()[i]; + let old = self_bit_vec.storage()[i].load(); let new = f(old, w); unsafe { - self_bit_vec.storage_mut().slice_mut()[i] = new; + *self_bit_vec.storage_mut().slice_mut()[i].get_mut() = new; } } } @@ -392,7 +393,7 @@ impl BitSet { .storage() .iter() .rev() - .take_while(|&&n| n == B::ZERO) + .take_while(|&n| n.load() == B::ZERO) .count(); // Truncate away all empty trailing blocks, then shrink_to_fit let trunc_len = old_len - n; @@ -657,9 +658,9 @@ impl BitSet { let other_blocks = util::blocks_for_bits::(other_bit_vec.len()); // Check that `self` intersect `other` is self - self_bit_vec.blocks().zip(other_bit_vec.blocks()).all(|(w1, w2)| w1 & w2 == w1) && + self_bit_vec.block_refs().zip(other_bit_vec.block_refs()).all(|(w1, w2)| { let w = w1.load(); w & w2.load() == w }) && // Make sure if `self` has any more blocks than `other`, they're all 0 - self_bit_vec.blocks().skip(other_blocks).all(|w| w == B::ZERO) + self_bit_vec.block_refs().skip(other_blocks).all(|w| w.load() == B::ZERO) } /// Returns `true` if the set is a superset of another. diff --git a/set/src/util copy.rs b/set/src/util copy.rs new file mode 100644 index 0000000..a5854e9 --- /dev/null +++ b/set/src/util copy.rs @@ -0,0 +1,60 @@ +use core::iter::Map; + +use bit_vec::block::Target; + +use crate::local_prelude::*; + +#[allow(type_alias_bounds)] +pub(crate) type Block = ::Block; +#[allow(type_alias_bounds)] +type MatchWords<'a, B: BitBlockOrStore> = + Chain>, Skip>, fn(Target) -> Block>>>>>; + +/// Computes how many blocks are needed to store that many bits +pub(crate) fn blocks_for_bits(bits: usize) -> usize { + // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we + // reserve enough. But if we want exactly a multiple of 32, this will actually allocate + // one too many. So we need to check if that's the case. We can do that by computing if + // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically + // superior modulo operator on a power of two to this. + // + // Note that we can technically avoid this branch with the expression + // `(nbits + BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. + if bits % B::BITS == 0 { + bits / B::BITS + } else { + bits / B::BITS + 1 + } +} + +#[allow(clippy::iter_skip_zero)] +// Take two BitVec's, and return iterators of their words, where the shorter one +// has been padded with 0's +pub(crate) fn match_words<'a, 'b, B: BitBlockOrStore>( + a: &'a BitVec, + b: &'b BitVec, +) -> (MatchWords<'a, B>, MatchWords<'b, B>) { + let a_len = a.storage().len(); + let b_len = b.storage().len(); + + // have to uselessly pretend to pad the longer one for type matching + if a_len < b_len { + ( + a.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(b_len).skip(a_len)), + b.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(0).skip(0)), + ) + } else { + ( + a.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(0).skip(0)), + b.blocks() + .enumerate() + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(a_len).skip(b_len)), + ) + } +} diff --git a/set/src/util.rs b/set/src/util.rs index 5f20398..5b89343 100644 --- a/set/src/util.rs +++ b/set/src/util.rs @@ -1,10 +1,14 @@ +use core::iter::Map; + +use bit_vec::block::Target; + use crate::local_prelude::*; #[allow(type_alias_bounds)] pub(crate) type Block = ::Block; #[allow(type_alias_bounds)] type MatchWords<'a, B: BitBlockOrStore> = - Chain>, Skip>>>>>; + Chain, fn(&Block) -> Target>>, Skip>>>>>; /// Computes how many blocks are needed to store that many bits pub(crate) fn blocks_for_bits(bits: usize) -> usize { @@ -38,19 +42,19 @@ pub(crate) fn match_words<'a, 'b, B: BitBlockOrStore>( ( a.blocks() .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(b_len).skip(a_len)), + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(b_len).skip(a_len)), b.blocks() .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(0).skip(0)), ) } else { ( a.blocks() .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(0).skip(0)), + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(0).skip(0)), b.blocks() .enumerate() - .chain(iter::repeat(B::ZERO).enumerate().take(a_len).skip(b_len)), + .chain(iter::repeat(B::ZERO).map(Into::into as fn(Target) -> Block).enumerate().take(a_len).skip(b_len)), ) } } diff --git a/vec/Cargo.toml b/vec/Cargo.toml index 7934973..5c34e8c 100644 --- a/vec/Cargo.toml +++ b/vec/Cargo.toml @@ -18,6 +18,7 @@ serde = { version = "1.0", default-features = false, features = ["derive", "allo miniserde = { version = "0.1", optional = true } nanoserde = { version = "0.1", optional = true } smallvec = { version = "1.15", optional = true } +portable-atomic = { version = "1.13", default-features = false, features = ["fallback"], optional = true } [dev-dependencies] serde_json = "1.0" @@ -27,8 +28,9 @@ generic-tests = "0.1" [features] default = ["std"] -std = ["serde?/std", "borsh?/std"] +std = ["serde?/std", "borsh?/std", "portable-atomic?/std"] allocator_api = [] +serde = ["dep:serde", "portable-atomic?/serde"] [package.metadata.docs.rs] features = ["borsh", "serde", "miniserde", "nanoserde"] diff --git a/vec/src/atomic/block.rs b/vec/src/atomic/block.rs new file mode 100644 index 0000000..02cf5c3 --- /dev/null +++ b/vec/src/atomic/block.rs @@ -0,0 +1,39 @@ +use portable_atomic::{AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicU128, AtomicUsize, Ordering}; + +use crate::local_prelude::*; + +macro_rules! atomic_block_impl { + ($(($t: ident, $u:ident, $size: expr)),*) => ($( + impl BitBlock for $t { + type Target = $u; + const BITS_: usize = $size; + #[inline] + fn from_byte(byte: u8) -> $u { <$u as From>::from(byte) } + #[inline] + fn count_ones(&self) -> usize { BitBlock::load(self).count_ones() as usize } + #[inline] + fn count_zeros(&self) -> usize { BitBlock::load(self).count_zeros() as usize } + #[inline] + fn from(val: $u) -> Self { From::from(val) } + #[inline] + fn load(&self) -> Self::Target { + self.load(Ordering::Relaxed) + } + #[inline] + fn get_mut(&mut self) -> &mut Self::Target { + self.get_mut() + } + const ONE_: Self::Target = 1; + const ZERO_: Self::Target = 0; + } + )*) +} + +atomic_block_impl! { + (AtomicU8, u8, 8), + (AtomicU16, u16, 16), + (AtomicU32, u32, 32), + (AtomicU64, u64, 64), + (AtomicU128, u128, 128), + (AtomicUsize, usize, usize::BITS as usize) +} diff --git a/vec/src/atomic/block_or_store.rs b/vec/src/atomic/block_or_store.rs new file mode 100644 index 0000000..b22fe57 --- /dev/null +++ b/vec/src/atomic/block_or_store.rs @@ -0,0 +1,20 @@ +use portable_atomic::{AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicU128, AtomicUsize}; + +use crate::local_prelude::*; + +macro_rules! atomic_bit_block_or_store_impl { + ($($t: ident),*) => ($( + impl BitBlockOrStore for $t { + type Store = Vec; + } + )*) +} + +atomic_bit_block_or_store_impl! { + AtomicU8, + AtomicU16, + AtomicU32, + AtomicU64, + AtomicU128, + AtomicUsize +} diff --git a/vec/src/atomic/mod.rs b/vec/src/atomic/mod.rs new file mode 100644 index 0000000..3902702 --- /dev/null +++ b/vec/src/atomic/mod.rs @@ -0,0 +1,3 @@ +mod block; +mod vec; +mod block_or_store; diff --git a/vec/src/atomic/vec.rs b/vec/src/atomic/vec.rs new file mode 100644 index 0000000..7fb8b76 --- /dev/null +++ b/vec/src/atomic/vec.rs @@ -0,0 +1,80 @@ +use portable_atomic::{AtomicU32, Ordering}; + +use crate::BitVec; +use crate::local_prelude::*; + +macro_rules! atomic ( + ($Atomic:ty) => { + impl BitVec> { + pub fn fetch_set(&self, i: usize, elem: bool, order: Ordering) -> bool { + self.ensure_invariant(); + assert!( + i < self.nbits, + "index out of bounds: {:?} >= {:?}", + i, + self.nbits + ); + let bits = mem::size_of::<$Atomic>() * 8; + let w = i / bits; + let b = i % bits; + let flag = <$Atomic>::ONE_ << b; + if elem { + self.storage.slice()[w].fetch_or(flag, order) & flag == flag + } else { + self.storage.slice()[w].fetch_and(!flag, order) & flag == flag + } + } + } + + impl BitVec<$Atomic> { + pub fn fetch_set(&self, i: usize, elem: bool, order: Ordering) -> bool { + self.ensure_invariant(); + assert!( + i < self.nbits, + "index out of bounds: {:?} >= {:?}", + i, + self.nbits + ); + let bits = mem::size_of::<$Atomic>() * 8; + let w = i / bits; + let b = i % bits; + let flag = <$Atomic>::ONE_ << b; + if elem { + self.storage.slice()[w].fetch_or(flag, order) & flag == flag + } else { + self.storage.slice()[w].fetch_and(!flag, order) & flag == flag + } + } + } + } +); + +atomic!(portable_atomic::AtomicU8); +atomic!(portable_atomic::AtomicU16); +atomic!(portable_atomic::AtomicU32); +atomic!(portable_atomic::AtomicU64); +atomic!(portable_atomic::AtomicU128); +atomic!(portable_atomic::AtomicUsize); + +// for IDE + +// impl BitVec> { +// pub fn fetch_set(&self, i: usize, elem: bool, order: Ordering) -> bool { +// self.ensure_invariant(); +// assert!( +// i < self.nbits, +// "index out of bounds: {:?} >= {:?}", +// i, +// self.nbits +// ); +// let bits = mem::size_of::() * 8; +// let w = i / bits; +// let b = i % bits; +// let flag = AtomicU32::ONE_ << b; +// if elem { +// self.storage.slice()[w].fetch_or(flag, order) & flag == flag +// } else { +// self.storage.slice()[w].fetch_and(!flag, order) & flag == flag +// } +// } +// } diff --git a/vec/src/block.rs b/vec/src/block.rs index 91bb2d1..38006f8 100644 --- a/vec/src/block.rs +++ b/vec/src/block.rs @@ -1,53 +1,73 @@ use crate::local_prelude::ops::*; use crate::local_prelude::*; +pub type Target = as BitBlock>::Target; + /// Abstracts over a pile of bits (basically unsigned primitives) -pub trait BitBlock: +pub trait BitBlock where Self: Sized, Self::Target: Copy - + Add - + Sub - + Shl - + Shr - + Not - + BitAnd - + BitOr - + BitXor - + Rem - + BitOrAssign + + Add + + Sub + + Shl + + Shr + + Not + + BitAnd + + BitOr + + BitXor + + Rem + + BitOrAssign + Eq + Ord + hash::Hash + + Into { + type Target; /// How many bits it has const BITS_: usize; /// How many bytes it has const BYTES_: usize = Self::BITS_ / 8; /// Convert a byte into this type (lowest-order bits set) - fn from_byte(byte: u8) -> Self; + fn from_byte(byte: u8) -> Self::Target; /// Count the number of 1's in the bitwise repr - fn count_ones(self) -> usize; + fn count_ones(&self) -> usize; /// Count the number of 0's in the bitwise repr - fn count_zeros(self) -> usize { + fn count_zeros(&self) -> usize { Self::BITS_ - self.count_ones() } + fn from(target: Self::Target) -> Self; + fn load(&self) -> Self::Target; + fn get_mut(&mut self) -> &mut Self::Target; /// Get `0` - const ZERO_: Self; + const ZERO_: Self::Target; /// Get `1` - const ONE_: Self; + const ONE_: Self::Target; } macro_rules! bit_block_impl { ($(($t: ident, $size: expr)),*) => ($( impl BitBlock for $t { + type Target = Self; const BITS_: usize = $size; #[inline] - fn from_byte(byte: u8) -> Self { $t::from(byte) } + fn from_byte(byte: u8) -> Self::Target { <$t as From>::from(byte) } + #[inline] + fn count_ones(&self) -> usize { self.load().count_ones() as usize } + #[inline] + fn count_zeros(&self) -> usize { self.load().count_zeros() as usize } + #[inline] + fn get_mut(&mut self) -> &mut Self { + self + } #[inline] - fn count_ones(self) -> usize { self.count_ones() as usize } + fn load(&self) -> Self { + *self + } #[inline] - fn count_zeros(self) -> usize { self.count_zeros() as usize } - const ONE_: Self = 1; - const ZERO_: Self = 0; + fn from(val: Self) -> Self { + val + } + const ONE_: Self::Target = 1; + const ZERO_: Self::Target = 0; } )*) } diff --git a/vec/src/block_or_store.rs b/vec/src/block_or_store.rs index 2e69ec5..e902db5 100644 --- a/vec/src/block_or_store.rs +++ b/vec/src/block_or_store.rs @@ -1,115 +1,136 @@ use crate::local_prelude::*; -macro_rules! bound_combination { - ( - type $T:ident: [$($B:tt)*]; - $cfg0:tt => [$($Bounds0:tt)*]; - $( - $cfg:tt => [$($Bounds:tt)*]; - )* - ) => { - #[cfg(not(feature = $cfg0))] - bound_combination!( - type $T: [$($B)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - #[cfg(feature = $cfg0)] - bound_combination!( - type $T: [$($B)* + $($Bounds0)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - }; - ( - type $T:ident: [$($B:tt)*]; - ) => { - type $T: $($B)*; - } -} +// macro_rules! bound_combination { +// ( +// type $T:ident: [$($B:tt)*]; +// $cfg0:tt => [$($Bounds0:tt)*]; +// $( +// $cfg:tt => [$($Bounds:tt)*]; +// )* +// ) => { +// #[cfg(not(feature = $cfg0))] +// bound_combination!( +// type $T: [$($B)*]; +// $( +// $cfg => [$($Bounds)*]; +// )* +// ); +// #[cfg(feature = $cfg0)] +// bound_combination!( +// type $T: [$($B)* + $($Bounds0)*]; +// $( +// $cfg => [$($Bounds)*]; +// )* +// ); +// }; +// ( +// type $T:ident: [$($B:tt)*]; +// ) => { +// type $T: $($B)*; +// } +// } pub trait BitBlockOrStore { - bound_combination!( - type Store: [BitStore]; - "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; - "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; - "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; - "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; - ); + // bound_combination!( + // type Store: [BitStore]; + // "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; + // "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; + // "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; + // "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; + // ); + type Store: BitStore; const BITS: usize = ::Block::BITS_; const BYTES: usize = ::Block::BYTES_; - const ONE: ::Block = ::Block::ONE_; - const ZERO: ::Block = ::Block::ZERO_; + const ONE: <::Block as BitBlock>::Target = ::Block::ONE_; + const ZERO: <::Block as BitBlock>::Target = ::Block::ZERO_; } -macro_rules! impl_combination { - ( - type $T:ty: $B0:tt + []; - $cfg0:tt => [$($Bounds0:tt)*]; - $( - $cfg:tt => [$($Bounds:tt)*]; - )* - ) => { - #[cfg(not(feature = $cfg0))] - impl_combination!( - type $T: $B0 + []; - $( - $cfg => [$($Bounds)*]; - )* - ); - #[cfg(feature = $cfg0)] - impl_combination!( - type $T: $B0 + [$($Bounds0)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - }; - ( - type $T:ty: $B0:tt + [$($B:tt)*]; - $cfg0:tt => [$($Bounds0:tt)*]; - $( - $cfg:tt => [$($Bounds:tt)*]; - )* - ) => { - #[cfg(not(feature = $cfg0))] - impl_combination!( - type $T: $B0 + [$($B)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - #[cfg(feature = $cfg0)] - impl_combination!( - type $T: $B0 + [$($B)* + $($Bounds0)*]; - $( - $cfg => [$($Bounds)*]; - )* - ); - }; - ( - type $T:ty: $B0:tt + [$($B:tt)*]; - ) => { - impl BitBlockOrStore for Vec { - type Store = Self; - } +pub trait CloneableBitBlockOrStore: BitBlockOrStore {} - impl BitBlockOrStore for Box> where Self: $($B)* { - type Store = Self; - } - } +#[cfg(feature = "serde")] +pub trait SerdeBitBlockOrStore<'de>: BitBlockOrStore> {} + +// macro_rules! impl_combination { +// ( +// type $T:ty: $B0:tt; +// $cfg0:tt => $([$($Bounds0:tt)*])*; +// $( +// $cfg:tt => $([$($Bounds:tt)+])*; +// )* +// ) => { +// #[cfg(not(feature = $cfg0))] +// impl_combination!( +// type $T: $B0; +// $( +// $cfg => $([$($Bounds)+])*; +// )* +// ); +// #[cfg(feature = $cfg0)] +// impl_combination!( +// type $T: $B0 $(+ [$($Bounds0)*])*; +// $( +// $cfg => $([$($Bounds)+])*; +// )* +// ); +// }; +// ( +// type $T:ty: $B0:tt $(+ [$($B:tt)+])*; +// $cfg0:tt => $([$($Bounds0:tt)+])*; +// $( +// $cfg:tt => $([$($Bounds:tt)+])*; +// )* +// ) => { +// #[cfg(not(feature = $cfg0))] +// impl_combination!( +// type $T: $B0 $(+ [$($B)+])*; +// $( +// $cfg => $([$($Bounds)+])*; +// )* +// ); +// #[cfg(feature = $cfg0)] +// impl_combination!( +// type $T: $B0 $(+ [$($B)+])* $(+ [$($Bounds0)+])*; +// $( +// $cfg => $([$($Bounds)+])*; +// )* +// ); +// }; +// ( +// type $T:ty: $B0:tt $(+ [$($B:tt)+])*; +// ) => { +// impl BitBlockOrStore for Vec { +// type Store = Self; +// } + +// // Note: The extra `Sized` is there just to fill the place before the `+`. +// impl BitBlockOrStore for Box> where Self: Sized $(+ $($B)+)* { +// type Store = Self; +// } + +// impl CloneableBitBlockOrStore for Vec {} +// } +// } + +// impl_combination!( +// type Vec: BitBlock; +// "nanoserde" => [DeBin] [DeJson] [DeRon] [SerBin] [SerJson] [SerRon]; +// "serde" => [serde::Serialize] [for<'a> serde::Deserialize<'a>]; +// "miniserde" => [miniserde::Deserialize] [miniserde::Serialize]; +// "borsh" => [borsh::BorshDeserialize] [borsh::BorshSerialize]; +// ); + +impl BitBlockOrStore for Vec { + type Store = Self; +} + +impl BitBlockOrStore for Box> { + type Store = Self; } -impl_combination!( - type Vec: BitBlock + []; - "nanoserde" => [DeBin + DeJson + DeRon + SerBin + SerJson + SerRon]; - "serde" => [serde::Serialize + for<'a> serde::Deserialize<'a>]; - "miniserde" => [miniserde::Deserialize + miniserde::Serialize]; - "borsh" => [borsh::BorshDeserialize + borsh::BorshSerialize]; -); +impl CloneableBitBlockOrStore for Vec {} + +impl CloneableBitBlockOrStore for Box> {} #[cfg(all(feature = "smallvec", not(feature = "nanoserde")))] impl BitBlockOrStore for smallvec::SmallVec
    @@ -124,6 +145,13 @@ macro_rules! bit_block_or_store_impl { impl BitBlockOrStore for $t { type Store = Vec; } + + impl CloneableBitBlockOrStore for $t {} + + #[cfg(feature = "serde")] + impl<'de> SerdeBitBlockOrStore<'de> for $t {} + #[cfg(feature = "serde")] + impl<'de> SerdeBitBlockOrStore<'de> for Vec<$t> {} )*) } diff --git a/vec/src/blocks.rs b/vec/src/blocks.rs index 2834c2a..72cdc15 100644 --- a/vec/src/blocks.rs +++ b/vec/src/blocks.rs @@ -6,23 +6,30 @@ impl BitVec { pub fn blocks(&self) -> Blocks<'_, B> { // (2) Blocks { - iter: self.storage.slice().iter(), + iter: self.storage.slice().iter().map(Block::::load), } } + + #[inline] + pub fn block_refs(&self) -> BlockRefs<'_, B> { + self.storage.slice().iter() + } } /// An iterator over the blocks of a `BitVec`. #[derive(Clone)] pub struct Blocks<'a, B: 'a + BitBlockOrStore> { - iter: slice::Iter<'a, Block>, + iter: iter::Map>, fn(&'a Block) -> Target>, } +pub type BlockRefs<'a, B: 'a + BitBlockOrStore> = slice::Iter<'a, Block>; + impl Iterator for Blocks<'_, B> { type Item = Block; #[inline] fn next(&mut self) -> Option> { - self.iter.next().cloned() + self.iter.next().map(|b| b.into()) } #[inline] @@ -34,7 +41,7 @@ impl Iterator for Blocks<'_, B> { impl DoubleEndedIterator for Blocks<'_, B> { #[inline] fn next_back(&mut self) -> Option> { - self.iter.next_back().cloned() + self.iter.next_back().map(|b| b.into()) } } diff --git a/vec/src/lib.rs b/vec/src/lib.rs index 88fd0e0..374c644 100644 --- a/vec/src/lib.rs +++ b/vec/src/lib.rs @@ -110,9 +110,11 @@ extern crate serde; #[cfg(not(feature = "std"))] extern crate alloc; -mod block; +#[cfg(feature = "portable-atomic")] +mod atomic; +pub mod block; mod block_or_store; -mod blocks; +pub mod blocks; mod blocks_mut; mod into_iter; mod iter; @@ -122,8 +124,7 @@ mod util; mod vec; pub use block::BitBlock; -pub use block_or_store::BitBlockOrStore; -pub use blocks::Blocks; +pub use block_or_store::{BitBlockOrStore, CloneableBitBlockOrStore}; pub use blocks_mut::BlocksMut; pub use into_iter::IntoIter; pub use iter::Iter; @@ -151,7 +152,6 @@ mod local_prelude { pub use std::vec::Vec; pub use core::cell::RefCell; - pub use core::cmp::Ordering; pub use core::fmt::Write; pub use core::iter::FromIterator; pub use core::{cmp, fmt, hash, iter, mem, ops, slice}; @@ -159,7 +159,7 @@ mod local_prelude { #[cfg(feature = "nanoserde")] pub use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon}; - pub use crate::block::BitBlock; + pub use crate::block::{BitBlock, Target}; pub use crate::block_or_store::BitBlockOrStore; pub use crate::store::BitStore; pub(crate) use crate::util::Block; diff --git a/vec/src/store.rs b/vec/src/store.rs index f7c285a..5698e30 100644 --- a/vec/src/store.rs +++ b/vec/src/store.rs @@ -1,7 +1,7 @@ use crate::local_prelude::*; #[allow(clippy::len_without_is_empty)] -pub trait BitStore: Clone { +pub trait BitStore { type Block: BitBlock; type Alloc: Default; fn new_in(alloc: Self::Alloc) -> Self; @@ -222,8 +222,7 @@ where } fn split_off(&mut self, at: usize) -> Self { - // TODO - self.to_vec().split_off(at).into() + self.drain(at..).collect() } fn truncate(&mut self, len: usize) { diff --git a/vec/src/vec.rs b/vec/src/vec.rs index 8163796..7c5a1b7 100644 --- a/vec/src/vec.rs +++ b/vec/src/vec.rs @@ -37,10 +37,10 @@ use crate::util::{self, FALSE, TRUE}; feature = "miniserde", derive(miniserde::Deserialize, miniserde::Serialize) )] -#[cfg_attr( - feature = "nanoserde", - derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) -)] +// #[cfg_attr( +// feature = "nanoserde", +// derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon) +// )] pub struct BitVec { /// Internal representation of the bit vector pub(crate) storage: B::Store, @@ -80,7 +80,7 @@ fn blocks_for_bits(bits: usize) -> usize { } /// Computes the bitmask for the final word of the vector -fn mask_for_bits(bits: usize) -> Block { +fn mask_for_bits(bits: usize) -> as BitBlock>::Target { // Note especially that a perfect multiple of U32_BITS should mask all 1s. (!B::ZERO) >> ((B::BITS - bits % B::BITS) % B::BITS) } @@ -210,7 +210,7 @@ impl BitVec { storage.extend(iter::repeat_n( if bit { !B::ZERO } else { B::ZERO }, nblocks, - )); + ).map(|t| t.into())); let mut bit_vec = BitVec { storage, nbits: len, @@ -282,7 +282,7 @@ impl BitVec { bytes[i * B::BYTES + idx], )) << (idx * 8) } - bit_vec.storage.push(accumulator); + bit_vec.storage.push(accumulator.into()); } if extra_bytes > 0 { @@ -291,7 +291,7 @@ impl BitVec { last_word |= ::Block::from_byte(util::reverse_bits(byte)) << (i * 8); } - bit_vec.storage.push(last_word); + bit_vec.storage.push(last_word.into()); } bit_vec @@ -326,15 +326,15 @@ impl BitVec { #[inline] fn process(&mut self, other: &BitVec, mut op: F) -> bool where - F: FnMut(Block, Block) -> Block, + F: FnMut(Target, Target) -> Target, { assert_eq!(self.len(), other.len()); debug_assert_eq!(self.storage.len(), other.storage.len()); let mut changed_bits = B::ZERO; for (a, b) in self.blocks_mut().zip(other.blocks()) { - let w = op(*a, b); - changed_bits |= *a ^ w; - *a = w; + let w = op(a.load(), b.load()); + changed_bits |= a.load() ^ w; + *a.get_mut() = w; } changed_bits != B::ZERO } @@ -359,12 +359,12 @@ impl BitVec { /// Helper for procedures involving spare space in the last block. #[inline] - fn last_block_with_mask(&self) -> Option<(Block, Block)> { + fn last_block_with_mask(&self) -> Option<(Target, Target)> { let extra_bits = self.len() % B::BITS; if extra_bits > 0 { let mask = (B::ONE << extra_bits) - B::ONE; let storage_len = self.storage.len(); - Some((self.storage.slice()[storage_len - 1], mask)) + Some((self.storage.slice()[storage_len - 1].load(), mask)) } else { None } @@ -372,12 +372,12 @@ impl BitVec { /// Helper for procedures involving spare space in the last block. #[inline] - fn last_block_mut_with_mask(&mut self) -> Option<(&mut Block, Block)> { + fn last_block_mut_with_mask(&mut self) -> Option<(&mut Target, Target)> { let extra_bits = self.len() % B::BITS; if extra_bits > 0 { let mask = (B::ONE << extra_bits) - B::ONE; let storage_len = self.storage.len(); - Some((&mut self.storage.slice_mut()[storage_len - 1], mask)) + Some((self.storage.slice_mut()[storage_len - 1].get_mut(), mask)) } else { None } @@ -448,7 +448,7 @@ impl BitVec { self.storage .slice() .get(w) - .map(|&block| (block & (B::ONE << b)) != B::ZERO) + .map(|block| (block.load() & (B::ONE << b)) != B::ZERO) } /// Retrieves the value at index `i`, without doing bounds checking. @@ -476,8 +476,8 @@ impl BitVec { self.ensure_invariant(); let w = i / B::BITS; let b = i % B::BITS; - let block = *self.storage.slice().get_unchecked(w); - block & (B::ONE << b) != B::ZERO + let block = self.storage.slice().get_unchecked(w); + block.load() & (B::ONE << b) != B::ZERO } /// Sets the value of a bit at an index `i`. @@ -508,11 +508,11 @@ impl BitVec { let b = i % B::BITS; let flag = B::ONE << b; let val = if x { - self.storage.slice()[w] | flag + self.storage.slice()[w].load() | flag } else { - self.storage.slice()[w] & !flag + self.storage.slice()[w].load() & !flag }; - self.storage.slice_mut()[w] = val; + *self.storage.slice_mut()[w].get_mut() = val; } /// Sets all bits to 1. @@ -534,7 +534,7 @@ impl BitVec { pub fn set_all(&mut self) { self.ensure_invariant(); for w in self.storage.slice_mut() { - *w = !B::ZERO; + *w.get_mut() = !B::ZERO; } self.fix_last_block(); } @@ -557,7 +557,7 @@ impl BitVec { pub fn negate(&mut self) { self.ensure_invariant(); for w in self.storage.slice_mut() { - *w = !*w; + *w.get_mut() = !w.load(); } self.fix_last_block(); } @@ -878,7 +878,7 @@ impl BitVec { // Check that every block but the last is all-ones... self.blocks().all(|elem| { let tmp = last_word; - last_word = elem; + last_word = elem.load(); tmp == !B::ZERO // and then check the last one has enough ones }) && (last_word == mask_for_bits::(self.nbits)) @@ -970,9 +970,9 @@ impl BitVec { for block in other.storage.drain(..) { { let last = self.storage.slice_mut().last_mut().unwrap(); - *last |= block << b; + *last.get_mut() |= block.load() << b; } - self.storage.push(block >> (B::BITS - b)); + self.storage.push((block.load() >> (B::BITS - b)).into()); } // Remove additional block if the last shift did not overflow @@ -1030,13 +1030,13 @@ impl BitVec { other.storage.reserve(self.storage.len() - w); { - let mut iter = self.storage.slice()[w..].iter(); - let mut last = *iter.next().unwrap(); - for &cur in iter { - other.storage.push((last >> b) | (cur << (B::BITS - b))); - last = cur; + let mut iter = self.block_refs().skip(w); + let mut last = iter.next().unwrap().load(); + for cur in iter { + other.storage.push(Into::into((last >> b) | (cur.load() << (B::BITS - b)))); + last = cur.load(); } - other.storage.push(last >> b); + other.storage.push(Into::into(last >> b)); } self.storage.truncate(w + 1); @@ -1061,7 +1061,7 @@ impl BitVec { /// ``` #[inline] pub fn none(&self) -> bool { - self.blocks().all(|w| w == B::ZERO) + self.block_refs().all(|w| w.load() == B::ZERO) } /// Returns `true` if any bit is 1. @@ -1285,7 +1285,7 @@ impl BitVec { let mask = mask_for_bits::(self.nbits); if value { let block = &mut self.storage.slice_mut()[num_cur_blocks - 1]; - *block |= !mask; + *block.get_mut() |= !mask; } else { // Extra bits are already zero by invariant. } @@ -1294,13 +1294,13 @@ impl BitVec { // Fill in words after the old tail word let stop_idx = cmp::min(self.storage.len(), new_nblocks); for idx in num_cur_blocks..stop_idx { - self.storage.slice_mut()[idx] = full_value; + self.storage.slice_mut()[idx] = full_value.into(); } // Allocate new words, if needed if new_nblocks > self.storage.len() { let to_add = new_nblocks - self.storage.len(); - self.storage.extend(iter::repeat_n(full_value, to_add)); + self.storage.extend(iter::repeat_n(full_value, to_add).map(|t| t.into())); } // Adjust internal bit count @@ -1356,7 +1356,7 @@ impl BitVec { #[inline] pub fn push(&mut self, elem: bool) { if self.nbits % B::BITS == 0 { - self.storage.push(B::ZERO); + self.storage.push(B::ZERO.into()); } let insert_pos = self.nbits; self.nbits = self.nbits.checked_add(1).expect("Capacity overflow"); @@ -1391,7 +1391,7 @@ impl BitVec { pub fn clear(&mut self) { self.ensure_invariant(); for w in self.storage.slice_mut() { - *w = B::ZERO; + *w.get_mut() = B::ZERO; } } @@ -1409,7 +1409,7 @@ impl BitVec { self.ensure_invariant(); let block = if bit { !B::ZERO } else { B::ZERO }; for w in self.storage.slice_mut() { - *w = block; + *w.get_mut() = block; } if bit { self.fix_last_block(); @@ -1463,21 +1463,21 @@ impl BitVec { let bit_at = at % B::BITS; // index within the block if last_block_bits == 0 { - self.storage.push(B::ZERO); + self.storage.push(B::ZERO.into()); } self.nbits += 1; - let mut carry = self.storage.slice()[block_at] >> (B::BITS - 1); + let mut carry = self.storage.slice()[block_at].load() >> (B::BITS - 1); let lsbits_mask = (B::ONE << bit_at) - B::ONE; let set_bit = if bit { B::ONE } else { B::ZERO } << bit_at; - self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) - | ((self.storage.slice()[block_at] & !lsbits_mask) << 1) + *self.storage.slice_mut()[block_at].get_mut() = (self.storage.slice()[block_at].load() & lsbits_mask) + | ((self.storage.slice()[block_at].load() & !lsbits_mask) << 1) | set_bit; for block_ref in &mut self.storage.slice_mut()[block_at + 1..] { - let curr_carry = *block_ref >> (B::BITS - 1); - *block_ref = *block_ref << 1 | carry; + let curr_carry = block_ref.load() >> (B::BITS - 1); + *block_ref.get_mut() = block_ref.load() << 1 | carry; carry = curr_carry; } } @@ -1527,17 +1527,17 @@ impl BitVec { let mut carry = B::ZERO; for block_ref in self.storage.slice_mut()[block_at + 1..].iter_mut().rev() { - let curr_carry = *block_ref & B::ONE; - *block_ref = *block_ref >> 1 | (carry << (B::BITS - 1)); + let curr_carry = block_ref.load() & B::ONE; + *block_ref.get_mut() = block_ref.load() >> 1 | (carry << (B::BITS - 1)); carry = curr_carry; } // Note: this is equivalent to `.get_unchecked(at)`, but we do // not want to introduce unsafe code here. - let result = (self.storage.slice()[block_at] >> bit_at) & B::ONE == B::ONE; + let result = (self.storage.slice()[block_at].load() >> bit_at) & B::ONE == B::ONE; - self.storage.slice_mut()[block_at] = (self.storage.slice()[block_at] & lsbits_mask) - | ((self.storage.slice()[block_at] & (!lsbits_mask << 1)) >> 1) + *self.storage.slice_mut()[block_at].get_mut() = (self.storage.slice()[block_at].load() & lsbits_mask) + | ((self.storage.slice()[block_at].load() & (!lsbits_mask << 1)) >> 1) | carry << (B::BITS - 1); if last_block_bits == 0 { @@ -1601,7 +1601,7 @@ impl BitVec { let bits = B::BITS; if len % bits == 0 { - self.storage.push(B::ZERO); + self.storage.push(B::ZERO.into()); } let block_at = len / bits; @@ -1612,7 +1612,7 @@ impl BitVec { self.nbits += 1; - self.storage.slice_mut()[block_at] = self.storage.slice()[block_at] | flag; // set the bit + *self.storage.slice_mut()[block_at].get_mut() = self.storage.slice()[block_at].load() | flag; // set the bit Ok(()) } @@ -1650,7 +1650,7 @@ impl Extend for BitVec { } } -impl Clone for BitVec { +impl Clone for BitVec where B::Store: Clone { #[inline] fn clone(&self) -> Self { self.ensure_invariant(); @@ -1670,14 +1670,14 @@ impl Clone for BitVec { impl PartialOrd for BitVec { #[inline] - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for BitVec { #[inline] - fn cmp(&self, other: &Self) -> Ordering { + fn cmp(&self, other: &Self) -> cmp::Ordering { self.ensure_invariant(); debug_assert!(other.is_last_block_fixed()); let mut a = self.iter(); @@ -1685,12 +1685,12 @@ impl Ord for BitVec { loop { match (a.next(), b.next()) { (Some(x), Some(y)) => match x.cmp(&y) { - Ordering::Equal => {} + cmp::Ordering::Equal => {} otherwise => return otherwise, }, - (None, None) => return Ordering::Equal, - (None, _) => return Ordering::Less, - (_, None) => return Ordering::Greater, + (None, None) => return cmp::Ordering::Equal, + (None, _) => return cmp::Ordering::Less, + (_, None) => return cmp::Ordering::Greater, } } } @@ -1729,7 +1729,7 @@ impl hash::Hash for BitVec { self.ensure_invariant(); self.nbits.hash(state); for elem in self.blocks() { - elem.hash(state); + elem.load().hash(state); } } } @@ -1742,7 +1742,7 @@ impl cmp::PartialEq for BitVec { other.ensure_invariant(); return false; } - self.blocks().zip(other.blocks()).all(|(w1, w2)| w1 == w2) + self.blocks().zip(other.blocks()).all(|(w1, w2)| w1.load() == w2.load()) } } diff --git a/vec/tests/vec.rs b/vec/tests/vec.rs index b060442..d8cab7b 100644 --- a/vec/tests/vec.rs +++ b/vec/tests/vec.rs @@ -6,7 +6,7 @@ mod tests { #![allow(clippy::shadow_unrelated)] #![allow(clippy::extra_unused_type_parameters)] - use bit_vec::{BitBlockOrStore, BitVec, Iter}; + use bit_vec::{BitBlockOrStore, CloneableBitBlockOrStore, BitVec, Iter}; // This is stupid, but I want to differentiate from a "random" 32 const U32_BITS: usize = 32; @@ -1353,7 +1353,7 @@ mod tests { } #[test] - fn test_remove_all() { + fn test_remove_all() { let v = BitVec::::from_elem_general(1024, false); for _ in 0..1024 { let mut v2 = v.clone();

%7drS@>BuClBmXFWb#mUsr_6Ll` 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%0A&e zaKee+{Hii5nBa`XS%*<7po@~`ka-j6Ll5{~CIcS7gT8+zZIaT$YH_&Ou%3(6q=hS7 zD5Y{utk8Q6|2AD-db(1(Ul-31%TeZ zj^#8HpxH#f0w&s(KS%plVNW%ZSUwfV=@M(W^DRMH6^KFrO;#a?G!0N)pBoqsL<9-% zpg{F*rWpa2?dPQ(-_@6`Mq!Bkf6H2?+c@1|mnQ)2xHkp$A4w%9HEsPCCK&_R)4M9V^RTpojioutCU+?gz{$6Y^EuFOMg)G7adR|6lLH3_ zUvIn3+w%~$><&VXBwO)oBw-@=6rEibuSlb@`+>x!d?8n(@|zyEr`gf+A0Kb*%0uhg752Z1-H z+B#6RZ{g@0aJ5x9GkV0^Ro=;gtGaY7KuroJvYf40(l$Y!3KyC;(}l7Hs4_tcdm$c6 zJmfq?+r!_ZXk)$8+pj@iq#AqTEh>AVB0o{kJZ{!mjE~^>w$bzkUp*VlJ8GzGasBN%Ca@l zWiAiwb&CCB;L8Qj7YbfF7x@{jeJvBl>)f7JRq%+b4=YPf$0#ltmCZZ&)Uf||6f6Q}jb<`a^mLpgq2tW5SeI)p zfsfAChIDvPDDNhp&$_{~hBqG8dt`|D!%beF92zKS)qIU|VfB5|h71)Ux)dVq$Z?%3 zP^z<|6SupU<*J_S&wd;OrD$& zNL2T1{qH!XU@ghx55|p)HE6I!`pA4#y(n!G*zL4hFrjI6O>uq<+|>&Xb1)8Tap%5> z=Ms9UQZ|0^TK-4=@U{`tj7uNbsj!hPZQ*@AfbnBhSd>~wjT4)i z^>Wp(FTJnoO@voXeB3D8LP6s0fe{|ALtJ9IBi&;G+{8mVltaFruA~X|z4nL8g_R0S^6`LVXW6@a))wpZ-ir&w0>TH62Bg z{S{@s40j!D4{&y`TM;f5r9~Iaw})>cV~4T5^GUBn?bo);dYb~BRAmcdDj%!0P;BKRvZQh44b9)8vkC z|1EOt2W8wu+>Sy-@>W~Lk8k8A{ThaYnYSuFBliy6AqRZM0CH%X`uUO9Pbe5`qi+Oo zoB$~Px+o{X*#L^yXSM&Pb~cN`{iKAGu)M9}LRo1>E~Un0|Gvz(YxIi|>x z`z$gh06pG^J67(4If2T$b?^xhIaOV5e!wojvY_Y4VzvurVl~+;Re*eo;HMdPbfzO$ zVVM!@2URfsg^`N7vu*Cvb~8m2)55&XmyG4BG=ijZaX?epiG^YOJ6pw+?Mr10C*#%a20^G=kdq^4f-j8*-6_Hj6n#D|9hwE(B*p=L5o`9v@4*@QE;v|1-)I78Fk(X@^d zWewOXN)p=Rl|xNIoyEC~3CWc3FSr^c(bplZ@4shVGJa)~82E+yjsiNv;OA8!Dp5tD z=XS#gow2N7o9j{*pd$tO=^QLT1m0nihZK}2RtxUh_jtcRXDdpQ1Ak2 z5iY9)?Rj1N@%Ih zX_6jpMDI9=wT>P*M-S);J!rg^Lln1Tp=x_8)IQ&x;jor5!s_P?`lGyH≠P#jpi{RaXPWrW90bp^E>aNk0w37g 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