@@ -25,6 +25,7 @@ type EntryIndex = usize;
2525pub struct Dict < T = PyObjectRef > {
2626 inner : PyRwLock < DictInner < T > > ,
2727}
28+
2829impl < T > fmt:: Debug for Dict < T > {
2930 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
3031 f. debug_struct ( "Debug" ) . finish ( )
@@ -37,10 +38,12 @@ enum IndexEntry {
3738 Free ,
3839 Index ( usize ) ,
3940}
41+
4042impl IndexEntry {
4143 const FREE : i64 = -1 ;
4244 const DUMMY : i64 = -2 ;
4345}
46+
4447impl From < i64 > for IndexEntry {
4548 fn from ( idx : i64 ) -> Self {
4649 match idx {
@@ -50,6 +53,7 @@ impl From<i64> for IndexEntry {
5053 }
5154 }
5255}
56+
5357impl From < IndexEntry > for i64 {
5458 fn from ( idx : IndexEntry ) -> Self {
5559 match idx {
@@ -65,7 +69,9 @@ struct DictInner<T> {
6569 used : usize ,
6670 filled : usize ,
6771 indices : Vec < i64 > ,
68- entries : Vec < DictEntry < T > > ,
72+ entries : Vec < Option < DictEntry < T > > > ,
73+ // index to new inserted element should be in entries
74+ next_new_entry_idx : usize ,
6975}
7076
7177impl < T : Clone > Clone for Dict < T > {
@@ -84,6 +90,7 @@ impl<T> Default for Dict<T> {
8490 filled : 0 ,
8591 indices : vec ! [ IndexEntry :: FREE ; 8 ] ,
8692 entries : Vec :: new ( ) ,
93+ next_new_entry_idx : 0 ,
8794 } ) ,
8895 }
8996 }
@@ -143,18 +150,23 @@ impl<T> DictInner<T> {
143150 self . indices = vec ! [ IndexEntry :: FREE ; new_size] ;
144151 let mask = ( new_size - 1 ) as i64 ;
145152 for ( entry_idx, entry) in self . entries . iter_mut ( ) . enumerate ( ) {
146- let mut idxs = GenIndexes :: new ( entry. hash , mask) ;
147- loop {
148- let index_index = idxs. next ( ) ;
149- let idx = & mut self . indices [ index_index] ;
150- if * idx == IndexEntry :: FREE {
151- * idx = entry_idx as i64 ;
152- entry. index = index_index;
153- break ;
153+ if let Some ( entry) = entry {
154+ let mut idxs = GenIndexes :: new ( entry. hash , mask) ;
155+ loop {
156+ let index_index = idxs. next ( ) ;
157+ let idx = & mut self . indices [ index_index] ;
158+ if * idx == IndexEntry :: FREE {
159+ * idx = entry_idx as i64 ;
160+ entry. index = index_index;
161+ break ;
162+ }
154163 }
164+ } else {
165+ //removed entry
155166 }
156167 }
157168 self . filled = self . used ;
169+ self . next_new_entry_idx = self . entries . len ( ) ;
158170 }
159171
160172 fn unchecked_push (
@@ -171,10 +183,15 @@ impl<T> DictInner<T> {
171183 value,
172184 index,
173185 } ;
174- let entry_index = self . entries . len ( ) ;
175- self . entries . push ( entry) ;
186+ let entry_index = self . next_new_entry_idx ;
187+ if self . entries . len ( ) == entry_index {
188+ self . entries . push ( Some ( entry) ) ;
189+ } else {
190+ self . entries [ entry_index] = Some ( entry) ;
191+ }
176192 self . indices [ index] = entry_index as i64 ;
177193 self . used += 1 ;
194+ self . next_new_entry_idx += 1 ;
178195 if let IndexEntry :: Free = index_entry {
179196 self . filled += 1 ;
180197 if let Some ( new_size) = self . should_resize ( ) {
@@ -223,6 +240,9 @@ impl<T: Clone> Dict<T> {
223240 let mut inner = self . write ( ) ;
224241 // Update existing key
225242 if let Some ( entry) = inner. entries . get_mut ( index) {
243+ let entry = entry
244+ . as_mut ( )
245+ . expect ( "The dict was changed since we did lookup." ) ;
226246 if entry. index == index_index {
227247 let removed = std:: mem:: replace ( & mut entry. value , value) ;
228248 // defer dec RC
@@ -266,6 +286,7 @@ impl<T: Clone> Dict<T> {
266286 if let IndexEntry :: Index ( index) = entry {
267287 let inner = self . read ( ) ;
268288 if let Some ( entry) = inner. entries . get ( index) {
289+ let entry = extract_dict_entry ( entry) ;
269290 if entry. index == index_index {
270291 break Some ( entry. value . clone ( ) ) ;
271292 } else {
@@ -303,6 +324,7 @@ impl<T: Clone> Dict<T> {
303324 inner. indices . resize ( 8 , IndexEntry :: FREE ) ;
304325 inner. used = 0 ;
305326 inner. filled = 0 ;
327+ inner. next_new_entry_idx = 0 ;
306328 // defer dec rc
307329 std:: mem:: take ( & mut inner. entries )
308330 } ;
@@ -377,6 +399,7 @@ impl<T: Clone> Dict<T> {
377399 if let IndexEntry :: Index ( index) = entry {
378400 let inner = self . read ( ) ;
379401 if let Some ( entry) = inner. entries . get ( index) {
402+ let entry = extract_dict_entry ( entry) ;
380403 if entry. index == index_index {
381404 break entry. value . clone ( ) ;
382405 } else {
@@ -419,6 +442,7 @@ impl<T: Clone> Dict<T> {
419442 if let IndexEntry :: Index ( index) = entry {
420443 let inner = self . read ( ) ;
421444 if let Some ( entry) = inner. entries . get ( index) {
445+ let entry = extract_dict_entry ( entry) ;
422446 if entry. index == index_index {
423447 break ( entry. key . clone ( ) , entry. value . clone ( ) ) ;
424448 } else {
@@ -453,10 +477,14 @@ impl<T: Clone> Dict<T> {
453477 }
454478
455479 pub fn next_entry ( & self , position : & mut EntryIndex ) -> Option < ( PyObjectRef , T ) > {
456- self . read ( ) . entries . get ( * position) . map ( |entry| {
480+ let inner = self . read ( ) ;
481+ loop {
482+ let entry = inner. entries . get ( * position) ?;
457483 * position += 1 ;
458- ( entry. key . clone ( ) , entry. value . clone ( ) )
459- } )
484+ if let Some ( entry) = entry {
485+ break Some ( ( entry. key . clone ( ) , entry. value . clone ( ) ) ) ;
486+ }
487+ }
460488 }
461489
462490 pub fn len_from_entry_index ( & self , position : EntryIndex ) -> usize {
@@ -469,7 +497,11 @@ impl<T: Clone> Dict<T> {
469497 }
470498
471499 pub fn keys ( & self ) -> Vec < PyObjectRef > {
472- self . read ( ) . entries . iter ( ) . map ( |v| v. key . clone ( ) ) . collect ( )
500+ self . read ( )
501+ . entries
502+ . iter ( )
503+ . filter_map ( |v| v. as_ref ( ) . map ( |v| v. key . clone ( ) ) )
504+ . collect ( )
473505 }
474506
475507 /// Lookup the index for the given key.
@@ -505,7 +537,7 @@ impl<T: Clone> Dict<T> {
505537 return Ok ( idxs) ;
506538 }
507539 IndexEntry :: Index ( i) => {
508- let entry = & inner. entries [ i] ;
540+ let entry = & inner. entries [ i] . as_ref ( ) . unwrap ( ) ;
509541 let ret = ( IndexEntry :: Index ( i) , index_index) ;
510542 if key. key_is ( & entry. key ) {
511543 break ' outer ret;
@@ -540,23 +572,17 @@ impl<T: Clone> Dict<T> {
540572 return Ok ( None ) ;
541573 } ;
542574 let mut inner = self . write ( ) ;
543- if matches ! ( inner. entries. get( entry_index) , Some ( entry) if entry. index == index_index) {
575+ if matches ! ( inner. entries. get( entry_index) , Some ( Some ( entry) ) if entry. index == index_index)
576+ {
544577 // all good
545578 } else {
546579 // The dict was changed since we did lookup. Let's try again.
547580 return Err ( ( ) ) ;
548581 } ;
549582 inner. indices [ index_index] = IndexEntry :: DUMMY ;
550583 inner. used -= 1 ;
551- let removed = if entry_index == inner. used {
552- inner. entries . pop ( ) . unwrap ( )
553- } else {
554- let last_index = inner. entries . last ( ) . unwrap ( ) . index ;
555- let removed = inner. entries . swap_remove ( entry_index) ;
556- inner. indices [ last_index] = entry_index as i64 ;
557- removed
558- } ;
559- Ok ( Some ( removed) )
584+ let removed = std:: mem:: take ( & mut inner. entries [ entry_index] ) ;
585+ Ok ( removed)
560586 }
561587
562588 /// Retrieve and delete a key
@@ -575,11 +601,19 @@ impl<T: Clone> Dict<T> {
575601
576602 pub fn pop_back ( & self ) -> Option < ( PyObjectRef , T ) > {
577603 let mut inner = self . write ( ) ;
578- inner. entries . pop ( ) . map ( |entry| {
579- inner. used -= 1 ;
580- inner. indices [ entry. index ] = IndexEntry :: DUMMY ;
581- ( entry. key , entry. value )
582- } )
604+ let mut idx = inner. next_new_entry_idx . checked_sub ( 1 ) ?;
605+ while inner. entries . get ( idx) . unwrap ( ) . is_none ( ) {
606+ idx = idx. checked_sub ( 1 ) ?;
607+ }
608+
609+ let entry = std:: mem:: take ( & mut inner. entries [ idx] ) . unwrap ( ) ;
610+ let removed_key = entry. key ;
611+ let removed_item = entry. value ;
612+
613+ inner. used -= 1 ;
614+ inner. indices [ entry. index ] = IndexEntry :: DUMMY ;
615+ inner. next_new_entry_idx = idx;
616+ Some ( ( removed_key, removed_item) )
583617 }
584618
585619 pub fn sizeof ( & self ) -> usize {
@@ -638,6 +672,7 @@ impl DictKey for PyStrRef {
638672 }
639673 }
640674}
675+
641676impl DictKey for PyRefExact < PyStr > {
642677 fn key_hash ( & self , vm : & VirtualMachine ) -> PyResult < HashValue > {
643678 ( * * self ) . key_hash ( vm)
@@ -699,6 +734,12 @@ fn str_exact<'a>(obj: &'a PyObjectRef, vm: &VirtualMachine) -> Option<&'a PyStr>
699734 }
700735}
701736
737+ fn extract_dict_entry < T > ( option_entry : & Option < DictEntry < T > > ) -> & DictEntry < T > {
738+ option_entry
739+ . as_ref ( )
740+ . expect ( "The dict was changed since we did lookup." )
741+ }
742+
702743#[ cfg( test) ]
703744mod tests {
704745 use super :: { Dict , DictKey } ;
0 commit comments