More functions that can never panic

This commit is contained in:
David Tolnay
2018-08-04 14:39:35 -07:00
parent 1a39060255
commit 10f0b1725d
7 changed files with 37 additions and 0 deletions
+8
View File
@@ -2,6 +2,9 @@ use core::{mem, str};
use pretty;
#[cfg(feature = "no-panic")]
use no_panic::no_panic;
#[derive(Copy, Clone)]
pub struct Buffer {
bytes: [u8; 24],
@@ -9,12 +12,14 @@ pub struct Buffer {
impl Buffer {
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn new() -> Self {
Buffer {
bytes: unsafe { mem::uninitialized() },
}
}
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn format<F: Float>(&mut self, f: F) -> &str {
f.write_to_ryu_buffer(self)
}
@@ -22,6 +27,7 @@ impl Buffer {
impl Default for Buffer {
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
fn default() -> Self {
Buffer::new()
}
@@ -34,6 +40,7 @@ pub trait Float: Sealed {
impl Float for f32 {
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
fn write_to_ryu_buffer(self, buffer: &mut Buffer) -> &str {
unsafe {
let n = pretty::f2s_buffered_n(self, &mut buffer.bytes[0]);
@@ -46,6 +53,7 @@ impl Float for f32 {
impl Float for f64 {
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
fn write_to_ryu_buffer(self, buffer: &mut Buffer) -> &str {
unsafe {
let n = pretty::d2s_buffered_n(self, &mut buffer.bytes[0]);
+4
View File
@@ -21,6 +21,7 @@
use core::ptr;
// Returns e == 0 ? 1 : ceil(log_2(5^e)).
#[cfg_attr(feature = "no-panic", inline)]
pub fn pow5bits(e: i32) -> u32 {
// This approximation works up to the point that the multiplication overflows at e = 3529.
// If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater
@@ -31,6 +32,7 @@ pub fn pow5bits(e: i32) -> u32 {
}
// Returns floor(log_10(2^e)).
#[cfg_attr(feature = "no-panic", inline)]
pub fn log10_pow2(e: i32) -> i32 {
// The first value this approximation fails for is 2^1651 which is just greater than 10^297.
debug_assert!(e >= 0);
@@ -39,6 +41,7 @@ pub fn log10_pow2(e: i32) -> i32 {
}
// Returns floor(log_10(5^e)).
#[cfg_attr(feature = "no-panic", inline)]
pub fn log10_pow5(e: i32) -> i32 {
// The first value this approximation fails for is 5^2621 which is just greater than 10^1832.
debug_assert!(e >= 0);
@@ -46,6 +49,7 @@ pub fn log10_pow5(e: i32) -> i32 {
((e as u32 * 732923) >> 20) as i32
}
#[cfg_attr(feature = "no-panic", inline)]
pub unsafe fn copy_special_str(result: *mut u8, sign: bool) -> usize {
if sign {
ptr::write(result, b'-');
+8
View File
@@ -33,6 +33,7 @@ pub const DOUBLE_EXPONENT_BITS: u32 = 11;
const DOUBLE_POW5_INV_BITCOUNT: i32 = 122;
const DOUBLE_POW5_BITCOUNT: i32 = 121;
#[cfg_attr(feature = "no-panic", inline)]
fn pow5_factor(mut value: u64) -> i32 {
let mut count = 0i32;
loop {
@@ -48,23 +49,27 @@ fn pow5_factor(mut value: u64) -> i32 {
}
// Returns true if value is divisible by 5^p.
#[cfg_attr(feature = "no-panic", inline)]
fn multiple_of_power_of_5(value: u64, p: u32) -> bool {
// I tried a case distinction on p, but there was no performance difference.
pow5_factor(value) >= p as i32
}
// Returns true if value is divisible by 2^p.
#[cfg_attr(feature = "no-panic", inline)]
fn multiple_of_power_of_2(value: u64, p: u32) -> bool {
// return __builtin_ctz(value) >= p;
(value & ((1u64 << (p - 1)) - 1)) == 0
}
#[cfg_attr(feature = "no-panic", inline)]
fn mul_shift(m: u64, mul: &(u64, u64), j: u32) -> u64 {
let b0 = m as u128 * mul.0 as u128;
let b2 = m as u128 * mul.1 as u128;
(((b0 >> 64) + b2) >> (j - 64)) as u64
}
#[cfg_attr(feature = "no-panic", inline)]
fn mul_shift_all(
m: u64,
mul: &(u64, u64),
@@ -78,6 +83,7 @@ fn mul_shift_all(
mul_shift(4 * m, mul, j)
}
#[cfg_attr(feature = "no-panic", inline)]
pub fn decimal_length(v: u64) -> u32 {
// This is slightly faster than a loop.
// The average output length is 16.38 digits, so we check high-to-low.
@@ -128,6 +134,7 @@ pub struct FloatingDecimal64 {
pub exponent: i32,
}
#[cfg_attr(feature = "no-panic", inline)]
pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
let bias = (1u32 << (DOUBLE_EXPONENT_BITS - 1)) - 1;
@@ -279,6 +286,7 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
}
}
#[cfg_attr(feature = "no-panic", inline)]
unsafe fn to_chars(v: FloatingDecimal64, sign: bool, result: *mut u8) -> usize {
// Step 5: Print the decimal representation.
let mut index = 0isize;
+8
View File
@@ -117,6 +117,7 @@ static FLOAT_POW5_SPLIT: [u64; 47] = [
2019483917365790221,
];
#[cfg_attr(feature = "no-panic", inline)]
fn pow5_factor(mut value: u32) -> i32 {
let mut count = 0i32;
loop {
@@ -132,12 +133,14 @@ fn pow5_factor(mut value: u32) -> i32 {
}
// Returns true if value is divisible by 5^p.
#[cfg_attr(feature = "no-panic", inline)]
fn multiple_of_power_of_5(value: u32, p: i32) -> bool {
pow5_factor(value) >= p
}
// It seems to be slightly faster to avoid uint128_t here, although the
// generated code for uint128_t looks slightly nicer.
#[cfg_attr(feature = "no-panic", inline)]
fn mul_shift(m: u32, factor: u64, shift: i32) -> u32 {
debug_assert!(shift > 32);
@@ -154,16 +157,19 @@ fn mul_shift(m: u32, factor: u64, shift: i32) -> u32 {
shifted_sum as u32
}
#[cfg_attr(feature = "no-panic", inline)]
fn mul_pow5_inv_div_pow2(m: u32, q: u32, j: i32) -> u32 {
debug_assert!(q < FLOAT_POW5_INV_SPLIT.len() as u32);
unsafe { mul_shift(m, *FLOAT_POW5_INV_SPLIT.get_unchecked(q as usize), j) }
}
#[cfg_attr(feature = "no-panic", inline)]
fn mul_pow5_div_pow2(m: u32, i: u32, j: i32) -> u32 {
debug_assert!(i < FLOAT_POW5_SPLIT.len() as u32);
unsafe { mul_shift(m, *FLOAT_POW5_SPLIT.get_unchecked(i as usize), j) }
}
#[cfg_attr(feature = "no-panic", inline)]
pub fn decimal_length(v: u32) -> u32 {
// Function precondition: v is not a 10-digit number.
// (9 digits are sufficient for round-tripping.)
@@ -196,6 +202,7 @@ pub struct FloatingDecimal32 {
pub exponent: i32,
}
#[cfg_attr(feature = "no-panic", inline)]
pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
let bias = (1u32 << (FLOAT_EXPONENT_BITS - 1)) - 1;
@@ -330,6 +337,7 @@ pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
}
}
#[cfg_attr(feature = "no-panic", inline)]
unsafe fn to_chars(v: FloatingDecimal32, sign: bool, result: *mut u8) -> usize {
// Step 5: Print the decimal representation.
let mut index = 0isize;
+2
View File
@@ -2,6 +2,7 @@ use core::ptr;
use digit_table::*;
#[cfg_attr(feature = "no-panic", inline)]
pub unsafe fn write_exponent3(mut k: isize, mut result: *mut u8) -> usize {
let sign = k < 0;
if sign {
@@ -26,6 +27,7 @@ pub unsafe fn write_exponent3(mut k: isize, mut result: *mut u8) -> usize {
}
}
#[cfg_attr(feature = "no-panic", inline)]
pub unsafe fn write_exponent2(mut k: isize, mut result: *mut u8) -> usize {
let sign = k < 0;
if sign {
+2
View File
@@ -2,6 +2,7 @@ use core::ptr;
use digit_table::*;
#[cfg_attr(feature = "no-panic", inline)]
pub unsafe fn write_mantissa_long(mut output: u64, mut result: *mut u8) {
if (output >> 32) != 0 {
// One expensive 64-bit division.
@@ -24,6 +25,7 @@ pub unsafe fn write_mantissa_long(mut output: u64, mut result: *mut u8) {
write_mantissa(output as u32, result);
}
#[cfg_attr(feature = "no-panic", inline)]
pub unsafe fn write_mantissa(mut output: u32, mut result: *mut u8) {
while output >= 10_000 {
let c = (output - 10_000 * (output / 10_000)) as u32;
+5
View File
@@ -8,7 +8,11 @@ use self::mantissa::*;
use d2s::{self, *};
use f2s::{self, *};
#[cfg(feature = "no-panic")]
use no_panic::no_panic;
#[must_use]
#[cfg_attr(feature = "no-panic", no_panic)]
pub unsafe fn d2s_buffered_n(f: f64, result: *mut u8) -> usize {
let bits = f.to_bits().to_le();
let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
@@ -80,6 +84,7 @@ pub unsafe fn d2s_buffered_n(f: f64, result: *mut u8) -> usize {
}
#[must_use]
#[cfg_attr(feature = "no-panic", no_panic)]
pub unsafe fn f2s_buffered_n(f: f32, result: *mut u8) -> usize {
let bits = f.to_bits().to_le();
let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;