use std::collections::HashMap;
use super::node::SuffixNode;
use crate::value::DictionaryValue;
use crate::CharUnit;
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(
all(feature = "serialization", not(feature = "persistent-artrie")),
serde(bound(
serialize = "U: serde::Serialize, V: serde::Serialize",
deserialize = "U: serde::Deserialize<'de>, V: serde::Deserialize<'de>",
))
)]
#[cfg_attr(
all(feature = "serialization", feature = "persistent-artrie"),
serde(bound(
serialize = "U: serde::Serialize, V: serde::Serialize",
deserialize = "U: serde::de::DeserializeOwned, V: serde::de::DeserializeOwned",
))
)]
pub struct SuffixAutomatonInner<U: CharUnit, V: DictionaryValue = ()> {
pub nodes: Vec<SuffixNode<U, V>>,
pub last_state: usize,
pub string_count: usize,
pub source_texts: Vec<String>,
#[cfg_attr(feature = "serialization", serde(default))]
pub source_values: Vec<Option<V>>,
#[cfg_attr(feature = "serialization", serde(skip))]
pub sorted_source_indices: Vec<usize>,
pub positions: HashMap<usize, Vec<(usize, usize)>>,
pub needs_compaction: bool,
}
impl<U: CharUnit, V: DictionaryValue> SuffixAutomatonInner<U, V> {
pub fn new() -> Self {
Self {
nodes: vec![SuffixNode::root()],
last_state: 0,
string_count: 0,
source_texts: Vec::new(),
source_values: Vec::new(),
sorted_source_indices: Vec::new(),
positions: HashMap::new(),
needs_compaction: false,
}
}
pub fn rebuild_sorted_source_indices(&mut self) {
let mut active = vec![false; self.source_texts.len()];
for positions in self.positions.values() {
for &(source_id, _) in positions {
if let Some(slot) = active.get_mut(source_id) {
*slot = true;
}
}
}
self.sorted_source_indices = active
.into_iter()
.enumerate()
.filter_map(|(source_id, is_active)| is_active.then_some(source_id))
.collect();
self.sorted_source_indices.sort_by(|&left, &right| {
self.source_texts[left]
.cmp(&self.source_texts[right])
.then_with(|| left.cmp(&right))
});
}
pub fn index_source(&mut self, source_id: usize) {
let insertion = self.sorted_source_indices.partition_point(|&existing| {
self.source_texts[existing] < self.source_texts[source_id]
|| (self.source_texts[existing] == self.source_texts[source_id]
&& existing < source_id)
});
self.sorted_source_indices.insert(insertion, source_id);
}
pub fn unindex_source(&mut self, source_id: usize) {
if let Some(index) = self
.sorted_source_indices
.iter()
.position(|&existing| existing == source_id)
{
self.sorted_source_indices.remove(index);
}
}
pub fn extend(&mut self, unit: U) {
let cur = self.nodes.len();
let mut new_node = SuffixNode::new(self.nodes[self.last_state].max_length + 1);
new_node.is_final = true;
self.nodes.push(new_node);
let mut p = Some(self.last_state);
while let Some(p_idx) = p {
if self.nodes[p_idx].find_edge(unit).is_some() {
break;
}
self.nodes[p_idx].add_edge(unit, cur);
p = self.nodes[p_idx].suffix_link;
}
if let Some(p_idx) = p {
let q = self.nodes[p_idx]
.find_edge(unit)
.expect("suffix-link walk exited with a known edge for unit at p_idx");
if self.nodes[p_idx].max_length + 1 == self.nodes[q].max_length {
self.nodes[cur].suffix_link = Some(q);
} else {
let clone = self.nodes.len();
let mut cloned_node = self.nodes[q].clone();
cloned_node.max_length = self.nodes[p_idx].max_length + 1;
cloned_node.is_final = true;
self.nodes.push(cloned_node);
self.nodes[cur].suffix_link = Some(clone);
self.nodes[q].suffix_link = Some(clone);
let mut p2 = Some(p_idx);
while let Some(p2_idx) = p2 {
if let Some(target) = self.nodes[p2_idx].find_edge(unit) {
if target == q {
self.nodes[p2_idx].update_edge(unit, clone);
p2 = self.nodes[p2_idx].suffix_link;
} else {
break;
}
} else {
break;
}
}
}
} else {
self.nodes[cur].suffix_link = Some(0);
}
self.last_state = cur;
}
}
impl<U: CharUnit, V: DictionaryValue> Default for SuffixAutomatonInner<U, V> {
fn default() -> Self {
Self::new()
}
}