From cc94b383a2764f4d4e7054c2c9fd21aa8542aa15 Mon Sep 17 00:00:00 2001 From: Kyle Clemens Date: Tue, 8 Oct 2019 16:01:34 +0100 Subject: [PATCH 1/3] refactor: use MaybeUninit over mem::uninitialized --- src/buffer/mod.rs | 12 +++++++----- src/d2s.rs | 30 +++++++++++++++++++----------- src/pretty/mod.rs | 16 ++++++++++------ 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 5731aea..7cb3e7a 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -1,4 +1,4 @@ -use core::{mem, slice, str}; +use core::{mem::{self, MaybeUninit}, slice, str}; use raw; @@ -20,7 +20,7 @@ const NEG_INFINITY: &'static str = "-inf"; /// ``` #[derive(Copy, Clone)] pub struct Buffer { - bytes: [u8; 24], + bytes: [MaybeUninit; 24], } impl Buffer { @@ -30,7 +30,9 @@ impl Buffer { #[cfg_attr(feature = "no-panic", no_panic)] pub fn new() -> Self { Buffer { - bytes: unsafe { mem::uninitialized() }, + // assume_init is safe here, since this is an array of MaybeUninit, which does not need + // to be initialized. + bytes: unsafe { MaybeUninit::uninit().assume_init() }, } } @@ -74,9 +76,9 @@ impl Buffer { #[cfg_attr(feature = "no-panic", no_panic)] pub fn format_finite(&mut self, f: F) -> &str { unsafe { - let n = f.write_to_ryu_buffer(&mut self.bytes[0]); + let n = f.write_to_ryu_buffer(self.bytes[0].as_mut_ptr()); debug_assert!(n <= self.bytes.len()); - let slice = slice::from_raw_parts(&self.bytes[0], n); + let slice = slice::from_raw_parts(self.bytes[0].as_ptr(), n); str::from_utf8_unchecked(slice) } } diff --git a/src/d2s.rs b/src/d2s.rs index 46fe54b..3407bf2 100644 --- a/src/d2s.rs +++ b/src/d2s.rs @@ -18,7 +18,7 @@ // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. -use core::mem; +use core::{mem::MaybeUninit, ptr}; use common::*; #[cfg(not(feature = "small"))] @@ -48,12 +48,14 @@ fn mul_shift_all( m: u64, mul: &(u64, u64), j: u32, - vp: &mut u64, - vm: &mut u64, + vp: *mut u64, + vm: *mut u64, mm_shift: u32, ) -> u64 { - *vp = mul_shift(4 * m + 2, mul, j); - *vm = mul_shift(4 * m - 1 - mm_shift as u64, mul, j); + unsafe { + ptr::write(vp, mul_shift(4 * m + 2, mul, j)); + ptr::write(vm, mul_shift(4 * m - 1 - mm_shift as u64, mul, j)); + } mul_shift(4 * m, mul, j) } @@ -177,8 +179,10 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { // Step 3: Convert to a decimal power base using 128-bit arithmetic. let mut vr: u64; - let mut vp: u64 = unsafe { mem::uninitialized() }; - let mut vm: u64 = unsafe { mem::uninitialized() }; + let mut vp: u64; + let mut vm: u64; + let mut vp_uninit: MaybeUninit = MaybeUninit::uninit(); + let mut vm_uninit: MaybeUninit = MaybeUninit::uninit(); let e10: i32; let mut vm_is_trailing_zeros = false; let mut vr_is_trailing_zeros = false; @@ -201,10 +205,12 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize) }, i as u32, - &mut vp, - &mut vm, + vp_uninit.as_mut_ptr(), + vm_uninit.as_mut_ptr(), mm_shift, ); + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; if q <= 21 { // This should use q <= 22, but I think 21 is also safe. Smaller values // may still be safe, but it's more difficult to reason about them. @@ -241,10 +247,12 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { DOUBLE_POW5_SPLIT.get_unchecked(i as usize) }, j as u32, - &mut vp, - &mut vm, + vp_uninit.as_mut_ptr(), + vm_uninit.as_mut_ptr(), mm_shift, ); + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; if q <= 1 { // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. // mv = 4 * m2, so it always has at least two trailing 0 bits. diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index 9184893..3dead1b 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -38,12 +38,14 @@ use no_panic::no_panic; /// ## Example /// /// ```edition2018 +/// use std::mem::MaybeUninit; +/// /// let f = 1.234f64; /// /// unsafe { -/// let mut buffer: [u8; 24] = std::mem::uninitialized(); -/// let len = ryu::raw::format64(f, buffer.as_mut_ptr()); -/// let slice = std::slice::from_raw_parts(buffer.as_ptr(), len); +/// let mut buffer: [MaybeUninit; 24] = MaybeUninit::uninit().assume_init(); +/// let len = ryu::raw::format64(f, buffer.as_mut_ptr() as *mut u8); +/// let slice = std::slice::from_raw_parts(buffer.as_ptr() as *const u8, len); /// let print = std::str::from_utf8_unchecked(slice); /// assert_eq!(print, "1.234"); /// } @@ -143,12 +145,14 @@ pub unsafe fn format64(f: f64, result: *mut u8) -> usize { /// ## Example /// /// ```edition2018 +/// use std::mem::MaybeUninit; +/// /// let f = 1.234f32; /// /// unsafe { -/// let mut buffer: [u8; 16] = std::mem::uninitialized(); -/// let len = ryu::raw::format32(f, buffer.as_mut_ptr()); -/// let slice = std::slice::from_raw_parts(buffer.as_ptr(), len); +/// let mut buffer: [MaybeUninit; 16] = MaybeUninit::uninit().assume_init(); +/// let len = ryu::raw::format32(f, buffer.as_mut_ptr() as *mut u8); +/// let slice = std::slice::from_raw_parts(buffer.as_ptr() as *const u8, len); /// let print = std::str::from_utf8_unchecked(slice); /// assert_eq!(print, "1.234"); /// } From a8dda073c50795e8445bb27ed4d0f100e93a5445 Mon Sep 17 00:00:00 2001 From: Kyle Clemens Date: Tue, 8 Oct 2019 18:25:18 +0100 Subject: [PATCH 2/3] refactor: support uninitialized and MaybeUninit --- build.rs | 6 ++++++ src/buffer/mod.rs | 39 ++++++++++++++++++++++++++++++++++--- src/d2s.rs | 49 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/build.rs b/build.rs index b1ea2f1..7b639e7 100644 --- a/build.rs +++ b/build.rs @@ -28,6 +28,12 @@ fn main() { if minor >= 27 { println!("cargo:rustc-cfg=must_use_return"); } + + // MaybeUninit stabilized in Rust 1.36: + // https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html + if minor >= 36 { + println!("cargo:rustc-cfg=maybe_uninit"); + } } fn rustc_minor_version() -> Option { diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 7cb3e7a..579e36d 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -1,4 +1,7 @@ -use core::{mem::{self, MaybeUninit}, slice, str}; +use core::{mem, slice, str}; + +#[cfg(maybe_uninit)] +use core::mem::MaybeUninit; use raw; @@ -20,7 +23,10 @@ const NEG_INFINITY: &'static str = "-inf"; /// ``` #[derive(Copy, Clone)] pub struct Buffer { + #[cfg(maybe_uninit)] bytes: [MaybeUninit; 24], + #[cfg(not(maybe_uninit))] + bytes: [u8; 24], } impl Buffer { @@ -32,7 +38,10 @@ impl Buffer { Buffer { // assume_init is safe here, since this is an array of MaybeUninit, which does not need // to be initialized. + #[cfg(maybe_uninit)] bytes: unsafe { MaybeUninit::uninit().assume_init() }, + #[cfg(not(maybe_uninit))] + bytes: unsafe { mem::uninitialized() }, } } @@ -76,12 +85,36 @@ impl Buffer { #[cfg_attr(feature = "no-panic", no_panic)] pub fn format_finite(&mut self, f: F) -> &str { unsafe { - let n = f.write_to_ryu_buffer(self.bytes[0].as_mut_ptr()); + let n = f.write_to_ryu_buffer(self.first_byte_pointer_mut()); debug_assert!(n <= self.bytes.len()); - let slice = slice::from_raw_parts(self.bytes[0].as_ptr(), n); + let slice = slice::from_raw_parts(self.first_byte_pointer(), n); str::from_utf8_unchecked(slice) } } + + #[inline] + #[cfg(maybe_uninit)] + fn first_byte_pointer(&self) -> *const u8 { + self.bytes[0].as_ptr() + } + + #[inline] + #[cfg(not(maybe_uninit))] + fn first_byte_pointer(&self) -> *const u8 { + &self.bytes[0] as *const u8 + } + + #[inline] + #[cfg(maybe_uninit)] + fn first_byte_pointer_mut(&mut self) -> *mut u8 { + self.bytes[0].as_mut_ptr() + } + + #[inline] + #[cfg(not(maybe_uninit))] + fn first_byte_pointer_mut(&mut self) -> *mut u8 { + &mut self.bytes[0] as *mut u8 + } } impl Default for Buffer { diff --git a/src/d2s.rs b/src/d2s.rs index 3407bf2..9c4243b 100644 --- a/src/d2s.rs +++ b/src/d2s.rs @@ -18,7 +18,13 @@ // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. -use core::{mem::MaybeUninit, ptr}; +use core::ptr; + +#[cfg(maybe_uninit)] +use core::mem::MaybeUninit; + +#[cfg(not(maybe_uninit))] +use core::mem; use common::*; #[cfg(not(feature = "small"))] @@ -181,7 +187,14 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { let mut vr: u64; let mut vp: u64; let mut vm: u64; + #[cfg(not(maybe_uninit))] + { + vp = unsafe { mem::uninitialized() }; + vm = unsafe { mem::uninitialized() }; + } + #[cfg(maybe_uninit)] let mut vp_uninit: MaybeUninit = MaybeUninit::uninit(); + #[cfg(maybe_uninit)] let mut vm_uninit: MaybeUninit = MaybeUninit::uninit(); let e10: i32; let mut vm_is_trailing_zeros = false; @@ -205,12 +218,21 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize) }, i as u32, - vp_uninit.as_mut_ptr(), - vm_uninit.as_mut_ptr(), + #[cfg(maybe_uninit)] + { vp_uninit.as_mut_ptr() }, + #[cfg(not(maybe_uninit))] + { &mut vp as *mut u64 }, + #[cfg(maybe_uninit)] + { vm_uninit.as_mut_ptr() }, + #[cfg(not(maybe_uninit))] + { &mut vm as *mut u64 }, mm_shift, ); - vp = unsafe { vp_uninit.assume_init() }; - vm = unsafe { vm_uninit.assume_init() }; + #[cfg(maybe_uninit)] + { + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; + } if q <= 21 { // This should use q <= 22, but I think 21 is also safe. Smaller values // may still be safe, but it's more difficult to reason about them. @@ -247,12 +269,21 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { DOUBLE_POW5_SPLIT.get_unchecked(i as usize) }, j as u32, - vp_uninit.as_mut_ptr(), - vm_uninit.as_mut_ptr(), + #[cfg(maybe_uninit)] + { vp_uninit.as_mut_ptr() }, + #[cfg(not(maybe_uninit))] + { &mut vp as *mut u64 }, + #[cfg(maybe_uninit)] + { vm_uninit.as_mut_ptr() }, + #[cfg(not(maybe_uninit))] + { &mut vm as *mut u64 }, mm_shift, ); - vp = unsafe { vp_uninit.assume_init() }; - vm = unsafe { vm_uninit.assume_init() }; + #[cfg(maybe_uninit)] + { + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; + } if q <= 1 { // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. // mv = 4 * m2, so it always has at least two trailing 0 bits. From 73721593038a67bd25e562a068b8f339c53c47fe Mon Sep 17 00:00:00 2001 From: Kyle Clemens Date: Tue, 8 Oct 2019 20:08:32 -0400 Subject: [PATCH 3/3] fix: correct old rust builds --- src/buffer/mod.rs | 14 ++++++++------ src/d2s.rs | 8 ++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 579e36d..fee80be 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -35,13 +35,15 @@ impl Buffer { #[inline] #[cfg_attr(feature = "no-panic", no_panic)] pub fn new() -> Self { + // assume_init is safe here, since this is an array of MaybeUninit, which does not need + // to be initialized. + #[cfg(maybe_uninit)] + let bytes = unsafe { MaybeUninit::uninit().assume_init() }; + #[cfg(not(maybe_uninit))] + let bytes = unsafe { mem::uninitialized() }; + Buffer { - // assume_init is safe here, since this is an array of MaybeUninit, which does not need - // to be initialized. - #[cfg(maybe_uninit)] - bytes: unsafe { MaybeUninit::uninit().assume_init() }, - #[cfg(not(maybe_uninit))] - bytes: unsafe { mem::uninitialized() }, + bytes: bytes, } } diff --git a/src/d2s.rs b/src/d2s.rs index 9c4243b..375e3cd 100644 --- a/src/d2s.rs +++ b/src/d2s.rs @@ -221,11 +221,11 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { #[cfg(maybe_uninit)] { vp_uninit.as_mut_ptr() }, #[cfg(not(maybe_uninit))] - { &mut vp as *mut u64 }, + { &mut vp }, #[cfg(maybe_uninit)] { vm_uninit.as_mut_ptr() }, #[cfg(not(maybe_uninit))] - { &mut vm as *mut u64 }, + { &mut vm }, mm_shift, ); #[cfg(maybe_uninit)] @@ -272,11 +272,11 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { #[cfg(maybe_uninit)] { vp_uninit.as_mut_ptr() }, #[cfg(not(maybe_uninit))] - { &mut vp as *mut u64 }, + { &mut vp }, #[cfg(maybe_uninit)] { vm_uninit.as_mut_ptr() }, #[cfg(not(maybe_uninit))] - { &mut vm as *mut u64 }, + { &mut vm }, mm_shift, ); #[cfg(maybe_uninit)]