use std::cmp::Ordering;
use std::ops;
#[cfg(feature = "serde")]
use serde_crate::{Deserialize, Serialize};
use crate::trie::get_characters;
use crate::trie_node::TrieDatalessNode;
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[derive(Debug, Default)]
pub struct Trie {
root: TrieDatalessNode,
len: usize,
}
impl Trie {
pub fn new() -> Self {
Trie {
root: TrieDatalessNode::new(),
len: 0,
}
}
pub fn insert(&mut self, word: &str) {
let mut current = &mut self.root;
for character in get_characters(word) {
if current.children.get_mut(character).is_none() {
current.children.insert_new(character);
}
current = current.children.get_mut(character).unwrap();
}
if !current.is_associated() {
self.len += 1;
}
current.associate();
}
pub fn remove(&mut self, word: &str) {
let Some(current) = self.get_final_node_mut(word) else {
return;
};
let characters = get_characters(word);
if !current.children.is_empty() {
return if current.is_associated() {
current.disassociate();
self.len -= 1;
};
}
self.root.remove_one_word(characters.into_iter());
self.len -= 1;
}
pub fn remove_prefix(&mut self, prefix: &str) {
let Some(current) = self.get_final_node_mut(prefix) else {
return;
};
self.len -= current.remove_all_words() - (current.is_associated() as usize);
}
pub fn get(&self, query: &str) -> Option<Vec<String>> {
let mut substring = String::new();
let mut current_node = &self.root;
let characters = get_characters(query);
for character in characters {
current_node = match current_node.children.get(character) {
None => return None,
Some(trie_node) => {
substring.push(character);
trie_node
}
}
}
let mut words_vec = Vec::new();
current_node.find_words(&mut substring, &mut words_vec);
Some(words_vec)
}
pub fn get_longest(&self) -> Vec<String> {
let mut words = Vec::new();
let mut collector = String::new();
let mut best_len = None;
self.root.words_min_max(
&mut collector,
0,
&mut words,
&mut best_len,
#[cfg(feature = "unicode")]
true,
Ordering::Greater,
);
words
}
pub fn get_shortest(&self) -> Vec<String> {
let mut words = Vec::new();
let mut collector = String::new();
let mut best_len = None;
self.root.words_min_max(
&mut collector,
0,
&mut words,
&mut best_len,
#[cfg(feature = "unicode")]
true,
Ordering::Less,
);
words
}
pub fn len(&self) -> usize {
self.len
}
pub fn len_prefix(&self, prefix: &str) -> usize {
match self.get_final_node(prefix) {
None => 0,
Some(node) => node.count_words() - node.is_associated() as usize,
}
}
pub fn get_all(&self) -> Vec<String> {
self.get("").unwrap()
}
pub fn contains(&self, query: &str) -> bool {
self.get_final_node(query)
.is_some_and(|node| node.is_associated())
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn clear(&mut self) {
self.root.clear_children();
self.len = 0;
}
fn get_final_node(&self, query: &str) -> Option<&TrieDatalessNode> {
let mut current = &self.root;
for character in get_characters(query) {
current = current.children.get(character)?;
}
Some(current)
}
fn get_final_node_mut(&mut self, query: &str) -> Option<&mut TrieDatalessNode> {
let mut current = &mut self.root;
for character in get_characters(query) {
current = current.children.get_mut(character)?;
}
Some(current)
}
}
impl ops::Add for Trie {
type Output = Trie;
fn add(self, rhs: Self) -> Self::Output {
let (smaller, mut bigger) = if self.len < rhs.len {
(self, rhs)
} else {
(rhs, self)
};
bigger.root += smaller.root;
bigger.len = bigger.root.count_words();
bigger
}
}
impl ops::AddAssign for Trie {
fn add_assign(&mut self, rhs: Self) {
self.root += rhs.root;
self.len = self.root.count_words();
}
}
impl PartialEq for Trie {
fn eq(&self, other: &Self) -> bool {
self.len == other.len && self.root == other.root
}
}