mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.13.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
@ -1231,17 +1222,6 @@ dependencies = [
|
|||||||
"arrayvec",
|
"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]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -2644,7 +2624,6 @@ dependencies = [
|
|||||||
"ciborium",
|
"ciborium",
|
||||||
"comemo",
|
"comemo",
|
||||||
"csv",
|
"csv",
|
||||||
"dashmap",
|
|
||||||
"ecow",
|
"ecow",
|
||||||
"fontdb",
|
"fontdb",
|
||||||
"hayagriva",
|
"hayagriva",
|
||||||
@ -2657,7 +2636,6 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.1.0",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
"lasso",
|
|
||||||
"lipsum",
|
"lipsum",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -38,7 +38,6 @@ clap_mangen = "0.2.10"
|
|||||||
codespan-reporting = "0.11"
|
codespan-reporting = "0.11"
|
||||||
comemo = "0.3.1"
|
comemo = "0.3.1"
|
||||||
csv = "1"
|
csv = "1"
|
||||||
dashmap = "5.5"
|
|
||||||
dirs = "5"
|
dirs = "5"
|
||||||
ecow = { version = "0.2", features = ["serde"] }
|
ecow = { version = "0.2", features = ["serde"] }
|
||||||
env_proxy = "0.4"
|
env_proxy = "0.4"
|
||||||
@ -59,7 +58,6 @@ include_dir = "0.7"
|
|||||||
indexmap = { version = "2", features = ["serde"] }
|
indexmap = { version = "2", features = ["serde"] }
|
||||||
inferno = "0.11.15"
|
inferno = "0.11.15"
|
||||||
kurbo = "0.9"
|
kurbo = "0.9"
|
||||||
lasso = { version = "0.7.2", features = ["ahasher", "multi-threaded"] }
|
|
||||||
lipsum = "0.9"
|
lipsum = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
miniz_oxide = "0.7"
|
miniz_oxide = "0.7"
|
||||||
|
@ -111,7 +111,7 @@ impl SystemWorld {
|
|||||||
|
|
||||||
/// Reset the compilation state in preparation of a new compilation.
|
/// Reset the compilation state in preparation of a new compilation.
|
||||||
pub fn reset(&mut self) {
|
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();
|
slot.reset();
|
||||||
}
|
}
|
||||||
self.now.take();
|
self.now.take();
|
||||||
|
@ -24,7 +24,6 @@ chinese-number = { workspace = true }
|
|||||||
ciborium = { workspace = true }
|
ciborium = { workspace = true }
|
||||||
comemo = { workspace = true }
|
comemo = { workspace = true }
|
||||||
csv = { workspace = true }
|
csv = { workspace = true }
|
||||||
dashmap = { workspace = true }
|
|
||||||
ecow = { workspace = true}
|
ecow = { workspace = true}
|
||||||
fontdb = { workspace = true }
|
fontdb = { workspace = true }
|
||||||
hayagriva = { workspace = true }
|
hayagriva = { workspace = true }
|
||||||
@ -37,7 +36,6 @@ icu_segmenter = { workspace = true }
|
|||||||
image = { workspace = true }
|
image = { workspace = true }
|
||||||
indexmap = { workspace = true }
|
indexmap = { workspace = true }
|
||||||
kurbo = { workspace = true }
|
kurbo = { workspace = true }
|
||||||
lasso = { workspace = true }
|
|
||||||
lipsum = { workspace = true }
|
lipsum = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
|
@ -2,9 +2,9 @@ use std::collections::{BTreeSet, HashMap};
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use comemo::Prehashed;
|
use comemo::Prehashed;
|
||||||
use dashmap::DashMap;
|
|
||||||
use ecow::{eco_format, EcoVec};
|
use ecow::{eco_format, EcoVec};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -32,7 +32,7 @@ pub struct Introspector {
|
|||||||
/// even if all top-level queries are distinct, they often have shared
|
/// even if all top-level queries are distinct, they often have shared
|
||||||
/// subqueries. Example: Individual counter queries with `before` that
|
/// subqueries. Example: Individual counter queries with `before` that
|
||||||
/// all depend on a global counter query.
|
/// all depend on a global counter query.
|
||||||
queries: DashMap<u128, EcoVec<Prehashed<Content>>>,
|
queries: QueryCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Introspector {
|
impl Introspector {
|
||||||
@ -118,8 +118,8 @@ impl Introspector {
|
|||||||
/// Query for all matching elements.
|
/// Query for all matching elements.
|
||||||
pub fn query(&self, selector: &Selector) -> EcoVec<Prehashed<Content>> {
|
pub fn query(&self, selector: &Selector) -> EcoVec<Prehashed<Content>> {
|
||||||
let hash = crate::util::hash128(selector);
|
let hash = crate::util::hash128(selector);
|
||||||
if let Some(output) = self.queries.get(&hash) {
|
if let Some(output) = self.queries.get(hash) {
|
||||||
return output.clone();
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = match selector {
|
let output = match selector {
|
||||||
@ -256,7 +256,7 @@ impl Default for Introspector {
|
|||||||
elems: IndexMap::new(),
|
elems: IndexMap::new(),
|
||||||
labels: HashMap::new(),
|
labels: HashMap::new(),
|
||||||
page_numberings: vec![],
|
page_numberings: vec![],
|
||||||
queries: DashMap::new(),
|
queries: QueryCache::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,3 +266,27 @@ impl Debug for Introspector {
|
|||||||
f.pad("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);
|
let disambiguator = self.disambiguator_impl(hash);
|
||||||
|
|
||||||
// Bump the next disambiguator up by one.
|
// 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.
|
// Create the location in its default variant.
|
||||||
Location { hash, disambiguator, variant: 0 }
|
Location { hash, disambiguator, variant: 0 }
|
||||||
@ -78,7 +78,7 @@ impl<'a> Locator<'a> {
|
|||||||
match item {
|
match item {
|
||||||
FrameItem::Group(group) => self.visit_frame(&group.frame),
|
FrameItem::Group(group) => self.visit_frame(&group.frame),
|
||||||
FrameItem::Meta(Meta::Elem(elem), _) => {
|
FrameItem::Meta(Meta::Elem(elem), _) => {
|
||||||
let mut hashes = self.hashes.borrow_mut();
|
let hashes = self.hashes.get_mut();
|
||||||
let loc = elem.location().unwrap();
|
let loc = elem.location().unwrap();
|
||||||
let entry = hashes.entry(loc.hash).or_default();
|
let entry = hashes.entry(loc.hash).or_default();
|
||||||
|
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use lasso::{Spur, ThreadedRodeo};
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::foundations::cast;
|
use crate::foundations::cast;
|
||||||
|
|
||||||
/// The global string interner.
|
/// 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.
|
/// 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`]
|
/// 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.
|
/// method to get the underlying string, such that the lookup is done only once.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct PicoStr(Spur);
|
pub struct PicoStr(u32);
|
||||||
|
|
||||||
impl PicoStr {
|
impl PicoStr {
|
||||||
/// Creates a new interned string.
|
/// Creates a new interned string.
|
||||||
pub fn new(s: impl AsRef<str>) -> Self {
|
pub fn new(string: &str) -> Self {
|
||||||
Self(INTERNER.get_or_intern(s.as_ref()))
|
if let Some(&id) = INTERNER.read().unwrap().to_id.get(string) {
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new interned string from a static string.
|
let mut interner = INTERNER.write().unwrap();
|
||||||
pub fn static_(s: &'static str) -> Self {
|
let num = interner.from_id.len().try_into().expect("out of string ids");
|
||||||
Self(INTERNER.get_or_intern_static(s))
|
|
||||||
|
// 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.
|
/// Resolves the interned string.
|
||||||
pub fn resolve(&self) -> &'static str {
|
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