-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Implement append and split_off for BitVec (RFC 509) #24890
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -89,6 +89,7 @@ use core::hash; | |
use core::iter::RandomAccessIterator; | ||
use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned}; | ||
use core::iter::{self, FromIterator}; | ||
use core::mem::swap; | ||
use core::ops::Index; | ||
use core::slice; | ||
use core::{u8, u32, usize}; | ||
|
@@ -602,6 +603,106 @@ impl BitVec { | |
Iter { bit_vec: self, next_idx: 0, end_idx: self.nbits } | ||
} | ||
|
||
/// Moves all bits from `other` into `Self`, leaving `other` empty. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// # #![feature(collections, bit_vec_append_split_off)] | ||
/// use std::collections::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])); | ||
/// ``` | ||
#[unstable(feature = "bit_vec_append_split_off", | ||
reason = "recently added as part of collections reform 2")] | ||
pub fn append(&mut self, other: &mut Self) { | ||
let b = self.len() % u32::BITS; | ||
|
||
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(..) { | ||
*(self.storage.last_mut().unwrap()) |= block << b; | ||
self.storage.push(block >> (u32::BITS - b)); | ||
} | ||
} | ||
} | ||
|
||
/// Splits the `BitVec` into two at the given bit, | ||
/// retaining the first half in-place and returning the second one. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// # #![feature(collections, bit_vec_append_split_off)] | ||
/// use std::collections::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])); | ||
/// ``` | ||
#[unstable(feature = "bit_vec_append_split_off", | ||
reason = "recently added as part of collections reform 2")] | ||
pub fn split_off(&mut self, at: usize) -> Self { | ||
assert!(at <= self.len(), "`at` out of bounds"); | ||
|
||
let mut other = BitVec::new(); | ||
|
||
if at == 0 { | ||
swap(self, &mut other); | ||
return other; | ||
} else if at == self.len() { | ||
return other; | ||
} | ||
|
||
let w = at / u32::BITS; | ||
let b = at % u32::BITS; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More useful names There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I was just using the same names as in the implementations of set() and get(). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm... that might be worth leaving it as is (I haven't touched this file in a while). |
||
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[w..].iter(); | ||
let mut last = *iter.next().unwrap(); | ||
for &cur in iter { | ||
other.storage.push((last >> b) | (cur << (u32::BITS - b))); | ||
last = cur; | ||
} | ||
other.storage.push(last >> b); | ||
} | ||
|
||
self.storage.truncate(w+1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You also need to mask out the now "extra" bits to be 0 in |
||
self.fix_last_block(); | ||
} | ||
|
||
other | ||
} | ||
|
||
/// Returns `true` if all bits are 0. | ||
/// | ||
/// # Examples | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -630,6 +630,141 @@ fn test_bit_vec_extend() { | |
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(&[0b10100000, 0b00010010, 0b10010010, 0b00110011]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't mind an assert in here to guard against someone changing the repr to be e.g. u64 without fixing this test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how to assert this as the repr is an implementation detail and not exposed publicly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, you're right. I wasn't sure what I was picturing. Ah well. |
||
let mut b = BitVec::new(); | ||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this an actual interface guarantee or implementation detail we want to verify? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to RFC 509, it should be possible to reuse the container on the right-hand side. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, fair enough. |
||
|
||
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(); | ||
a.push(true); | ||
a.push(false); | ||
|
||
let mut b = BitVec::from_bytes(&[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(); | ||
let mut b = BitVec::from_bytes(&[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(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]); | ||
let mut b = BitVec::new(); | ||
|
||
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])); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ponders if it's worth checking that append does the right thing when |
||
|
||
#[test] | ||
fn test_bit_vec_split_off() { | ||
// Split at 0 | ||
let mut a = BitVec::new(); | ||
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(&[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(&[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])); | ||
} | ||
|
||
mod bench { | ||
use std::collections::BitVec; | ||
use std::u32; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd appreciate a more useful name than
b
.