diff --git a/src/common.rs b/src/common.rs index 66f3435..6d3138b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -90,11 +90,8 @@ impl<'a> AsciiStr<'a> { #[inline] pub fn read_u64(&self) -> u64 { debug_assert!(self.check_len(8)); - let mut value = 0_u64; - let src = self.ptr; - let dst = &mut value as *mut _ as *mut u8; - unsafe { ptr::copy_nonoverlapping(src, dst, 8) }; - value + let src = self.ptr as *const u64; + u64::from_le(unsafe { ptr::read_unaligned(src) }) } #[inline] @@ -159,26 +156,22 @@ pub trait ByteSlice: AsRef<[u8]> + AsMut<[u8]> { #[inline] fn read_u64(&self) -> u64 { debug_assert!(self.as_ref().len() >= 8); - let mut value = 0_u64; - let src = self.as_ref().as_ptr(); - let dst = &mut value as *mut _ as *mut u8; - unsafe { ptr::copy_nonoverlapping(src, dst, 8) }; - value + let src = self.as_ref().as_ptr() as *const u64; + u64::from_le(unsafe { ptr::read_unaligned(src) }) } #[inline] fn write_u64(&mut self, value: u64) { debug_assert!(self.as_ref().len() >= 8); - let src = &value as *const _ as *const u8; - let dst = self.as_mut().as_mut_ptr(); - unsafe { ptr::copy_nonoverlapping(src, dst, 8) }; + let dst = self.as_mut().as_mut_ptr() as *mut u64; + unsafe { ptr::write_unaligned(dst, u64::to_le(value)) }; } } impl ByteSlice for [u8] {} #[inline] -pub fn is_8digits_le(v: u64) -> bool { +pub fn is_8digits(v: u64) -> bool { let a = v.wrapping_add(0x4646_4646_4646_4646); let b = v.wrapping_sub(0x3030_3030_3030_3030); (a | b) & 0x8080_8080_8080_8080 == 0 @@ -212,3 +205,23 @@ impl AdjustedMantissa { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_read_write_u64() { + let bytes = b"01234567"; + let string = AsciiStr::new(bytes); + let int = string.read_u64(); + assert_eq!(int, 0x3736353433323130); + + let int = bytes.read_u64(); + assert_eq!(int, 0x3736353433323130); + + let mut slc = [0u8; 8]; + slc.write_u64(0x3736353433323130); + assert_eq!(&slc, bytes); + } +} diff --git a/src/decimal.rs b/src/decimal.rs index c36d6d3..2e7aaa0 100644 --- a/src/decimal.rs +++ b/src/decimal.rs @@ -1,6 +1,6 @@ use core::fmt::{self, Debug}; -use crate::common::{is_8digits_le, parse_digits, ByteSlice}; +use crate::common::{is_8digits, parse_digits, ByteSlice}; #[derive(Clone)] pub struct Decimal { @@ -204,16 +204,14 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal { if d.num_digits == 0 { s = s.skip_chars(b'0'); } - if cfg!(target_endian = "little") { - while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS { - let v = s.read_u64(); - if !is_8digits_le(v) { - break; - } - d.digits[d.num_digits..].write_u64(v - 0x3030_3030_3030_3030); - d.num_digits += 8; - s = s.advance(8); + while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS { + let v = s.read_u64(); + if !is_8digits(v) { + break; } + d.digits[d.num_digits..].write_u64(v - 0x3030_3030_3030_3030); + d.num_digits += 8; + s = s.advance(8); } parse_digits(&mut s, |digit| d.try_add_digit(digit)); d.decimal_point = s.len() as i32 - first.len() as i32; diff --git a/src/number.rs b/src/number.rs index 194cbf6..b3d95f5 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,4 +1,4 @@ -use crate::common::{is_8digits_le, AsciiStr, ByteSlice}; +use crate::common::{is_8digits, AsciiStr, ByteSlice}; use crate::float::Float; const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000; @@ -70,7 +70,7 @@ impl Number { } #[inline] -fn parse_8digits_le(mut v: u64) -> u64 { +fn parse_8digits(mut v: u64) -> u64 { const MASK: u64 = 0x0000_00FF_0000_00FF; const MUL1: u64 = 0x000F_4240_0000_0064; const MUL2: u64 = 0x0000_2710_0000_0001; @@ -98,22 +98,20 @@ fn try_parse_19digits(s: &mut AsciiStr<'_>, x: &mut u64) { } #[inline] -fn try_parse_8digits_le(s: &mut AsciiStr<'_>, x: &mut u64) { +fn try_parse_8digits(s: &mut AsciiStr<'_>, x: &mut u64) { // may cause overflows, to be handled later - if cfg!(target_endian = "little") { - if let Some(v) = s.try_read_u64() { - if is_8digits_le(v) { - *x = x - .wrapping_mul(1_0000_0000) - .wrapping_add(parse_8digits_le(v)); - s.step_by(8); - if let Some(v) = s.try_read_u64() { - if is_8digits_le(v) { - *x = x - .wrapping_mul(1_0000_0000) - .wrapping_add(parse_8digits_le(v)); - s.step_by(8); - } + if let Some(v) = s.try_read_u64() { + if is_8digits(v) { + *x = x + .wrapping_mul(1_0000_0000) + .wrapping_add(parse_8digits(v)); + s.step_by(8); + if let Some(v) = s.try_read_u64() { + if is_8digits(v) { + *x = x + .wrapping_mul(1_0000_0000) + .wrapping_add(parse_8digits(v)); + s.step_by(8); } } } @@ -180,7 +178,7 @@ pub fn parse_number(s: &[u8]) -> Option<(Number, usize)> { if s.check_first(b'.') { s.step(); let before = s; - try_parse_8digits_le(&mut s, &mut mantissa); + try_parse_8digits(&mut s, &mut mantissa); try_parse_digits(&mut s, &mut mantissa); n_after_dot = s.offset_from(&before); exponent = -n_after_dot as i64;