From 5ae30c5fd2725132c4daa0ef9f6d2f14f1308bd5 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Mon, 25 Nov 2024 17:06:05 +0200 Subject: [PATCH] perf: NonZeroU64 to optimize encoded_len_varint (#1192) The leading zeros count may perform better on many architectures when the zero case is excluded. Also use ilog2 as shorthand for the leading zeros trick because it makes more clearly what we mean to get, and should be ideally optimized by the compiler. --- prost/src/encoding/varint.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/prost/src/encoding/varint.rs b/prost/src/encoding/varint.rs index 5c1b477aa..b913fe684 100644 --- a/prost/src/encoding/varint.rs +++ b/prost/src/encoding/varint.rs @@ -1,4 +1,5 @@ use core::cmp::min; +use core::num::NonZeroU64; use ::bytes::{Buf, BufMut}; @@ -25,8 +26,10 @@ pub fn encode_varint(mut value: u64, buf: &mut impl BufMut) { #[inline] pub fn encoded_len_varint(value: u64) -> usize { // Based on [VarintSize64][1]. - // [1]: https://github.com/google/protobuf/blob/3.3.x/src/google/protobuf/io/coded_stream.h#L1301-L1309 - ((((value | 1).leading_zeros() ^ 63) * 9 + 73) / 64) as usize + // [1]: https://github.com/protocolbuffers/protobuf/blob/v28.3/src/google/protobuf/io/coded_stream.h#L1744-L1756 + // Safety: value | 1 is non-zero. + let log2value = unsafe { NonZeroU64::new_unchecked(value | 1) }.ilog2(); + ((log2value * 9 + (64 + 9)) / 64) as usize } /// Decodes a LEB128-encoded variable length integer from the buffer.