Files
aoc/2025/05/p1-opt3.rs
javalsai da7ab076f2 add: d05 & debug utils
- includes a script to generate a 2GB big challenge
- added utils to internally time functions with minimal overhead
- add functionality to tester.rs
2025-12-05 22:11:15 +01:00

89 lines
2.8 KiB
Rust

use std::{
collections::BTreeMap,
time::{Duration, Instant},
};
pub type RangeU = u128;
pub type NestingCountT = i16;
#[unsafe(no_mangle)]
pub static mut TIMERS: [(&str, Duration); TIMERS_LEN] = [
("after-parse", Duration::ZERO),
("flatten-vec", Duration::ZERO),
("count-ids", Duration::ZERO),
];
#[unsafe(no_mangle)]
pub static TIMERS_LEN: usize = 3;
#[unsafe(no_mangle)]
extern "Rust" fn challenge_t_usize(buf: &[u8], t: &Instant) -> usize {
let mut count = 0;
let s = unsafe { str::from_utf8_unchecked(buf) };
let mut lines = s.lines();
let mut bmap = BTreeMap::<_, NestingCountT>::new();
(&mut lines)
.take_while(|ln| !ln.is_empty())
.for_each(|range| {
let (l, r) = range.split_once('-').unwrap();
let (l, r) = (l.parse().unwrap(), r.parse().unwrap());
bmap.entry(l).and_modify(|k| *k += 1).or_insert(1);
bmap.entry(r).and_modify(|k| *k -= 1).or_insert(-1);
});
unsafe { TIMERS[0].1 = t.elapsed() };
let mut arr = Vec::with_capacity(size_of::<bool>() * bmap.len());
// I could directly search on the btree, but I feel flattening at once and then searching can
// speed up things bcs continuity indirection and stuff. It also makes it easier to iterate at
// once. This would be O(n) and the latter access in O(log n) (O(n log n) bcs it iterates for
// each id)
let mut last_pushed = false;
let mut nested_ran_acc = 0;
for (idx, nesting) in bmap {
nested_ran_acc += nesting;
if last_pushed != (nested_ran_acc > 0) {
last_pushed = !last_pushed;
arr.push((idx, last_pushed));
}
}
unsafe { TIMERS[1].1 = t.elapsed() };
let all_ranges_bounds = (arr[0].0, arr[arr.len() - 1].0);
for id in lines {
let id: RangeU = id.parse().unwrap();
if id < all_ranges_bounds.0 || id > all_ranges_bounds.1 {
continue;
}
// let idx = arr.binary_search_by_key(&id, |p| p.0).err(|i| i);
// let is_in_any_range = arr.get(idx).map(|p| p.1).unwrap();
let is_in_any_range = binary_search_inclusive_or_lower_bound(&arr, id);
if is_in_any_range {
count += 1
}
}
unsafe { TIMERS[2].1 = t.elapsed() };
count
}
fn binary_search_inclusive_or_lower_bound(arr: &[(RangeU, bool)], id: RangeU) -> bool {
let all_ranges_bounds = (arr[0].0, arr[arr.len() - 1].0);
if id < all_ranges_bounds.0 || id > all_ranges_bounds.1 {
return false;
}
match arr.binary_search_by_key(&id, |p| p.0) {
Ok(_) => true, // the rising edge is true and if falling edge its false but included so
// should get truthed. In general if its found it was an edge so return true
Err(idx) => arr[idx - 1].1,
}
}