advent-of-code/2023/src/common.rs
2023-12-06 11:42:06 +01:00

71 lines
1.8 KiB
Rust

use std::{
fmt::Display,
iter::Step,
ops::{Add, Mul},
str::FromStr,
};
pub fn read_file(day: usize) -> String {
std::fs::read_to_string(std::env::var("AOC_INPUT").unwrap_or_else(|_| format!("inputs/day{day:0>2}"))).unwrap()
}
pub trait ParseableNumber<I>: FromStr + Display + From<u8> + Add<I, Output = I> + Mul<I, Output = I> {}
macro_rules! parseable {
($($t: ty),*) => {
$(impl ParseableNumber<$t> for $t {})*
};
}
parseable! {usize, u32, u64, isize, i32, i64}
pub fn parse_nums<I: ParseableNumber<I>>(l: &str) -> Vec<I> {
l.lines().map(parse_num::<I>).collect()
}
pub fn parse_nums_comma<I: ParseableNumber<I>>(l: &str) -> Vec<I> {
l.trim().split(',').map(parse_num::<I>).collect()
}
pub trait Splitting {
fn before<'a>(&'a self, sep: &str) -> &'a str;
fn after<'a>(&'a self, sep: &str) -> &'a str;
}
impl Splitting for &str {
fn after<'a>(&'a self, sep: &str) -> &'a str {
self.split_once(sep).unwrap().1
}
fn before<'a>(&'a self, sep: &str) -> &'a str {
self.split_once(sep).unwrap().0
}
}
pub trait Inc: Default + Copy + Step {
fn inc(self) -> Self;
fn dec(self) -> Self;
}
impl<T: Step + Default + Copy> Inc for T {
fn inc(self) -> Self {
T::forward(self, 1)
}
fn dec(self) -> Self {
T::backward(self, 1)
}
}
#[cfg(debug_assertions)]
pub fn parse_num<I: ParseableNumber<I>>(s: &str) -> I {
s.parse().unwrap_or_else(|_| panic!("Invalid number {s}"))
}
// For benchmarks.
// This function assumes that the input will always be valid numbers and is UB otherwise
#[cfg(not(debug_assertions))]
pub fn parse_num<I: ParseableNumber<I>>(s: &str) -> I {
let mut digits = s.bytes().map(|b| I::from(b - b'0'));
let start = unsafe { digits.next().unwrap_unchecked() };
digits.fold(start, |acc, n| acc * I::from(10) + n)
}