Skip to content

Commit

Permalink
Append / prepend
Browse files Browse the repository at this point in the history
  • Loading branch information
haxelion committed Jul 8, 2024
1 parent f3c4cb5 commit fe7f011
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 42 deletions.
70 changes: 52 additions & 18 deletions src/auto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ impl BitVector for BV {
}
}

fn capacity(&self) -> usize {
match self {
BV::Fixed(_) => BVP::capacity(),
BV::Dynamic(b) => b.capacity(),
}
}

fn len(&self) -> usize {
match self {
BV::Fixed(b) => b.len(),
BV::Dynamic(b) => b.len(),
}
}

fn from_binary<S: AsRef<str>>(string: S) -> Result<Self, ConvertionError> {
if string.as_ref().len() <= BVP::capacity() {
Ok(BV::Fixed(BVP::from_binary(string)?))
Expand Down Expand Up @@ -252,6 +266,40 @@ impl BitVector for BV {
}
}

fn append<B: BitVector>(&mut self, suffix: &B) {
match self {
BV::Fixed(bvf) => {
if bvf.len() + suffix.len() <= BVP::capacity() {
bvf.append(suffix);
} else {
let mut bvd = BVD::from(&*bvf);
bvd.append(suffix);
*self = BV::Dynamic(bvd);
}
}
BV::Dynamic(bvd) => {
bvd.append(suffix);
}
}
}

fn prepend<B: BitVector>(&mut self, prefix: &B) {
match self {
BV::Fixed(bvf) => {
if bvf.len() + prefix.len() <= BVP::capacity() {
bvf.prepend(prefix);
} else {
let mut bvd = BVD::from(&*bvf);
bvd.prepend(prefix);
*self = BV::Dynamic(bvd);
}
}
BV::Dynamic(bvd) => {
bvd.prepend(prefix);
}
}
}

fn shl_in(&mut self, bit: Bit) -> Bit {
match self {
BV::Fixed(b) => b.shl_in(bit),
Expand Down Expand Up @@ -280,24 +328,6 @@ impl BitVector for BV {
}
}

fn capacity(&self) -> usize {
match self {
BV::Fixed(_) => BVP::capacity(),
BV::Dynamic(b) => b.capacity(),
}
}

fn len(&self) -> usize {
match self {
BV::Fixed(b) => b.len(),
BV::Dynamic(b) => b.len(),
}
}

fn iter(&self) -> BitIterator<'_, Self> {
self.into_iter()
}

fn leading_zeros(&self) -> usize {
match self {
BV::Fixed(b) => b.leading_zeros(),
Expand Down Expand Up @@ -359,6 +389,10 @@ impl BitVector for BV {

(quotient, rem)
}

fn iter(&self) -> BitIterator<'_, Self> {
self.into_iter()
}
}

// ------------------------------------------------------------------------------------------------
Expand Down
44 changes: 32 additions & 12 deletions src/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ impl BitVector for BVD {
}
}

fn capacity(&self) -> usize {
self.data.len() * Self::BIT_UNIT
}

fn len(&self) -> usize {
self.length
}

fn from_binary<S: AsRef<str>>(string: S) -> Result<Self, ConvertionError> {
let length = string.as_ref().chars().count();
let offset = (Self::BIT_UNIT - length % Self::BIT_UNIT) % Self::BIT_UNIT;
Expand Down Expand Up @@ -323,6 +331,7 @@ impl BitVector for BVD {
return None;
}
let bit = self.get(self.length - 1);
self.set(self.length - 1, Bit::Zero);
self.length -= 1;
Some(bit)
}
Expand Down Expand Up @@ -355,6 +364,25 @@ impl BitVector for BVD {
}
}

fn append<B: BitVector>(&mut self, suffix: &B) {
self.reserve(self.length + suffix.len());
// TODO: can be optimized with a shift and data copy via IArray.
// The IArray trait would need rework to support this.
for b in suffix.iter() {
self.push(b);
}
}

fn prepend<B: BitVector>(&mut self, prefix: &B) {
self.resize(prefix.len() + self.length, Bit::Zero);
*self <<= prefix.len();
// TODO: can be optimized with data copy via IArray.
// The IArray trait would need rework to support this.
for (i, b) in prefix.iter().enumerate() {
self.set(i, b);
}
}

fn shl_in(&mut self, bit: Bit) -> Bit {
let mut carry = bit;
for i in 0..(self.length / Self::BIT_UNIT) {
Expand Down Expand Up @@ -426,18 +454,6 @@ impl BitVector for BVD {
self.data = new_data.into_boxed_slice();
}

fn capacity(&self) -> usize {
self.data.len() * Self::BIT_UNIT
}

fn len(&self) -> usize {
self.length
}

fn iter(&self) -> BitIterator<'_, Self> {
self.into_iter()
}

fn leading_zeros(&self) -> usize {
let mut count = 0;
let mut i = Self::capacity_from_bit_len(self.length);
Expand Down Expand Up @@ -540,6 +556,10 @@ impl BitVector for BVD {

(quotient, rem)
}

fn iter(&self) -> BitIterator<'_, Self> {
self.into_iter()
}
}

// ------------------------------------------------------------------------------------------------
Expand Down
45 changes: 33 additions & 12 deletions src/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ where
ones
}

fn capacity(&self) -> usize {
BVF::<I, N>::capacity()
}

fn len(&self) -> usize {
self.length
}

fn from_binary<S: AsRef<str>>(string: S) -> Result<Self, ConvertionError> {
let length = string.as_ref().chars().count();
if length > Self::capacity() {
Expand Down Expand Up @@ -313,6 +321,7 @@ where
let mut b = None;
if self.length > 0 {
b = Some(self.get(self.length - 1));
self.set(self.length - 1, Bit::Zero);
self.length -= 1;
}
b
Expand Down Expand Up @@ -346,6 +355,26 @@ where
}
}

fn append<B: BitVector>(&mut self, suffix: &B) {
debug_assert!(self.length + suffix.len() <= self.capacity());
// TODO: can be optimized with a shift and data copy via IArray.
// The IArray trait would need rework to support this.
for b in suffix.iter() {
self.push(b);
}
}

fn prepend<B: BitVector>(&mut self, prefix: &B) {
debug_assert!(prefix.len() + self.length <= self.capacity());
self.resize(prefix.len() + self.length, Bit::Zero);
*self <<= prefix.len();
// TODO: can be optimized with data copy via IArray.
// The IArray trait would need rework to support this.
for (i, b) in prefix.iter().enumerate() {
self.set(i, b);
}
}

fn shl_in(&mut self, bit: Bit) -> Bit {
let mut carry = bit;
for i in 0..(self.length / Self::BIT_UNIT) {
Expand Down Expand Up @@ -417,18 +446,6 @@ where
self.data = new_data;
}

fn capacity(&self) -> usize {
BVF::<I, N>::capacity()
}

fn len(&self) -> usize {
self.length
}

fn iter(&self) -> BitIterator<'_, Self> {
self.into_iter()
}

fn leading_zeros(&self) -> usize {
let mut count = 0;
let mut i = Self::capacity_from_bit_len(self.length);
Expand Down Expand Up @@ -529,6 +546,10 @@ where

(quotient, rem)
}

fn iter(&self) -> BitIterator<'_, Self> {
self.into_iter()
}
}

// ------------------------------------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ pub trait BitVector:
/// Will panic if there is not enough capacity and it is a fixed variant.
fn resize(&mut self, new_length: usize, bit: Bit);

/// Append the `suffix` bit vector at the end (most significant part) of this bit vector.
/// Will panic if there is not enough capacity and this is a fixed variant.
fn append<B: BitVector>(&mut self, suffix: &B);

/// Prepend the `prefix` bit vector at the beginning (least significant part) of this bit vector.
/// Will panic if there is not enough capacity and this is a fixed variant.
fn prepend<B: BitVector>(&mut self, prefix: &B);

/// Shift the bits by one to the left.
/// The rightmost bit is set to `bit` and the leftmost bit is returned.
fn shl_in(&mut self, bit: Bit) -> Bit;
Expand Down
64 changes: 64 additions & 0 deletions src/tests/bitvector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,70 @@ fn resize_bv() {
resize_inner::<BV>(256);
}

fn append_inner<B: BitVector>(max_capacity: usize) {
for capacity in 0..max_capacity {
for split in 0..capacity {
let mut bv1 = random_bv::<B>(split);
let bv2 = random_bv::<B>(capacity - split);
let mut bits1: Vec<Bit> = bv1.iter().collect();
let bits2: Vec<Bit> = bv2.iter().collect();

bv1.append(&bv2);
bits1.extend(bits2.iter());
for (b1, &b2) in bv1.iter().zip(bits1.iter()) {
assert_eq!(b1, b2);
}
}
}
}

#[test]
fn append_bvf() {
bvf_inner_unroll_cap!(append_inner, {u8, u16, u32, u64, u128}, {1, 2, 3, 4, 5});
}

#[test]
fn append_bvd() {
append_inner::<BVD>(256);
}

#[test]
fn append_bv() {
append_inner::<BV>(256);
}

fn prepend_inner<B: BitVector>(max_capacity: usize) {
for capacity in 0..max_capacity {
for split in 0..capacity {
let mut bv1 = random_bv::<B>(split);
let bv2 = random_bv::<B>(capacity - split);
let bits1: Vec<Bit> = bv1.iter().collect();
let mut bits2: Vec<Bit> = bv2.iter().collect();

bv1.prepend(&bv2);
bits2.extend(bits1.iter());
for (b1, &b2) in bv1.iter().zip(bits2.iter()) {
assert_eq!(b1, b2);
}
}
}
}

#[test]
fn prepend_bvf() {
bvf_inner_unroll_cap!(prepend_inner, {u8, u16, u32, u64, u128}, {1, 2, 3, 4, 5});
}

#[test]
fn prepend_bvd() {
prepend_inner::<BVD>(256);
}

#[test]
fn prepend_bv() {
prepend_inner::<BV>(256);
}

fn shl_inner<B: BitVector>(max_capacity: usize) {
let mut rng = thread_rng();
for capacity in 0..max_capacity {
Expand Down
27 changes: 27 additions & 0 deletions src/tests/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,30 @@ fn iter_auto() {
iter_inner::<BV>(capacity);
}
}

fn from_iter_inner<B: BitVector + FromIterator<Bit>>(capacity: usize) {
let mut rng = thread_rng();
let bits: Vec<Bit> = (0..capacity)
.map(|_| Bit::from(rng.gen::<bool>()))
.collect();
let bv: B = bits.iter().copied().collect();
for (b1, &b2) in bv.iter().zip(bits.iter()) {
assert_eq!(b1, b2);
}
}

#[test]
fn from_iter_bvf() {
bvf_inner_unroll_cap!(from_iter_inner, {u8, u16, u32, u64, u128}, {1, 2, 3, 4, 5});
}

#[test]
fn from_iter_bvd() {
from_iter_inner::<BVD>(256);
}

#[test]
fn from_iter_bv() {
from_iter_inner::<BV>(64);
from_iter_inner::<BV>(256);
}

0 comments on commit fe7f011

Please sign in to comment.