11use crate :: fx:: { FxHashMap , FxHasher } ;
2- use crate :: sync:: { Lock , LockGuard } ;
2+ use crate :: sync:: LockLike ;
3+ use parking_lot:: { Mutex , MutexGuard } ;
34use std:: borrow:: Borrow ;
5+ use std:: cell:: { RefCell , RefMut } ;
46use std:: collections:: hash_map:: RawEntryMut ;
57use std:: hash:: { Hash , Hasher } ;
8+ use std:: mem;
69
7- const SHARD_BITS : usize = 0 ;
10+ pub trait Shard {
11+ type Impl < T > : ShardImpl < T > ;
12+ }
813
9- pub const SHARDS : usize = 1 << SHARD_BITS ;
14+ pub trait ShardImpl < T > {
15+ type Lock : LockLike < T > ;
16+
17+ fn new ( value : impl FnMut ( ) -> T ) -> Self ;
18+
19+ fn get_shard_by_value < K : Hash + ?Sized > ( & self , _val : & K ) -> & Self :: Lock ;
20+
21+ fn get_shard_by_hash ( & self , _hash : u64 ) -> & Self :: Lock ;
22+
23+ fn lock_shards ( & self ) -> Vec < <Self :: Lock as LockLike < T > >:: LockGuard < ' _ > > ;
24+
25+ fn try_lock_shards ( & self ) -> Option < Vec < <Self :: Lock as LockLike < T > >:: LockGuard < ' _ > > > ;
26+ }
27+
28+ #[ derive( Default ) ]
29+ pub struct SingleShard ;
30+
31+ impl Shard for SingleShard {
32+ type Impl < T > = SingleShardImpl < T > ;
33+ }
1034
1135/// An array of cache-line aligned inner locked structures with convenience methods.
12- pub struct Sharded < T > {
13- shard : Lock < T > ,
36+ pub struct SingleShardImpl < T > {
37+ shard : RefCell < T > ,
38+ }
39+
40+ impl < T : Default > Default for SingleShardImpl < T > {
41+ #[ inline]
42+ fn default ( ) -> Self {
43+ Self { shard : RefCell :: new ( T :: default ( ) ) }
44+ }
45+ }
46+
47+ impl < T > ShardImpl < T > for SingleShardImpl < T > {
48+ type Lock = RefCell < T > ;
49+
50+ #[ inline]
51+ fn new ( mut value : impl FnMut ( ) -> T ) -> Self {
52+ SingleShardImpl { shard : RefCell :: new ( value ( ) ) }
53+ }
54+
55+ #[ inline]
56+ fn get_shard_by_value < K : Hash + ?Sized > ( & self , _val : & K ) -> & RefCell < T > {
57+ & self . shard
58+ }
59+
60+ #[ inline]
61+ fn get_shard_by_hash ( & self , _hash : u64 ) -> & RefCell < T > {
62+ & self . shard
63+ }
64+
65+ fn lock_shards ( & self ) -> Vec < RefMut < ' _ , T > > {
66+ vec ! [ self . shard. lock( ) ]
67+ }
68+
69+ fn try_lock_shards ( & self ) -> Option < Vec < RefMut < ' _ , T > > > {
70+ Some ( vec ! [ self . shard. try_lock( ) ?] )
71+ }
72+ }
73+
74+ const SHARD_BITS : usize = 5 ;
75+
76+ pub const SHARDS : usize = 1 << SHARD_BITS ;
77+
78+ #[ derive( Default ) ]
79+ pub struct Sharded ;
80+
81+ impl Shard for Sharded {
82+ type Impl < T > = ShardedImpl < T > ;
83+ }
84+
85+ #[ derive( Default ) ]
86+ #[ repr( align( 64 ) ) ]
87+ pub struct CacheAligned < T > ( pub T ) ;
88+
89+ pub struct ShardedImpl < T > {
90+ shards : [ CacheAligned < Mutex < T > > ; SHARDS ] ,
1491}
1592
16- impl < T : Default > Default for Sharded < T > {
93+ impl < T : Default > Default for ShardedImpl < T > {
1794 #[ inline]
1895 fn default ( ) -> Self {
1996 Self :: new ( T :: default)
2097 }
2198}
2299
23- impl < T : Default > Sharded < T > {
100+ impl < T > ShardImpl < T > for ShardedImpl < T > {
101+ type Lock = Mutex < T > ;
102+
103+ #[ inline]
104+ fn new ( mut value : impl FnMut ( ) -> T ) -> Self {
105+ ShardedImpl { shards : [ ( ) ; SHARDS ] . map ( |( ) | CacheAligned ( Mutex :: new ( value ( ) ) ) ) }
106+ }
107+
108+ /// The shard is selected by hashing `val` with `FxHasher`.
109+ #[ inline]
110+ fn get_shard_by_value < K : Hash + ?Sized > ( & self , val : & K ) -> & Mutex < T > {
111+ self . get_shard_by_hash ( make_hash ( val) )
112+ }
113+
114+ #[ inline]
115+ fn get_shard_by_hash ( & self , hash : u64 ) -> & Mutex < T > {
116+ & self . shards [ get_shard_index_by_hash ( hash) ] . 0
117+ }
118+
119+ fn lock_shards ( & self ) -> Vec < MutexGuard < ' _ , T > > {
120+ ( 0 ..SHARDS ) . map ( |i| self . shards [ i] . 0 . lock ( ) ) . collect ( )
121+ }
122+
123+ fn try_lock_shards ( & self ) -> Option < Vec < MutexGuard < ' _ , T > > > {
124+ ( 0 ..SHARDS ) . map ( |i| self . shards [ i] . 0 . try_lock ( ) ) . collect ( )
125+ }
126+ }
127+
128+ pub struct DynSharded < T > {
129+ single_thread : bool ,
130+ single_shard : RefCell < T > ,
131+ parallel_shard : ShardedImpl < T > ,
132+ }
133+
134+ // just for speed test
135+ unsafe impl < T > Sync for DynSharded < T > { }
136+
137+ impl < T : Default > Default for DynSharded < T > {
24138 #[ inline]
139+ fn default ( ) -> Self {
140+ let single_thread = !crate :: sync:: active ( ) ;
141+ DynSharded {
142+ single_thread,
143+ single_shard : RefCell :: new ( T :: default ( ) ) ,
144+ parallel_shard : ShardedImpl :: default ( ) ,
145+ }
146+ }
147+ }
148+
149+ impl < T : Default > DynSharded < T > {
25150 pub fn new ( mut value : impl FnMut ( ) -> T ) -> Self {
26- Sharded { shard : Lock :: new ( value ( ) ) }
151+ if !crate :: sync:: active ( ) {
152+ DynSharded {
153+ single_thread : true ,
154+ single_shard : RefCell :: new ( value ( ) ) ,
155+ parallel_shard : ShardedImpl :: default ( ) ,
156+ }
157+ } else {
158+ DynSharded {
159+ single_thread : false ,
160+ single_shard : RefCell :: new ( T :: default ( ) ) ,
161+ parallel_shard : ShardedImpl :: new ( value) ,
162+ }
163+ }
27164 }
28165
29166 /// The shard is selected by hashing `val` with `FxHasher`.
30167 #[ inline]
31168 pub fn with_get_shard_by_value < K : Hash + ?Sized , F : FnOnce ( & mut T ) -> R , R > (
32169 & self ,
33- _val : & K ,
170+ val : & K ,
34171 f : F ,
35172 ) -> R {
36- self . shard . with_lock ( f)
173+ if self . single_thread {
174+ let mut lock = self . single_shard . borrow_mut ( ) ;
175+ f ( & mut * lock)
176+ } else {
177+ let mut lock = self . parallel_shard . get_shard_by_value ( val) . lock ( ) ;
178+ f ( & mut * lock)
179+ }
37180 }
38181
39182 #[ inline]
40- pub fn with_get_shard_by_hash < F : FnOnce ( & mut T ) -> R , R > ( & self , _hash : u64 , f : F ) -> R {
41- self . shard . with_lock ( f)
183+ pub fn with_get_shard_by_hash < F : FnOnce ( & mut T ) -> R , R > ( & self , hash : u64 , f : F ) -> R {
184+ if self . single_thread {
185+ let mut lock = self . single_shard . borrow_mut ( ) ;
186+ f ( & mut * lock)
187+ } else {
188+ let mut lock = self . parallel_shard . get_shard_by_hash ( hash) . lock ( ) ;
189+ f ( & mut * lock)
190+ }
42191 }
43192
44193 #[ inline]
45- pub fn get_shard_by_value < K : Hash + ?Sized > ( & self , _val : & K ) -> & Lock < T > {
46- & self . shard
194+ pub fn with_lock_shards < F : FnMut ( & mut T ) -> R , R > ( & self , mut f : F ) -> Vec < R > {
195+ if self . single_thread {
196+ let mut lock = self . single_shard . borrow_mut ( ) ;
197+ vec ! [ f( & mut * lock) ]
198+ } else {
199+ ( 0 ..SHARDS ) . map ( |i| f ( & mut * self . parallel_shard . shards [ i] . 0 . lock ( ) ) ) . collect ( )
200+ }
47201 }
48202
49203 #[ inline]
50- pub fn get_shard_by_hash ( & self , _hash : u64 ) -> & Lock < T > {
51- & self . shard
204+ pub fn with_try_lock_shards < F : FnMut ( & mut T ) -> R , R > ( & self , mut f : F ) -> Option < Vec < R > > {
205+ if self . single_thread {
206+ let mut lock = self . single_shard . try_borrow_mut ( ) . ok ( ) ?;
207+ Some ( vec ! [ f( & mut * lock) ] )
208+ } else {
209+ ( 0 ..SHARDS )
210+ . map ( |i| {
211+ let mut shard = self . parallel_shard . shards [ i] . 0 . try_lock ( ) ?;
212+ Some ( f ( & mut * shard) )
213+ } )
214+ . collect ( )
215+ }
52216 }
53217
54- pub fn lock_shards ( & self ) -> Vec < LockGuard < ' _ , T > > {
55- vec ! [ self . shard. lock( ) ]
218+ #[ inline]
219+ pub fn get_lock_by_value < K : Hash + ?Sized > ( & self , val : & K ) -> & Mutex < T > {
220+ self . parallel_shard . get_shard_by_value ( val)
56221 }
57222
58- pub fn try_lock_shards ( & self ) -> Option < Vec < LockGuard < ' _ , T > > > {
59- Some ( vec ! [ self . shard. try_lock( ) ?] )
223+ #[ inline]
224+ pub fn get_borrow_by_value < K : Hash + ?Sized > ( & self , _val : & K ) -> & RefCell < T > {
225+ & self . single_shard
60226 }
61227}
62228
63- pub type ShardedHashMap < K , V > = Sharded < FxHashMap < K , V > > ;
229+ pub type ShardedHashMap < K , V > = DynSharded < FxHashMap < K , V > > ;
64230
65231impl < K : Eq , V > ShardedHashMap < K , V > {
66232 pub fn len ( & self ) -> usize {
67- self . lock_shards ( ) . iter ( ) . map ( |shard| shard. len ( ) ) . sum ( )
233+ self . with_lock_shards ( |shard| shard. len ( ) ) . into_iter ( ) . sum ( )
68234 }
69235}
70236
@@ -120,7 +286,6 @@ pub trait IntoPointer {
120286impl < K : Eq + Hash + Copy + IntoPointer > ShardedHashMap < K , ( ) > {
121287 pub fn contains_pointer_to < T : Hash + IntoPointer > ( & self , value : & T ) -> bool {
122288 let hash = make_hash ( & value) ;
123-
124289 self . with_get_shard_by_hash ( hash, |shard| {
125290 let value = value. into_pointer ( ) ;
126291 shard. raw_entry ( ) . from_hash ( hash, |entry| entry. into_pointer ( ) == value) . is_some ( )
@@ -135,19 +300,17 @@ pub fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
135300 state. finish ( )
136301}
137302
138- /*
139303/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
140304/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
141305/// instance, then `hash` must be computed with `FxHasher`. Otherwise,
142306/// `hash` can be computed with any hasher, so long as that hasher is used
143307/// consistently for each `Sharded` instance.
144308#[ inline]
145309#[ allow( clippy:: modulo_one) ]
146- fn get_shard_index_by_hash(hash: u64) -> usize {
310+ pub fn get_shard_index_by_hash ( hash : u64 ) -> usize {
147311 let hash_len = mem:: size_of :: < usize > ( ) ;
148312 // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
149313 // hashbrown also uses the lowest bits, so we can't use those
150314 let bits = ( hash >> ( hash_len * 8 - 7 - SHARD_BITS ) ) as usize ;
151315 bits % SHARDS
152316}
153- */
0 commit comments