From a95090632348126ea93a459ddbef84bccf8f82eb Mon Sep 17 00:00:00 2001 From: Christian Lewe Date: Fri, 17 Nov 2023 13:10:10 +0100 Subject: [PATCH] Encode: Rewrite encode_natural The new algorithm is nonrecursive. --- src/bit_encoding/encode.rs | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/bit_encoding/encode.rs b/src/bit_encoding/encode.rs index 8575ccb6..5e8ddf4d 100644 --- a/src/bit_encoding/encode.rs +++ b/src/bit_encoding/encode.rs @@ -343,18 +343,34 @@ pub fn encode_hash(h: &[u8], w: &mut BitWriter) -> io::Result(n: usize, w: &mut BitWriter) -> io::Result { - assert_ne!(n, 0); // Cannot encode zero +/// Encode a positive integer to bits. +pub fn encode_natural(mut n: usize, w: &mut BitWriter) -> io::Result { + assert!(n > 0, "Zero cannot be encoded"); let n_start = w.n_total_written(); - let len = 8 * mem::size_of::() - n.leading_zeros() as usize - 1; - if len == 0 { - w.write_bit(false)?; - } else { - w.write_bit(true)?; - encode_natural(len, w)?; - w.write_bits_be(n as u64, len)?; + /// Minimum number of bits to represent `n` minus the most-significant bit + fn truncated_bit_len(n: usize) -> usize { + 8 * mem::size_of::() - n.leading_zeros() as usize - 1 + } + + let mut suffix = Vec::new(); + + loop { + debug_assert!(n > 0); + let len = truncated_bit_len(n); + if len == 0 { + w.write_bit(false)?; + break; + } else { + w.write_bit(true)?; + suffix.push((n, len)); + n = len; + } + } + + while let Some((bits, len)) = suffix.pop() { + let bits = bits as u64; // Case safety: assuming 64-bit machine or lower + w.write_bits_be(bits, len)?; } Ok(w.n_total_written() - n_start)