From 10f0b1725d036fc95efa1a741a779fd055a667db Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 4 Aug 2018 14:39:35 -0700 Subject: [PATCH] More functions that can never panic --- src/buffer/mod.rs | 8 ++++++++ src/common.rs | 4 ++++ src/d2s.rs | 8 ++++++++ src/f2s.rs | 8 ++++++++ src/pretty/exponent.rs | 2 ++ src/pretty/mantissa.rs | 2 ++ src/pretty/mod.rs | 5 +++++ 7 files changed, 37 insertions(+) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index c683777..8e6a86a 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -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(&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]); diff --git a/src/common.rs b/src/common.rs index 034f86e..e28288e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -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'-'); diff --git a/src/d2s.rs b/src/d2s.rs index 0e98a12..74f8898 100644 --- a/src/d2s.rs +++ b/src/d2s.rs @@ -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; diff --git a/src/f2s.rs b/src/f2s.rs index 470df3d..fbb2b56 100644 --- a/src/f2s.rs +++ b/src/f2s.rs @@ -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; diff --git a/src/pretty/exponent.rs b/src/pretty/exponent.rs index 618c1a1..ab20825 100644 --- a/src/pretty/exponent.rs +++ b/src/pretty/exponent.rs @@ -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 { diff --git a/src/pretty/mantissa.rs b/src/pretty/mantissa.rs index 7b8afe7..4280232 100644 --- a/src/pretty/mantissa.rs +++ b/src/pretty/mantissa.rs @@ -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; diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index 1d4232f..b68bc36 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -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;