@@ -19,7 +19,8 @@ use core::default::Default;
19
19
use core:: fmt;
20
20
use core:: iter;
21
21
use core:: iter:: { Enumerate , FilterMap } ;
22
- use core:: mem:: replace;
22
+ use core:: mem:: { replace, swap} ;
23
+ use core:: kinds:: marker:: ContravariantLifetime ;
23
24
24
25
use { Mutable , Map , MutableMap , MutableSeq } ;
25
26
use { vec, slice} ;
@@ -295,6 +296,19 @@ impl<V> SmallIntMap<V> {
295
296
v. map ( |v| ( i, v) )
296
297
} )
297
298
}
299
+
300
+ /// Gets the given key's corresponding entry in the map for in-place manipulation
301
+ pub fn entry < ' a > ( & ' a mut self , key : uint ) -> Entry < ' a , V > {
302
+ let self_ptr = self as * mut _ ;
303
+ match self . find_mut ( & key) {
304
+ // FIXME: So, this is absolutely awful. We absolutely *do not* need a raw ptr for
305
+ // VacantEntry, but borrowck thinks that self is borrowed in both this None branch,
306
+ // and after the match if we return in the Some branch. If anyone knows how to work
307
+ // around this, *please do*.
308
+ None => Vacant ( VacantEntry { map : self_ptr, key : key, marker : ContravariantLifetime } ) ,
309
+ Some ( val) => Occupied ( OccupiedEntry { map : self_ptr, key : key, val : val } ) ,
310
+ }
311
+ }
298
312
}
299
313
300
314
impl < V : Clone > SmallIntMap < V > {
@@ -494,14 +508,90 @@ pub type Keys<'a, T> =
494
508
pub type Values < ' a , T > =
495
509
iter:: Map < ' static , ( uint , & ' a T ) , & ' a T , Entries < ' a , T > > ;
496
510
511
+ /// A view into a single occupied location in a SmallIntMap
512
+ pub struct OccupiedEntry < ' a , V : ' a > {
513
+ key : uint ,
514
+ val : & ' a mut V ,
515
+ // We only need this for `take`. Should never be null, and we'll only use it when
516
+ // we we'll never touch `val` again. Totally safe, just lame that we need this.
517
+ // The alternative would be doing the indexing on every op, which would make this API
518
+ // *worse* than useless. This way it's *only* useless.
519
+ map : * mut SmallIntMap < V > ,
520
+ }
521
+
522
+ /// A view into a single empty location in a SmallIntMap
523
+ pub struct VacantEntry < ' a , V : ' a > {
524
+ // See the FIXME in `entry` for why this mess happened
525
+ map : * mut SmallIntMap < V > ,
526
+ key : uint ,
527
+ marker : ContravariantLifetime < ' a > ,
528
+ }
529
+
530
+ /// A view into a single location in a map, which may be vacant or occupied
531
+ pub enum Entry < ' a , V : ' a > {
532
+ /// An occupied Entry
533
+ Occupied ( OccupiedEntry < ' a , V > ) ,
534
+ /// A vacant Entry
535
+ Vacant ( VacantEntry < ' a , V > ) ,
536
+ }
537
+
538
+ impl < ' a , V > OccupiedEntry < ' a , V > {
539
+ /// Gets a reference to the value in the entry
540
+ pub fn get ( & self ) -> & V {
541
+ & * self . val
542
+ }
543
+
544
+ /// Gets a mutable reference to the value in the entry
545
+ pub fn get_mut ( & mut self ) -> & mut V {
546
+ self . val
547
+ }
548
+
549
+ /// Converts the OccupiedEntry into a mutable reference to the value in the entry
550
+ /// with a lifetime bound to the map itself
551
+ pub fn into_mut ( self ) -> & ' a mut V {
552
+ self . val
553
+ }
554
+
555
+ /// Sets the value of the entry, and returns the entry's old value
556
+ pub fn set ( & mut self , mut value : V ) -> V {
557
+ swap ( & mut value, self . val ) ;
558
+ value
559
+ }
560
+
561
+ /// Takes the value out of the entry, and returns it
562
+ pub fn take ( self ) -> V {
563
+ // This is pretty much as effecient as this can be, short of storing *another* raw ptr
564
+ // to the option, so that we can `None` it out directly, and then decrement the map's
565
+ // length directly. That would be... awful.
566
+ unsafe {
567
+ ( * self . map ) . pop ( & self . key ) . unwrap ( )
568
+ }
569
+ }
570
+ }
571
+
572
+ impl < ' a , V > VacantEntry < ' a , V > {
573
+ /// Sets the value of the entry with the VacantEntry's key,
574
+ /// and returns a mutable reference to it
575
+ pub fn set ( self , value : V ) -> & ' a mut V {
576
+ // This is moderately inefficient because we do two indexing operations, where we could
577
+ // only do one. However insert handles all the growing and length logic for us,
578
+ // and this API is already pretty silly on SmallIntMap. Not worth a big refactor over.
579
+ //
580
+ // There isn't any clear way to avoid an `unwrap` of the underlying option, regardless.
581
+ let map = unsafe { & mut * self . map } ;
582
+ map. insert ( self . key , value) ;
583
+ map. find_mut ( & self . key ) . unwrap ( )
584
+ }
585
+ }
586
+
497
587
#[ cfg( test) ]
498
588
mod test_map {
499
589
use std:: prelude:: * ;
500
590
use vec:: Vec ;
501
591
use hash;
502
592
503
593
use { Map , MutableMap , Mutable , MutableSeq } ;
504
- use super :: SmallIntMap ;
594
+ use super :: { SmallIntMap , Occupied , Vacant } ;
505
595
506
596
#[ test]
507
597
fn test_find_mut ( ) {
@@ -863,6 +953,58 @@ mod test_map {
863
953
864
954
map[ 4 ] ;
865
955
}
956
+
957
+ #[ test]
958
+ fn test_entry ( ) {
959
+ let xs = [ ( 1 i, 10 i) , ( 2 , 20 ) , ( 3 , 30 ) , ( 4 , 40 ) , ( 5 , 50 ) , ( 6 , 60 ) ] ;
960
+
961
+ let mut map: SmallIntMap < int > = xs. iter ( ) . map ( |& x| x) . collect ( ) ;
962
+
963
+ // Existing key (insert)
964
+ match map. entry ( 1 ) {
965
+ Vacant ( _) => unreachable ! ( ) ,
966
+ Occupied ( mut view) => {
967
+ assert_eq ! ( view. get( ) , & 10 ) ;
968
+ assert_eq ! ( view. set( 100 ) , 10 ) ;
969
+ }
970
+ }
971
+ assert_eq ! ( map. find( & 1 ) . unwrap( ) , & 100 ) ;
972
+ assert_eq ! ( map. len( ) , 6 ) ;
973
+
974
+
975
+ // Existing key (update)
976
+ match map. entry ( 2 ) {
977
+ Vacant ( _) => unreachable ! ( ) ,
978
+ Occupied ( mut view) => {
979
+ let v = view. get_mut ( ) ;
980
+ let new_v = ( * v) * 10 ;
981
+ * v = new_v;
982
+ }
983
+ }
984
+ assert_eq ! ( map. find( & 2 ) . unwrap( ) , & 200 ) ;
985
+ assert_eq ! ( map. len( ) , 6 ) ;
986
+
987
+ // Existing key (take)
988
+ match map. entry ( 3 ) {
989
+ Vacant ( _) => unreachable ! ( ) ,
990
+ Occupied ( view) => {
991
+ assert_eq ! ( view. take( ) , 30 ) ;
992
+ }
993
+ }
994
+ assert_eq ! ( map. find( & 3 ) , None ) ;
995
+ assert_eq ! ( map. len( ) , 5 ) ;
996
+
997
+
998
+ // Inexistent key (insert)
999
+ match map. entry ( 10 ) {
1000
+ Occupied ( _) => unreachable ! ( ) ,
1001
+ Vacant ( view) => {
1002
+ assert_eq ! ( * view. set( 1000 ) , 1000 ) ;
1003
+ }
1004
+ }
1005
+ assert_eq ! ( map. find( & 10 ) . unwrap( ) , & 1000 ) ;
1006
+ assert_eq ! ( map. len( ) , 6 ) ;
1007
+ }
866
1008
}
867
1009
868
1010
#[ cfg( test) ]
0 commit comments