mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Drop dependency on DashMap
DashMap doesn't work in multi-threaded WebAssembly in Safari: https://bugs.webkit.org/show_bug.cgi?id=265581
This commit is contained in:
parent
de40124adb
commit
f16a9ea9ad
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -781,15 +781,6 @@ version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
@ -1231,17 +1222,6 @@ dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lasso"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4644821e1c3d7a560fe13d842d13f587c07348a1a05d3a797152d41c90c56df2"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"dashmap",
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@ -2644,7 +2624,6 @@ dependencies = [
|
||||
"ciborium",
|
||||
"comemo",
|
||||
"csv",
|
||||
"dashmap",
|
||||
"ecow",
|
||||
"fontdb",
|
||||
"hayagriva",
|
||||
@ -2657,7 +2636,6 @@ dependencies = [
|
||||
"image",
|
||||
"indexmap 2.1.0",
|
||||
"kurbo",
|
||||
"lasso",
|
||||
"lipsum",
|
||||
"log",
|
||||
"once_cell",
|
||||
|
@ -38,7 +38,6 @@ clap_mangen = "0.2.10"
|
||||
codespan-reporting = "0.11"
|
||||
comemo = "0.3.1"
|
||||
csv = "1"
|
||||
dashmap = "5.5"
|
||||
dirs = "5"
|
||||
ecow = { version = "0.2", features = ["serde"] }
|
||||
env_proxy = "0.4"
|
||||
@ -59,7 +58,6 @@ include_dir = "0.7"
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
inferno = "0.11.15"
|
||||
kurbo = "0.9"
|
||||
lasso = { version = "0.7.2", features = ["ahasher", "multi-threaded"] }
|
||||
lipsum = "0.9"
|
||||
log = "0.4"
|
||||
miniz_oxide = "0.7"
|
||||
|
@ -111,7 +111,7 @@ impl SystemWorld {
|
||||
|
||||
/// Reset the compilation state in preparation of a new compilation.
|
||||
pub fn reset(&mut self) {
|
||||
for slot in self.slots.borrow_mut().values_mut() {
|
||||
for slot in self.slots.get_mut().values_mut() {
|
||||
slot.reset();
|
||||
}
|
||||
self.now.take();
|
||||
|
@ -24,7 +24,6 @@ chinese-number = { workspace = true }
|
||||
ciborium = { workspace = true }
|
||||
comemo = { workspace = true }
|
||||
csv = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
ecow = { workspace = true}
|
||||
fontdb = { workspace = true }
|
||||
hayagriva = { workspace = true }
|
||||
@ -37,7 +36,6 @@ icu_segmenter = { workspace = true }
|
||||
image = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
kurbo = { workspace = true }
|
||||
lasso = { workspace = true }
|
||||
lipsum = { workspace = true }
|
||||
log = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
|
@ -2,9 +2,9 @@ use std::collections::{BTreeSet, HashMap};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::hash::Hash;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use comemo::Prehashed;
|
||||
use dashmap::DashMap;
|
||||
use ecow::{eco_format, EcoVec};
|
||||
use indexmap::IndexMap;
|
||||
use smallvec::SmallVec;
|
||||
@ -32,7 +32,7 @@ pub struct Introspector {
|
||||
/// even if all top-level queries are distinct, they often have shared
|
||||
/// subqueries. Example: Individual counter queries with `before` that
|
||||
/// all depend on a global counter query.
|
||||
queries: DashMap<u128, EcoVec<Prehashed<Content>>>,
|
||||
queries: QueryCache,
|
||||
}
|
||||
|
||||
impl Introspector {
|
||||
@ -118,8 +118,8 @@ impl Introspector {
|
||||
/// Query for all matching elements.
|
||||
pub fn query(&self, selector: &Selector) -> EcoVec<Prehashed<Content>> {
|
||||
let hash = crate::util::hash128(selector);
|
||||
if let Some(output) = self.queries.get(&hash) {
|
||||
return output.clone();
|
||||
if let Some(output) = self.queries.get(hash) {
|
||||
return output;
|
||||
}
|
||||
|
||||
let output = match selector {
|
||||
@ -256,7 +256,7 @@ impl Default for Introspector {
|
||||
elems: IndexMap::new(),
|
||||
labels: HashMap::new(),
|
||||
page_numberings: vec![],
|
||||
queries: DashMap::new(),
|
||||
queries: QueryCache::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,3 +266,27 @@ impl Debug for Introspector {
|
||||
f.pad("Introspector(..)")
|
||||
}
|
||||
}
|
||||
|
||||
/// Caches queries.
|
||||
#[derive(Default)]
|
||||
struct QueryCache(RwLock<HashMap<u128, EcoVec<Prehashed<Content>>>>);
|
||||
|
||||
impl QueryCache {
|
||||
fn get(&self, hash: u128) -> Option<EcoVec<Prehashed<Content>>> {
|
||||
self.0.read().unwrap().get(&hash).cloned()
|
||||
}
|
||||
|
||||
fn insert(&self, hash: u128, output: EcoVec<Prehashed<Content>>) {
|
||||
self.0.write().unwrap().insert(hash, output);
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.0.get_mut().unwrap().clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for QueryCache {
|
||||
fn clone(&self) -> Self {
|
||||
Self(RwLock::new(self.0.read().unwrap().clone()))
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ impl<'a> Locator<'a> {
|
||||
let disambiguator = self.disambiguator_impl(hash);
|
||||
|
||||
// Bump the next disambiguator up by one.
|
||||
self.hashes.borrow_mut().insert(hash, disambiguator + 1);
|
||||
self.hashes.get_mut().insert(hash, disambiguator + 1);
|
||||
|
||||
// Create the location in its default variant.
|
||||
Location { hash, disambiguator, variant: 0 }
|
||||
@ -78,7 +78,7 @@ impl<'a> Locator<'a> {
|
||||
match item {
|
||||
FrameItem::Group(group) => self.visit_frame(&group.frame),
|
||||
FrameItem::Meta(Meta::Elem(elem), _) => {
|
||||
let mut hashes = self.hashes.borrow_mut();
|
||||
let hashes = self.hashes.get_mut();
|
||||
let loc = elem.location().unwrap();
|
||||
let entry = hashes.entry(loc.hash).or_default();
|
||||
|
||||
|
@ -1,13 +1,21 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::sync::RwLock;
|
||||
|
||||
use ecow::EcoString;
|
||||
use lasso::{Spur, ThreadedRodeo};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::foundations::cast;
|
||||
|
||||
/// The global string interner.
|
||||
static INTERNER: Lazy<ThreadedRodeo> = Lazy::new(ThreadedRodeo::new);
|
||||
static INTERNER: Lazy<RwLock<Interner>> =
|
||||
Lazy::new(|| RwLock::new(Interner { to_id: HashMap::new(), from_id: Vec::new() }));
|
||||
|
||||
/// A string interner.
|
||||
struct Interner {
|
||||
to_id: HashMap<&'static str, PicoStr>,
|
||||
from_id: Vec<&'static str>,
|
||||
}
|
||||
|
||||
/// An interned string.
|
||||
///
|
||||
@ -16,22 +24,30 @@ static INTERNER: Lazy<ThreadedRodeo> = Lazy::new(ThreadedRodeo::new);
|
||||
/// unnecessarily. For this reason, the user should use the [`PicoStr::resolve`]
|
||||
/// method to get the underlying string, such that the lookup is done only once.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct PicoStr(Spur);
|
||||
pub struct PicoStr(u32);
|
||||
|
||||
impl PicoStr {
|
||||
/// Creates a new interned string.
|
||||
pub fn new(s: impl AsRef<str>) -> Self {
|
||||
Self(INTERNER.get_or_intern(s.as_ref()))
|
||||
}
|
||||
pub fn new(string: &str) -> Self {
|
||||
if let Some(&id) = INTERNER.read().unwrap().to_id.get(string) {
|
||||
return id;
|
||||
}
|
||||
|
||||
/// Creates a new interned string from a static string.
|
||||
pub fn static_(s: &'static str) -> Self {
|
||||
Self(INTERNER.get_or_intern_static(s))
|
||||
let mut interner = INTERNER.write().unwrap();
|
||||
let num = interner.from_id.len().try_into().expect("out of string ids");
|
||||
|
||||
// Create a new entry forever by leaking the string. PicoStr is only
|
||||
// used for strings that aren't created en masse, so it is okay.
|
||||
let id = Self(num);
|
||||
let string = Box::leak(string.to_string().into_boxed_str());
|
||||
interner.to_id.insert(string, id);
|
||||
interner.from_id.push(string);
|
||||
id
|
||||
}
|
||||
|
||||
/// Resolves the interned string.
|
||||
pub fn resolve(&self) -> &'static str {
|
||||
INTERNER.resolve(&self.0)
|
||||
INTERNER.read().unwrap().from_id[self.0 as usize]
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user