From 28853fd3cc784458ae0ae2d24b22fcbdec918b90 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 8 Aug 2022 16:24:25 +1000 Subject: [PATCH] Use generics instead of dynamic dispatch Currently in the `bip158` module we do a bunch of dynamic dispatch using the reader/writer objects. We can improve runtime performance, at the cost of compile time, by using generics instead of dynamic dispatch. --- src/util/bip158.rs | 76 +++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/src/util/bip158.rs b/src/util/bip158.rs index 2643d8e5..2b9e49d2 100644 --- a/src/util/bip158.rs +++ b/src/util/bip158.rs @@ -137,27 +137,33 @@ impl BlockFilter { } /// match any query pattern - pub fn match_any(&self, block_hash: &BlockHash, query: &mut dyn Iterator) -> Result { + pub fn match_any<'a, I>(&self, block_hash: &BlockHash, query: I) -> Result + where + I: Iterator, + { let filter_reader = BlockFilterReader::new(block_hash); filter_reader.match_any(&mut self.content.as_slice(), query) } /// match all query pattern - pub fn match_all(&self, block_hash: &BlockHash, query: &mut dyn Iterator) -> Result { + pub fn match_all<'a, I>(&self, block_hash: &BlockHash, query: I) -> Result + where + I: Iterator, + { let filter_reader = BlockFilterReader::new(block_hash); filter_reader.match_all(&mut self.content.as_slice(), query) } } /// Compiles and writes a block filter -pub struct BlockFilterWriter<'a> { +pub struct BlockFilterWriter<'a, W> { block: &'a Block, - writer: GCSFilterWriter<'a>, + writer: GCSFilterWriter<'a, W>, } -impl<'a> BlockFilterWriter<'a> { +impl<'a, W: io::Write> BlockFilterWriter<'a, W> { /// Create a block filter writer - pub fn new(writer: &'a mut dyn io::Write, block: &'a Block) -> BlockFilterWriter<'a> { + pub fn new(writer: &'a mut W, block: &'a Block) -> BlockFilterWriter<'a, W> { let block_hash_as_int = block.block_hash().into_inner(); let k0 = endian::slice_to_u64_le(&block_hash_as_int[0..8]); let k1 = endian::slice_to_u64_le(&block_hash_as_int[8..16]); @@ -218,12 +224,20 @@ impl BlockFilterReader { } /// match any query pattern - pub fn match_any(&self, reader: &mut dyn io::Read, query: &mut dyn Iterator) -> Result { + pub fn match_any<'a, I, R>(&self, reader: &mut R, query: I) -> Result + where + I: Iterator, + R: io::Read + ?Sized, + { self.reader.match_any(reader, query) } /// match all query pattern - pub fn match_all(&self, reader: &mut dyn io::Read, query: &mut dyn Iterator) -> Result { + pub fn match_all<'a, I, R>(&self, reader: &mut R, query: I) -> Result + where + I: Iterator, + R: io::Read + ?Sized, + { self.reader.match_all(reader, query) } } @@ -242,7 +256,11 @@ impl GCSFilterReader { } /// match any query pattern - pub fn match_any(&self, reader: &mut dyn io::Read, query: &mut dyn Iterator) -> Result { + pub fn match_any<'a, I, R>(&self, reader: &mut R, query: I) -> Result + where + I: Iterator, + R: io::Read + ?Sized, + { let mut decoder = reader; let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0)); let reader = &mut decoder; @@ -282,7 +300,11 @@ impl GCSFilterReader { } /// match all query pattern - pub fn match_all(&self, reader: &mut dyn io::Read, query: &mut dyn Iterator) -> Result { + pub fn match_all<'a, I, R>(&self, reader: &mut R, query: I) -> Result + where + I: Iterator, + R: io::Read + ?Sized, + { let mut decoder = reader; let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0)); let reader = &mut decoder; @@ -329,16 +351,16 @@ fn map_to_range(hash: u64, nm: u64) -> u64 { } /// Colomb-Rice encoded filter writer -pub struct GCSFilterWriter<'a> { +pub struct GCSFilterWriter<'a, W> { filter: GCSFilter, - writer: &'a mut dyn io::Write, + writer: &'a mut W, elements: HashSet>, m: u64 } -impl<'a> GCSFilterWriter<'a> { +impl<'a, W: io::Write> GCSFilterWriter<'a, W> { /// Create a new GCS writer wrapping a generic writer, with specific seed to siphash - pub fn new(writer: &'a mut dyn io::Write, k0: u64, k1: u64, m: u64, p: u8) -> GCSFilterWriter<'a> { + pub fn new(writer: &'a mut W, k0: u64, k1: u64, m: u64, p: u8) -> GCSFilterWriter<'a, W> { GCSFilterWriter { filter: GCSFilter::new(k0, k1, p), writer, @@ -392,7 +414,10 @@ impl GCSFilter { } /// Golomb-Rice encode a number n to a bit stream (Parameter 2^k) - fn golomb_rice_encode(&self, writer: &mut BitStreamWriter, n: u64) -> Result { + fn golomb_rice_encode<'a, W>(&self, writer: &mut BitStreamWriter<'a, W>, n: u64) -> Result + where + W: io::Write, + { let mut wrote = 0; let mut q = n >> self.p; while q > 0 { @@ -406,7 +431,10 @@ impl GCSFilter { } /// Golomb-Rice decode a number from a bit stream (Parameter 2^k) - fn golomb_rice_decode(&self, reader: &mut BitStreamReader) -> Result { + fn golomb_rice_decode(&self, reader: &mut BitStreamReader) -> Result + where + R: io::Read + { let mut q = 0u64; while reader.read(1)? == 1 { q += 1; @@ -422,15 +450,15 @@ impl GCSFilter { } /// Bitwise stream reader -pub struct BitStreamReader<'a> { +pub struct BitStreamReader<'a, R> { buffer: [u8; 1], offset: u8, - reader: &'a mut dyn io::Read, + reader: &'a mut R, } -impl<'a> BitStreamReader<'a> { +impl<'a, R: io::Read> BitStreamReader<'a, R> { /// Create a new BitStreamReader that reads bitwise from a given reader - pub fn new(reader: &'a mut dyn io::Read) -> BitStreamReader { + pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> { BitStreamReader { buffer: [0u8], reader, @@ -460,15 +488,15 @@ impl<'a> BitStreamReader<'a> { } /// Bitwise stream writer -pub struct BitStreamWriter<'a> { +pub struct BitStreamWriter<'a, W> { buffer: [u8; 1], offset: u8, - writer: &'a mut dyn io::Write, + writer: &'a mut W, } -impl<'a> BitStreamWriter<'a> { +impl<'a, W: io::Write> BitStreamWriter<'a, W> { /// Create a new BitStreamWriter that writes bitwise to a given writer - pub fn new(writer: &'a mut dyn io::Write) -> BitStreamWriter { + pub fn new(writer: &'a mut W) -> BitStreamWriter<'a, W> { BitStreamWriter { buffer: [0u8], writer,