mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-14 17:45:02 +01:00
compare
This commit is contained in:
parent
2bacc67280
commit
a7e039a51b
3 changed files with 210 additions and 9 deletions
55
2024/Cargo.lock
generated
55
2024/Cargo.lock
generated
|
|
@ -51,12 +51,29 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -116,9 +133,12 @@ dependencies = [
|
||||||
name = "day01"
|
name = "day01"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bstr",
|
||||||
"divan",
|
"divan",
|
||||||
"helper",
|
"helper",
|
||||||
|
"memchr",
|
||||||
"nom",
|
"nom",
|
||||||
|
"num-traits",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -206,6 +226,15 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.92"
|
version = "1.0.92"
|
||||||
|
|
@ -224,6 +253,12 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-lite"
|
name = "regex-lite"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|
@ -249,6 +284,26 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.215"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.215"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ nom.workspace = true
|
||||||
helper.workspace = true
|
helper.workspace = true
|
||||||
divan.workspace = true
|
divan.workspace = true
|
||||||
rustc-hash = "2.1.0"
|
rustc-hash = "2.1.0"
|
||||||
|
memchr = "2.7.4"
|
||||||
|
num-traits = "0.2.19"
|
||||||
|
bstr = "1.11.0"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "benches"
|
name = "benches"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![feature(portable_simd)]
|
||||||
use core::str;
|
use core::str;
|
||||||
use std::{collections::HashMap, hash::BuildHasherDefault};
|
use std::{collections::HashMap, hash::BuildHasherDefault};
|
||||||
|
|
||||||
|
|
@ -16,15 +17,17 @@ helper::define_variants! {
|
||||||
basic => crate::part1;
|
basic => crate::part1;
|
||||||
}
|
}
|
||||||
part2 {
|
part2 {
|
||||||
basic => crate::part2;
|
//basic => crate::part2;
|
||||||
hash => crate::part2_hash;
|
//hash => crate::part2_hash;
|
||||||
hash_no_hash => crate::part2_hash_nohash;
|
//hash_no_hash => crate::part2_hash_nohash;
|
||||||
faster_parsing => crate::part2_parsing;
|
//faster_parsing => crate::part2_parsing;
|
||||||
array => crate::part2_array;
|
//array => crate::part2_array;
|
||||||
μopt_parsing => crate::part2_μopt_parsing;
|
//μopt_parsing => crate::part2_μopt_parsing;
|
||||||
bytes => crate::part2_bytes;
|
//bytes => crate::part2_bytes;
|
||||||
assume_len => crate::part2_assume_len;
|
//assume_len => crate::part2_assume_len;
|
||||||
simd => crate::part2_simd;
|
nora => crate::part2_simd;
|
||||||
|
clubby => crate::part2_clubby;
|
||||||
|
part2_max397 => crate::part2_max397;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,6 +392,146 @@ fn part2_simd(input_str: &str) -> u64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn part2_clubby(input: &str) -> u64 {
|
||||||
|
use std::{
|
||||||
|
hint::assert_unchecked,
|
||||||
|
simd::{num::SimdUint, LaneCount, Simd, SupportedLaneCount},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn for_each_line<F>(input: &str, mut f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(u64, u64),
|
||||||
|
{
|
||||||
|
let mut input = input.as_bytes();
|
||||||
|
let line_length = memchr::memchr(b'\n', input).unwrap();
|
||||||
|
// Length of first column
|
||||||
|
let first_col_len = memchr::memchr(b' ', &input[..line_length]).unwrap();
|
||||||
|
// SAFETY: `memchr` returns a value less than the length
|
||||||
|
unsafe { assert_unchecked(first_col_len < line_length) };
|
||||||
|
|
||||||
|
// Offset from start to second column
|
||||||
|
let second_col_offset = memchr::memrchr(b' ', &input[..line_length]).unwrap() + 1;
|
||||||
|
// SAFETY: `memchr` returns a value less than the length
|
||||||
|
unsafe { assert_unchecked(second_col_offset < line_length) };
|
||||||
|
assert!(second_col_offset > first_col_len);
|
||||||
|
|
||||||
|
while !input.is_empty() {
|
||||||
|
assert!(input.len() > line_length);
|
||||||
|
|
||||||
|
let (num1, num2) =
|
||||||
|
parse_line_simd(input, first_col_len, second_col_offset, line_length);
|
||||||
|
f(num1, num2);
|
||||||
|
input = &input[line_length + 1..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_line_simd(
|
||||||
|
input: &[u8],
|
||||||
|
first_col_len: usize,
|
||||||
|
second_col_offset: usize,
|
||||||
|
line_length: usize,
|
||||||
|
) -> (u64, u64) {
|
||||||
|
assert!(input.len() >= second_col_offset);
|
||||||
|
assert!(input.len() >= first_col_len);
|
||||||
|
assert!(input.len() >= line_length);
|
||||||
|
|
||||||
|
match (first_col_len, second_col_offset, line_length) {
|
||||||
|
(5, 8, 13) => (
|
||||||
|
simd_parse_start::<8, 5>(input[..second_col_offset].try_into().unwrap()),
|
||||||
|
simd_parse_end::<8, 3>(input[first_col_len..line_length].try_into().unwrap()),
|
||||||
|
),
|
||||||
|
(1, 4, 5) => (
|
||||||
|
simd_parse_start::<4, 1>(input[..second_col_offset].try_into().unwrap()),
|
||||||
|
simd_parse_end::<4, 3>(input[first_col_len..line_length].try_into().unwrap()),
|
||||||
|
),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simd_parse_start<const INP_LEN: usize, const NUM_SIZE: usize>(line: &[u8; INP_LEN]) -> u64
|
||||||
|
where
|
||||||
|
LaneCount<INP_LEN>: SupportedLaneCount,
|
||||||
|
{
|
||||||
|
let multipliers = Simd::from(std::array::from_fn(|i| 10u64.pow(i as u32))).reverse();
|
||||||
|
let mask = Simd::from(std::array::from_fn(
|
||||||
|
|i| if i < NUM_SIZE { u64::MAX } else { 0 },
|
||||||
|
));
|
||||||
|
let line = Simd::<u8, INP_LEN>::load_or_default(line);
|
||||||
|
let digits = line - Simd::splat(b'0');
|
||||||
|
let digits: Simd<u64, INP_LEN> = digits.cast();
|
||||||
|
let digits = digits & mask;
|
||||||
|
(digits * multipliers).reduce_sum() / 10u64.pow((INP_LEN - NUM_SIZE) as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simd_parse_end<const INP_LEN: usize, const GAP_LEN: usize>(line: &[u8; INP_LEN]) -> u64
|
||||||
|
where
|
||||||
|
LaneCount<INP_LEN>: SupportedLaneCount,
|
||||||
|
{
|
||||||
|
let multipliers = Simd::from(std::array::from_fn(|i| 10u64.pow(i as u32))).reverse();
|
||||||
|
let mask = Simd::from(std::array::from_fn(
|
||||||
|
|i| if i >= GAP_LEN { u64::MAX } else { 0 },
|
||||||
|
));
|
||||||
|
let line = Simd::<u8, INP_LEN>::load_or_default(line);
|
||||||
|
let digits = line - Simd::splat(b'0');
|
||||||
|
let digits: Simd<u64, INP_LEN> = digits.cast();
|
||||||
|
let digits = digits & mask;
|
||||||
|
(digits * multipliers).reduce_sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut num_counts = vec![0u16; 99999];
|
||||||
|
let line_length = memchr::memchr(b'\n', input.as_bytes()).unwrap();
|
||||||
|
let lines = input.len() / line_length;
|
||||||
|
let mut appeared = Vec::with_capacity(lines);
|
||||||
|
|
||||||
|
for_each_line(input, |num1, num2| {
|
||||||
|
appeared.push(num1);
|
||||||
|
num_counts[num2 as usize] += 1;
|
||||||
|
});
|
||||||
|
appeared
|
||||||
|
.iter()
|
||||||
|
.map(|&num| num * num_counts[num as usize] as u64)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2_max397(input: &str) -> u64 {
|
||||||
|
use bstr::ByteSlice;
|
||||||
|
|
||||||
|
pub fn part2(input: &str) -> u64 {
|
||||||
|
let input = input.as_bytes();
|
||||||
|
let mut col1: Vec<usize> = Vec::with_capacity(1000);
|
||||||
|
let mut counts: [u16; 100000] = [0; 100000];
|
||||||
|
let idx1 = unsafe { input.find_byte(b' ').unwrap_unchecked() };
|
||||||
|
let idx2 = idx1 + 3;
|
||||||
|
let idx3 = idx1 + idx2;
|
||||||
|
input.lines().for_each(|line| {
|
||||||
|
col1.push(line[0..idx1].as_num());
|
||||||
|
counts[line[idx2..idx3].as_num::<usize>()] += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
col1.iter()
|
||||||
|
.map(|num| num * counts[*num] as usize)
|
||||||
|
.sum::<usize>() as u64
|
||||||
|
}
|
||||||
|
// the parsing
|
||||||
|
use num_traits::PrimInt;
|
||||||
|
|
||||||
|
pub trait ByteParsing {
|
||||||
|
fn as_num<T: PrimInt>(&self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ByteParsing for [u8] {
|
||||||
|
fn as_num<T: PrimInt>(&self) -> T {
|
||||||
|
let mut out = T::zero();
|
||||||
|
for byte in self {
|
||||||
|
out = out * T::from(10).unwrap() + T::from(byte - b'0').unwrap();
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
part2(input)
|
||||||
|
}
|
||||||
|
|
||||||
helper::tests! {
|
helper::tests! {
|
||||||
day01 Day01;
|
day01 Day01;
|
||||||
part1 {
|
part1 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue