@@ -34,6 +34,42 @@ type HashUint = usize;
34
34
35
35
const EMPTY_BUCKET : HashUint = 0 ;
36
36
37
+ /// Special `Unique<HashUint>` that uses the lower bit of the pointer
38
+ /// to expose a boolean tag.
39
+ /// Note: when the pointer is initialized to EMPTY `.ptr()` will return
40
+ /// null and the tag functions shouldn't be used.
41
+ struct TaggedHashUintPtr ( Unique < HashUint > ) ;
42
+
43
+ impl TaggedHashUintPtr {
44
+ #[ inline]
45
+ unsafe fn new ( ptr : * mut HashUint ) -> Self {
46
+ debug_assert ! ( ptr as usize & 1 == 0 || ptr as usize == EMPTY as usize ) ;
47
+ TaggedHashUintPtr ( Unique :: new ( ptr) )
48
+ }
49
+
50
+ #[ inline]
51
+ fn set_tag ( & mut self , value : bool ) {
52
+ let usize_ptr = & * self . 0 as * const * mut HashUint as * mut usize ;
53
+ unsafe {
54
+ if value {
55
+ * usize_ptr |= 1 ;
56
+ } else {
57
+ * usize_ptr &= !1 ;
58
+ }
59
+ }
60
+ }
61
+
62
+ #[ inline]
63
+ fn tag ( & self ) -> bool {
64
+ ( * self . 0 as usize ) & 1 == 1
65
+ }
66
+
67
+ #[ inline]
68
+ fn ptr ( & self ) -> * mut HashUint {
69
+ ( * self . 0 as usize & !1 ) as * mut HashUint
70
+ }
71
+ }
72
+
37
73
/// The raw hashtable, providing safe-ish access to the unzipped and highly
38
74
/// optimized arrays of hashes, and key-value pairs.
39
75
///
@@ -72,10 +108,14 @@ const EMPTY_BUCKET: HashUint = 0;
72
108
/// around just the "table" part of the hashtable. It enforces some
73
109
/// invariants at the type level and employs some performance trickery,
74
110
/// but in general is just a tricked out `Vec<Option<(u64, K, V)>>`.
111
+ ///
112
+ /// The hashtable also exposes a special boolean tag. The tag defaults to false
113
+ /// when the RawTable is created and is accessible with the `tag` and `set_tag`
114
+ /// functions.
75
115
pub struct RawTable < K , V > {
76
116
capacity : usize ,
77
117
size : usize ,
78
- hashes : Unique < HashUint > ,
118
+ hashes : TaggedHashUintPtr ,
79
119
80
120
// Because K/V do not appear directly in any of the types in the struct,
81
121
// inform rustc that in fact instances of K and V are reachable from here.
@@ -208,6 +248,10 @@ impl<K, V, M> FullBucket<K, V, M> {
208
248
pub fn table ( & self ) -> & M {
209
249
& self . table
210
250
}
251
+ /// Borrow a mutable reference to the table.
252
+ pub fn table_mut ( & mut self ) -> & mut M {
253
+ & mut self . table
254
+ }
211
255
/// Move out the reference to the table.
212
256
pub fn into_table ( self ) -> M {
213
257
self . table
@@ -227,6 +271,10 @@ impl<K, V, M> EmptyBucket<K, V, M> {
227
271
pub fn table ( & self ) -> & M {
228
272
& self . table
229
273
}
274
+ /// Borrow a mutable reference to the table.
275
+ pub fn table_mut ( & mut self ) -> & mut M {
276
+ & mut self . table
277
+ }
230
278
}
231
279
232
280
impl < K , V , M > Bucket < K , V , M > {
@@ -687,7 +735,7 @@ impl<K, V> RawTable<K, V> {
687
735
return RawTable {
688
736
size : 0 ,
689
737
capacity : 0 ,
690
- hashes : Unique :: new ( EMPTY as * mut HashUint ) ,
738
+ hashes : TaggedHashUintPtr :: new ( EMPTY as * mut HashUint ) ,
691
739
marker : marker:: PhantomData ,
692
740
} ;
693
741
}
@@ -728,7 +776,7 @@ impl<K, V> RawTable<K, V> {
728
776
RawTable {
729
777
capacity : capacity,
730
778
size : 0 ,
731
- hashes : Unique :: new ( hashes) ,
779
+ hashes : TaggedHashUintPtr :: new ( hashes) ,
732
780
marker : marker:: PhantomData ,
733
781
}
734
782
}
@@ -737,13 +785,13 @@ impl<K, V> RawTable<K, V> {
737
785
let hashes_size = self . capacity * size_of :: < HashUint > ( ) ;
738
786
let pairs_size = self . capacity * size_of :: < ( K , V ) > ( ) ;
739
787
740
- let buffer = * self . hashes as * mut u8 ;
788
+ let buffer = self . hashes . ptr ( ) as * mut u8 ;
741
789
let ( pairs_offset, _, oflo) =
742
790
calculate_offsets ( hashes_size, pairs_size, align_of :: < ( K , V ) > ( ) ) ;
743
791
debug_assert ! ( !oflo, "capacity overflow" ) ;
744
792
unsafe {
745
793
RawBucket {
746
- hash : * self . hashes ,
794
+ hash : self . hashes . ptr ( ) ,
747
795
pair : buffer. offset ( pairs_offset as isize ) as * const _ ,
748
796
_marker : marker:: PhantomData ,
749
797
}
@@ -755,7 +803,7 @@ impl<K, V> RawTable<K, V> {
755
803
pub fn new ( capacity : usize ) -> RawTable < K , V > {
756
804
unsafe {
757
805
let ret = RawTable :: new_uninitialized ( capacity) ;
758
- ptr:: write_bytes ( * ret. hashes , 0 , capacity) ;
806
+ ptr:: write_bytes ( ret. hashes . ptr ( ) , 0 , capacity) ;
759
807
ret
760
808
}
761
809
}
@@ -774,7 +822,7 @@ impl<K, V> RawTable<K, V> {
774
822
fn raw_buckets ( & self ) -> RawBuckets < K , V > {
775
823
RawBuckets {
776
824
raw : self . first_bucket_raw ( ) ,
777
- hashes_end : unsafe { self . hashes . offset ( self . capacity as isize ) } ,
825
+ hashes_end : unsafe { self . hashes . ptr ( ) . offset ( self . capacity as isize ) } ,
778
826
marker : marker:: PhantomData ,
779
827
}
780
828
}
@@ -832,6 +880,16 @@ impl<K, V> RawTable<K, V> {
832
880
marker : marker:: PhantomData ,
833
881
}
834
882
}
883
+
884
+ /// Set the table tag
885
+ pub fn set_tag ( & mut self , value : bool ) {
886
+ self . hashes . set_tag ( value)
887
+ }
888
+
889
+ /// Get the table tag
890
+ pub fn tag ( & self ) -> bool {
891
+ self . hashes . tag ( )
892
+ }
835
893
}
836
894
837
895
/// A raw iterator. The basis for some other iterators in this module. Although
@@ -1156,7 +1214,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
1156
1214
debug_assert ! ( !oflo, "should be impossible" ) ;
1157
1215
1158
1216
unsafe {
1159
- deallocate ( * self . hashes as * mut u8 , size, align) ;
1217
+ deallocate ( self . hashes . ptr ( ) as * mut u8 , size, align) ;
1160
1218
// Remember how everything was allocated out of one buffer
1161
1219
// during initialization? We only need one call to free here.
1162
1220
}
0 commit comments