pub type Cap = Option<(usize, usize)>;
#[derive(Clone, Debug)]
pub struct PartialCandidate {
pub end: usize,
pub completed: usize,
pub caps: Vec<Cap>,
pub open: Vec<(usize, usize)>,
}
pub struct State {
pub chars: Vec<char>,
pub char_to_byte: Vec<usize>,
pub pos: usize,
pub search_start: usize,
pub n_groups: usize,
pub caps: Vec<Cap>,
pub log: Vec<Vec<(usize, usize)>>,
pub partial_mode: bool,
pub partial_best: Option<PartialCandidate>,
pub open_groups: Vec<(usize, usize)>,
}
#[derive(Clone)]
pub struct Snapshot {
pub pos: usize,
pub caps: Vec<Cap>,
pub log_lens: Vec<usize>,
pub open_groups: Vec<(usize, usize)>,
}
impl State {
pub fn new(chars: Vec<char>, char_to_byte: Vec<usize>, n_groups: usize) -> Self {
State {
chars,
char_to_byte,
pos: 0,
search_start: 0,
n_groups,
caps: vec![None; n_groups + 1],
log: (0..=n_groups).map(|_| Vec::new()).collect(),
partial_mode: false,
partial_best: None,
open_groups: Vec::new(),
}
}
pub fn snapshot(&self) -> Snapshot {
Snapshot {
pos: self.pos,
caps: self.caps.clone(),
log_lens: self.log.iter().map(|v| v.len()).collect(),
open_groups: self.open_groups.clone(),
}
}
pub fn restore(&mut self, s: Snapshot) {
self.pos = s.pos;
self.caps = s.caps;
for (v, len) in self.log.iter_mut().zip(s.log_lens.iter()) {
v.truncate(*len);
}
self.open_groups = s.open_groups;
}
pub fn reset_for_search(&mut self, start: usize) {
self.pos = start;
self.search_start = start;
for c in self.caps.iter_mut() {
*c = None;
}
for v in self.log.iter_mut() {
v.clear();
}
self.open_groups.clear();
self.partial_best = None;
}
pub fn record_partial_block(&mut self) {
let completed = self.caps.iter().filter(|c| c.is_some()).count();
let cand = PartialCandidate {
end: self.pos,
completed,
caps: self.caps.clone(),
open: self.open_groups.clone(),
};
let better = match &self.partial_best {
None => true,
Some(b) => (cand.end, cand.completed) > (b.end, b.completed),
};
if better {
self.partial_best = Some(cand);
}
}
#[inline]
pub fn close_group(&mut self, idx: usize, start: usize) {
let end = self.pos;
self.caps[idx] = Some((start, end));
self.log[idx].push((start, end));
}
#[inline]
pub fn cur(&self) -> Option<char> {
self.chars.get(self.pos).copied()
}
#[inline]
pub fn prev(&self) -> Option<char> {
if self.pos == 0 {
None
} else {
self.chars.get(self.pos - 1).copied()
}
}
#[inline]
pub fn len(&self) -> usize {
self.chars.len()
}
}