1
1
use std:: {
2
2
borrow:: Cow ,
3
- fmt :: Debug ,
3
+ ffi :: c_void ,
4
4
hash:: { BuildHasherDefault , Hash , Hasher } ,
5
+ mem:: ManuallyDrop ,
6
+ ops:: Deref ,
5
7
ptr:: NonNull ,
6
8
} ;
7
9
8
10
use rustc_hash:: FxHasher ;
9
- use triomphe:: Arc ;
11
+ use triomphe:: { HeaderWithLength , ThinArc } ;
10
12
11
13
use crate :: {
12
14
tagged_value:: { TaggedValue , MAX_INLINE_LEN } ,
13
15
Atom , INLINE_TAG_INIT , LEN_OFFSET , TAG_MASK ,
14
16
} ;
15
17
16
- #[ derive( Debug ) ]
17
- pub ( crate ) struct Entry {
18
- pub string : Box < str > ,
18
+ pub ( crate ) struct Metadata {
19
19
pub hash : u64 ,
20
20
}
21
21
22
- impl Entry {
23
- pub unsafe fn cast ( ptr : TaggedValue ) -> * const Entry {
24
- ptr. get_ptr ( ) . cast ( )
25
- }
22
+ #[ derive( Clone ) ]
23
+ pub ( crate ) struct Item ( ThinArc < HeaderWithLength < Metadata > , u8 > ) ;
26
24
27
- pub unsafe fn deref_from < ' i > ( ptr : TaggedValue ) -> & ' i Entry {
28
- & * Self :: cast ( ptr)
29
- }
25
+ impl Deref for Item {
26
+ type Target = <ThinArc < HeaderWithLength < Metadata > , u8 > as Deref >:: Target ;
30
27
31
- pub unsafe fn restore_arc ( v : TaggedValue ) -> Arc < Entry > {
32
- let ptr = v. get_ptr ( ) as * const Entry ;
33
- Arc :: from_raw ( ptr)
28
+ fn deref ( & self ) -> & Self :: Target {
29
+ & self . 0
34
30
}
35
31
}
36
32
37
- impl PartialEq for Entry {
38
- fn eq ( & self , other : & Self ) -> bool {
39
- // Assumption: `store_id` and `alias` don't matter for equality within a single
40
- // store (what we care about here). Compare hash first because that's cheaper.
41
- self . hash == other. hash && self . string == other. string
33
+ /// TODO: Use real weak pointer
34
+ type WeakItem = Item ;
35
+
36
+ impl Hash for Item {
37
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
38
+ state. write_u64 ( self . 0 . header . header . header . hash ) ;
42
39
}
43
40
}
44
41
45
- impl Eq for Entry { }
42
+ pub ( crate ) unsafe fn deref_from ( ptr : TaggedValue ) -> ManuallyDrop < Item > {
43
+ let item = restore_arc ( ptr) ;
46
44
47
- impl Hash for Entry {
48
- fn hash < H : Hasher > ( & self , state : & mut H ) {
49
- // Assumption: type H is an EntryHasher
50
- state. write_u64 ( self . hash ) ;
51
- }
45
+ ManuallyDrop :: new ( item)
46
+ }
47
+
48
+ pub ( crate ) unsafe fn restore_arc ( v : TaggedValue ) -> Item {
49
+ let ptr = v. get_ptr ( ) ;
50
+ Item ( ThinArc :: from_raw ( ptr) )
52
51
}
53
52
54
53
/// A store that stores [Atom]s. Can be merged with other [AtomStore]s for
55
54
/// better performance.
56
55
///
57
56
///
58
57
/// # Merging [AtomStore]
59
- #[ derive( Debug ) ]
60
58
pub struct AtomStore {
61
- pub ( crate ) data : hashbrown:: HashMap < Arc < Entry > , ( ) , BuildEntryHasher > ,
59
+ pub ( crate ) data : hashbrown:: HashMap < WeakItem , ( ) , BuildEntryHasher > ,
62
60
}
63
61
64
62
impl Default for AtomStore {
@@ -96,11 +94,11 @@ where
96
94
97
95
let hash = calc_hash ( & text) ;
98
96
let entry = storage. insert_entry ( text, hash) ;
99
- let entry = Arc :: into_raw ( entry) ;
97
+ let entry = ThinArc :: into_raw ( entry. 0 ) as * mut c_void ;
100
98
101
- let ptr: NonNull < Entry > = unsafe {
99
+ let ptr: NonNull < c_void > = unsafe {
102
100
// Safety: Arc::into_raw returns a non-null pointer
103
- NonNull :: new_unchecked ( entry as * mut Entry )
101
+ NonNull :: new_unchecked ( entry)
104
102
} ;
105
103
debug_assert ! ( 0 == ptr. as_ptr( ) as u8 & TAG_MASK ) ;
106
104
Atom {
@@ -109,22 +107,24 @@ where
109
107
}
110
108
111
109
pub ( crate ) trait Storage {
112
- fn insert_entry ( self , text : Cow < str > , hash : u64 ) -> Arc < Entry > ;
110
+ fn insert_entry ( self , text : Cow < str > , hash : u64 ) -> Item ;
113
111
}
114
112
115
113
impl Storage for & ' _ mut AtomStore {
116
114
#[ inline( never) ]
117
- fn insert_entry ( self , text : Cow < str > , hash : u64 ) -> Arc < Entry > {
115
+ fn insert_entry ( self , text : Cow < str > , hash : u64 ) -> Item {
118
116
let ( entry, _) = self
119
117
. data
120
118
. raw_entry_mut ( )
121
- . from_hash ( hash, |key| key. hash == hash && * key. string == * text)
119
+ . from_hash ( hash, |key| {
120
+ key. header . header . header . hash == hash && key. slice == * text. as_bytes ( )
121
+ } )
122
122
. or_insert_with ( move || {
123
123
(
124
- Arc :: new ( Entry {
125
- string : text. into_owned ( ) . into_boxed_str ( ) ,
126
- hash ,
127
- } ) ,
124
+ Item ( ThinArc :: from_header_and_slice (
125
+ HeaderWithLength :: new ( Metadata { hash } , text. len ( ) ) ,
126
+ text . as_bytes ( ) ,
127
+ ) ) ,
128
128
( ) ,
129
129
)
130
130
} ) ;
0 commit comments