Skip to content

Commit eb264fb

Browse files
Merge #8303
8303: Allow interning strings r=jonas-schievink a=jonas-schievink We don't use it yet, that's a bit more complicated. bors r+ Co-authored-by: Jonas Schievink <[email protected]>
2 parents 8e3e13f + 85757be commit eb264fb

File tree

1 file changed

+46
-9
lines changed

1 file changed

+46
-9
lines changed

crates/hir_def/src/intern.rs

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33
//! Eventually this should probably be replaced with salsa-based interning.
44
55
use std::{
6+
collections::HashMap,
67
fmt::{self, Debug},
78
hash::{BuildHasherDefault, Hash},
89
ops::Deref,
910
sync::Arc,
1011
};
1112

12-
use dashmap::{DashMap, SharedValue};
13+
use dashmap::{lock::RwLockWriteGuard, DashMap, SharedValue};
1314
use once_cell::sync::OnceCell;
1415
use rustc_hash::FxHasher;
1516

1617
type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
18+
type Guard<T> =
19+
RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>;
1720

1821
#[derive(Hash)]
1922
pub struct Interned<T: Internable + ?Sized> {
@@ -22,10 +25,22 @@ pub struct Interned<T: Internable + ?Sized> {
2225

2326
impl<T: Internable> Interned<T> {
2427
pub fn new(obj: T) -> Self {
28+
match Interned::lookup(&obj) {
29+
Ok(this) => this,
30+
Err(shard) => {
31+
let arc = Arc::new(obj);
32+
Self::alloc(arc, shard)
33+
}
34+
}
35+
}
36+
}
37+
38+
impl<T: Internable + ?Sized> Interned<T> {
39+
fn lookup(obj: &T) -> Result<Self, Guard<T>> {
2540
let storage = T::storage().get();
26-
let shard_idx = storage.determine_map(&obj);
41+
let shard_idx = storage.determine_map(obj);
2742
let shard = &storage.shards()[shard_idx];
28-
let mut shard = shard.write();
43+
let shard = shard.write();
2944

3045
// Atomically,
3146
// - check if `obj` is already in the map
@@ -34,13 +49,15 @@ impl<T: Internable> Interned<T> {
3449
// This needs to be atomic (locking the shard) to avoid races with other thread, which could
3550
// insert the same object between us looking it up and inserting it.
3651

37-
// FIXME: avoid double lookup by using raw entry API (once stable, or when hashbrown can be
38-
// plugged into dashmap)
39-
if let Some((arc, _)) = shard.get_key_value(&obj) {
40-
return Self { arc: arc.clone() };
52+
// FIXME: avoid double lookup/hashing by using raw entry API (once stable, or when
53+
// hashbrown can be plugged into dashmap)
54+
match shard.get_key_value(obj) {
55+
Some((arc, _)) => Ok(Self { arc: arc.clone() }),
56+
None => Err(shard),
4157
}
58+
}
4259

43-
let arc = Arc::new(obj);
60+
fn alloc(arc: Arc<T>, mut shard: Guard<T>) -> Self {
4461
let arc2 = arc.clone();
4562

4663
shard.insert(arc2, SharedValue::new(()));
@@ -49,6 +66,18 @@ impl<T: Internable> Interned<T> {
4966
}
5067
}
5168

69+
impl Interned<str> {
70+
pub fn new_str(s: &str) -> Self {
71+
match Interned::lookup(s) {
72+
Ok(this) => this,
73+
Err(shard) => {
74+
let arc = Arc::<str>::from(s);
75+
Self::alloc(arc, shard)
76+
}
77+
}
78+
}
79+
}
80+
5281
impl<T: Internable + ?Sized> Drop for Interned<T> {
5382
#[inline]
5483
fn drop(&mut self) {
@@ -98,6 +127,14 @@ impl<T: Internable> PartialEq for Interned<T> {
98127

99128
impl<T: Internable> Eq for Interned<T> {}
100129

130+
impl PartialEq for Interned<str> {
131+
fn eq(&self, other: &Self) -> bool {
132+
Arc::ptr_eq(&self.arc, &other.arc)
133+
}
134+
}
135+
136+
impl Eq for Interned<str> {}
137+
101138
impl<T: Internable + ?Sized> AsRef<T> for Interned<T> {
102139
#[inline]
103140
fn as_ref(&self) -> &T {
@@ -157,4 +194,4 @@ macro_rules! impl_internable {
157194
)+ };
158195
}
159196

160-
impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath);
197+
impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath, str);

0 commit comments

Comments
 (0)