3
3
//! type, and vice versa.
4
4
5
5
use rustc_arena:: DroplessArena ;
6
- use rustc_data_structures:: fx:: FxHashMap ;
6
+ use rustc_data_structures:: fx:: FxIndexSet ;
7
7
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher , ToStableHashKey } ;
8
8
use rustc_data_structures:: sync:: Lock ;
9
9
use rustc_macros:: HashStable_Generic ;
@@ -2076,43 +2076,33 @@ impl<CTX> ToStableHashKey<CTX> for Symbol {
2076
2076
}
2077
2077
}
2078
2078
2079
- #[ derive( Default ) ]
2080
2079
pub ( crate ) struct Interner ( Lock < InternerInner > ) ;
2081
2080
2082
2081
// The `&'static str`s in this type actually point into the arena.
2083
2082
//
2084
- // The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278
2085
- // found that to regress performance up to 2% in some cases. This might be
2086
- // revisited after further improvements to `indexmap`.
2087
- //
2088
2083
// This type is private to prevent accidentally constructing more than one
2089
2084
// `Interner` on the same thread, which makes it easy to mix up `Symbol`s
2090
2085
// between `Interner`s.
2091
- #[ derive( Default ) ]
2092
2086
struct InternerInner {
2093
2087
arena : DroplessArena ,
2094
- names : FxHashMap < & ' static str , Symbol > ,
2095
- strings : Vec < & ' static str > ,
2088
+ strings : FxIndexSet < & ' static str > ,
2096
2089
}
2097
2090
2098
2091
impl Interner {
2099
2092
fn prefill ( init : & [ & ' static str ] ) -> Self {
2100
2093
Interner ( Lock :: new ( InternerInner {
2101
- strings : init. into ( ) ,
2102
- names : init. iter ( ) . copied ( ) . zip ( ( 0 ..) . map ( Symbol :: new) ) . collect ( ) ,
2103
- ..Default :: default ( )
2094
+ arena : Default :: default ( ) ,
2095
+ strings : init. iter ( ) . copied ( ) . collect ( ) ,
2104
2096
} ) )
2105
2097
}
2106
2098
2107
2099
#[ inline]
2108
2100
fn intern ( & self , string : & str ) -> Symbol {
2109
2101
let mut inner = self . 0 . lock ( ) ;
2110
- if let Some ( & name ) = inner. names . get ( string) {
2111
- return name ;
2102
+ if let Some ( idx ) = inner. strings . get_index_of ( string) {
2103
+ return Symbol :: new ( idx as u32 ) ;
2112
2104
}
2113
2105
2114
- let name = Symbol :: new ( inner. strings . len ( ) as u32 ) ;
2115
-
2116
2106
// SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena,
2117
2107
// and immediately convert the clone back to `&[u8]`, all because there
2118
2108
// is no `inner.arena.alloc_str()` method. This is clearly safe.
@@ -2122,20 +2112,21 @@ impl Interner {
2122
2112
// SAFETY: we can extend the arena allocation to `'static` because we
2123
2113
// only access these while the arena is still alive.
2124
2114
let string: & ' static str = unsafe { & * ( string as * const str ) } ;
2125
- inner. strings . push ( string) ;
2126
2115
2127
2116
// This second hash table lookup can be avoided by using `RawEntryMut`,
2128
2117
// but this code path isn't hot enough for it to be worth it. See
2129
2118
// #91445 for details.
2130
- inner. names . insert ( string, name) ;
2131
- name
2119
+ let ( idx, is_new) = inner. strings . insert_full ( string) ;
2120
+ debug_assert ! ( is_new) ; // due to the get_index_of check above
2121
+
2122
+ Symbol :: new ( idx as u32 )
2132
2123
}
2133
2124
2134
2125
/// Get the symbol as a string.
2135
2126
///
2136
2127
/// [`Symbol::as_str()`] should be used in preference to this function.
2137
2128
fn get ( & self , symbol : Symbol ) -> & str {
2138
- self . 0 . lock ( ) . strings [ symbol. 0 . as_usize ( ) ]
2129
+ self . 0 . lock ( ) . strings . get_index ( symbol. 0 . as_usize ( ) ) . unwrap ( )
2139
2130
}
2140
2131
}
2141
2132
0 commit comments