3 Commits

Author SHA1 Message Date
1cd5579bf6 Use iterators instead of explicit indexing 2022-12-06 18:37:38 +01:00
7c7c69255d Replace indirect indexing
230 byte overhead is worth it to avoid conversions and potential
indexing errors
2022-12-06 18:23:43 +01:00
391bba24c5 Use enumerate combinator 2022-12-06 18:19:42 +01:00
3 changed files with 27 additions and 20 deletions

View File

@@ -1,6 +1,7 @@
//! Common helper utilities to all days //! Common helper utilities to all days
use anyhow::Result; use anyhow::Result;
use nom::combinator::map;
use nom::error::ErrorKind; use nom::error::ErrorKind;
use nom::error::ParseError; use nom::error::ParseError;
use nom::Finish; use nom::Finish;
@@ -93,6 +94,17 @@ where
} }
} }
/// Add an index to repeated successful invocations of the embedded parser.
pub fn enumerate<I, O, E>(f: impl Parser<I, O, E>) -> impl FnMut(I) -> IResult<I, (usize, O), E> {
let mut index = 0usize;
map(f, move |v| {
let res = (index, v);
index += 1;
res
})
}
/// Return the minimum and maximum of two unordered variables /// Return the minimum and maximum of two unordered variables
pub fn minmax<T>(a: T, b: T) -> (T, T) pub fn minmax<T>(a: T, b: T) -> (T, T)
where where

View File

@@ -16,17 +16,16 @@ use nom::sequence::terminated;
use nom::sequence::tuple; use nom::sequence::tuple;
use nom::IResult; use nom::IResult;
use crate::common::enumerate;
use crate::common::parse_input; use crate::common::parse_input;
type Move = (usize, usize, usize); type Move = (usize, usize, usize);
type OwnedStacks = Vec<Vec<u8>>; type OwnedStacks = Vec<Vec<u8>>;
fn parse_row<'a>(input: &'a [u8], stacks: &mut OwnedStacks) -> IResult<&'a [u8], ()> { fn parse_row<'a>(input: &'a [u8], stacks: &mut OwnedStacks) -> IResult<&'a [u8], ()> {
let mut index = 0usize;
// Forgive me for this crime // Forgive me for this crime
fold_many1( fold_many1(
terminated( enumerate(terminated(
alt(( alt((
// Parse a delimited value into a Some(content) // Parse a delimited value into a Some(content)
map(delimited(tag("["), take(1usize), tag("]")), |v: &[u8]| { map(delimited(tag("["), take(1usize), tag("]")), |v: &[u8]| {
@@ -36,9 +35,9 @@ fn parse_row<'a>(input: &'a [u8], stacks: &mut OwnedStacks) -> IResult<&'a [u8],
map(tag(" "), |_| None), map(tag(" "), |_| None),
)), )),
opt(tag(" ")), opt(tag(" ")),
), )),
|| (), || (),
move |_, c| { move |_, (index, c)| {
if let Some(b) = c { if let Some(b) = c {
if stacks.len() <= index { if stacks.len() <= index {
stacks.resize_with(index + 1, Vec::new); stacks.resize_with(index + 1, Vec::new);
@@ -46,8 +45,6 @@ fn parse_row<'a>(input: &'a [u8], stacks: &mut OwnedStacks) -> IResult<&'a [u8],
stacks[index].push(b) stacks[index].push(b)
} }
index += 1;
}, },
)(input) )(input)
} }

View File

@@ -1,29 +1,27 @@
use anyhow::Result; use anyhow::Result;
fn find_first(input: &[u8], unique: usize) -> Result<usize> { fn find_first(input: &[u8], unique: usize) -> Result<usize> {
#[inline] let mut seen = [false; 256];
const fn index(c: u8) -> usize {
(c - b'a') as usize let mut tail_it = input.iter();
}
let mut seen = [false; 26];
let mut first = 0; let mut first = 0;
// Loop invariant: input[first..last] contains only unique characters // Loop invariant: input[first..last] contains only unique characters
for (last, &c) in input.iter().enumerate() { for (last, &c) in input.iter().enumerate() {
if seen[index(c)] { if seen[c as usize] {
while input[first] != c { first += (&mut tail_it)
seen[index(input[first])] = false; .take_while(|&&b| b != c)
first += 1; .map(|&b| seen[b as usize] = false)
} .count()
first += 1; + 1; // +1 because take_while doesn't return the first element that didn't satisfy the condition, while we do need to count it
} else { } else {
// New unique character found: input[first..=last] contains unique characters // New unique character found: input[first..=last] contains unique characters
if last - first + 1 == unique { if last - first + 1 == unique {
return Ok(first + unique); return Ok(last + 1);
} }
seen[index(c)] = true; seen[c as usize] = true;
} }
} }