Created
September 21, 2018 16:23
-
-
Save DutchGhost/9f4488f19c3555426c15c28bd854e037 to your computer and use it in GitHub Desktop.
Atoi with exact_chunks
This file contains 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
#![feature(exact_chunks)] | |
const POW10_U64: [u64; 20] = [ | |
10_000_000_000_000_000_000, | |
1_000_000_000_000_000_000, | |
100_000_000_000_000_000, | |
10_000_000_000_000_000, | |
1_000_000_000_000_000, | |
100_000_000_000_000, | |
10_000_000_000_000, | |
1_000_000_000_000, | |
100_000_000_000, | |
10_000_000_000, | |
1_000_000_000, | |
100_000_000, | |
10_000_000, | |
1_000_000, | |
100_000, | |
10_000, | |
1_000, | |
100, | |
10, | |
1, | |
]; | |
const ASCII_TO_INT_FACTOR: u8 = 48; | |
macro_rules! try_parse_byte { | |
($byte:expr, $const_table:ident, $offset:expr) => {{ | |
let d = u64::from($byte.wrapping_sub(ASCII_TO_INT_FACTOR)); | |
//if the digit is greater than 9, something went terribly horribly wrong. | |
//return an Err(()) | |
if d > 9 { | |
return Err(()); | |
} | |
d * unsafe { $const_table.get_unchecked($offset) } | |
}}; | |
} | |
/* | |
Place ourselves into the correct position (const_table.len() - bytes.len() ), | |
Then for each byte, convert it to an integer, and multiply by the corresponding power of 10. (This is unrolled 4 times) | |
If converting the byte to an integer fails, return an Err(()) | |
Notice that the bytes get converted from the `largest` to the `smallest` (e.g: while converting "543", '5' is converted first) | |
*/ | |
#[inline(always)] | |
fn bytes_to_int(bytes: &[u8]) -> Result<u64, ()> { | |
let mut result: u64 = 0; | |
let mut chunks = bytes.exact_chunks(4); | |
let mut idx: usize = POW10_U64.len() - bytes.len(); | |
// The main loop, unrolled 4 times, using a match statement on the slice for each Iteration. | |
for chunk in chunks.by_ref() { | |
match chunk { | |
[a, b, c, d] => { | |
let r1 = try_parse_byte!(a, POW10_U64, idx + 0); | |
let r2 = try_parse_byte!(b, POW10_U64, idx + 1); | |
let r3 = try_parse_byte!(c, POW10_U64, idx + 2); | |
let r4 = try_parse_byte!(d, POW10_U64, idx + 3); | |
idx += 4; | |
result = result.wrapping_add(r1 + r2 + r3 + r4); | |
} | |
_ => unreachable!(), | |
} | |
} | |
// Fixuploop with .remainder() | |
for (offset, byte) in chunks.remainder().iter().enumerate() { | |
let r = try_parse_byte!(byte, POW10_U64, idx + offset); | |
result = result.wrapping_add(r); | |
} | |
Ok(result) | |
} | |
#[inline(always)] | |
fn atoi<T: AsRef<[u8]>>(bytes: T) -> Result<u64, ()> { | |
bytes_to_int(bytes.as_ref()) | |
} | |
fn main() { | |
assert_eq!(atoi("1234567"), Ok(1234567)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment