use alloc::vec::Vec;
pub(crate) fn pattern_starts(input: &str, pattern: &str) -> Vec<usize> {
(0..input.len())
.filter(|index| input.as_bytes()[*index..].starts_with(pattern.as_bytes()))
.collect()
}
#[derive(Default)]
pub(crate) struct Positions {
positions: Option<Vec<usize>>,
}
impl Positions {
pub(crate) fn first_at_or_after(
&mut self,
from: usize,
collect: impl FnOnce() -> Vec<usize>,
) -> Option<usize> {
let positions = self.positions.get_or_insert_with(collect);
positions
.get(positions.partition_point(|position| *position < from))
.copied()
}
}
pub(crate) enum Step {
Done(Option<usize>),
Next(usize),
}
const UNKNOWN: usize = usize::MAX;
const NO_ANSWER: usize = usize::MAX - 1;
fn encode(answer: Option<usize>) -> usize {
answer.unwrap_or(NO_ANSWER)
}
fn decode(slot: usize) -> Option<usize> {
(slot != NO_ANSWER).then_some(slot)
}
pub(crate) fn path_walk(start: usize, mut step: impl FnMut(usize) -> Step) -> Option<usize> {
let mut node = start;
loop {
match step(node) {
Step::Done(answer) => return answer,
Step::Next(next) => node = next,
}
}
}
#[derive(Default)]
pub(crate) struct PathMemo {
answers: Vec<usize>,
pending: Vec<usize>,
}
impl PathMemo {
pub(crate) fn resolve(
&mut self,
nodes: usize,
start: usize,
mut step: impl FnMut(usize) -> Step,
) -> Option<usize> {
if self.answers.is_empty() {
self.answers = alloc::vec![UNKNOWN; nodes];
}
let mut cursor = start;
let answer = loop {
let known = self.answers[cursor];
if known != UNKNOWN {
break decode(known);
}
self.pending.push(cursor);
match step(cursor) {
Step::Done(answer) => break answer,
Step::Next(next) => cursor = next,
}
};
for position in self.pending.drain(..) {
self.answers[position] = encode(answer);
}
answer
}
}
pub(crate) enum BracketStep {
End,
Open(usize),
Close(usize),
Pass(usize),
}
pub(crate) fn bracket_walk(
start: usize,
mut step: impl FnMut(usize) -> BracketStep,
) -> Option<usize> {
let mut position = start;
let mut depth = 0usize;
loop {
match step(position) {
BracketStep::End => return None,
BracketStep::Open(next) => {
depth += 1;
position = next;
}
BracketStep::Close(next) => {
if depth == 0 {
return Some(position);
}
depth -= 1;
position = next;
}
BracketStep::Pass(next) => position = next,
}
}
}
#[derive(Default)]
pub(crate) struct BracketMemo {
answers: Vec<usize>,
frames: Vec<(usize, Phase)>,
}
#[derive(Clone, Copy)]
enum Phase {
Enter,
AfterPass,
AfterInnerMatch,
AfterOuter,
}
impl BracketMemo {
pub(crate) fn resolve(
&mut self,
positions: usize,
start: usize,
mut step: impl FnMut(usize) -> BracketStep,
) -> Option<usize> {
if self.answers.is_empty() {
self.answers = alloc::vec![UNKNOWN; positions];
}
self.frames.push((start, Phase::Enter));
let mut answer = None;
while let Some((position, phase)) = self.frames.pop() {
match phase {
Phase::Enter => {
let known = self.answers[position];
if known != UNKNOWN {
answer = decode(known);
continue;
}
match step(position) {
BracketStep::End => {
answer = None;
self.answers[position] = NO_ANSWER;
}
BracketStep::Close(_) => {
answer = Some(position);
self.answers[position] = position;
}
BracketStep::Pass(next) => {
self.frames.push((position, Phase::AfterPass));
self.frames.push((next, Phase::Enter));
}
BracketStep::Open(next) => {
self.frames.push((position, Phase::AfterInnerMatch));
self.frames.push((next, Phase::Enter));
}
}
}
Phase::AfterPass | Phase::AfterOuter => {
self.answers[position] = encode(answer);
}
Phase::AfterInnerMatch => match answer {
None => self.answers[position] = NO_ANSWER,
Some(inner_match) => {
let BracketStep::Close(after_match) = step(inner_match) else {
unreachable!("a walk answer is always a close");
};
self.frames.push((position, Phase::AfterOuter));
self.frames.push((after_match, Phase::Enter));
}
},
}
}
answer
}
}