Skip to content

Commit 8525a4e

Browse files
committed
Merge rust-bitcoin/rust-bitcoin#1053: Implement iter::size_hint and ExactSizeIterator for Witness Iter
ec8dada Implement iter::size_hint and ExactSizeIterator for Witness Iter (Riccardo Casatta) Pull request description: close rust-bitcoin/rust-bitcoin#1050 I don't think we need to change the `collect` since it use the `size_hint()` lower bound to initially allocate // with size_hint // test blockdata::witness::benches::bench_big_witness_to_vec ... bench: 313 ns/iter (+/- 13) // test blockdata::witness::benches::bench_witness_to_vec ... bench: 204 ns/iter (+/- 11) // without // test blockdata::witness::benches::bench_big_witness_to_vec ... bench: 489 ns/iter (+/- 28) // test blockdata::witness::benches::bench_witness_to_vec ... bench: 221 ns/iter (+/- 102) The reason why the small witness doesn't get big perf boost is because by default vec allocates 4 slots ACKs for top commit: Kixunil: ACK ec8dada apoelstra: ACK ec8dada Tree-SHA512: dbe09ba6ebd4014fe0639412894beedab6cc7e844a5ec1697af8f0694b62ae5d423a801df1b48ac7029444c01877975e2d5168728f038fbd4f5808bda90e0f2f
2 parents 8543004 + ae07151 commit 8525a4e

File tree

1 file changed

+59
-6
lines changed

1 file changed

+59
-6
lines changed

src/blockdata/witness.rs

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ pub struct Witness {
4343
}
4444

4545
/// Support structure to allow efficient and convenient iteration over the Witness elements
46-
pub struct Iter<'a>(::core::slice::Iter<'a, u8>);
46+
pub struct Iter<'a> {
47+
inner: core::slice::Iter<'a, u8>,
48+
remaining: usize,
49+
}
4750

4851
impl Decodable for Witness {
4952
fn consensus_decode<D: Read>(mut d: D) -> Result<Self, Error> {
@@ -172,7 +175,7 @@ impl Witness {
172175

173176
/// Returns a struct implementing [`Iterator`]
174177
pub fn iter(&self) -> Iter {
175-
Iter(self.content.iter())
178+
Iter { inner: self.content.iter(), remaining: self.witness_elements }
176179
}
177180

178181
/// Returns the number of elements this witness holds
@@ -253,18 +256,25 @@ impl<'a> Iterator for Iter<'a> {
253256
type Item = &'a [u8];
254257

255258
fn next(&mut self) -> Option<Self::Item> {
256-
let varint = VarInt::consensus_decode(self.0.as_slice()).ok()?;
257-
self.0.nth(varint.len() - 1)?; // VarInt::len returns at least 1
259+
let varint = VarInt::consensus_decode(self.inner.as_slice()).ok()?;
260+
self.inner.nth(varint.len() - 1)?; // VarInt::len returns at least 1
258261
let len = varint.0 as usize;
259-
let slice = &self.0.as_slice()[..len];
262+
let slice = &self.inner.as_slice()[..len];
260263
if len > 0 {
261264
// we don't need to advance if the element is empty
262-
self.0.nth(len - 1)?;
265+
self.inner.nth(len - 1)?;
263266
}
267+
self.remaining -= 1;
264268
Some(slice)
265269
}
270+
271+
fn size_hint(&self) -> (usize, Option<usize>) {
272+
(self.remaining, Some(self.remaining))
273+
}
266274
}
267275

276+
impl<'a> ExactSizeIterator for Iter<'a> {}
277+
268278
// Serde keep backward compatibility with old Vec<Vec<u8>> format
269279
#[cfg(feature = "serde")]
270280
impl serde::Serialize for Witness {
@@ -323,6 +333,21 @@ mod test {
323333
assert_eq!(witness.second_to_last(), Some(&[0u8][..]));
324334
}
325335

336+
337+
#[test]
338+
fn test_iter_len() {
339+
let mut witness = Witness::default();
340+
for i in 0..5 {
341+
assert_eq!(witness.iter().len(), i);
342+
witness.push(&vec![0u8]);
343+
}
344+
let mut iter = witness.iter();
345+
for i in (0..=5).rev() {
346+
assert_eq!(iter.len(), i);
347+
iter.next();
348+
}
349+
}
350+
326351
#[test]
327352
fn test_push_ecdsa_sig() {
328353
// The very first signature in block 734,958
@@ -408,3 +433,31 @@ mod test {
408433
assert_eq!(new_witness_format, back);
409434
}
410435
}
436+
437+
438+
#[cfg(all(test, feature = "unstable"))]
439+
mod benches {
440+
use test::{Bencher, black_box};
441+
use super::Witness;
442+
443+
#[bench]
444+
pub fn bench_big_witness_to_vec(bh: &mut Bencher) {
445+
let raw_witness = vec![vec![1u8]; 5];
446+
let witness = Witness::from_vec(raw_witness);
447+
448+
bh.iter(|| {
449+
black_box(witness.to_vec());
450+
});
451+
}
452+
453+
#[bench]
454+
pub fn bench_witness_to_vec(bh: &mut Bencher) {
455+
let raw_witness = vec![vec![1u8]; 3];
456+
let witness = Witness::from_vec(raw_witness);
457+
458+
bh.iter(|| {
459+
black_box(witness.to_vec());
460+
});
461+
}
462+
463+
}

0 commit comments

Comments
 (0)