heh
hmm
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/main.rs | 32 | ||||
| -rw-r--r-- | src/util.rs | 146 |
3 files changed, 160 insertions, 19 deletions
@@ -7,6 +7,7 @@ edition = "2021" [dependencies] itertools = "0.12.0" +memchr = "2.6.4" [profile.release] lto = true codegen-units = 1 diff --git a/src/main.rs b/src/main.rs index bda69a0..6926456 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,18 @@ #![allow(confusable_idents, uncommon_codepoints, mixed_script_confusables)] -#![feature(array_windows, test, slice_as_chunks, array_chunks)] +#![feature( + array_windows, + test, + slice_as_chunks, + array_chunks, + slice_split_once, + byte_slice_trim_ascii +)] extern crate test; mod util; pub use util::prelude::*; #[inline(always)] -fn k(s: &str) -> u16 { +fn k(s: &[u8]) -> u16 { unsafe { *s.as_ptr().cast::<[u8; 3]>() } .iter() .enumerate() @@ -21,17 +28,12 @@ fn end(x: u16) -> bool { (x >> (2 * 5) & 0b11111) == (b'Z' - b'A') as u16 } -pub fn run(i: &str) -> impl Display { - let mut lines = i.lines(); - let line = lines.by_ref().Δ().as_bytes(); - let map = lines - .skip(1) - .map(|x| { - x.μ('=') - .mr(|x| x.trim()[1..x.len() - 2].μ(',').mb(str::trim).mb(k)) - .ml(str::trim) - .ml(k) - }) +pub fn run(mut i: &str) -> impl Display { + let line = i.take_line().unwrap(); + let map = i + .as_bytes() + .array_chunks::<17>() + .map(|x| (k(&x[1..4]), (k(&x[8..11]), k(&x[13..16])))) .collect::<HashMap<_, _>>(); let mut positions = map .keys() @@ -68,9 +70,7 @@ pub fn run(i: &str) -> impl Display { steps += 1; } let v = lcm(cycle.values().copied()); - std::mem::forget(cycle); - std::mem::forget(findings); - std::mem::forget(positions); + leek!(cycle findings positions); v } diff --git a/src/util.rs b/src/util.rs index b633247..a7e5dc8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,8 +3,8 @@ use std::{mem::swap, str::FromStr}; pub mod prelude { pub use super::{ - gcd, lcm, GreekTools, IterͶ, NumTupleIterTools, TupleIterTools, TupleUtils, - UnifiedTupleUtils, Ͷ, Α, Κ, Λ, Μ, + gcd, lcm, GreekTools, IntoLines, IterͶ, NumTupleIterTools, Skip, TakeLine, TupleIterTools, + TupleUtils, UnifiedTupleUtils, Ͷ, Α, Κ, Λ, Μ, }; pub use itertools::izip; pub use itertools::Itertools; @@ -17,7 +17,7 @@ pub mod prelude { ops::Range, }; #[allow(unused_imports)] - pub(crate) use {super::bits, super::dang}; + pub(crate) use {super::bits, super::dang, super::leek}; } macro_rules! dang { @@ -27,6 +27,13 @@ macro_rules! dang { } pub(crate) use dang; +macro_rules! leek { + ($($allocation:ident)+) => { + $(std::mem::forget($allocation);)+ + }; +} +pub(crate) use leek; + pub fn lcm(n: impl IntoIterator<Item = u64>) -> u64 { let mut x = n.into_iter(); let mut lcm = x.by_ref().next().expect("cannot compute LCM of 0 numbers"); @@ -86,6 +93,15 @@ pub trait Κ { <T as FromStr>::Err: std::fmt::Display; } +impl Κ for &[u8] { + fn κ<T: FromStr>(self) -> impl Iterator<Item = T> + where + <T as FromStr>::Err: std::fmt::Display, + { + std::str::from_utf8(self).unwrap().κ() + } +} + impl Κ for &str { fn κ<T: FromStr>(self) -> impl Iterator<Item = T> where @@ -148,6 +164,39 @@ pub trait Μ where <T as FromStr>::Err: std::fmt::Display; } +impl Μ for &[u8] { + fn μ(self, d: char) -> (Self, Self) { + self.split_once(|&x| x == d as u8).unwrap_or_else(|| { + panic!( + "{} should split at {d} fine", + std::str::from_utf8(self).expect("utf8") + ) + }) + } + + fn μκ<T: FromStr>(self, d: char) -> impl Iterator<Item = (T, T)> + where + <T as FromStr>::Err: std::fmt::Display, + { + let (α, β) = self.μ(d); + α.κ::<T>().zip(β.κ::<T>()) + } + + fn μ1<T: FromStr>(self, d: char) -> impl Iterator<Item = T> + where + <T as FromStr>::Err: std::fmt::Display, + { + self.μ(d).1.κ() + } + + fn μ0<T: FromStr>(self, d: char) -> impl Iterator<Item = T> + where + <T as FromStr>::Err: std::fmt::Display, + { + self.μ(d).0.κ() + } +} + impl Μ for &str { fn μ(self, d: char) -> (Self, Self) { self.split_once(d) @@ -302,3 +351,94 @@ fn do_bits() { bits!(bitset[4] = true); assert!(bits!(bitset[4])); } + +pub struct Lines<'a> { + bytes: &'a [u8], +} + +impl<'a> Iterator for Lines<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option<Self::Item> { + self.bytes.take_line() + } +} + +impl<'a> std::iter::FusedIterator for Lines<'a> {} + +pub trait IntoLines { + fn 行(&self) -> Lines<'_>; +} + +impl<T: AsRef<[u8]>> IntoLines for T { + fn 行(&self) -> Lines<'_> { + Lines { + bytes: self.as_ref(), + } + } +} + +pub trait TakeLine<'b> { + fn take_line<'a>(&'a mut self) -> Option<&'b [u8]>; +} + +impl<'b> TakeLine<'b> for &'b [u8] { + fn take_line<'a>(&'a mut self) -> Option<&'b [u8]> { + match memchr::memchr(b'\n', self) { + None if self.is_empty() => None, + None => { + let line = *self; + *self = b""; + Some(line) + } + Some(end) => { + let line = &self[..end]; + *self = &self[end + 1..]; + Some(line) + } + } + } +} + +impl<'b> TakeLine<'b> for &'b str { + fn take_line<'a>(&'a mut self) -> Option<&'b [u8]> { + match memchr::memchr(b'\n', self.as_bytes()) { + None if self.is_empty() => None, + None => { + let line = self.as_bytes(); + *self = ""; + Some(line) + } + Some(end) => { + let line = self[..end].as_bytes(); + *self = &self[end + 1..]; + Some(line) + } + } + } +} + +pub trait Skip { + fn skip(&mut self, n: usize); +} + +impl Skip for &[u8] { + fn skip(&mut self, n: usize) { + *self = &self[n..]; + } +} + +impl Skip for &str { + fn skip(&mut self, n: usize) { + *self = &self[n..]; + } +} + +#[test] +fn liney() { + let mut i = b"xyz\nlmaolol\nhuh".行(); + assert_eq!(i.next(), Some(&b"xyz"[..])); + assert_eq!(i.next(), Some(&b"lmaolol"[..])); + assert_eq!(i.next(), Some(&b"huh"[..])); + assert_eq!(i.next(), None); +} |