Rollup merge of #143730 - pascaldekloe:fmt-radix-trim, r=tgross35
fmt of non-decimal radix untangled
Have the implementation match its decimal counterpart.
* Digit table instead of conversion functions
* Correct buffer size per radix
* Elimination of dead code for negative
* No trait abstraction for integers
#### Original Performance
```
fmt::write_10ints_bin 393.03ns/iter +/- 1.41
fmt::write_10ints_hex 316.84ns/iter +/- 1.49
fmt::write_10ints_oct 327.16ns/iter +/- 0.46
```
#### Patched Performance
```
fmt::write_10ints_bin 392.31ns/iter +/- 3.05
fmt::write_10ints_hex 302.41ns/iter +/- 5.48
fmt::write_10ints_oct 322.01ns/iter +/- 3.82
```
r? tgross35
This commit is contained in:
commit
4327e69030
2 changed files with 312 additions and 213 deletions
|
|
@ -3,164 +3,78 @@
|
|||
use crate::fmt::NumBuffer;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::num::fmt as numfmt;
|
||||
use crate::ops::{Div, Rem, Sub};
|
||||
use crate::{fmt, ptr, slice, str};
|
||||
|
||||
#[doc(hidden)]
|
||||
trait DisplayInt:
|
||||
PartialEq + PartialOrd + Div<Output = Self> + Rem<Output = Self> + Sub<Output = Self> + Copy
|
||||
{
|
||||
fn zero() -> Self;
|
||||
fn from_u8(u: u8) -> Self;
|
||||
fn to_u8(&self) -> u8;
|
||||
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
|
||||
fn to_u32(&self) -> u32;
|
||||
fn to_u64(&self) -> u64;
|
||||
fn to_u128(&self) -> u128;
|
||||
}
|
||||
|
||||
macro_rules! impl_int {
|
||||
($($t:ident)*) => (
|
||||
$(impl DisplayInt for $t {
|
||||
fn zero() -> Self { 0 }
|
||||
fn from_u8(u: u8) -> Self { u as Self }
|
||||
fn to_u8(&self) -> u8 { *self as u8 }
|
||||
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
|
||||
fn to_u32(&self) -> u32 { *self as u32 }
|
||||
fn to_u64(&self) -> u64 { *self as u64 }
|
||||
fn to_u128(&self) -> u128 { *self as u128 }
|
||||
})*
|
||||
)
|
||||
}
|
||||
|
||||
impl_int! {
|
||||
i8 i16 i32 i64 i128 isize
|
||||
u8 u16 u32 u64 u128 usize
|
||||
}
|
||||
|
||||
/// A type that represents a specific radix
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `digit` must return an ASCII character.
|
||||
#[doc(hidden)]
|
||||
unsafe trait GenericRadix: Sized {
|
||||
/// The number of digits.
|
||||
const BASE: u8;
|
||||
|
||||
/// A radix-specific prefix string.
|
||||
const PREFIX: &'static str;
|
||||
|
||||
/// Converts an integer to corresponding radix digit.
|
||||
fn digit(x: u8) -> u8;
|
||||
|
||||
/// Format an integer using the radix using a formatter.
|
||||
fn fmt_int<T: DisplayInt>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// The radix can be as low as 2, so we need a buffer of at least 128
|
||||
// characters for a base 2 number.
|
||||
let zero = T::zero();
|
||||
let is_nonnegative = x >= zero;
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); 128];
|
||||
let mut offset = buf.len();
|
||||
let base = T::from_u8(Self::BASE);
|
||||
if is_nonnegative {
|
||||
// Accumulate each digit of the number from the least significant
|
||||
// to the most significant figure.
|
||||
loop {
|
||||
let n = x % base; // Get the current place value.
|
||||
x = x / base; // Deaccumulate the number.
|
||||
offset -= 1;
|
||||
buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer.
|
||||
if x == zero {
|
||||
// No more digits left to accumulate.
|
||||
break;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Do the same as above, but accounting for two's complement.
|
||||
loop {
|
||||
let n = zero - (x % base); // Get the current place value.
|
||||
x = x / base; // Deaccumulate the number.
|
||||
offset -= 1;
|
||||
buf[offset].write(Self::digit(n.to_u8())); // Store the digit in the buffer.
|
||||
if x == zero {
|
||||
// No more digits left to accumulate.
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
// SAFETY: Starting from `offset`, all elements of the slice have been set.
|
||||
let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
|
||||
f.pad_integral(is_nonnegative, Self::PREFIX, buf_slice)
|
||||
}
|
||||
}
|
||||
|
||||
/// A binary (base 2) radix
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct Binary;
|
||||
|
||||
/// An octal (base 8) radix
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct Octal;
|
||||
|
||||
/// A hexadecimal (base 16) radix, formatted with lower-case characters
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct LowerHex;
|
||||
|
||||
/// A hexadecimal (base 16) radix, formatted with upper-case characters
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct UpperHex;
|
||||
|
||||
macro_rules! radix {
|
||||
($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
|
||||
unsafe impl GenericRadix for $T {
|
||||
const BASE: u8 = $base;
|
||||
const PREFIX: &'static str = $prefix;
|
||||
fn digit(x: u8) -> u8 {
|
||||
match x {
|
||||
$($x => $conv,)+
|
||||
x => panic!("number not in the range 0..={}: {}", Self::BASE - 1, x),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radix! { Binary, 2, "0b", x @ 0 ..= 1 => b'0' + x }
|
||||
radix! { Octal, 8, "0o", x @ 0 ..= 7 => b'0' + x }
|
||||
radix! { LowerHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'a' + (x - 10) }
|
||||
radix! { UpperHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'A' + (x - 10) }
|
||||
|
||||
macro_rules! int_base {
|
||||
(fmt::$Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
|
||||
/// Formatting of integers with a non-decimal radix.
|
||||
macro_rules! radix_integer {
|
||||
(fmt::$Trait:ident for $Signed:ident and $Unsigned:ident, $prefix:literal, $dig_tab:literal) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::$Trait for $T {
|
||||
impl fmt::$Trait for $Unsigned {
|
||||
/// Format unsigned integers in the radix.
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
$Radix.fmt_int(*self as $U, f)
|
||||
// Check macro arguments at compile time.
|
||||
const {
|
||||
assert!($Unsigned::MIN == 0, "need unsigned");
|
||||
assert!($dig_tab.is_ascii(), "need single-byte entries");
|
||||
}
|
||||
|
||||
// ASCII digits in ascending order are used as a lookup table.
|
||||
const DIG_TAB: &[u8] = $dig_tab;
|
||||
const BASE: $Unsigned = DIG_TAB.len() as $Unsigned;
|
||||
const MAX_DIG_N: usize = $Unsigned::MAX.ilog(BASE) as usize + 1;
|
||||
|
||||
// Buffer digits of self with right alignment.
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DIG_N];
|
||||
// Count the number of bytes in buf that are not initialized.
|
||||
let mut offset = buf.len();
|
||||
|
||||
// Accumulate each digit of the number from the least
|
||||
// significant to the most significant figure.
|
||||
let mut remain = *self;
|
||||
loop {
|
||||
let digit = remain % BASE;
|
||||
remain /= BASE;
|
||||
|
||||
offset -= 1;
|
||||
// SAFETY: `remain` will reach 0 and we will break before `offset` wraps
|
||||
unsafe { core::hint::assert_unchecked(offset < buf.len()) }
|
||||
buf[offset].write(DIG_TAB[digit as usize]);
|
||||
if remain == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: Starting from `offset`, all elements of the slice have been set.
|
||||
let digits = unsafe { slice_buffer_to_str(&buf, offset) };
|
||||
f.pad_integral(true, $prefix, digits)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::$Trait for $Signed {
|
||||
/// Format signed integers in the two’s-complement form.
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::$Trait::fmt(&self.cast_unsigned(), f)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! integer {
|
||||
($Int:ident, $Uint:ident) => {
|
||||
int_base! { fmt::Binary for $Int as $Uint -> Binary }
|
||||
int_base! { fmt::Octal for $Int as $Uint -> Octal }
|
||||
int_base! { fmt::LowerHex for $Int as $Uint -> LowerHex }
|
||||
int_base! { fmt::UpperHex for $Int as $Uint -> UpperHex }
|
||||
|
||||
int_base! { fmt::Binary for $Uint as $Uint -> Binary }
|
||||
int_base! { fmt::Octal for $Uint as $Uint -> Octal }
|
||||
int_base! { fmt::LowerHex for $Uint as $Uint -> LowerHex }
|
||||
int_base! { fmt::UpperHex for $Uint as $Uint -> UpperHex }
|
||||
/// Formatting of integers with a non-decimal radix.
|
||||
macro_rules! radix_integers {
|
||||
($Signed:ident, $Unsigned:ident) => {
|
||||
radix_integer! { fmt::Binary for $Signed and $Unsigned, "0b", b"01" }
|
||||
radix_integer! { fmt::Octal for $Signed and $Unsigned, "0o", b"01234567" }
|
||||
radix_integer! { fmt::LowerHex for $Signed and $Unsigned, "0x", b"0123456789abcdef" }
|
||||
radix_integer! { fmt::UpperHex for $Signed and $Unsigned, "0x", b"0123456789ABCDEF" }
|
||||
};
|
||||
}
|
||||
integer! { isize, usize }
|
||||
integer! { i8, u8 }
|
||||
integer! { i16, u16 }
|
||||
integer! { i32, u32 }
|
||||
integer! { i64, u64 }
|
||||
integer! { i128, u128 }
|
||||
radix_integers! { isize, usize }
|
||||
radix_integers! { i8, u8 }
|
||||
radix_integers! { i16, u16 }
|
||||
radix_integers! { i32, u32 }
|
||||
radix_integers! { i64, u64 }
|
||||
radix_integers! { i128, u128 }
|
||||
|
||||
macro_rules! impl_Debug {
|
||||
($($T:ident)*) => {
|
||||
|
|
@ -205,16 +119,21 @@ unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
|
|||
}
|
||||
|
||||
macro_rules! impl_Display {
|
||||
($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
|
||||
($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
|
||||
|
||||
$(
|
||||
const _: () = {
|
||||
assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
|
||||
assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
|
||||
};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for $unsigned {
|
||||
impl fmt::Display for $Unsigned {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
{
|
||||
const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
|
||||
// Buffer decimals for $unsigned with right alignment.
|
||||
const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
|
||||
// Buffer decimals for self with right alignment.
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
|
||||
|
||||
// SAFETY: `buf` is always big enough to contain all the digits.
|
||||
|
|
@ -222,18 +141,20 @@ macro_rules! impl_Display {
|
|||
}
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
{
|
||||
$gen_name(self.$conv_fn(), true, f)
|
||||
// Lossless conversion (with as) is asserted at the top of
|
||||
// this macro.
|
||||
${concat($fmt_fn, _small)}(*self as $T, true, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for $signed {
|
||||
impl fmt::Display for $Signed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
{
|
||||
const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1;
|
||||
// Buffer decimals for $unsigned with right alignment.
|
||||
const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
|
||||
// Buffer decimals for self with right alignment.
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
|
||||
|
||||
// SAFETY: `buf` is always big enough to contain all the digits.
|
||||
|
|
@ -241,13 +162,15 @@ macro_rules! impl_Display {
|
|||
}
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
{
|
||||
return $gen_name(self.unsigned_abs().$conv_fn(), *self >= 0, f);
|
||||
// Lossless conversion (with as) is asserted at the top of
|
||||
// this macro.
|
||||
return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
impl $unsigned {
|
||||
impl $Unsigned {
|
||||
#[doc(hidden)]
|
||||
#[unstable(
|
||||
feature = "fmt_internals",
|
||||
|
|
@ -268,7 +191,7 @@ macro_rules! impl_Display {
|
|||
let mut remain = self;
|
||||
|
||||
// Format per four digits from the lookup table.
|
||||
// Four digits need a 16-bit $unsigned or wider.
|
||||
// Four digits need a 16-bit $Unsigned or wider.
|
||||
while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
|
||||
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N
|
||||
// and the while condition ensures at least 4 more decimals.
|
||||
|
|
@ -327,7 +250,7 @@ macro_rules! impl_Display {
|
|||
}
|
||||
}
|
||||
|
||||
impl $signed {
|
||||
impl $Signed {
|
||||
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
|
||||
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
|
||||
///
|
||||
|
|
@ -337,15 +260,15 @@ macro_rules! impl_Display {
|
|||
/// #![feature(int_format_into)]
|
||||
/// use core::fmt::NumBuffer;
|
||||
///
|
||||
#[doc = concat!("let n = 0", stringify!($signed), ";")]
|
||||
#[doc = concat!("let n = 0", stringify!($Signed), ";")]
|
||||
/// let mut buf = NumBuffer::new();
|
||||
/// assert_eq!(n.format_into(&mut buf), "0");
|
||||
///
|
||||
#[doc = concat!("let n1 = 32", stringify!($signed), ";")]
|
||||
#[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
|
||||
/// assert_eq!(n1.format_into(&mut buf), "32");
|
||||
///
|
||||
#[doc = concat!("let n2 = ", stringify!($signed::MAX), ";")]
|
||||
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($signed::MAX), ".to_string());")]
|
||||
#[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
|
||||
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_format_into", issue = "138215")]
|
||||
pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
|
||||
|
|
@ -358,7 +281,9 @@ macro_rules! impl_Display {
|
|||
}
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
{
|
||||
offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf);
|
||||
// Lossless conversion (with as) is asserted at the top of
|
||||
// this macro.
|
||||
offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
|
||||
}
|
||||
// Only difference between signed and unsigned are these 4 lines.
|
||||
if self < 0 {
|
||||
|
|
@ -370,7 +295,7 @@ macro_rules! impl_Display {
|
|||
}
|
||||
}
|
||||
|
||||
impl $unsigned {
|
||||
impl $Unsigned {
|
||||
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
|
||||
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
|
||||
///
|
||||
|
|
@ -380,15 +305,15 @@ macro_rules! impl_Display {
|
|||
/// #![feature(int_format_into)]
|
||||
/// use core::fmt::NumBuffer;
|
||||
///
|
||||
#[doc = concat!("let n = 0", stringify!($unsigned), ";")]
|
||||
#[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
|
||||
/// let mut buf = NumBuffer::new();
|
||||
/// assert_eq!(n.format_into(&mut buf), "0");
|
||||
///
|
||||
#[doc = concat!("let n1 = 32", stringify!($unsigned), ";")]
|
||||
#[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
|
||||
/// assert_eq!(n1.format_into(&mut buf), "32");
|
||||
///
|
||||
#[doc = concat!("let n2 = ", stringify!($unsigned::MAX), ";")]
|
||||
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($unsigned::MAX), ".to_string());")]
|
||||
#[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
|
||||
#[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_format_into", issue = "138215")]
|
||||
pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
|
||||
|
|
@ -401,7 +326,9 @@ macro_rules! impl_Display {
|
|||
}
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
{
|
||||
offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf);
|
||||
// Lossless conversion (with as) is asserted at the top of
|
||||
// this macro.
|
||||
offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
|
||||
}
|
||||
// SAFETY: Starting from `offset`, all elements of the slice have been set.
|
||||
unsafe { slice_buffer_to_str(&buf.buf, offset) }
|
||||
|
|
@ -412,7 +339,7 @@ macro_rules! impl_Display {
|
|||
)*
|
||||
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize {
|
||||
fn ${concat($fmt_fn, _in_buf_small)}(mut n: $T, buf: &mut [MaybeUninit::<u8>]) -> usize {
|
||||
let mut curr = buf.len();
|
||||
|
||||
// SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
|
||||
|
|
@ -433,11 +360,11 @@ macro_rules! impl_Display {
|
|||
}
|
||||
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
fn $gen_name(n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1;
|
||||
fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
const MAX_DEC_N: usize = $T::MAX.ilog(10) as usize + 1;
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
|
||||
|
||||
let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf);
|
||||
let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
|
||||
// SAFETY: Starting from `offset`, all elements of the slice have been set.
|
||||
let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
|
||||
f.pad_integral(is_nonnegative, "", buf_slice)
|
||||
|
|
@ -446,9 +373,9 @@ macro_rules! impl_Display {
|
|||
}
|
||||
|
||||
macro_rules! impl_Exp {
|
||||
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
|
||||
fn $name(
|
||||
mut n: $u,
|
||||
($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
|
||||
fn $fmt_fn(
|
||||
mut n: $T,
|
||||
is_nonnegative: bool,
|
||||
upper: bool,
|
||||
f: &mut fmt::Formatter<'_>
|
||||
|
|
@ -582,32 +509,41 @@ macro_rules! impl_Exp {
|
|||
|
||||
$(
|
||||
#[stable(feature = "integer_exp_format", since = "1.42.0")]
|
||||
impl fmt::LowerExp for $t {
|
||||
#[allow(unused_comparisons)]
|
||||
impl fmt::LowerExp for $Signed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let is_nonnegative = *self >= 0;
|
||||
let n = if is_nonnegative {
|
||||
self.$conv_fn()
|
||||
*self as $T
|
||||
} else {
|
||||
// convert the negative num to positive by summing 1 to its 2s complement
|
||||
(!self.$conv_fn()).wrapping_add(1)
|
||||
self.unsigned_abs() as $T
|
||||
};
|
||||
$name(n, is_nonnegative, false, f)
|
||||
$fmt_fn(n, is_nonnegative, false, f)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "integer_exp_format", since = "1.42.0")]
|
||||
impl fmt::LowerExp for $Unsigned {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
$fmt_fn(*self as $T, true, false, f)
|
||||
}
|
||||
})*
|
||||
|
||||
$(
|
||||
#[stable(feature = "integer_exp_format", since = "1.42.0")]
|
||||
impl fmt::UpperExp for $t {
|
||||
#[allow(unused_comparisons)]
|
||||
impl fmt::UpperExp for $Signed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let is_nonnegative = *self >= 0;
|
||||
let n = if is_nonnegative {
|
||||
self.$conv_fn()
|
||||
*self as $T
|
||||
} else {
|
||||
// convert the negative num to positive by summing 1 to its 2s complement
|
||||
(!self.$conv_fn()).wrapping_add(1)
|
||||
self.unsigned_abs() as $T
|
||||
};
|
||||
$name(n, is_nonnegative, true, f)
|
||||
$fmt_fn(n, is_nonnegative, true, f)
|
||||
}
|
||||
}
|
||||
#[stable(feature = "integer_exp_format", since = "1.42.0")]
|
||||
impl fmt::UpperExp for $Unsigned {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
$fmt_fn(*self as $T, true, true, f)
|
||||
}
|
||||
})*
|
||||
};
|
||||
|
|
@ -623,37 +559,20 @@ impl_Debug! {
|
|||
#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
|
||||
mod imp {
|
||||
use super::*;
|
||||
impl_Display!(
|
||||
i8, u8,
|
||||
i16, u16,
|
||||
i32, u32,
|
||||
i64, u64,
|
||||
isize, usize,
|
||||
; as u64 via to_u64 named fmt_u64
|
||||
);
|
||||
impl_Exp!(
|
||||
i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
|
||||
as u64 via to_u64 named exp_u64
|
||||
);
|
||||
impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
|
||||
impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
|
||||
mod imp {
|
||||
use super::*;
|
||||
impl_Display!(
|
||||
i8, u8,
|
||||
i16, u16,
|
||||
i32, u32,
|
||||
isize, usize,
|
||||
; as u32 via to_u32 named fmt_u32);
|
||||
impl_Display!(
|
||||
i64, u64,
|
||||
; as u64 via to_u64 named fmt_u64);
|
||||
impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
|
||||
impl_Display!(i64, u64; as u64 into display_u64);
|
||||
|
||||
impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
|
||||
impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
|
||||
impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
|
||||
impl_Exp!(i64, u64; as u64 into exp_u64);
|
||||
}
|
||||
impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
|
||||
impl_Exp!(i128, u128; as u128 into exp_u128);
|
||||
|
||||
const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -162,3 +162,183 @@ fn write_u8_min(bh: &mut Bencher) {
|
|||
black_box(format!("{}", black_box(u8::MIN)));
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i8_bin(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:b}", black_box(0_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(100_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(-100_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(1_i8 << 4)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i16_bin(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:b}", black_box(0_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(100_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(-100_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(1_i16 << 8)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i32_bin(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:b}", black_box(0_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(100_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(-100_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(1_i32 << 16)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i64_bin(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:b}", black_box(0_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(100_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(-100_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(1_i64 << 32)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i128_bin(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:b}", black_box(0_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(100_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(-100_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:b}", black_box(1_i128 << 64)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i8_oct(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:o}", black_box(0_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(100_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(-100_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(1_i8 << 4)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i16_oct(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:o}", black_box(0_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(100_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(-100_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(1_i16 << 8)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i32_oct(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:o}", black_box(0_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(100_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(-100_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(1_i32 << 16)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i64_oct(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:o}", black_box(0_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(100_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(-100_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(1_i64 << 32)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i128_oct(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:o}", black_box(0_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(100_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(-100_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:o}", black_box(1_i128 << 64)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i8_hex(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:x}", black_box(0_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(100_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(-100_i8)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(1_i8 << 4)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i16_hex(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:x}", black_box(0_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(100_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(-100_i16)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(1_i16 << 8)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i32_hex(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:x}", black_box(0_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(100_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(-100_i32)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(1_i32 << 16)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i64_hex(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:x}", black_box(0_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(100_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(-100_i64)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(1_i64 << 32)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn write_i128_hex(bh: &mut Bencher) {
|
||||
let mut buf = String::with_capacity(256);
|
||||
bh.iter(|| {
|
||||
write!(black_box(&mut buf), "{:x}", black_box(0_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(100_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(-100_i128)).unwrap();
|
||||
write!(black_box(&mut buf), "{:x}", black_box(1_i128 << 64)).unwrap();
|
||||
black_box(&mut buf).clear();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue