Skip to content

Commit

Permalink
Merge #345
Browse files Browse the repository at this point in the history
345: Avoid 64-bit arithmetic in LEB encoding r=Lotterleben a=jonas-schievink

Fixes #75

This uses `usize` instead of `u64` in `leb64`, which is now possible since timestamps aren't hard-coded to LEB64-encoded-`u64` anymore.

Before:

```
   text	   data	    bss	    dec	    hex	filename
  32084	      0	      8	  32092	   7d5c	../../target/thumbv7m-none-eabi/release/log
```

After:
```
   text	   data	    bss	    dec	    hex	filename
  31876	      0	      8	  31884	   7c8c	../../target/thumbv7m-none-eabi/release/log
```

So, ~200 bytes of code saved.

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
  • Loading branch information
bors[bot] and jonas-schievink authored Jan 18, 2021
2 parents eb8c3b1 + 9a8911f commit 072cb2e
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 13 deletions.
24 changes: 19 additions & 5 deletions src/leb.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
pub(crate) fn leb64(x: u64, buf: &mut [u8; 10]) -> usize {
/// LEB128-encodes a `usize` value into `buf`.
///
/// This handles 32-bit and 64-bit `usize`.
pub(crate) fn leb64(x: usize, buf: &mut [u8; 10]) -> usize {
let mut low = x as u32;
let mut high = (x >> 32) as u32;
// Shift by 16 twice, to avoid a panic/error when shifting a 32-bit usize by 32 bits.
let mut high = ((x >> 16) >> 16) as u32;

let mut i = 0;
loop {
Expand Down Expand Up @@ -58,8 +62,11 @@ pub(crate) fn leb64(x: u64, buf: &mut [u8; 10]) -> usize {
}
}

pub fn zigzag_encode(v: i64) -> u64 {
((v << 1) ^ (v >> 63)) as u64
/// Encodes an `isize` as a `usize` by pulling its sign bit to the least-significant place (this
/// makes it have an efficient LEB-encoding for small positive and negative values).
pub fn zigzag_encode(v: isize) -> usize {
const USIZE_BITS: usize = core::mem::size_of::<usize>() * 8;
((v << 1) ^ (v >> (USIZE_BITS - 1))) as usize
}

#[cfg(test)]
Expand All @@ -85,6 +92,13 @@ mod tests {
let i = leb64(1 << 7, &mut buf);
assert_eq!(buf[..i], [0x80, 1]);
buf.iter_mut().for_each(|b| *b = 0x55);
}

/// Smoke test for bit patterns that require 64-bit `usize`s.
#[test]
#[cfg(target_pointer_width = "64")]
fn leb_64_bit() {
let mut buf = [0x55; 10];

let i = leb64((1 << 32) - 1, &mut buf);
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0xf]);
Expand All @@ -102,7 +116,7 @@ mod tests {
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = leb64(u64::max_value(), &mut buf);
let i = leb64(usize::max_value(), &mut buf);
assert_eq!(
buf[..i],
[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1]
Expand Down
14 changes: 6 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,7 @@ impl InternalFormatter {

/// Implementation detail
/// leb64-encode `x` and write it to self.bytes
pub fn leb64(&mut self, x: u64) {
// FIXME: Avoid 64-bit arithmetic on 32-bit systems. This should only be used for
// pointer-sized values.
pub fn leb64(&mut self, x: usize) {
let mut buf: [u8; 10] = [0; 10];
let i = leb::leb64(x, &mut buf);
self.write(&buf[..i])
Expand Down Expand Up @@ -453,12 +451,12 @@ impl InternalFormatter {
/// Implementation detail
pub fn isize(&mut self, b: &isize) {
// Zig-zag encode the signed value.
self.leb64(leb::zigzag_encode(*b as i64));
self.leb64(leb::zigzag_encode(*b));
}

/// Implementation detail
pub fn fmt_slice(&mut self, values: &[impl Format]) {
self.leb64(values.len() as u64);
self.leb64(values.len());
let mut is_first = true;
for value in values {
let omit_tag = !is_first;
Expand Down Expand Up @@ -505,7 +503,7 @@ impl InternalFormatter {

/// Implementation detail
pub fn usize(&mut self, b: &usize) {
self.leb64(*b as u64);
self.leb64(*b);
}

/// Implementation detail
Expand All @@ -514,12 +512,12 @@ impl InternalFormatter {
}

pub fn str(&mut self, s: &str) {
self.leb64(s.len() as u64);
self.leb64(s.len());
self.write(s.as_bytes());
}

pub fn slice(&mut self, s: &[u8]) {
self.leb64(s.len() as u64);
self.leb64(s.len());
self.write(s);
}

Expand Down

0 comments on commit 072cb2e

Please sign in to comment.