SuffixAutomatonCore<U, V>Factor SuffixAutomatonCore<U: CharUnit, V> parallel to DawgCore. Both
the byte-keyed (SuffixAutomaton<V>, src/suffix_automaton.rs) and
char-keyed (SuffixAutomatonChar<V>,
src/suffix_automaton_char.rs) variants become thin wrappers.
The audit estimated 3-4 weeks. Inspection confirms:
src/suffix_automaton.rs — 1584 LOC plus 6 trait impls and the
on-line construction state machine.src/suffix_automaton_char.rs — 1656 LOC, nearly identical structure
but char-keyed.Suffix-automaton construction state has invariants that span the entire
state graph (suffix links, length intervals, equiv classes). Generifying
without breaking these invariants requires careful refactoring,
including the extend() per-character growth algorithm and the
clone()-based split for off-suffix-link transitions.
cargo doc --no-deps -p libdictenstein then read the rendered
pages).SuffixAutomatonInner<U, V> first (no public
API change yet) and verify each variant can switch to use it
internally one method at a time.(Each step a commit.)
Create src/suffix_automaton_core/mod.rs with:
pub struct SuffixAutomatonInner<U: CharUnit, V> {
pub nodes: Vec<SuffixNode<U, V>>,
pub last_state: usize,
pub source_texts: Vec<String>,
pub positions: std::collections::HashMap<usize, Vec<(usize, usize)>>,
pub string_count: usize,
// …
}
pub struct SuffixNode<U: CharUnit, V> {
pub edges: Vec<(U, usize)>,
pub suffix_link: Option<usize>,
pub max_length: usize,
pub is_final: bool,
pub value: Option<V>,
}
extend(u: U) to the generic stateThe current extend(u8) in suffix_automaton.rs:341 and extend(char)
in suffix_automaton_char.rs are nearly identical apart from edge-label
typing. Move both to SuffixAutomatonInner::extend(u: U).
insert(&str), from_text(&str), from_texts(I)For each variant, replace the inherent method's body with a call to
U::iter_str(s) then inner.extend(u) per unit.
contains, match_positions, count_substring,find, state_count, iter_terms, source_texts
Generic over U: CharUnit. Each method body becomes:
pub fn contains(&self, term: &str) -> bool {
self.contains_units(&U::from_str(term).as_slice())
}
fn contains_units(&self, units: &[U]) -> bool { ... }
impl<V> Dictionary for SuffixAutomaton<V> becomes impl<V> Dictionary for SuffixAutomatonCore<u8, V>. The byte/char variants become aliases:
pub type SuffixAutomaton<V = ()> = SuffixAutomatonCore<u8, V>;
pub type SuffixAutomatonChar<V = ()> = SuffixAutomatonCore<char, V>;
Public API preserved via type aliases.
Run cargo test --all-features -- suffix_automaton:: and confirm no
regression. Re-run cargo bench --bench suffix_*.
suffix_automaton.rs: ~1584 → ~50 LOC (type alias + re-exports)suffix_automaton_char.rs: ~1656 → ~50 LOCsuffix_automaton_core/: ~1600 LOC sharedclone()-based suffix-automaton split in extend() creates a
new node and copies edges; the byte variant uses find_edge(u8) and
the char variant uses find_edge(char). These need a generic
find_edge(u: U) method on SuffixNode<U, V>.U = u8 and a format bump for U = char. Plan a serialization
back-compat shim if there are existing on-disk indexes.Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |