diff --git a/.gitignore b/.gitignore index 9dd4081..cc676ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ input*.txt +target \ No newline at end of file diff --git a/2023/day1/.gitignore b/2023/day1/.gitignore deleted file mode 100644 index ea8c4bf..0000000 --- a/2023/day1/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/2023/day1/Cargo.toml b/2023/day1/Cargo.toml index afab261..a3c4e52 100644 --- a/2023/day1/Cargo.toml +++ b/2023/day1/Cargo.toml @@ -3,9 +3,6 @@ name = "day1" version = "0.1.0" edition = "2021" -[profile.release] -debug = 1 - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/2023/day1/src/main.rs b/2023/day1/src/main.rs index 85873f9..e437985 100644 --- a/2023/day1/src/main.rs +++ b/2023/day1/src/main.rs @@ -2,6 +2,7 @@ use std::mem::MaybeUninit; mod branchless; mod naive; +mod no_lines; mod zero_alloc; fn main() { @@ -22,6 +23,7 @@ fn main() { "naive" => naive::part2(&input), "zero_alloc" => zero_alloc::part2(&input), "branchless" => unsafe { branchless::part2(&input) }, + "no_lines" => unsafe { no_lines::part2(&input) }, _ => { eprintln!("error: invalid mode, must be part1,naive,zero_alloc,branchless"); std::process::exit(1); diff --git a/2023/day1/src/no_lines.rs b/2023/day1/src/no_lines.rs new file mode 100644 index 0000000..49daa9e --- /dev/null +++ b/2023/day1/src/no_lines.rs @@ -0,0 +1,77 @@ +pub unsafe fn part2(input: &str) { + let mut sum = 0; + + let bytes = input.as_bytes(); + + let mut digits = [0_u8; 128]; + + let mut byte_idx = 0; + let mut line_idx = 0; + + while byte_idx < bytes.len() { + // in memory: + // o n e X X X X X + // in the integer bytes: + // X X X X X e n o + // this out of bounds read is UB under SB, but fine under models that don't do provenance narrowing with slices. i dont care enough to fix it. + let block = bytes.as_ptr().add(byte_idx).cast::().read_unaligned().to_le(); + + let one = (block & ((1 << (8 * 1)) - 1)) as u8; + let three = block & ((1 << (8 * 3)) - 1); + let four = block & ((1 << (8 * 4)) - 1); + let five = block & ((1 << (8 * 5)) - 1); + + if one == b'\n' { + let first = digits[..line_idx].iter().find(|&&d| d > b'0').unwrap(); + let last = digits[..line_idx] + .iter() + .rev() + .find(|&&d| d > b'0') + .unwrap(); + + let first = (first - b'0') as u64; + let last = (last - b'0') as u64; + sum += first * 10 + last; + digits = [0_u8; 128]; + line_idx = 0; + } + + const fn gorble(s: &[u8]) -> u64 { + let mut bytes = [0; 8]; + let mut i = 0; + while i < s.len() { + bytes[7 - i] = s[i]; + i += 1; + } + // like: u64::from_be_bytes([0, 0, 0, b't', b'h', b'g', b'i', b'e']) + u64::from_be_bytes(bytes) + } + macro_rules! check { + ($const:ident $len:ident == $str:expr => $value:expr) => { + const $const: u64 = gorble($str); + digits[line_idx] |= (if $len == $const { $value } else { 0 }); + }; + } + + assert!(line_idx < digits.len()); + + digits[line_idx] |= if one >= b'0' && one <= b'9' { one } else { 0 }; + + check!(EIGHT five == b"eight" => b'8'); + check!(SEVEN five == b"seven" => b'7'); + check!(THREE five == b"three" => b'3'); + + check!(FIVE four == b"five" => b'5'); + check!(FOUR four == b"four" => b'4'); + check!(NINE four == b"nine" => b'9'); + + check!(SIX three == b"six" => b'6'); + check!(TWO three == b"two" => b'2'); + check!(ONE three == b"one" => b'1'); + + byte_idx += 1; + line_idx += 1; + } + + println!("part2: {sum}"); +} diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ae5bfe8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "day1" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ffbee8a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] +resolver = "2" +members = ["2023/*"] + +[profile.release] +debug = 1