@@ -7,7 +7,7 @@ use crate::{
77 tagged_value:: { MAX_INLINE_LEN , TaggedValue } ,
88} ;
99
10- pub ( crate ) struct PrehashedString {
10+ pub struct PrehashedString {
1111 pub value : String ,
1212 /// This is not the actual `fxhash`, but rather it's a value that passed to
1313 /// `write_u64` of [rustc_hash::FxHasher].
@@ -61,23 +61,9 @@ pub(crate) fn new_atom<T: AsRef<str> + Into<String>>(text: T) -> RcStr {
6161 }
6262}
6363
64- pub ( crate ) fn new_static_atom ( text : & ' static str ) -> RcStr {
65- debug_assert ! (
66- text. len( ) >= MAX_INLINE_LEN ,
67- "should have use the rcstr! macro? this string is too short"
68- ) ;
69- let hash = hash_bytes ( text. as_bytes ( ) ) ;
70-
71- let entry: Box < PrehashedString > = Box :: new ( PrehashedString {
72- value : text. into ( ) ,
73- hash,
74- } ) ;
75- // Hello memory leak!
76- // We are leaking here because the caller is asserting that this RcStr will have a static
77- // lifetime Ideally we wouldn't be copying the static str into the PrehashedString as a
78- // String but instead keeping the `&'static str` reference somehow, perhaps using a Cow?? or
79- // perhaps switching to a ThinArc
80- let mut entry = Box :: into_raw ( entry) ;
64+ #[ inline( always) ]
65+ pub ( crate ) fn new_static_atom ( string : & ' static PrehashedString ) -> RcStr {
66+ let mut entry = string as * const PrehashedString ;
8167 debug_assert ! ( 0 == entry as u8 & TAG_MASK ) ;
8268 // Tag it as a static pointer
8369 entry = ( ( entry as usize ) | STATIC_TAG as usize ) as * mut PrehashedString ;
@@ -120,7 +106,7 @@ const SEED2: u64 = 0x13198a2e03707344;
120106const PREVENT_TRIVIAL_ZERO_COLLAPSE : u64 = 0xa4093822299f31d0 ;
121107
122108#[ inline]
123- fn multiply_mix ( x : u64 , y : u64 ) -> u64 {
109+ const fn multiply_mix ( x : u64 , y : u64 ) -> u64 {
124110 #[ cfg( target_pointer_width = "64" ) ]
125111 {
126112 // We compute the full u64 x u64 -> u128 product, this is a single mul
@@ -161,6 +147,26 @@ fn multiply_mix(x: u64, y: u64) -> u64 {
161147 }
162148}
163149
150+ // Const compatible helper function to read a u64 from a byte array at a given offset
151+ const fn read_u64_le ( bytes : & [ u8 ] , offset : usize ) -> u64 {
152+ ( bytes[ offset] as u64 )
153+ | ( ( bytes[ offset + 1 ] as u64 ) << 8 )
154+ | ( ( bytes[ offset + 2 ] as u64 ) << 16 )
155+ | ( ( bytes[ offset + 3 ] as u64 ) << 24 )
156+ | ( ( bytes[ offset + 4 ] as u64 ) << 32 )
157+ | ( ( bytes[ offset + 5 ] as u64 ) << 40 )
158+ | ( ( bytes[ offset + 6 ] as u64 ) << 48 )
159+ | ( ( bytes[ offset + 7 ] as u64 ) << 56 )
160+ }
161+
162+ // Const compatible helper function to read a u32 from a byte array at a given offset
163+ const fn read_u32_le ( bytes : & [ u8 ] , offset : usize ) -> u32 {
164+ ( bytes[ offset] as u32 )
165+ | ( ( bytes[ offset + 1 ] as u32 ) << 8 )
166+ | ( ( bytes[ offset + 2 ] as u32 ) << 16 )
167+ | ( ( bytes[ offset + 3 ] as u32 ) << 24 )
168+ }
169+
164170/// Copied from `hash_bytes` of `rustc-hash`.
165171///
166172/// See: https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs#L252-L297
@@ -179,19 +185,20 @@ fn multiply_mix(x: u64, y: u64) -> u64 {
179185/// We don't bother avalanching here as we'll feed this hash into a
180186/// multiplication after which we take the high bits, which avalanches for us.
181187#[ inline]
182- fn hash_bytes ( bytes : & [ u8 ] ) -> u64 {
188+ #[ doc( hidden) ]
189+ pub const fn hash_bytes ( bytes : & [ u8 ] ) -> u64 {
183190 let len = bytes. len ( ) ;
184191 let mut s0 = SEED1 ;
185192 let mut s1 = SEED2 ;
186193
187194 if len <= 16 {
188195 // XOR the input into s0, s1.
189196 if len >= 8 {
190- s0 ^= u64 :: from_le_bytes ( bytes[ 0 .. 8 ] . try_into ( ) . unwrap ( ) ) ;
191- s1 ^= u64 :: from_le_bytes ( bytes[ len - 8 .. ] . try_into ( ) . unwrap ( ) ) ;
197+ s0 ^= read_u64_le ( bytes, 0 ) ;
198+ s1 ^= read_u64_le ( bytes, len - 8 ) ;
192199 } else if len >= 4 {
193- s0 ^= u32 :: from_le_bytes ( bytes[ 0 .. 4 ] . try_into ( ) . unwrap ( ) ) as u64 ;
194- s1 ^= u32 :: from_le_bytes ( bytes[ len - 4 .. ] . try_into ( ) . unwrap ( ) ) as u64 ;
200+ s0 ^= read_u32_le ( bytes, 0 ) as u64 ;
201+ s1 ^= read_u32_le ( bytes, len - 4 ) as u64 ;
195202 } else if len > 0 {
196203 let lo = bytes[ 0 ] ;
197204 let mid = bytes[ len / 2 ] ;
@@ -203,8 +210,8 @@ fn hash_bytes(bytes: &[u8]) -> u64 {
203210 // Handle bulk (can partially overlap with suffix).
204211 let mut off = 0 ;
205212 while off < len - 16 {
206- let x = u64 :: from_le_bytes ( bytes[ off..off + 8 ] . try_into ( ) . unwrap ( ) ) ;
207- let y = u64 :: from_le_bytes ( bytes[ off + 8 .. off + 16 ] . try_into ( ) . unwrap ( ) ) ;
213+ let x = read_u64_le ( bytes, off ) ;
214+ let y = read_u64_le ( bytes, off + 8 ) ;
208215
209216 // Replace s1 with a mix of s0, x, and y, and s0 with s1.
210217 // This ensures the compiler can unroll this loop into two
@@ -218,9 +225,8 @@ fn hash_bytes(bytes: &[u8]) -> u64 {
218225 off += 16 ;
219226 }
220227
221- let suffix = & bytes[ len - 16 ..] ;
222- s0 ^= u64:: from_le_bytes ( suffix[ 0 ..8 ] . try_into ( ) . unwrap ( ) ) ;
223- s1 ^= u64:: from_le_bytes ( suffix[ 8 ..16 ] . try_into ( ) . unwrap ( ) ) ;
228+ s0 ^= read_u64_le ( bytes, len - 16 ) ;
229+ s1 ^= read_u64_le ( bytes, len - 8 ) ;
224230 }
225231
226232 multiply_mix ( s0, s1) ^ ( len as u64 )
0 commit comments