use different buffer size for every type

This commit is contained in:
Object905 2018-03-21 07:44:57 +05:00
parent ab5b81e08d
commit e86a5a54cc
2 changed files with 53 additions and 22 deletions

View File

@ -55,8 +55,8 @@ pub trait Integer: private::Sealed {
fn fmt<W: fmt::Write>(self, W) -> fmt::Result; fn fmt<W: fmt::Write>(self, W) -> fmt::Result;
} }
trait IntegerPrivate { trait IntegerPrivate<B> {
fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8]; fn write_to(self, buf: &mut B) -> &[u8];
} }
const DEC_DIGITS_LUT: &'static[u8] = const DEC_DIGITS_LUT: &'static[u8] =
@ -66,23 +66,21 @@ const DEC_DIGITS_LUT: &'static[u8] =
6061626364656667686970717273747576777879\ 6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899"; 8081828384858687888990919293949596979899";
const MAX_LEN: usize = 40; // i128::MIN (including minus sign)
// Adaptation of the original implementation at // Adaptation of the original implementation at
// https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266 // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266
macro_rules! impl_IntegerCommon { macro_rules! impl_IntegerCommon {
($t:ident) => { ($max_len:expr, $t:ident) => {
impl Integer for $t { impl Integer for $t {
#[cfg(feature = "std")] #[cfg(feature = "std")]
fn write<W: io::Write>(self, mut wr: W) -> io::Result<usize> { fn write<W: io::Write>(self, mut wr: W) -> io::Result<usize> {
let mut buf = unsafe { mem::uninitialized() }; let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() };
let bytes = self.write_to(&mut buf); let bytes = self.write_to(&mut buf);
try!(wr.write_all(bytes)); try!(wr.write_all(bytes));
Ok(bytes.len()) Ok(bytes.len())
} }
fn fmt<W: fmt::Write>(self, mut wr: W) -> fmt::Result { fn fmt<W: fmt::Write>(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); let bytes = self.write_to(&mut buf);
wr.write_str(unsafe { str::from_utf8_unchecked(bytes) }) wr.write_str(unsafe { str::from_utf8_unchecked(bytes) })
} }
@ -93,12 +91,11 @@ macro_rules! impl_IntegerCommon {
} }
macro_rules! impl_Integer { macro_rules! impl_Integer {
($($t:ident),* as $conv_fn:ident) => {$( (private $($max_len:expr => $t:ident),* as $conv_fn:ident) => {$(
impl_IntegerCommon!($t);
impl IntegerPrivate for $t { impl IntegerPrivate<[u8; $max_len]> for $t {
#[allow(unused_comparisons)] #[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 is_nonnegative = self >= 0;
let mut n = if is_nonnegative { let mut n = if is_nonnegative {
self as $conv_fn 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); const I8_MAX_LEN: usize = 4;
impl_Integer!(i64, u64 as u64); 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")] #[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")] #[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")] #[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"))] #[cfg(all(feature = "i128"))]
macro_rules! impl_Integer128 { macro_rules! impl_Integer128 {
($($t:ident),*) => {$( ($($max_len:expr => $t:ident),*) => {$(
impl_IntegerCommon!($t); impl_IntegerCommon!($max_len, $t);
impl IntegerPrivate for $t { impl IntegerPrivate<[u8; $max_len]> for $t {
#[allow(unused_comparisons)] #[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 is_nonnegative = self >= 0;
let n = if is_nonnegative { let n = if is_nonnegative {
self as u128 self as u128
@ -200,7 +222,7 @@ macro_rules! impl_Integer128 {
// Divide by 10^19 again. // Divide by 10^19 again.
let (n, rem) = udiv128::udivmod_1e19(n); 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; curr -= rem.write_to(&mut *buf2).len() as isize;
if n != 0 { if n != 0 {
@ -230,4 +252,12 @@ macro_rules! impl_Integer128 {
} }
#[cfg(all(feature = "i128"))] #[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);

View File

@ -21,6 +21,7 @@
// (https://github.com/rust-lang/rust/issues/44545) and to allow function // (https://github.com/rust-lang/rust/issues/44545) and to allow function
// inlining which doesnt happen with the intrinsic. // inlining which doesnt happen with the intrinsic.
#[inline]
pub fn udivmod_1e19(n: u128) -> (u128, u64) { pub fn udivmod_1e19(n: u128) -> (u128, u64) {
let d = 10_000_000_000_000_000_000_u64; // 10^19 let d = 10_000_000_000_000_000_000_u64; // 10^19