heh
bendn 2023-12-09
parent 550804e · commit 067dad1
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs32
-rw-r--r--src/util.rs146
3 files changed, 160 insertions, 19 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 38377ce..14af4b6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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);
+}