@@ -37,34 +37,24 @@ impl<T> fmt::Debug for Dict<T> {
3737 }
3838}
3939
40- #[ derive( Debug , Copy , Clone ) ]
41- enum IndexEntry {
42- Dummy ,
43- Free ,
44- Index ( usize ) ,
45- }
40+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
41+ #[ repr( transparent) ]
42+ struct IndexEntry ( i64 ) ;
4643
4744impl IndexEntry {
48- const FREE : i64 = -1 ;
49- const DUMMY : i64 = -2 ;
50- }
45+ const FREE : Self = Self ( -1 ) ;
46+ const DUMMY : Self = Self ( -2 ) ;
5147
52- impl From < i64 > for IndexEntry {
53- fn from ( idx : i64 ) -> Self {
54- match idx {
55- IndexEntry :: FREE => IndexEntry :: Free ,
56- IndexEntry :: DUMMY => IndexEntry :: Dummy ,
57- x => IndexEntry :: Index ( x as usize ) ,
58- }
48+ unsafe fn from_index_unchecked ( idx : usize ) -> Self {
49+ debug_assert ! ( ( idx as isize ) >= 0 ) ;
50+ Self ( idx as i64 )
5951 }
60- }
6152
62- impl From < IndexEntry > for i64 {
63- fn from ( idx : IndexEntry ) -> Self {
64- match idx {
65- IndexEntry :: Free => IndexEntry :: FREE ,
66- IndexEntry :: Dummy => IndexEntry :: DUMMY ,
67- IndexEntry :: Index ( i) => i as i64 ,
53+ fn index ( self ) -> Option < usize > {
54+ if self . 0 >= 0 {
55+ Some ( self . 0 as usize )
56+ } else {
57+ None
6858 }
6959 }
7060}
@@ -73,7 +63,7 @@ impl From<IndexEntry> for i64 {
7363struct DictInner < T > {
7464 used : usize ,
7565 filled : usize ,
76- indices : Vec < i64 > ,
66+ indices : Vec < IndexEntry > ,
7767 entries : Vec < Option < DictEntry < T > > > ,
7868}
7969
@@ -175,7 +165,10 @@ impl<T> DictInner<T> {
175165 let index_index = idxs. next ( ) ;
176166 let idx = & mut self . indices [ index_index] ;
177167 if * idx == IndexEntry :: FREE {
178- * idx = entry_idx as i64 ;
168+ * idx = unsafe {
169+ // entry_idx never grow up to usize::MAX
170+ IndexEntry :: from_index_unchecked ( entry_idx)
171+ } ;
179172 entry. index = index_index;
180173 break ;
181174 }
@@ -203,9 +196,9 @@ impl<T> DictInner<T> {
203196 } ;
204197 let entry_index = self . entries . len ( ) ;
205198 self . entries . push ( Some ( entry) ) ;
206- self . indices [ index] = entry_index as i64 ;
199+ self . indices [ index] = unsafe { IndexEntry :: from_index_unchecked ( entry_index ) } ;
207200 self . used += 1 ;
208- if let IndexEntry :: Free = index_entry {
201+ if let IndexEntry :: FREE = index_entry {
209202 self . filled += 1 ;
210203 if let Some ( new_size) = self . should_resize ( ) {
211204 self . resize ( new_size)
@@ -252,7 +245,7 @@ impl<T: Clone> Dict<T> {
252245 let _removed = loop {
253246 let ( entry_index, index_index) = self . lookup ( vm, key, hash, None ) ?;
254247 let mut inner = self . write ( ) ;
255- if let IndexEntry :: Index ( index) = entry_index {
248+ if let Some ( index) = entry_index. index ( ) {
256249 // Update existing key
257250 if let Some ( entry) = inner. entries . get_mut ( index) {
258251 let entry = entry
@@ -279,7 +272,7 @@ impl<T: Clone> Dict<T> {
279272
280273 pub fn contains < K : DictKey + ?Sized > ( & self , vm : & VirtualMachine , key : & K ) -> PyResult < bool > {
281274 let ( entry, _) = self . lookup ( vm, key, key. key_hash ( vm) ?, None ) ?;
282- Ok ( matches ! ( entry, IndexEntry :: Index ( _ ) ) )
275+ Ok ( entry. index ( ) . is_some ( ) )
283276 }
284277
285278 /// Retrieve a key
@@ -297,7 +290,7 @@ impl<T: Clone> Dict<T> {
297290 ) -> PyResult < Option < T > > {
298291 let ret = loop {
299292 let ( entry, index_index) = self . lookup ( vm, key, hash, None ) ?;
300- if let IndexEntry :: Index ( index) = entry {
293+ if let Some ( index) = entry. index ( ) {
301294 let inner = self . read ( ) ;
302295 if let Some ( entry) = inner. entries . get ( index) {
303296 let entry = extract_dict_entry ( entry) ;
@@ -385,7 +378,7 @@ impl<T: Clone> Dict<T> {
385378 let _removed = loop {
386379 let lookup = self . lookup ( vm, key, hash, None ) ?;
387380 let ( entry, index_index) = lookup;
388- if let IndexEntry :: Index ( _ ) = entry {
381+ if entry . index ( ) . is_some ( ) {
389382 match self . pop_inner ( lookup) {
390383 ControlFlow :: Break ( Some ( entry) ) => break Some ( entry) ,
391384 _ => continue ,
@@ -407,8 +400,8 @@ impl<T: Clone> Dict<T> {
407400 let hash = key. key_hash ( vm) ?;
408401 let res = loop {
409402 let lookup = self . lookup ( vm, key, hash, None ) ?;
410- let ( entry , index_index) = lookup;
411- if let IndexEntry :: Index ( index) = entry {
403+ let ( index_entry , index_index) = lookup;
404+ if let Some ( index) = index_entry . index ( ) {
412405 let inner = self . read ( ) ;
413406 if let Some ( entry) = inner. entries . get ( index) {
414407 let entry = extract_dict_entry ( entry) ;
@@ -424,7 +417,13 @@ impl<T: Clone> Dict<T> {
424417 } else {
425418 let value = default ( ) ;
426419 let mut inner = self . write ( ) ;
427- inner. unchecked_push ( index_index, hash, key. to_pyobject ( vm) , value. clone ( ) , entry) ;
420+ inner. unchecked_push (
421+ index_index,
422+ hash,
423+ key. to_pyobject ( vm) ,
424+ value. clone ( ) ,
425+ index_entry,
426+ ) ;
428427 break value;
429428 }
430429 } ;
@@ -445,8 +444,8 @@ impl<T: Clone> Dict<T> {
445444 let hash = key. key_hash ( vm) ?;
446445 let res = loop {
447446 let lookup = self . lookup ( vm, key, hash, None ) ?;
448- let ( entry , index_index) = lookup;
449- if let IndexEntry :: Index ( index) = entry {
447+ let ( index_entry , index_index) = lookup;
448+ if let Some ( index) = index_entry . index ( ) {
450449 let inner = self . read ( ) ;
451450 if let Some ( entry) = inner. entries . get ( index) {
452451 let entry = extract_dict_entry ( entry) ;
@@ -464,7 +463,7 @@ impl<T: Clone> Dict<T> {
464463 let key = key. to_pyobject ( vm) ;
465464 let mut inner = self . write ( ) ;
466465 let ret = ( key. clone ( ) , value. clone ( ) ) ;
467- inner. unchecked_push ( index_index, hash, key, value, entry ) ;
466+ inner. unchecked_push ( index_index, hash, key, value, index_entry ) ;
468467 break ret;
469468 }
470469 } ;
@@ -541,22 +540,26 @@ impl<T: Clone> Dict<T> {
541540 } ) ;
542541 loop {
543542 let index_index = idxs. next ( ) ;
544- match IndexEntry :: from ( inner. indices [ index_index] ) {
545- IndexEntry :: Dummy => {
543+ match inner. indices [ index_index] {
544+ IndexEntry :: DUMMY => {
546545 if freeslot. is_none ( ) {
547546 freeslot = Some ( index_index) ;
548547 }
549548 }
550- IndexEntry :: Free => {
549+ IndexEntry :: FREE => {
551550 let idxs = match freeslot {
552- Some ( free) => ( IndexEntry :: Dummy , free) ,
553- None => ( IndexEntry :: Free , index_index) ,
551+ Some ( free) => ( IndexEntry :: DUMMY , free) ,
552+ None => ( IndexEntry :: FREE , index_index) ,
554553 } ;
555554 return Ok ( idxs) ;
556555 }
557- IndexEntry :: Index ( i) => {
556+ idx => {
557+ let i = idx. index ( ) . unwrap_or_else ( || unsafe {
558+ // DUMMY and FREE is already checked above.
559+ std:: hint:: unreachable_unchecked ( )
560+ } ) ;
558561 let entry = & inner. entries [ i] . as_ref ( ) . unwrap ( ) ;
559- let ret = ( IndexEntry :: Index ( i ) , index_index) ;
562+ let ret = ( idx , index_index) ;
560563 if key. key_is ( & entry. key ) {
561564 break ' outer ret;
562565 } else if entry. hash == hash_value {
@@ -593,7 +596,7 @@ impl<T: Clone> Dict<T> {
593596 pred : impl Fn ( & T ) -> Result < bool , E > ,
594597 ) -> Result < PopInnerResult < T > , E > {
595598 let ( entry_index, index_index) = lookup;
596- let entry_index = if let IndexEntry :: Index ( entry_index) = entry_index {
599+ let entry_index = if let Some ( entry_index) = entry_index. index ( ) {
597600 entry_index
598601 } else {
599602 return Ok ( ControlFlow :: Break ( None ) ) ;
0 commit comments