Prehashed query result

This commit is contained in:
Laurenz 2025-07-19 22:48:59 +02:00
parent af173acd59
commit 5764c65ec9
9 changed files with 19 additions and 15 deletions

View File

@ -79,6 +79,7 @@ fn retrieve(
Ok(document
.introspector
.query(&selector.0)
.into_inner()
.into_iter()
.collect::<Vec<_>>())
}

View File

@ -430,7 +430,7 @@ const OUTLINE_RULE: ShowFn<OutlineElem> = |elem, engine, styles| {
let depth = elem.depth.get(styles).unwrap_or(NonZeroUsize::MAX);
// Build the outline entries.
for elem in elems {
for elem in elems.into_inner() {
let Some(outlinable) = elem.with::<dyn Outlinable>() else {
bail!(span, "cannot outline {}", elem.func().name());
};

View File

@ -312,7 +312,7 @@ impl Counter {
let mut page = NonZeroUsize::ONE;
let mut stops = eco_vec![(state.clone(), page)];
for elem in introspector.query(&self.selector()) {
for elem in introspector.query(&self.selector()).into_inner() {
if self.is_page() {
let prev = page;
page = introspector.page(elem.location().unwrap());

View File

@ -4,6 +4,7 @@ use std::hash::Hash;
use std::num::NonZeroUsize;
use std::sync::RwLock;
use comemo::Prehashed;
use ecow::{EcoString, EcoVec};
use smallvec::SmallVec;
use typst_utils::NonZeroExt;
@ -108,7 +109,7 @@ impl Introspector {
#[comemo::track]
impl Introspector {
/// Query for all matching elements.
pub fn query(&self, selector: &Selector) -> EcoVec<Content> {
pub fn query(&self, selector: &Selector) -> Prehashed<EcoVec<Content>> {
let hash = typst_utils::hash128(selector);
if let Some(output) = self.queries.get(hash) {
return output;
@ -131,7 +132,7 @@ impl Introspector {
.collect(),
Selector::Or(selectors) => selectors
.iter()
.flat_map(|sel| self.query(sel))
.flat_map(|sel| self.query(sel).into_inner())
.map(|elem| self.elem_index(&elem))
.collect::<BTreeSet<usize>>()
.into_iter()
@ -139,7 +140,7 @@ impl Introspector {
.collect(),
Selector::And(selectors) => {
let mut results: Vec<_> =
selectors.iter().map(|sel| self.query(sel)).collect();
selectors.iter().map(|sel| self.query(sel).into_inner()).collect();
// Extract the smallest result list and then keep only those
// elements in the smallest list that are also in all other
@ -161,7 +162,7 @@ impl Introspector {
.collect()
}
Selector::Before { selector, end, inclusive } => {
let mut list = self.query(selector);
let mut list = self.query(selector).into_inner();
if let Some(end) = self.query_first(end) {
// Determine which elements are before `end`.
let split = match self.binary_search(&list, &end) {
@ -175,7 +176,7 @@ impl Introspector {
list
}
Selector::After { selector, start, inclusive } => {
let mut list = self.query(selector);
let mut list = self.query(selector).into_inner();
if let Some(start) = self.query_first(start) {
// Determine which elements are after `start`.
let split = match self.binary_search(&list, &start) {
@ -192,6 +193,7 @@ impl Introspector {
Selector::Can(_) | Selector::Regex(_) => EcoVec::new(),
};
let output = Prehashed::new(output);
self.queries.insert(hash, output.clone());
output
}
@ -223,6 +225,7 @@ impl Introspector {
bail!("selector matches multiple elements",);
}
elems
.into_inner()
.into_iter()
.next()
.ok_or_else(|| "selector does not match any element".into())
@ -340,14 +343,14 @@ impl<K, V> Default for MultiMap<K, V> {
/// Caches queries.
#[derive(Default)]
struct QueryCache(RwLock<HashMap<u128, EcoVec<Content>>>);
struct QueryCache(RwLock<HashMap<u128, Prehashed<EcoVec<Content>>>>);
impl QueryCache {
fn get(&self, hash: u128) -> Option<EcoVec<Content>> {
fn get(&self, hash: u128) -> Option<Prehashed<EcoVec<Content>>> {
self.0.read().unwrap().get(&hash).cloned()
}
fn insert(&self, hash: u128, output: EcoVec<Content>) {
fn insert(&self, hash: u128, output: Prehashed<EcoVec<Content>>) {
self.0.write().unwrap().insert(hash, output);
}
}

View File

@ -149,5 +149,5 @@ pub fn query(
) -> HintedStrResult<Array> {
context.introspect()?;
let vec = engine.introspector.query(&target.0);
Ok(vec.into_iter().map(Value::Content).collect())
Ok(vec.into_inner().into_iter().map(Value::Content).collect())
}

View File

@ -242,7 +242,7 @@ impl State {
let mut state = self.init.clone();
let mut stops = eco_vec![state.clone()];
for elem in introspector.query(&self.selector()) {
for elem in introspector.query(&self.selector()).into_inner() {
let elem = elem.to_packed::<StateUpdateElem>().unwrap();
match &elem.update {
StateUpdate::Set(value) => state = value.clone(),

View File

@ -563,7 +563,7 @@ impl<'a> Generator<'a> {
introspector: Tracked<Introspector>,
) -> StrResult<Self> {
let bibliography = BibliographyElem::find(introspector)?;
let groups = introspector.query(&CiteGroup::ELEM.select());
let groups = introspector.query(&CiteGroup::ELEM.select()).into_inner();
let infos = Vec::with_capacity(groups.len());
Ok(Self {
routines,

View File

@ -656,7 +656,7 @@ fn query_prefix_widths(
) -> SmallVec<[Option<Abs>; 4]> {
let mut widths = SmallVec::<[Option<Abs>; 4]>::new();
let elems = introspector.query(&select_where!(PrefixInfo, key => outline_loc));
for elem in &elems {
for elem in &elems.into_inner() {
let info = elem.to_packed::<PrefixInfo>().unwrap();
let level = info.level.get();
if widths.len() < level {

View File

@ -13,7 +13,7 @@ pub(crate) fn embed_files(
) -> SourceResult<()> {
let elements = typst_doc.introspector.query(&EmbedElem::ELEM.select());
for elem in &elements {
for elem in &elements.into_inner() {
let embed = elem.to_packed::<EmbedElem>().unwrap();
let span = embed.span();
let derived_path = &embed.path.derived;