Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add no-panic feature to confirm no panicking codepaths #29

Merged
merged 1 commit into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ jobs:
toolchain: ${{matrix.rust}}
- run: cargo build
- run: cargo test
- run: cargo build --tests --features no-panic --release
if: matrix.rust == 'nightly'

miri:
name: Miri
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/dtolnay/dtoa"
rust-version = "1.36"

[dependencies]
no-panic = { version = "0.1", optional = true }

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
19 changes: 18 additions & 1 deletion src/diyfp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
// the License.

use core::ops::{Mul, Sub};
#[cfg(feature = "no-panic")]
use no_panic::no_panic;

#[derive(Copy, Clone, Debug)]
pub struct DiyFp<F, E> {
Expand All @@ -35,6 +37,7 @@ pub struct DiyFp<F, E> {
}

impl<F, E> DiyFp<F, E> {
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn new(f: F, e: E) -> Self {
DiyFp { f, e }
}
Expand All @@ -45,6 +48,8 @@ where
F: Sub<F, Output = F>,
{
type Output = Self;

#[cfg_attr(feature = "no-panic", no_panic)]
fn sub(self, rhs: Self) -> Self {
DiyFp {
f: self.f - rhs.f,
Expand All @@ -55,6 +60,8 @@ where

impl Mul for DiyFp<u32, i32> {
type Output = Self;

#[cfg_attr(feature = "no-panic", no_panic)]
fn mul(self, rhs: Self) -> Self {
let mut tmp = self.f as u64 * rhs.f as u64;
tmp += 1u64 << 31; // mult_round
Expand All @@ -67,6 +74,8 @@ impl Mul for DiyFp<u32, i32> {

impl Mul for DiyFp<u64, isize> {
type Output = Self;

#[cfg_attr(feature = "no-panic", no_panic)]
fn mul(self, rhs: Self) -> Self {
let m32 = 0xFFFFFFFFu64;
let a = self.f >> 32;
Expand Down Expand Up @@ -127,6 +136,7 @@ macro_rules! diyfp {
}
}
*/
#[cfg_attr(feature = "no-panic", no_panic)]
unsafe fn from(d: $fty) -> Self {
let u: $mask_type = mem::transmute(d);

Expand Down Expand Up @@ -156,6 +166,7 @@ macro_rules! diyfp {
return res;
}
*/
#[cfg_attr(feature = "no-panic", no_panic)]
fn normalize(self) -> DiyFp {
let mut res = self;
while (res.f & (1 << ($diy_significand_size - 1))) == 0 {
Expand All @@ -181,6 +192,7 @@ macro_rules! diyfp {
return res;
}
*/
#[cfg_attr(feature = "no-panic", no_panic)]
fn normalize_boundary(self) -> DiyFp {
let mut res = self;
while (res.f & $hidden_bit << 1) == 0 {
Expand Down Expand Up @@ -210,6 +222,7 @@ macro_rules! diyfp {
*minus = mi;
}
*/
#[cfg_attr(feature = "no-panic", no_panic)]
fn normalized_boundaries(self) -> (DiyFp, DiyFp) {
let pl = DiyFp::new((self.f << 1) + 1, self.e - 1).normalize_boundary();
let mut mi = if self.f == $hidden_bit {
Expand Down Expand Up @@ -238,6 +251,7 @@ macro_rules! diyfp {
}
*/
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
fn get_cached_power(e: $expty) -> (DiyFp, isize) {
let dk = (3 - $diy_significand_size - e) as f64 * 0.30102999566398114f64
- ($min_power + 1) as f64;
Expand All @@ -250,7 +264,10 @@ macro_rules! diyfp {
let k = -($min_power + (index << 3) as isize);

(
DiyFp::new($cached_powers_f[index], $cached_powers_e[index] as $expty),
DiyFp::new(*unsafe { $cached_powers_f.get_unchecked(index) }, *unsafe {
$cached_powers_e.get_unchecked(index)
}
as $expty),
k,
)
}
Expand Down
26 changes: 23 additions & 3 deletions src/dtoa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
// the License.

use core::ptr;
#[cfg(feature = "no-panic")]
use no_panic::no_panic;

/*
inline unsigned CountDecimalDigit32(uint32_t n) {
Expand All @@ -47,6 +49,7 @@ inline unsigned CountDecimalDigit32(uint32_t n) {
*/

#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn count_decimal_digit32(n: u32) -> usize {
if n < 10 {
1
Expand Down Expand Up @@ -98,6 +101,7 @@ inline char* WriteExponent(int K, char* buffer) {
*/

#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
unsafe fn write_exponent(mut k: isize, mut buffer: *mut u8) -> *mut u8 {
if k < 0 {
*buffer = b'-';
Expand Down Expand Up @@ -127,6 +131,7 @@ inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
*/

#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
pub unsafe fn prettify(buffer: *mut u8, length: isize, k: isize) -> *mut u8 {
let kk = length + k; // 10^(kk-1) <= v < 10^kk

Expand Down Expand Up @@ -301,6 +306,7 @@ macro_rules! dtoa {
*/

#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
unsafe fn grisu_round(buffer: *mut u8, len: isize, delta: $sigty, mut rest: $sigty, ten_kappa: $sigty, wp_w: $sigty) {
while rest < wp_w && delta - rest >= ten_kappa &&
(rest + ten_kappa < wp_w || // closer
Expand All @@ -323,6 +329,7 @@ macro_rules! dtoa {

// Returns length and k.
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
unsafe fn digit_gen(w: DiyFp, mp: DiyFp, mut delta: $sigty, buffer: *mut u8, mut k: isize) -> (isize, isize) {
static POW10: [$sigty; 10] = [ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 ];
let one = DiyFp::new(1 << -mp.e, mp.e);
Expand Down Expand Up @@ -377,10 +384,10 @@ macro_rules! dtoa {
len += 1;
}
kappa -= 1;
let tmp = (p1 as $sigty << -one.e) + p2;
let tmp = ((p1 as $sigty) << -one.e) + p2;
if tmp <= delta {
k += kappa as isize;
grisu_round(buffer, len, delta, tmp, POW10[kappa] << -one.e, wp_w.f);
grisu_round(buffer, len, delta, tmp, *POW10.get_unchecked(kappa) << -one.e, wp_w.f);
return (len, k);
}
}
Expand Down Expand Up @@ -416,7 +423,18 @@ macro_rules! dtoa {
if p2 < delta {
k += kappa as isize;
let index = -(kappa as isize);
grisu_round(buffer, len, delta, p2, one.f, wp_w.f * if index < 9 { POW10[-(kappa as isize) as usize] } else { 0 });
grisu_round(
buffer,
len,
delta,
p2,
one.f,
wp_w.f * if index < 9 {
*POW10.get_unchecked(-(kappa as isize) as usize)
} else {
0
},
);
return (len, k);
}
}
Expand All @@ -440,6 +458,7 @@ macro_rules! dtoa {

// Returns length and k.
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
unsafe fn grisu2(value: $fty, buffer: *mut u8) -> (isize, isize) {
let v = DiyFp::from(value);
let (w_m, w_p) = v.normalized_boundaries();
Expand Down Expand Up @@ -478,6 +497,7 @@ macro_rules! dtoa {
*/

#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
unsafe fn dtoa(buf: &mut Buffer, mut value: $fty) -> &str {
if value == 0.0 {
if value.is_sign_negative() {
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ mod dtoa;
use core::mem::{self, MaybeUninit};
use core::slice;
use core::str;
#[cfg(feature = "no-panic")]
use no_panic::no_panic;

const NAN: &str = "NaN";
const INFINITY: &str = "inf";
Expand Down Expand Up @@ -95,6 +97,7 @@ impl Buffer {
/// This is a cheap operation; you don't need to worry about reusing buffers
/// for efficiency.
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn new() -> Buffer {
let bytes = [MaybeUninit::<u8>::uninit(); 25];
Buffer { bytes }
Expand All @@ -111,6 +114,7 @@ impl Buffer {
/// If your input is known to be finite, you may get better performance by
/// calling the `format_finite` method instead of `format` to avoid the
/// checks for special cases.
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn format<F: Float>(&mut self, value: F) -> &str {
if value.is_nonfinite() {
value.format_nonfinite()
Expand All @@ -134,6 +138,7 @@ impl Buffer {
/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite
/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan
/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn format_finite<F: Float>(&mut self, value: F) -> &str {
value.write(self)
}
Expand All @@ -158,13 +163,15 @@ mod private {

impl private::Sealed for f32 {
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
fn is_nonfinite(self) -> bool {
const EXP_MASK: u32 = 0x7f800000;
let bits = self.to_bits();
bits & EXP_MASK == EXP_MASK
}

#[cold]
#[cfg_attr(feature = "no-panic", no_panic)]
fn format_nonfinite(self) -> &'static str {
const MANTISSA_MASK: u32 = 0x007fffff;
const SIGN_MASK: u32 = 0x80000000;
Expand Down Expand Up @@ -202,13 +209,15 @@ impl private::Sealed for f32 {

impl private::Sealed for f64 {
#[inline]
#[cfg_attr(feature = "no-panic", no_panic)]
fn is_nonfinite(self) -> bool {
const EXP_MASK: u64 = 0x7ff0000000000000;
let bits = self.to_bits();
bits & EXP_MASK == EXP_MASK
}

#[cold]
#[cfg_attr(feature = "no-panic", no_panic)]
fn format_nonfinite(self) -> &'static str {
const MANTISSA_MASK: u64 = 0x000fffffffffffff;
const SIGN_MASK: u64 = 0x8000000000000000;
Expand Down