blazingly fast day5::second
This commit is contained in:
parent
9092e342c5
commit
19e4f1932a
5 changed files with 159 additions and 33 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1 +1,6 @@
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
flamegraph.svg
|
||||||
|
perf.data
|
||||||
|
perf.data.old
|
||||||
|
|
||||||
|
|
70
Cargo.lock
generated
70
Cargo.lock
generated
|
@ -5,3 +5,73 @@ version = 3
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "advent_of_code"
|
name = "advent_of_code"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"heapless",
|
||||||
|
"lexical-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hash32"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heapless"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||||
|
dependencies = [
|
||||||
|
"hash32",
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lexical-core"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46"
|
||||||
|
dependencies = [
|
||||||
|
"lexical-parse-integer",
|
||||||
|
"lexical-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lexical-parse-integer"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9"
|
||||||
|
dependencies = [
|
||||||
|
"lexical-util",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lexical-util"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc"
|
||||||
|
dependencies = [
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
|
@ -6,3 +6,11 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
heapless = "0.8.0"
|
||||||
|
lexical-core = { version = "0.8.5", default-features = false, features = [
|
||||||
|
"parse-integers",
|
||||||
|
] }
|
||||||
|
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
|
|
107
src/day5.rs
107
src/day5.rs
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
|
||||||
io::{BufRead, Cursor},
|
io::{BufRead, Cursor},
|
||||||
|
mem,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,11 +12,14 @@ pub struct Mapping {
|
||||||
|
|
||||||
impl Mapping {
|
impl Mapping {
|
||||||
fn parse(input: &str) -> Self {
|
fn parse(input: &str) -> Self {
|
||||||
let mut parts = input.split(' ').map(|s| s.parse::<usize>().unwrap());
|
let input_bytes = input.as_bytes();
|
||||||
|
let (dst_start, mut offset): (usize, usize) =
|
||||||
let dst_start = parts.next().unwrap();
|
lexical_core::parse_partial(input_bytes).unwrap();
|
||||||
let src_start = parts.next().unwrap();
|
offset += 1;
|
||||||
let length = parts.next().unwrap();
|
let (src_start, src_count): (usize, usize) =
|
||||||
|
lexical_core::parse_partial(&input_bytes[offset..]).unwrap();
|
||||||
|
offset += src_count + 1;
|
||||||
|
let length: usize = lexical_core::parse(&input_bytes[offset..]).unwrap();
|
||||||
|
|
||||||
Mapping {
|
Mapping {
|
||||||
source: src_start..(src_start + length),
|
source: src_start..(src_start + length),
|
||||||
|
@ -33,51 +36,53 @@ pub struct Mappings {
|
||||||
impl Mappings {
|
impl Mappings {
|
||||||
pub fn new(mut mappings: Vec<Mapping>) -> Self {
|
pub fn new(mut mappings: Vec<Mapping>) -> Self {
|
||||||
// order mappings by src_start
|
// order mappings by src_start
|
||||||
mappings.sort_by_key(|m| m.source.start);
|
mappings.sort_unstable_by_key(|m| m.source.start);
|
||||||
Mappings { mappings }
|
Mappings { mappings }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find(&self, value: usize) -> Option<usize> {
|
pub fn find(&self, value: usize) -> Option<usize> {
|
||||||
for mapping in &self.mappings {
|
for mapping in &self.mappings {
|
||||||
if mapping.source.contains(&value) {
|
if mapping.source.contains(&value) {
|
||||||
return Some(value.checked_add_signed(mapping.offset).unwrap());
|
return Some(value.wrapping_add_signed(mapping.offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_range(&self, range: Range<usize>) -> Vec<Range<usize>> {
|
pub fn map_range(&self, range: Range<usize>) -> heapless::Vec<Range<usize>, 10> {
|
||||||
let mut ranges = Vec::new();
|
let mut ranges = heapless::Vec::new();
|
||||||
|
|
||||||
let mut next_start = range.start;
|
let mut next_start = range.start;
|
||||||
|
|
||||||
for mapping in &self.mappings {
|
for mapping in &self.mappings {
|
||||||
if mapping.source.end <= range.start || range.end <= mapping.source.start {
|
if mapping.source.end <= range.start {
|
||||||
// mapping out of range, skip it
|
// mapping out of range, skip it
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if range.end <= mapping.source.start {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// add the unmapped range
|
// add the unmapped range
|
||||||
let unmapped_range = next_start..usize::min(range.end, mapping.source.start);
|
let unmapped_range = next_start..mapping.source.start;
|
||||||
if !unmapped_range.is_empty() {
|
if !unmapped_range.is_empty() {
|
||||||
ranges.push(unmapped_range);
|
ranges.push(unmapped_range).unwrap();
|
||||||
}
|
|
||||||
if mapping.source.end > next_start {
|
|
||||||
next_start = mapping.source.end;
|
|
||||||
}
|
}
|
||||||
|
next_start = mapping.source.end;
|
||||||
|
|
||||||
// add the mapped range
|
// add the mapped range
|
||||||
let overlap = usize::max(range.start, mapping.source.start)
|
let overlap = usize::max(range.start, mapping.source.start)
|
||||||
..usize::min(range.end, mapping.source.end);
|
..usize::min(range.end, mapping.source.end);
|
||||||
if !overlap.is_empty() {
|
if !overlap.is_empty() {
|
||||||
let dest_start = overlap.start.checked_add_signed(mapping.offset).unwrap();
|
let dest_start = overlap.start.wrapping_add_signed(mapping.offset);
|
||||||
let dest_end = dest_start + overlap.len();
|
let dest_end = dest_start + overlap.len();
|
||||||
ranges.push(dest_start..dest_end);
|
ranges.push(dest_start..dest_end).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the final unmapped range, if any
|
// add the final unmapped range, if any
|
||||||
if next_start < range.end {
|
if next_start < range.end {
|
||||||
ranges.push(next_start..range.end);
|
ranges.push(next_start..range.end).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
ranges
|
ranges
|
||||||
|
@ -146,15 +151,50 @@ pub struct Part2Input {
|
||||||
|
|
||||||
impl Part2Input {
|
impl Part2Input {
|
||||||
fn parse(input: &str) -> Self {
|
fn parse(input: &str) -> Self {
|
||||||
let part1_input = Part1Input::parse(input);
|
// let input = Cursor::new(input);
|
||||||
let mut seed_pairs = Vec::new();
|
let mut lines = input.lines();
|
||||||
for &[start, length] in part1_input.seeds.array_chunks::<2>() {
|
|
||||||
seed_pairs.push(start..(start + length));
|
// first line describes seeds
|
||||||
|
let seeds = lines
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.strip_prefix("seeds: ")
|
||||||
|
.unwrap()
|
||||||
|
.split(' ')
|
||||||
|
.map(|s| s.parse::<usize>().unwrap())
|
||||||
|
.array_chunks::<2>()
|
||||||
|
.map(|[start, length]| start..(start + length))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// skip empty line
|
||||||
|
lines.next();
|
||||||
|
|
||||||
|
let mut all_mappings = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// skip header
|
||||||
|
let header_line = lines.next();
|
||||||
|
if header_line.is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut mappings = Vec::new();
|
||||||
|
// read lines until we get to an empty line
|
||||||
|
loop {
|
||||||
|
let Some(line) = lines.next() else { break };
|
||||||
|
if line.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mapping = Mapping::parse(&line);
|
||||||
|
mappings.push(mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
all_mappings.push(Mappings::new(mappings));
|
||||||
}
|
}
|
||||||
|
|
||||||
Part2Input {
|
Self {
|
||||||
seeds: seed_pairs,
|
seeds,
|
||||||
all_mappings: part1_input.all_mappings,
|
all_mappings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,16 +223,19 @@ pub fn first(input: &str) -> usize {
|
||||||
pub fn second(input: &str) -> usize {
|
pub fn second(input: &str) -> usize {
|
||||||
let input = Part2Input::parse(input);
|
let input = Part2Input::parse(input);
|
||||||
|
|
||||||
let mut current = input.seeds;
|
let mut current = heapless::Vec::new();
|
||||||
|
current.extend(input.seeds.into_iter());
|
||||||
|
|
||||||
|
let mut new = heapless::Vec::<_, 100>::new();
|
||||||
for mappings in &input.all_mappings {
|
for mappings in &input.all_mappings {
|
||||||
let mut new = HashSet::new();
|
for range in ¤t {
|
||||||
for range in current {
|
new.extend(mappings.map_range(range.clone()));
|
||||||
new.extend(mappings.map_range(range));
|
|
||||||
}
|
}
|
||||||
current = Vec::from_iter(new);
|
current.clear();
|
||||||
|
mem::swap(&mut current, &mut new);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lowest = current.iter().map(|r| r.start).min().unwrap();
|
let lowest = current.into_iter().map(|r| r.start).min().unwrap();
|
||||||
|
|
||||||
return lowest;
|
return lowest;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![feature(array_chunks)]
|
#![feature(iter_array_chunks)]
|
||||||
|
|
||||||
mod day5;
|
mod day5;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue