diff --git a/day14/src/ext.rs b/day14/src/ext.rs new file mode 100644 index 0000000..49e9d87 --- /dev/null +++ b/day14/src/ext.rs @@ -0,0 +1,207 @@ +//! Extensions +use std::iter::{ + self, + FusedIterator, +}; + +/// An iterator adaptor for taking two items off an iterator +#[derive(Debug, Clone)] +pub struct TakeTwo(I); + +impl Iterator for TakeTwo +where I: Iterator +{ + type Item = (T, Option); + #[inline] + fn next(&mut self) -> Option + { + let first = self.0.next()?; + Some((first, self.0.next())) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.0.size_hint(); + (low / 2, high.map(|x| x/2)) + } +} + +impl ExactSizeIterator for TakeTwo{} +impl FusedIterator for TakeTwo {} + +pub trait TakeTwoExt: Sized { + /// Create an adaptor from `T` to `(T, Option)`, taking the next available value if one exists in the iterator + fn take_two(self) -> TakeTwo; +} +pub trait TakeTwoBoxedExt { + /// Create an adaptor from `T` to `(T, Option)`, taking the next available value if one exists in the iterator + fn take_two(self: Box) -> TakeTwo>; +} + +impl TakeTwoExt for I +{ + #[inline(always)] + fn take_two(self) -> TakeTwo { + TakeTwo(self) + } +} + +impl TakeTwoBoxedExt for I +{ + #[inline(always)] + fn take_two(self: Box) -> TakeTwo> { + TakeTwo(self) + } +} + +pub trait Tuple2OptExt: Sized +{ + /// The unwrapped type for the option in the tuple + type OptionType; + /// Unwrap a tuple containing an option into an option containing the full tuple if the `Option` value in the tuple is `Some` + fn unwrap_two(self) -> Option<(T, U)>; + + /// Unwrap the option value or get the value from `f` + fn unwrap_two_or_else(self, f: F) -> (T, U) + where F: FnOnce() -> Self::OptionType; +} + +impl Tuple2OptExt for (T, Option) +{ + type OptionType = U; + + #[inline] + fn unwrap_two(self) -> Option<(T, U)> { + self.1.map(move |u| (self.0, u)) + } + + #[inline] + fn unwrap_two_or_else(self, f: F) -> (T, U) + where F: FnOnce() -> Self::OptionType { + match self.1 { + Some(u) => (self.0, u), + None => (self.0, f()), + } + } +} + +impl Tuple2OptExt for (Option, U) +{ + type OptionType = T; + #[inline] + fn unwrap_two(self) -> Option<(T, U)> { + self.0.map(move |u| (u, self.1)) + } + + #[inline] + fn unwrap_two_or_else(self, f: F) -> (T, U) + where F: FnOnce() -> Self::OptionType { + match self.0 { + Some(u) => (u, self.1), + None => (f(), self.1), + } + } +} + +impl Tuple2OptExt for (Option, Option) +{ + type OptionType = (T, U); + #[inline] + fn unwrap_two(self) -> Option<(T, U)> { + self.0.and_then(move |u| self.1.map(move |v| (u, v))) + } + + #[inline] + fn unwrap_two_or_else(self, f: F) -> (T, U) + where F: FnOnce() -> Self::OptionType { + match self { + //XXX: This is not ideal... + (Some(u), Some(v)) => (u, v), + (Some(u), None) => (u, f().1), + (None, Some(v)) => (f().0, v), + _ => f() + } + } +} + +pub trait Tuple2Ext: Sized +{ + /// Swap the elements in a 2-tuple + fn swap(self) -> (U, T); + + /// Reduce the tuple elements into `V` + fn reduce(self, into: V) -> V + where V: Extend + Extend; + + /// Collect the tuple elements into `O` + fn collect(self) -> O + where V: From + From + FromIterator, + O: FromIterator; + + /// Consume into `V` + fn consume(self) -> V + where V: FromIterator + Extend; + + /// Consume both elements into a new single type. + fn into(self) -> (V, V) + where V: From + From; +} + +pub trait Tuple2STExt: Sized +{ + /// Consume into an array of two elements. + fn into_array(self) -> [T; 2]; + + /// Consume into an iterator of both elements + fn into_iter(self) -> <[T; 2] as IntoIterator>::IntoIter; +} + +impl Tuple2Ext for (T, U) +{ + #[inline] + fn swap(self) -> (U, T) { + (self.1, self.0) + } + + #[inline] + fn reduce(self, mut into: V) -> V + where V: Extend + Extend { + into.extend(iter::once(self.0)); + into.extend(iter::once(self.1)); + into + } + + #[inline] + fn collect(self) -> O + where V: From + From, + O: FromIterator { + [self.0.into(), self.1.into()].into_iter().collect() + } + + #[inline] + fn consume(self) -> V + where V: FromIterator + Extend { + let mut o: V = iter::once(self.0).collect(); + o.extend(iter::once(self.1)); + o + } + + #[inline] + fn into(self) -> (V, V) + where V: From + From { + (self.0.into(), self.1.into()) + } +} + +impl Tuple2STExt for (T, T) +{ + #[inline] + fn into_array(self) -> [T; 2] { + [self.0, self.1] + } + + #[inline] + fn into_iter(self) -> <[T; 2] as IntoIterator>::IntoIter { + self.into_array().into_iter() + } +} diff --git a/day14/src/grid.rs b/day14/src/grid.rs new file mode 100644 index 0000000..e8c3f72 --- /dev/null +++ b/day14/src/grid.rs @@ -0,0 +1,3 @@ +//! Grid of lines and sands +use super::*; + diff --git a/day14/src/main.rs b/day14/src/main.rs index 3b64651..31c3981 100644 --- a/day14/src/main.rs +++ b/day14/src/main.rs @@ -31,62 +31,17 @@ const _:() = { static GLOBAL: Jemalloc = Jemalloc; }; -mod ext { - use super::iter::FusedIterator; - - #[derive(Debug, Clone)] - pub struct TakeTwo(I); - - impl Iterator for TakeTwo - where I: Iterator - { - type Item = (T, Option); - #[inline] - fn next(&mut self) -> Option - { - let first = self.0.next()?; - Some((first, self.0.next())) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.0.size_hint(); - (low / 2, high.map(|x| x/2)) - } - } - - impl ExactSizeIterator for TakeTwo{} - impl FusedIterator for TakeTwo {} - - pub trait TakeTwoExt: Sized { - fn take_two(self) -> TakeTwo; - } - pub trait TakeTwoBoxedExt { - fn take_two(self: Box) -> TakeTwo>; - } - - impl TakeTwoExt for I - { - #[inline(always)] - fn take_two(self) -> TakeTwo { - TakeTwo(self) - } - } - - impl TakeTwoBoxedExt for I - { - #[inline(always)] - fn take_two(self: Box) -> TakeTwo> { - TakeTwo(self) - } - } - -} +mod ext; use ext::{ TakeTwoExt as _, TakeTwoBoxedExt as _, + Tuple2Ext as _, + Tuple2OptExt as _, + Tuple2STExt as _, }; +mod grid; + /// A point is a vector #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)] #[repr(simd)]