Created
February 26, 2021 13:57
-
-
Save 3Hren/e2c3e41a3b83f1b8e5aa8b6323463495 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 0..4294967295 | |
// buf.len() after stripping leading zeros must be >= 16. | |
pub fn parse_u32(buf: &[u8]) -> Result<(&[u8], u32), ExpectedDecNumber> { | |
const RANGES: [u8; 16] = [b'0', b'9', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; | |
const SHUFFLE_MASK: [u8; 16] = [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]; | |
const FACTOR1: [u16; 8] = [1, 10, 100, 1000, 1, 10, 100, 1000]; | |
const FACTOR2: [u32; 4] = [1, 10000, 100000000, 0]; | |
let mut zi = 0; | |
let len = buf.len(); | |
if len == 0 { | |
return Err(ExpectedDecNumber); | |
} | |
// Strip leading zeros. | |
while zi < len && buf[zi] == b'0' { | |
zi += 1; | |
} | |
let xmm2 = unsafe { _mm_setzero_si128() }; | |
let ranges16 = unsafe { _mm_loadu_si128(RANGES.as_ptr() as *const _) }; | |
let xmm1 = unsafe { buf.as_ptr().offset(zi as isize) } as usize; | |
let xmm1 = unsafe { _mm_loadu_si128(xmm1 as *const _) }; | |
let idx = unsafe { | |
_mm_cmpistri( | |
ranges16, | |
xmm1, | |
_SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY, | |
) | |
}; | |
if idx == 0 { | |
return if zi > 0 { | |
Ok((&buf[zi..], 0)) | |
} else { | |
Err(ExpectedDecNumber) | |
}; | |
} | |
let i = idx - 16; | |
// Reverse. | |
let xmm0 = unsafe { Xmm { i32: i }.xmm }; | |
let xmm0 = unsafe { _mm_shuffle_epi8(xmm0, xmm2) }; | |
let shuffle16 = unsafe { _mm_loadu_si128(SHUFFLE_MASK.as_ptr() as *const _) }; | |
let xmm0 = unsafe { _mm_add_epi8(xmm0, shuffle16) }; | |
let xmm1 = unsafe { _mm_shuffle_epi8(xmm1, xmm0) }; | |
let xmm0 = unsafe { Xmm { u8: b'0' }.xmm }; | |
let xmm0 = unsafe { _mm_shuffle_epi8(xmm0, xmm2) }; | |
// Subtract b'0'. | |
let xmm1 = unsafe { _mm_subs_epu8(xmm1, xmm0) }; | |
let xmm0 = xmm1; | |
// Multiply by 10^0, 10^1, ... 10^5, 0, 0, 0. | |
let xmm0 = unsafe { _mm_unpacklo_epi8(xmm0, xmm2) }; | |
let xmm1 = unsafe { _mm_unpackhi_epi8(xmm1, xmm2) }; | |
let factor16 = unsafe { _mm_loadu_si128(FACTOR1.as_ptr() as *const _) }; | |
let xmm0 = unsafe { _mm_madd_epi16(xmm0, factor16) }; | |
let xmm1 = unsafe { _mm_madd_epi16(xmm1, factor16) }; | |
let xmm0 = unsafe { _mm_hadd_epi32(xmm0, xmm1) }; | |
let factor16l = unsafe { _mm_loadu_si128(FACTOR2.as_ptr() as *const _) }; | |
let xmm0 = unsafe { _mm_mullo_epi32(xmm0, factor16l) }; | |
let xmm1 = unsafe { _mm_shuffle_epi32(xmm0, 0b11101110) }; | |
let xmm0 = unsafe { _mm_add_epi32(xmm0, xmm1) }; | |
let xmm1 = unsafe { _mm_shuffle_epi32(xmm0, 0b01010101) }; | |
let xmm0 = unsafe { _mm_add_epi32(xmm0, xmm1) }; | |
let out = unsafe { Xmm { xmm: xmm0 }.u32 }; | |
Ok((&buf[idx as usize..], out)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment