Skip to content

Commit

Permalink
codec - universal_decode_number optimziation
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei-marinica committed Apr 8, 2024
1 parent a56b3ee commit 978c562
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 28 deletions.
8 changes: 4 additions & 4 deletions data/codec/src/impl_for_types/impl_num_signed.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
dep_encode_num_mimic, num_conv::universal_decode_number, DecodeError, DecodeErrorHandler,
EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode, NestedEncodeOutput,
TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
dep_encode_num_mimic, num_conv::universal_decode_number_unchecked, DecodeError,
DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode,
NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
};

macro_rules! top_encode_num_signed {
Expand Down Expand Up @@ -42,7 +42,7 @@ macro_rules! dep_decode_num_signed {
{
let mut bytes = [0u8; $num_bytes];
input.read_into(&mut bytes[..], h)?;
let num = universal_decode_number(&bytes[..], true) as $ty;
let num = universal_decode_number_unchecked(&bytes[..], true) as $ty;
Ok(num)
}
}
Expand Down
8 changes: 4 additions & 4 deletions data/codec/src/impl_for_types/impl_num_unsigned.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
dep_encode_num_mimic, num_conv::universal_decode_number, DecodeError, DecodeErrorHandler,
EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode, NestedEncodeOutput,
TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
dep_encode_num_mimic, num_conv::universal_decode_number_unchecked, DecodeError,
DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode,
NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
};

// No reversing needed for u8, because it is a single byte.
Expand Down Expand Up @@ -102,7 +102,7 @@ macro_rules! dep_decode_num_unsigned {
{
let mut bytes = [0u8; $num_bytes];
input.read_into(&mut bytes[..], h)?;
let num = universal_decode_number(&bytes[..], false) as $ty;
let num = universal_decode_number_unchecked(&bytes[..], false) as $ty;
Ok(num)
}
}
Expand Down
41 changes: 25 additions & 16 deletions data/codec/src/num_conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,23 +110,32 @@ fn fill_buffer_find_offset(x: u64, signed: bool, buffer: &mut TopEncodeNumberBuf
///
/// No generics here, we avoid monomorphization to make the SC binary as small as possible.
pub fn universal_decode_number(bytes: &[u8], signed: bool) -> u64 {
if bytes.is_empty() {
return 0;
}
let negative = signed && msbit_is_one(bytes[0]);
let mut result = if negative {
// start with all bits set to 1,
// to ensure that if there are fewer bytes than the result type width,
// the leading bits will be 1 instead of 0
u64::MAX
} else {
0u64
};
for byte in bytes.iter() {
result <<= 8;
result |= *byte as u64;
// it is almost impossible to get a slice longer than 8
// just a basic overflow/underflow protection
let safe_len = bytes.len() % 9;
universal_decode_number_impl(bytes, safe_len, signed)
}

/// Same as [`universal_decode_number`], but assumes that the input length does not exceed 8.
pub fn universal_decode_number_unchecked(bytes: &[u8], signed: bool) -> u64 {
universal_decode_number_impl(bytes, bytes.len(), signed)
}

fn universal_decode_number_impl(bytes: &[u8], len: usize, signed: bool) -> u64 {
let negative = signed && len > 0 && msbit_is_one(bytes[0]);
let skippable_byte = skippable_byte(negative);

let mut extended_buffer = [skippable_byte; 8];
let offset = 8 - len;
unsafe {
core::ptr::copy_nonoverlapping(
bytes.as_ptr(),
extended_buffer.as_mut_ptr().add(offset),
len,
)
}
result

u64::from_be_bytes(extended_buffer)
}

/// Most significant bit is 1.
Expand Down
9 changes: 5 additions & 4 deletions data/codec/src/single/top_de_input.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
num_conv::universal_decode_number, transmute::vec_into_boxed_slice, DecodeError,
DecodeErrorHandler, NestedDecodeInput, OwnedBytesNestedDecodeInput, TryStaticCast,
num_conv::{universal_decode_number, universal_decode_number_unchecked},
transmute::vec_into_boxed_slice,
DecodeError, DecodeErrorHandler, NestedDecodeInput, OwnedBytesNestedDecodeInput, TryStaticCast,
};
use alloc::{boxed::Box, vec::Vec};

Expand Down Expand Up @@ -38,7 +39,7 @@ pub trait TopDecodeInput: Sized {
{
let mut buffer = [0u8; 8];
let slice = self.into_max_size_buffer(&mut buffer, h)?;
Ok(universal_decode_number(slice, false))
Ok(universal_decode_number_unchecked(slice, false))
}

/// Retrieves the underlying data as a pre-parsed i64.
Expand All @@ -51,7 +52,7 @@ pub trait TopDecodeInput: Sized {
{
let mut buffer = [0u8; 8];
let slice = self.into_max_size_buffer(&mut buffer, h)?;
Ok(universal_decode_number(slice, true) as i64)
Ok(universal_decode_number_unchecked(slice, true) as i64)
}

#[inline]
Expand Down
1 change: 1 addition & 0 deletions data/codec/tests/derive_hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use crate::Result::{Err, Ok};
// They are not used in the derive, but just to make sure:
fn top_encode_number() {}
fn universal_decode_number() {}
fn universal_decode_number_unchecked() {}
fn dep_decode_from_byte_slice() {}
fn dep_encode_to_vec() {}
fn top_decode_from_nested_or_handle_err() {}
Expand Down

0 comments on commit 978c562

Please sign in to comment.