Skip to content

Commit ec1b7d4

Browse files
authored
Merge pull request #27 from Alexhuszagh/read_u64
Added read_u64 optimizations to big endian.
2 parents 0c714bb + bc9ed2e commit ec1b7d4

File tree

3 files changed

+51
-42
lines changed

3 files changed

+51
-42
lines changed

src/common.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,8 @@ impl<'a> AsciiStr<'a> {
9090
#[inline]
9191
pub fn read_u64(&self) -> u64 {
9292
debug_assert!(self.check_len(8));
93-
let mut value = 0_u64;
94-
let src = self.ptr;
95-
let dst = &mut value as *mut _ as *mut u8;
96-
unsafe { ptr::copy_nonoverlapping(src, dst, 8) };
97-
value
93+
let src = self.ptr as *const u64;
94+
u64::from_le(unsafe { ptr::read_unaligned(src) })
9895
}
9996

10097
#[inline]
@@ -159,26 +156,22 @@ pub trait ByteSlice: AsRef<[u8]> + AsMut<[u8]> {
159156
#[inline]
160157
fn read_u64(&self) -> u64 {
161158
debug_assert!(self.as_ref().len() >= 8);
162-
let mut value = 0_u64;
163-
let src = self.as_ref().as_ptr();
164-
let dst = &mut value as *mut _ as *mut u8;
165-
unsafe { ptr::copy_nonoverlapping(src, dst, 8) };
166-
value
159+
let src = self.as_ref().as_ptr() as *const u64;
160+
u64::from_le(unsafe { ptr::read_unaligned(src) })
167161
}
168162

169163
#[inline]
170164
fn write_u64(&mut self, value: u64) {
171165
debug_assert!(self.as_ref().len() >= 8);
172-
let src = &value as *const _ as *const u8;
173-
let dst = self.as_mut().as_mut_ptr();
174-
unsafe { ptr::copy_nonoverlapping(src, dst, 8) };
166+
let dst = self.as_mut().as_mut_ptr() as *mut u64;
167+
unsafe { ptr::write_unaligned(dst, u64::to_le(value)) };
175168
}
176169
}
177170

178171
impl ByteSlice for [u8] {}
179172

180173
#[inline]
181-
pub fn is_8digits_le(v: u64) -> bool {
174+
pub fn is_8digits(v: u64) -> bool {
182175
let a = v.wrapping_add(0x4646_4646_4646_4646);
183176
let b = v.wrapping_sub(0x3030_3030_3030_3030);
184177
(a | b) & 0x8080_8080_8080_8080 == 0
@@ -212,3 +205,23 @@ impl AdjustedMantissa {
212205
}
213206
}
214207
}
208+
209+
#[cfg(test)]
210+
mod tests {
211+
use super::*;
212+
213+
#[test]
214+
fn test_read_write_u64() {
215+
let bytes = b"01234567";
216+
let string = AsciiStr::new(bytes);
217+
let int = string.read_u64();
218+
assert_eq!(int, 0x3736353433323130);
219+
220+
let int = bytes.read_u64();
221+
assert_eq!(int, 0x3736353433323130);
222+
223+
let mut slc = [0u8; 8];
224+
slc.write_u64(0x3736353433323130);
225+
assert_eq!(&slc, bytes);
226+
}
227+
}

src/decimal.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::fmt::{self, Debug};
22

3-
use crate::common::{is_8digits_le, parse_digits, ByteSlice};
3+
use crate::common::{is_8digits, parse_digits, ByteSlice};
44

55
#[derive(Clone)]
66
pub struct Decimal {
@@ -204,16 +204,14 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
204204
if d.num_digits == 0 {
205205
s = s.skip_chars(b'0');
206206
}
207-
if cfg!(target_endian = "little") {
208-
while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS {
209-
let v = s.read_u64();
210-
if !is_8digits_le(v) {
211-
break;
212-
}
213-
d.digits[d.num_digits..].write_u64(v - 0x3030_3030_3030_3030);
214-
d.num_digits += 8;
215-
s = s.advance(8);
207+
while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS {
208+
let v = s.read_u64();
209+
if !is_8digits(v) {
210+
break;
216211
}
212+
d.digits[d.num_digits..].write_u64(v - 0x3030_3030_3030_3030);
213+
d.num_digits += 8;
214+
s = s.advance(8);
217215
}
218216
parse_digits(&mut s, |digit| d.try_add_digit(digit));
219217
d.decimal_point = s.len() as i32 - first.len() as i32;

src/number.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::common::{is_8digits_le, AsciiStr, ByteSlice};
1+
use crate::common::{is_8digits, AsciiStr, ByteSlice};
22
use crate::float::Float;
33

44
const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000;
@@ -70,7 +70,7 @@ impl Number {
7070
}
7171

7272
#[inline]
73-
fn parse_8digits_le(mut v: u64) -> u64 {
73+
fn parse_8digits(mut v: u64) -> u64 {
7474
const MASK: u64 = 0x0000_00FF_0000_00FF;
7575
const MUL1: u64 = 0x000F_4240_0000_0064;
7676
const MUL2: u64 = 0x0000_2710_0000_0001;
@@ -98,22 +98,20 @@ fn try_parse_19digits(s: &mut AsciiStr<'_>, x: &mut u64) {
9898
}
9999

100100
#[inline]
101-
fn try_parse_8digits_le(s: &mut AsciiStr<'_>, x: &mut u64) {
101+
fn try_parse_8digits(s: &mut AsciiStr<'_>, x: &mut u64) {
102102
// may cause overflows, to be handled later
103-
if cfg!(target_endian = "little") {
104-
if let Some(v) = s.try_read_u64() {
105-
if is_8digits_le(v) {
106-
*x = x
107-
.wrapping_mul(1_0000_0000)
108-
.wrapping_add(parse_8digits_le(v));
109-
s.step_by(8);
110-
if let Some(v) = s.try_read_u64() {
111-
if is_8digits_le(v) {
112-
*x = x
113-
.wrapping_mul(1_0000_0000)
114-
.wrapping_add(parse_8digits_le(v));
115-
s.step_by(8);
116-
}
103+
if let Some(v) = s.try_read_u64() {
104+
if is_8digits(v) {
105+
*x = x
106+
.wrapping_mul(1_0000_0000)
107+
.wrapping_add(parse_8digits(v));
108+
s.step_by(8);
109+
if let Some(v) = s.try_read_u64() {
110+
if is_8digits(v) {
111+
*x = x
112+
.wrapping_mul(1_0000_0000)
113+
.wrapping_add(parse_8digits(v));
114+
s.step_by(8);
117115
}
118116
}
119117
}
@@ -180,7 +178,7 @@ pub fn parse_number(s: &[u8]) -> Option<(Number, usize)> {
180178
if s.check_first(b'.') {
181179
s.step();
182180
let before = s;
183-
try_parse_8digits_le(&mut s, &mut mantissa);
181+
try_parse_8digits(&mut s, &mut mantissa);
184182
try_parse_digits(&mut s, &mut mantissa);
185183
n_after_dot = s.offset_from(&before);
186184
exponent = -n_after_dot as i64;

0 commit comments

Comments
 (0)