From e86a5a54cc8f97e2f35b125fb44f83ec387a6d5b Mon Sep 17 00:00:00 2001 From: Object905 Date: Wed, 21 Mar 2018 07:44:57 +0500 Subject: [PATCH 1/4] use different buffer size for every type --- src/lib.rs | 74 +++++++++++++++++++++++++++++++++++--------------- src/udiv128.rs | 1 + 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0deabb4..9a95d02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,8 +55,8 @@ pub trait Integer: private::Sealed { fn fmt(self, W) -> fmt::Result; } -trait IntegerPrivate { - fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8]; +trait IntegerPrivate { + fn write_to(self, buf: &mut B) -> &[u8]; } const DEC_DIGITS_LUT: &'static[u8] = @@ -66,23 +66,21 @@ const DEC_DIGITS_LUT: &'static[u8] = 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; -const MAX_LEN: usize = 40; // i128::MIN (including minus sign) - // Adaptation of the original implementation at // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266 macro_rules! impl_IntegerCommon { - ($t:ident) => { + ($max_len:expr, $t:ident) => { impl Integer for $t { #[cfg(feature = "std")] fn write(self, mut wr: W) -> io::Result { - let mut buf = unsafe { mem::uninitialized() }; + let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() }; let bytes = self.write_to(&mut buf); try!(wr.write_all(bytes)); Ok(bytes.len()) } fn fmt(self, mut wr: W) -> fmt::Result { - let mut buf = unsafe { mem::uninitialized() }; + let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() }; let bytes = self.write_to(&mut buf); wr.write_str(unsafe { str::from_utf8_unchecked(bytes) }) } @@ -93,12 +91,11 @@ macro_rules! impl_IntegerCommon { } macro_rules! impl_Integer { - ($($t:ident),* as $conv_fn:ident) => {$( - impl_IntegerCommon!($t); + (private $($max_len:expr => $t:ident),* as $conv_fn:ident) => {$( - impl IntegerPrivate for $t { + impl IntegerPrivate<[u8; $max_len]> for $t { #[allow(unused_comparisons)] - fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8] { + fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let mut n = if is_nonnegative { self as $conv_fn @@ -158,25 +155,50 @@ macro_rules! impl_Integer { } } )*}; + + ($($max_len:expr => $t:ident),* as $conv_fn:ident) => { + $(impl_IntegerCommon!($max_len, $t);)* + impl_Integer!(private $($max_len => $t),* as $conv_fn); + }; } -impl_Integer!(i8, u8, i16, u16, i32, u32 as u32); -impl_Integer!(i64, u64 as u64); +const I8_MAX_LEN: usize = 4; +const U8_MAX_LEN: usize = 3; +const I16_MAX_LEN: usize = 6; +const U16_MAX_LEN: usize = 5; +const I32_MAX_LEN: usize = 11; +const U32_MAX_LEN: usize = 10; +const I64_MAX_LEN: usize = 20; +const U64_MAX_LEN: usize = 20; + +impl_Integer!( + I8_MAX_LEN => i8, + U8_MAX_LEN => u8, + I16_MAX_LEN => i16, + U16_MAX_LEN => u16, + I32_MAX_LEN => i32, + U32_MAX_LEN => u32 + as u32); + +impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64); + #[cfg(target_pointer_width = "16")] -impl_Integer!(isize, usize as u16); +impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16); + #[cfg(target_pointer_width = "32")] -impl_Integer!(isize, usize as u32); +impl_Integer!( I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32); + #[cfg(target_pointer_width = "64")] -impl_Integer!(isize, usize as u64); +impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64); #[cfg(all(feature = "i128"))] macro_rules! impl_Integer128 { - ($($t:ident),*) => {$( - impl_IntegerCommon!($t); + ($($max_len:expr => $t:ident),*) => {$( + impl_IntegerCommon!($max_len, $t); - impl IntegerPrivate for $t { + impl IntegerPrivate<[u8; $max_len]> for $t { #[allow(unused_comparisons)] - fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8] { + fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let n = if is_nonnegative { self as u128 @@ -200,7 +222,7 @@ macro_rules! impl_Integer128 { // Divide by 10^19 again. let (n, rem) = udiv128::udivmod_1e19(n); - let buf2 = buf_ptr.offset(curr - buf.len() as isize) as *mut _; + let buf2 = buf_ptr.offset(curr - buf.len() as isize) as *mut [u8; $max_len]; curr -= rem.write_to(&mut *buf2).len() as isize; if n != 0 { @@ -230,4 +252,12 @@ macro_rules! impl_Integer128 { } #[cfg(all(feature = "i128"))] -impl_Integer128!(i128, u128); +const U128_MAX_LEN: usize = 39; +#[cfg(all(feature = "i128"))] +const I128_MAX_LEN: usize = 40; + +#[cfg(all(feature = "i128"))] +impl_Integer!(private U128_MAX_LEN => u64, I128_MAX_LEN => u64 as u64); + +#[cfg(all(feature = "i128"))] +impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128); diff --git a/src/udiv128.rs b/src/udiv128.rs index 24233c6..70fffc6 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -21,6 +21,7 @@ // (https://github.com/rust-lang/rust/issues/44545) and to allow function // inlining which doesn’t happen with the intrinsic. +#[inline] pub fn udivmod_1e19(n: u128) -> (u128, u64) { let d = 10_000_000_000_000_000_000_u64; // 10^19 From 4499b94fcddfe55b15c693f260c103fe3c137445 Mon Sep 17 00:00:00 2001 From: Object905 Date: Wed, 21 Mar 2018 07:48:34 +0500 Subject: [PATCH 2/4] add #[inline] --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9a95d02..35c3ecd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,6 +72,7 @@ macro_rules! impl_IntegerCommon { ($max_len:expr, $t:ident) => { impl Integer for $t { #[cfg(feature = "std")] + #[inline] fn write(self, mut wr: W) -> io::Result { let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() }; let bytes = self.write_to(&mut buf); @@ -79,6 +80,7 @@ macro_rules! impl_IntegerCommon { Ok(bytes.len()) } + #[inline] fn fmt(self, mut wr: W) -> fmt::Result { let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() }; let bytes = self.write_to(&mut buf); @@ -95,6 +97,7 @@ macro_rules! impl_Integer { impl IntegerPrivate<[u8; $max_len]> for $t { #[allow(unused_comparisons)] + #[inline] fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let mut n = if is_nonnegative { @@ -198,6 +201,7 @@ macro_rules! impl_Integer128 { impl IntegerPrivate<[u8; $max_len]> for $t { #[allow(unused_comparisons)] + #[inline] fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let n = if is_nonnegative { From d29c6a671833e9f941480e84d5b12646e9958b9e Mon Sep 17 00:00:00 2001 From: Object905 Date: Thu, 22 Mar 2018 13:18:40 +0500 Subject: [PATCH 3/4] remove space --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 35c3ecd..af0f1f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,7 +189,7 @@ impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64); impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16); #[cfg(target_pointer_width = "32")] -impl_Integer!( I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32); +impl_Integer!(I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32); #[cfg(target_pointer_width = "64")] impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64); From e6f1c2ee7ebaedefad188d46222cfa1a7f3cd0f5 Mon Sep 17 00:00:00 2001 From: Object905 Date: Thu, 22 Mar 2018 13:38:52 +0500 Subject: [PATCH 4/4] use one u64 impl --- src/lib.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index af0f1f5..ea513de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,8 @@ macro_rules! impl_IntegerCommon { } macro_rules! impl_Integer { - (private $($max_len:expr => $t:ident),* as $conv_fn:ident) => {$( + ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$( + impl_IntegerCommon!($max_len, $t); impl IntegerPrivate<[u8; $max_len]> for $t { #[allow(unused_comparisons)] @@ -158,11 +159,6 @@ macro_rules! impl_Integer { } } )*}; - - ($($max_len:expr => $t:ident),* as $conv_fn:ident) => { - $(impl_IntegerCommon!($max_len, $t);)* - impl_Integer!(private $($max_len => $t),* as $conv_fn); - }; } const I8_MAX_LEN: usize = 4; @@ -216,7 +212,8 @@ macro_rules! impl_Integer128 { unsafe { // Divide by 10^19 which is the highest power less than 2^64. let (n, rem) = udiv128::udivmod_1e19(n); - curr -= rem.write_to(buf).len() as isize; + let buf1 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN]; + curr -= rem.write_to(&mut *buf1).len() as isize; if n != 0 { // Memset the base10 leading zeros of rem. @@ -226,7 +223,7 @@ macro_rules! impl_Integer128 { // Divide by 10^19 again. let (n, rem) = udiv128::udivmod_1e19(n); - let buf2 = buf_ptr.offset(curr - buf.len() as isize) as *mut [u8; $max_len]; + let buf2 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN]; curr -= rem.write_to(&mut *buf2).len() as isize; if n != 0 { @@ -260,8 +257,5 @@ const U128_MAX_LEN: usize = 39; #[cfg(all(feature = "i128"))] const I128_MAX_LEN: usize = 40; -#[cfg(all(feature = "i128"))] -impl_Integer!(private U128_MAX_LEN => u64, I128_MAX_LEN => u64 as u64); - #[cfg(all(feature = "i128"))] impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128);