diff --git a/milli/src/search/new/ranking_rule_graph/dead_ends_cache.rs b/milli/src/search/new/ranking_rule_graph/dead_ends_cache.rs new file mode 100644 index 000000000..ecb6ae8da --- /dev/null +++ b/milli/src/search/new/ranking_rule_graph/dead_ends_cache.rs @@ -0,0 +1,93 @@ +use crate::search::new::{ + interner::{FixedSizeInterner, Interned}, + small_bitmap::SmallBitmap, +}; + +pub struct DeadEndsCache { + conditions: Vec>, + next: Vec, + pub forbidden: SmallBitmap, +} +impl Clone for DeadEndsCache { + fn clone(&self) -> Self { + Self { + conditions: self.conditions.clone(), + next: self.next.clone(), + forbidden: self.forbidden.clone(), + } + } +} +impl DeadEndsCache { + pub fn new(for_interner: &FixedSizeInterner) -> Self { + Self { + conditions: vec![], + next: vec![], + forbidden: SmallBitmap::for_interned_values_in(for_interner), + } + } + pub fn forbid_condition(&mut self, condition: Interned) { + self.forbidden.insert(condition); + } + + pub fn advance(&mut self, condition: Interned) -> Option<&mut Self> { + if let Some(idx) = self.conditions.iter().position(|c| *c == condition) { + Some(&mut self.next[idx]) + } else { + None + } + } + pub fn forbidden_conditions_for_all_prefixes_up_to( + &mut self, + prefix: &[Interned], + ) -> SmallBitmap { + let mut forbidden = self.forbidden.clone(); + let mut cursor = self; + for c in prefix.iter() { + if let Some(next) = cursor.advance(*c) { + cursor = next; + forbidden.union(&cursor.forbidden); + } else { + break; + } + } + forbidden + } + pub fn forbidden_conditions_after_prefix( + &mut self, + prefix: &[Interned], + ) -> Option> { + let mut cursor = self; + for c in prefix.iter() { + if let Some(next) = cursor.advance(*c) { + cursor = next; + } else { + return None; + } + } + Some(cursor.forbidden.clone()) + } + pub fn forbid_condition_after_prefix( + &mut self, + mut prefix: impl Iterator>, + forbidden: Interned, + ) { + match prefix.next() { + None => { + self.forbidden.insert(forbidden); + } + Some(first_condition) => { + if let Some(idx) = self.conditions.iter().position(|c| *c == first_condition) { + return self.next[idx].forbid_condition_after_prefix(prefix, forbidden); + } + let mut rest = DeadEndsCache { + conditions: vec![], + next: vec![], + forbidden: SmallBitmap::new(self.forbidden.universe_length()), + }; + rest.forbid_condition_after_prefix(prefix, forbidden); + self.conditions.push(first_condition); + self.next.push(rest); + } + } + } +}