diff options
Diffstat (limited to 'third_party/rust/dtoa/src')
-rw-r--r-- | third_party/rust/dtoa/src/diyfp.rs | 253 | ||||
-rw-r--r-- | third_party/rust/dtoa/src/dtoa.rs | 509 | ||||
-rw-r--r-- | third_party/rust/dtoa/src/lib.rs | 205 |
3 files changed, 967 insertions, 0 deletions
diff --git a/third_party/rust/dtoa/src/diyfp.rs b/third_party/rust/dtoa/src/diyfp.rs new file mode 100644 index 0000000000..9d797657d6 --- /dev/null +++ b/third_party/rust/dtoa/src/diyfp.rs @@ -0,0 +1,253 @@ +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// --- +// +// The C++ implementation preserved here in comments is licensed as follows: +// +// Tencent is pleased to support the open source community by making RapidJSON +// available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All +// rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License +// at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +use std::ops; + +#[derive(Copy, Clone, Debug)] +pub struct DiyFp<F, E> { + pub f: F, + pub e: E, +} + +impl<F, E> DiyFp<F, E> { + pub fn new(f: F, e: E) -> Self { + DiyFp { f: f, e: e } + } +} + +impl ops::Mul for DiyFp<u32, i32> { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + let mut tmp = self.f as u64 * rhs.f as u64; + tmp += 1u64 << 31; // mult_round + DiyFp { + f: (tmp >> 32) as u32, + e: self.e + rhs.e + 32, + } + } +} + +impl ops::Mul for DiyFp<u64, isize> { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + let m32 = 0xFFFFFFFFu64; + let a = self.f >> 32; + let b = self.f & m32; + let c = rhs.f >> 32; + let d = rhs.f & m32; + let ac = a * c; + let bc = b * c; + let ad = a * d; + let bd = b * d; + let mut tmp = (bd >> 32) + (ad & m32) + (bc & m32); + tmp += 1u64 << 31; // mult_round + DiyFp { + f: ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), + e: self.e + rhs.e + 64, + } + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! diyfp {( + floating_type: $fty:ty, + significand_type: $sigty:ty, + exponent_type: $expty:ty, + + diy_significand_size: $diy_significand_size:expr, + significand_size: $significand_size:expr, + exponent_bias: $exponent_bias:expr, + mask_type: $mask_type:ty, + exponent_mask: $exponent_mask:expr, + significand_mask: $significand_mask:expr, + hidden_bit: $hidden_bit:expr, + cached_powers_f: $cached_powers_f:expr, + cached_powers_e: $cached_powers_e:expr, + min_power: $min_power:expr, +) => { + +type DiyFp = diyfp::DiyFp<$sigty, $expty>; + +impl DiyFp { + // Preconditions: + // `d` must have a positive sign and must not be infinity or NaN. + /* + explicit DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } + */ + unsafe fn from(d: $fty) -> Self { + let u: $mask_type = mem::transmute(d); + + let biased_e = ((u & $exponent_mask) >> $significand_size) as $expty; + let significand = u & $significand_mask; + if biased_e != 0 { + DiyFp { + f: significand + $hidden_bit, + e: biased_e - $exponent_bias - $significand_size, + } + } else { + DiyFp { + f: significand, + e: 1 - $exponent_bias - $significand_size, + } + } + } + + // Normalizes so that the highest bit of the diy significand is 1. + /* + DiyFp Normalize() const { + DiyFp res = *this; + while (!(res.f & (static_cast<uint64_t>(1) << 63))) { + res.f <<= 1; + res.e--; + } + return res; + } + */ + fn normalize(self) -> DiyFp { + let mut res = self; + while (res.f & (1 << ($diy_significand_size - 1))) == 0 { + res.f <<= 1; + res.e -= 1; + } + res + } + + // Normalizes so that the highest bit of the diy significand is 1. + // + // Precondition: + // `self.f` must be no more than 2 bits longer than the f64 significand. + /* + DiyFp NormalizeBoundary() const { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; + } + */ + fn normalize_boundary(self) -> DiyFp { + let mut res = self; + while (res.f & $hidden_bit << 1) == 0 { + res.f <<= 1; + res.e -= 1; + } + res.f <<= $diy_significand_size - $significand_size - 2; + res.e -= $diy_significand_size - $significand_size - 2; + res + } + + // Normalizes `self - e` and `self + e` where `e` is half of the least + // significant digit of `self`. The plus is normalized so that the highest + // bit of the diy significand is 1. The minus is normalized so that it has + // the same exponent as the plus. + // + // Preconditions: + // `self` must have been returned directly from `DiyFp::from_f64`. + // `self.f` must not be zero. + /* + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + */ + 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 { + DiyFp::new((self.f << 2) - 1, self.e - 2) + } else { + DiyFp::new((self.f << 1) - 1, self.e - 1) + }; + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + (mi, pl) + } +} + +impl ops::Sub for DiyFp { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + DiyFp { + f: self.f - rhs.f, + e: self.e, + } + } +} + +/* +inline DiyFp GetCachedPower(int e, int* K) { + //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast<int>(dk); + if (dk - k > 0.0) + k++; + + unsigned index = static_cast<unsigned>((k >> 3) + 1); + *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table + + return GetCachedPowerByIndex(index); +} +*/ +#[inline] +fn get_cached_power(e: $expty) -> (DiyFp, isize) { + let dk = (3 - $diy_significand_size - e) as f64 * 0.30102999566398114f64 - ($min_power + 1) as f64; + let mut k = dk as isize; + if dk - k as f64 > 0.0 { + k += 1; + } + + let index = ((k >> 3) + 1) as usize; + let k = -($min_power + (index << 3) as isize); + + (DiyFp::new($cached_powers_f[index], $cached_powers_e[index] as $expty), k) +} + +}} diff --git a/third_party/rust/dtoa/src/dtoa.rs b/third_party/rust/dtoa/src/dtoa.rs new file mode 100644 index 0000000000..8642a38920 --- /dev/null +++ b/third_party/rust/dtoa/src/dtoa.rs @@ -0,0 +1,509 @@ +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// --- +// +// The C++ implementation preserved here in comments is licensed as follows: +// +// Tencent is pleased to support the open source community by making RapidJSON +// available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All +// rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License +// at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#[doc(hidden)] +#[macro_export] +macro_rules! dtoa {( + floating_type: $fty:ty, + significand_type: $sigty:ty, + exponent_type: $expty:ty, + $($diyfp_param:ident: $diyfp_value:tt,)* +) => { + +diyfp! { + floating_type: $fty, + significand_type: $sigty, + exponent_type: $expty, + $($diyfp_param: $diyfp_value,)* +}; + +/* +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } +} +*/ + +#[inline] +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 + wp_w - rest > rest + ten_kappa - wp_w) { + *buffer.offset(len - 1) -= 1; + rest += ten_kappa; + } +} + +/* +inline unsigned CountDecimalDigit32(uint32_t n) { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; +} +*/ + +#[inline] +fn count_decimal_digit32(n: u32) -> usize { + if n < 10 { 1 } + else if n < 100 { 2 } + else if n < 1000 { 3 } + else if n < 10000 { 4 } + else if n < 100000 { 5 } + else if n < 1000000 { 6 } + else if n < 10000000 { 7 } + else if n < 100000000 { 8 } + // Will not reach 10 digits in digit_gen() + else { 9 } +} + +/* +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; +*/ + +// Returns length and k. +#[inline] +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); + let wp_w = mp - w; + let mut p1 = (mp.f >> -one.e) as u32; + let mut p2 = mp.f & (one.f - 1); + let mut kappa = count_decimal_digit32(p1); // kappa in [0, 9] + let mut len = 0; + + /* + while (kappa > 0) { + uint32_t d = 0; + switch (kappa) { + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default:; + } + if (d || *len) + buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); + kappa--; + uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + */ + while kappa > 0 { + let mut d = 0u32; + match kappa { + 9 => { d = p1 / 100000000; p1 %= 100000000; } + 8 => { d = p1 / 10000000; p1 %= 10000000; } + 7 => { d = p1 / 1000000; p1 %= 1000000; } + 6 => { d = p1 / 100000; p1 %= 100000; } + 5 => { d = p1 / 10000; p1 %= 10000; } + 4 => { d = p1 / 1000; p1 %= 1000; } + 3 => { d = p1 / 100; p1 %= 100; } + 2 => { d = p1 / 10; p1 %= 10; } + 1 => { d = p1; p1 = 0; } + _ => {} + } + if d != 0 || len != 0 { + *buffer.offset(len) = b'0' + d as u8; + len += 1; + } + kappa -= 1; + 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); + return (len, k); + } + } + + // kappa = 0 + /* + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast<char>(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = static_cast<char>('0' + d); + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + int index = -static_cast<int>(kappa); + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0)); + return; + } + } + */ + loop { + p2 *= 10; + delta *= 10; + let d = (p2 >> -one.e) as u8; + if d != 0 || len != 0 { + *buffer.offset(len) = b'0' + d; + len += 1; + } + p2 &= one.f - 1; + kappa = kappa.wrapping_sub(1); + 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 }); + return (len, k); + } + } +} + +/* +inline void Grisu2(double value, char* buffer, int* length, int* K) { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} +*/ + +// Returns length and k. +#[inline] +unsafe fn grisu2(value: $fty, buffer: *mut u8) -> (isize, isize) { + let v = DiyFp::from(value); + let (w_m, w_p) = v.normalized_boundaries(); + + let (c_mk, k) = get_cached_power(w_p.e); + let w = v.normalize() * c_mk; + let mut wp = w_p * c_mk; + let mut wm = w_m * c_mk; + wm.f += 1; + wp.f -= 1; + digit_gen(w, wp, wp.f - wm.f, buffer, k) +} + +/* +inline char* WriteExponent(int K, char* buffer) { + if (K < 0) { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) { + *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100)); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = static_cast<char>('0' + static_cast<char>(K)); + + return buffer; +} +*/ + +#[inline] +unsafe fn write_exponent(mut k: isize, mut buffer: *mut u8) -> *mut u8 { + if k < 0 { + *buffer = b'-'; + buffer = buffer.offset(1); + k = -k; + } + + if k >= 100 { + *buffer = b'0' + (k / 100) as u8; + k %= 100; + let d = DEC_DIGITS_LUT.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, buffer.offset(1), 2); + buffer.offset(3) + } else if k >= 10 { + let d = DEC_DIGITS_LUT.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, buffer, 2); + buffer.offset(2) + } else { + *buffer = b'0' + k as u8; + buffer.offset(1) + } +} + +/* +inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { + const int kk = length + k; // 10^(kk-1) <= v < 10^kk +*/ + +#[inline] +unsafe fn prettify(buffer: *mut u8, length: isize, k: isize) -> *mut u8 { + let kk = length + k; // 10^(kk-1) <= v < 10^kk + + /* + if (0 <= k && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + */ + if 0 <= k && kk <= 21 { + // 1234e7 -> 12340000000 + for i in length..kk { + *buffer.offset(i) = b'0'; + } + *buffer.offset(kk) = b'.'; + *buffer.offset(kk + 1) = b'0'; + buffer.offset(kk + 2) + } + + /* + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); + buffer[kk] = '.'; + if (0 > k + maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[kk + 2]; // Reserve one zero + } + else + return &buffer[length + 1]; + } + */ + else if 0 < kk && kk <= 21 { + // 1234e-2 -> 12.34 + ptr::copy(buffer.offset(kk), buffer.offset(kk + 1), (length - kk) as usize); + *buffer.offset(kk) = b'.'; + if 0 > k + MAX_DECIMAL_PLACES { + // When MAX_DECIMAL_PLACES = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for i in (kk + 2 .. kk + MAX_DECIMAL_PLACES + 1).rev() { + if *buffer.offset(i) != b'0' { + return buffer.offset(i + 1); + } + } + buffer.offset(kk + 2) // Reserve one zero + } else { + buffer.offset(length + 1) + } + } + + /* + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length)); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + if (length - kk > maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = maxDecimalPlaces + 1; i > 2; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[3]; // Reserve one zero + } + else + return &buffer[length + offset]; + } + */ + else if -6 < kk && kk <= 0 { + // 1234e-6 -> 0.001234 + let offset = 2 - kk; + ptr::copy(buffer, buffer.offset(offset), length as usize); + *buffer = b'0'; + *buffer.offset(1) = b'.'; + for i in 2..offset { + *buffer.offset(i) = b'0'; + } + if length - kk > MAX_DECIMAL_PLACES { + // When MAX_DECIMAL_PLACES = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for i in (3 .. MAX_DECIMAL_PLACES + 2).rev() { + if *buffer.offset(i) != b'0' { + return buffer.offset(i + 1); + } + } + buffer.offset(3) // Reserve one zero + } else { + buffer.offset(length + offset) + } + } + + /* + else if (kk < -maxDecimalPlaces) { + // Truncate to zero + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + */ + else if kk < -MAX_DECIMAL_PLACES { + *buffer = b'0'; + *buffer.offset(1) = b'.'; + *buffer.offset(2) = b'0'; + buffer.offset(3) + } + + /* + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + */ + else if length == 1 { + // 1e30 + *buffer.offset(1) = b'e'; + write_exponent(kk - 1, buffer.offset(2)) + } + + /* + else { + // 1234e30 -> 1.234e33 + std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1)); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } + */ + else { + // 1234e30 -> 1.234e33 + ptr::copy(buffer.offset(1), buffer.offset(2), (length - 1) as usize); + *buffer.offset(1) = b'.'; + *buffer.offset(length + 1) = b'e'; + write_exponent(kk - 1, buffer.offset(length + 2)) + } +} + +/* +inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); + Double d(value); + if (d.IsZero()) { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K, maxDecimalPlaces); + } +} +*/ + +#[allow(deprecated)] +#[inline] +unsafe fn dtoa<W: io::Write>(mut wr: W, mut value: $fty) -> io::Result<usize> { + if value == 0.0 { + if value.is_sign_negative() { + match wr.write_all(b"-0.0") { + Ok(()) => Ok(4), + Err(e) => Err(e), + } + } else { + match wr.write_all(b"0.0") { + Ok(()) => Ok(3), + Err(e) => Err(e), + } + } + } else { + let negative = value < 0.0; + if negative { + if let Err(e) = wr.write_all(b"-") { + return Err(e); + } + value = -value; + } + let mut buffer: [u8; 24] = mem::uninitialized(); + let buf_ptr = buffer.as_mut_ptr(); + let (length, k) = grisu2(value, buf_ptr); + let end = prettify(buf_ptr, length, k); + let len = end as usize - buf_ptr as usize; + if let Err(e) = wr.write_all(slice::from_raw_parts(buf_ptr, len)) { + return Err(e); + } + if negative { + Ok(len + 1) + } else { + Ok(len) + } + } +} + +}} diff --git a/third_party/rust/dtoa/src/lib.rs b/third_party/rust/dtoa/src/lib.rs new file mode 100644 index 0000000000..aed62f500b --- /dev/null +++ b/third_party/rust/dtoa/src/lib.rs @@ -0,0 +1,205 @@ +//! [![github]](https://github.com/dtolnay/dtoa) [![crates-io]](https://crates.io/crates/dtoa) [![docs-rs]](https://docs.rs/dtoa) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K +//! +//! <br> +//! +//! This crate provides fast functions for printing floating-point primitives to +//! an [`io::Write`]. The implementation is a straightforward Rust port of [Milo +//! Yip]'s C++ implementation [dtoa.h]. The original C++ code of each function +//! is included in comments. +//! +//! See also [`itoa`] for printing integer primitives. +//! +//! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +//! [Milo Yip]: https://github.com/miloyip +//! [dtoa.h]: https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/internal/dtoa.h +//! [`itoa`]: https://github.com/dtolnay/itoa +//! +//! <br> +//! +//! ## Performance (lower is better) +//! +//! ![performance](https://raw.githubusercontent.com/dtolnay/dtoa/master/performance.png) +//! +//! <br> +//! +//! # Examples +//! +//! ```edition2018 +//! use std::io; +//! +//! fn main() -> io::Result<()> { +//! // Write to a vector or other io::Write. +//! let mut buf = Vec::new(); +//! dtoa::write(&mut buf, 2.71828f64)?; +//! println!("{:?}", buf); +//! +//! // Write to a stack buffer. +//! let mut bytes = [b'\0'; 20]; +//! let n = dtoa::write(&mut bytes[..], 2.71828f64)?; +//! println!("{:?}", &bytes[..n]); +//! +//! Ok(()) +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/dtoa/0.4.8")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr( + feature = "cargo-clippy", + allow( + cast_lossless, + cast_possible_truncation, + if_not_else, + missing_errors_doc, + range_plus_one, + shadow_unrelated, + transmute_float_to_int, + unreadable_literal, + unseparated_literal_suffix + ) +)] + +#[macro_use] mod diyfp; +#[macro_use] mod dtoa; + +use std::{io, mem, ops, ptr, slice}; + +/// Write float to an `io::Write`. +#[inline] +pub fn write<W: io::Write, V: Floating>(wr: W, value: V) -> io::Result<usize> { + value.write(wr) +} + +/// An floating point number that can be formatted by `dtoa::write`. +pub trait Floating { + fn write<W: io::Write>(self, wr: W) -> io::Result<usize>; +} + +impl Floating for f32 { + fn write<W: io::Write>(self, wr: W) -> io::Result<usize> { + dtoa! { + floating_type: f32, + significand_type: u32, + exponent_type: i32, + + diy_significand_size: 32, + significand_size: 23, + exponent_bias: 0x7F, + mask_type: u32, + exponent_mask: 0x7F800000, + significand_mask: 0x007FFFFF, + hidden_bit: 0x00800000, + cached_powers_f: CACHED_POWERS_F_32, + cached_powers_e: CACHED_POWERS_E_32, + min_power: (-36), + }; + unsafe { dtoa(wr, self) } + } +} + +impl Floating for f64 { + fn write<W: io::Write>(self, wr: W) -> io::Result<usize> { + dtoa! { + floating_type: f64, + significand_type: u64, + exponent_type: isize, + + diy_significand_size: 64, + significand_size: 52, + exponent_bias: 0x3FF, + mask_type: u64, + exponent_mask: 0x7FF0000000000000, + significand_mask: 0x000FFFFFFFFFFFFF, + hidden_bit: 0x0010000000000000, + cached_powers_f: CACHED_POWERS_F_64, + cached_powers_e: CACHED_POWERS_E_64, + min_power: (-348), + }; + unsafe { dtoa(wr, self) } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +const MAX_DECIMAL_PLACES: isize = 324; + +static DEC_DIGITS_LUT: [u8; 200] = *b"\ + 0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; + +// 10^-36, 10^-28, ..., 10^52 +static CACHED_POWERS_F_32: [u32; 12] = [ + 0xaa242499, 0xfd87b5f3, 0xbce50865, 0x8cbccc09, + 0xd1b71759, 0x9c400000, 0xe8d4a510, 0xad78ebc6, + 0x813f3979, 0xc097ce7c, 0x8f7e32ce, 0xd5d238a5, +]; + +static CACHED_POWERS_E_32: [i16; 12] = [ + -151, -125, -98, -71, -45, -18, 8, 35, 62, 88, 115, 141, +]; + +// 10^-348, 10^-340, ..., 10^340 +static CACHED_POWERS_F_64: [u64; 87] = [ + 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, + 0x8b16fb203055ac76, 0xcf42894a5dce35ea, + 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, + 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, + 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, 0xaecc49914078536d, + 0x823c12795db6ce57, 0xc21094364dfb5637, + 0x9096ea6f3848984f, 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, 0xef340a98172aace5, + 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, + 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, + 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, + 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8, + 0x87625f056c7c4a8b, 0xc9bcff6034c13053, + 0x964e858c91ba2655, 0xdff9772470297ebd, + 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, + 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, 0x993fe2c6d07b7fac, + 0xe45c10c42a2b3b06, 0xaa242499697392d3, + 0xfd87b5f28300ca0e, 0xbce5086492111aeb, + 0x8cbccc096f5088cc, 0xd1b71758e219652c, + 0x9c40000000000000, 0xe8d4a51000000000, + 0xad78ebc5ac620000, 0x813f3978f8940984, + 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, + 0xd5d238a4abe98068, 0x9f4f2726179a2245, + 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, 0xc45d1df942711d9a, + 0x924d692ca61be758, 0xda01ee641a708dea, + 0xa26da3999aef774a, 0xf209787bb47d6b85, + 0xb454e4a179dd1877, 0x865b86925b9bc5c2, + 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3, + 0xde469fbd99a05fe3, 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, + 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, + 0x98165af37b2153df, 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, + 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a, + 0xd01fef10a657842c, 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, 0xac2820d9623bf429, + 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, + 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, + 0xaf87023b9bf0ee6b, +]; +static CACHED_POWERS_E_64: [i16; 87] = [ + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066, +]; |