-
Notifications
You must be signed in to change notification settings - Fork 5
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
Implemented iterator type for BitVec #1
base: master
Are you sure you want to change the base?
Conversation
Pull Request Test Coverage Report for Build 225
💛 - Coveralls |
Thanks for the PR! I have two thoughts/questions:
What do you think? |
Thanks for the reply!
|
Okay, if you needed it then it must be at least a bit useful, and I don't think we'd be increasing API complexity significantly anyway. Do you want to implement |
Yeah I can do that. Should have time for that latest next week. |
I changed things around and now we have a Also, I can't check for Rust 1.20.0 compliance, as when compiling with 1.20.0 I get errors for lazy_static v1.2.0, which does not seem to be Rust 1.20.0 compatible. But I feel like we have a good implementation for iterating bits now. What do you think? Edit: Okay, I just realized that you require 1.24.0, not 1.20.0. Then the |
* Changed return impl Iterator to return BitsIter
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.
Cool, thanks! This looks very good to me, though there are a few things that I think aren’t quite there yet.
// Invariant: pos <= bits.block_len() | ||
|
||
impl<T: Bits> BitsIter<T> { | ||
/// Creates a new block iterator from a `Bits` instance. |
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.
The comment seems wrong.
} | ||
} | ||
|
||
fn cmp_bits_iter<T, U>(iter1: &BitsIter<T>, iter2: &BitsIter<U>) -> Ordering |
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 think this function is the wrong approach, but I don’t think it’s your fault—I was wrong to write cmp_block_iter
, which this appears to be derived from, in the first place.
I should have just called Iterator::cmp, and so (probably) should you. The standard library implements lexicographical order for iterators correctly, whereas my implementation of cmp_block_iter
is inconsistent with that, because it treats length (and not even the iterator’s length—the bit length!) as sort of a 0th key before it starts comparing elements. I don’t know if I thought that was a feature or an optimization, or what, but now I think it’s a bug in my code.
That said, there is possibly an optimization opportunity here, which is that you could compare BitsIter
s block-wise. This assumes the bit order is consistent with comparing whole blocks—and I think that it is regardless of host byte order—but I’m not totally sure. And then it's a bit tricky, because:
-
If you aren’t starting block-aligned then you have to either go bit-wise until you hit a block boundary, or (probably better) mask out the first block for only the remaining bits you care about.
-
If the last block is partial then you need to compare in a way that’s consistent with bitwise iteration. For example, if both
Bits
es last blocks are all 0 bits, but one is longer than the other, then bits-wise you'll notice the difference, but just comparing blocks you won't.
I’m not saying you should do this, but if it looks like a fun project, then there you go. If you do want to do it, you should replace this code here with a call to Iterator::cmp
for now, and then I’ll accept this PR. And then if you can replace the library call with an equivalent but faster version (benchmarks?), we’ll make that a separate PR.
|
||
impl<T, U> PartialEq<BitsIter<U>> for BitsIter<T> | ||
where T: Bits, | ||
U: Bits<Block = T::Block> { |
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.
It’s worth noting that requiring T
and U
to have the same Block
type is useful if we want to do a block-wise optimization (as I discussed above), but otherwise there’s no reason to do so, right? Because we can just iterate over the bits.
@@ -126,7 +126,8 @@ mod bit_vec; | |||
pub use self::bit_vec::BitVec; | |||
|
|||
mod array_n_impls; | |||
mod iter; | |||
mod block_iter; | |||
mod bits_iter; |
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.
Is this module exposed anywhere, or is the only way to access BitsIter
via the BitVec::iter()
method? Yeah, it looks like when I build the documentation, there is no link from the result type of that method to any docs for the BitsIter
struct, since it isn’t public.
And this makes me note that neither is BlockIter
public. The reason, I think, is that I found it useful internally (?) but didn’t want to commit to it as a public API yet.
Anyway, I think that for this to make sense, BitsIter
needs to be public, à la BitSlice
, BitSliceMut
, BitVec
, etc., above.
I switched from 1.20.0 to 1.24.0 because it depended something that depended on lazy_static, and it didn't seem worth fighting that. As for the issue of returning |
I noticed the BitVec in the bv crate is missing an option to iterate over the bits. The succinct crate has this option. I think the bv crate would benefit from this.