use std::collections::HashMap;
use nodedb_types::Surrogate;
use crate::block::CompactPosting;
use crate::codec::smallfloat;
#[derive(Default)]
pub(crate) struct ScopeState {
pub(super) postings: HashMap<String, Vec<CompactPosting>>,
pub(super) total_postings: usize,
pub(super) stats: (u32, u64),
pub(super) fieldnorms: Vec<u8>,
pub(super) fieldnorms_exact: Vec<u32>,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Removed {
pub(crate) postings: usize,
pub(crate) terms: usize,
}
impl ScopeState {
pub(super) fn insert(&mut self, term: &str, posting: CompactPosting) -> bool {
self.total_postings += 1;
match self.postings.get_mut(term) {
Some(list) => {
list.push(posting);
false
}
None => {
self.postings.insert(term.to_string(), vec![posting]);
true
}
}
}
pub(super) fn record_doc(&mut self, doc_id: Surrogate, doc_len: u32) {
self.stats.0 += 1;
self.stats.1 += doc_len as u64;
let idx = doc_id.0 as usize;
if idx >= self.fieldnorms.len() {
self.fieldnorms.resize(idx + 1, 0);
}
self.fieldnorms[idx] = smallfloat::encode(doc_len);
if idx >= self.fieldnorms_exact.len() {
self.fieldnorms_exact.resize(idx + 1, 0);
}
self.fieldnorms_exact[idx] = doc_len;
}
pub(super) fn remove_doc(&mut self, doc_id: Surrogate) -> Removed {
let mut removed = Removed::default();
self.postings.retain(|_, postings| {
let before = postings.len();
postings.retain(|p| p.doc_id != doc_id);
removed.postings += before - postings.len();
if postings.len() < before
&& !postings.is_empty()
&& postings.capacity() > postings.len().saturating_mul(2).max(4)
{
postings.shrink_to(postings.len());
}
let keep = !postings.is_empty();
if !keep {
removed.terms += 1;
}
keep
});
self.total_postings -= removed.postings;
if let Some(slot) = self.fieldnorms_exact.get_mut(doc_id.0 as usize)
&& *slot > 0
{
let doc_len = *slot;
*slot = 0;
self.stats.0 = self.stats.0.saturating_sub(1);
self.stats.1 = self.stats.1.saturating_sub(doc_len as u64);
}
removed
}
pub(super) fn is_vacant(&self) -> bool {
self.postings.is_empty() && self.stats.0 == 0
}
pub(super) fn footprint(&self) -> Removed {
Removed {
postings: self.total_postings,
terms: self.postings.len(),
}
}
}