Merge pull request #16 from Object905/master
Use different buffer size for every integer type
This commit is contained in:
commit
ce0dc0452d
74
src/lib.rs
74
src/lib.rs
|
@ -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,23 @@ 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")]
|
||||||
|
#[inline]
|
||||||
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
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 +93,13 @@ macro_rules! impl_IntegerCommon {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_Integer {
|
macro_rules! impl_Integer {
|
||||||
($($t:ident),* as $conv_fn:ident) => {$(
|
($($max_len:expr => $t:ident),* as $conv_fn: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] {
|
#[inline]
|
||||||
|
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
|
||||||
|
@ -160,23 +161,44 @@ macro_rules! impl_Integer {
|
||||||
)*};
|
)*};
|
||||||
}
|
}
|
||||||
|
|
||||||
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] {
|
#[inline]
|
||||||
|
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
|
||||||
|
@ -190,7 +212,8 @@ macro_rules! impl_Integer128 {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Divide by 10^19 which is the highest power less than 2^64.
|
// Divide by 10^19 which is the highest power less than 2^64.
|
||||||
let (n, rem) = udiv128::udivmod_1e19(n);
|
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 {
|
if n != 0 {
|
||||||
// Memset the base10 leading zeros of rem.
|
// Memset the base10 leading zeros of rem.
|
||||||
|
@ -200,7 +223,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 - U64_MAX_LEN as isize) as *mut [u8; U64_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 +253,9 @@ 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_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128);
|
||||||
|
|
|
@ -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 doesn’t happen with the intrinsic.
|
// inlining which doesn’t 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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue