diff --git a/2024/day01/src/lib.rs b/2024/day01/src/lib.rs index 4ab6cc4..9232a18 100644 --- a/2024/day01/src/lib.rs +++ b/2024/day01/src/lib.rs @@ -21,6 +21,7 @@ helper::define_variants! { faster_parsing => crate::part2_parsing; array => crate::part2_array; μopt_parsing => crate::part2_μopt_parsing; + part2_bytes => crate::part2_bytes; } } @@ -177,42 +178,90 @@ fn part2_array(input: &str) -> u64 { score } - fn part2_μopt_parsing(input: &str) -> u64 { + assert_eq!(input.as_bytes().last(), Some(&b'\n')); + const BIGGEST_ELEMENT: usize = 100_000; let mut right_map = vec![0_u16; BIGGEST_ELEMENT]; - let mut left = Vec::with_capacity(input.len() / 8); + let mut left = Vec::with_capacity(input.len()); + + let digit_len = input.as_bytes().iter().position(|b| *b == b' ').unwrap(); + let line_len = 2 * digit_len + 3 + 1; + + fn parse_digit(input: &str, len: usize) -> u64 { + let mut result = 0; + for i in 0..len { + result *= 10; + result += (input.as_bytes()[i] - b'0') as u64; + } + result + } let mut input = input; - loop { - let Some(space) = input.as_bytes().iter().position(|b| *b == b' ') else { - break; - }; - let number = input[..space].parse::().unwrap(); - left.push(number); - input = &input[(space + 3)..]; - let Some(newline) = input.as_bytes().iter().position(|b| *b == b'\n') else { - break; - }; - let number = input[..space].parse::().unwrap(); + while input.len() >= line_len { + let number = parse_digit(input, digit_len); + + left.push(number as u32); + input = &input[(digit_len + 3)..]; + + let number = parse_digit(input, digit_len); right_map[number as usize] += 1; - input = &input[newline..]; - // handle lack of trailing newline - if !input.is_empty() { - input = &input[1..]; - } + input = &input[digit_len..]; + input = &input[1..]; } let mut score = 0; for number in left { let occurs = right_map[number as usize]; - score += number * (occurs as u64); + score += (number as u64) * (occurs as u64); } score } +fn part2_bytes(input: &str) -> u64 { + let input = input.as_bytes(); + assert_eq!(input.last(), Some(&b'\n')); + + const BIGGEST_ELEMENT: usize = 100_000; + let mut right_map = vec![0_u16; BIGGEST_ELEMENT]; + let mut left = Vec::::with_capacity(input.len()); + + let digit_len = input.iter().position(|b| *b == b' ').unwrap(); + let line_len = 2 * digit_len + 3 + 1; + + fn parse_digit(input: &[u8], len: usize) -> u32 { + let mut result = 0; + for i in 0..len { + result *= 10; + result += (unsafe { input.get_unchecked(i) } - b'0') as u32; + } + result + } + + let mut input = input; + while input.len() >= line_len { + let number = parse_digit(input, digit_len); + + left.push(number); + input = unsafe { &input.get_unchecked((digit_len + 3)..) }; + + let number = parse_digit(input, digit_len); + right_map[number as usize] += 1; + input = unsafe { &input.get_unchecked((digit_len + 1)..) }; + } + + let mut score = 0; + + for number in left { + let occurs = right_map[number as usize]; + score += number * (occurs as u32); + } + + score as u64 +} + helper::tests! { day01 Day01; part1 { diff --git a/helper/src/lib.rs b/helper/src/lib.rs index c136a0d..ae53437 100644 --- a/helper/src/lib.rs +++ b/helper/src/lib.rs @@ -97,7 +97,7 @@ macro_rules! construct_variants { ( $day:ty; $( ($name:ident, $func:expr, [ $($_:tt)* ]) ),*) => { $crate::Variants { variants: vec![$( - $crate::Variant::new(stringify!($name), $func) + $crate::Variant::new(stringify!($name), std::hint::black_box($func)) ),*] } };