@@ -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} ;
@@ -332,6 +333,19 @@ impl<V> SmallIntMap<V> {
332
333
v. map ( |v| ( i, v) )
333
334
} )
334
335
}
336
+
337
+ /// Gets the given key's corresponding entry in the map for in-place manipulation
338
+ pub fn entry < ' a > ( & ' a mut self , key : uint ) -> Entry < ' a , V > {
339
+ let self_ptr = self as * mut _ ;
340
+ match self . find_mut ( & key) {
341
+ // FIXME: So, this is absolutely awful. We absolutely *do not* need a raw ptr for
342
+ // VacantEntry, but borrowck thinks that self is borrowed in both this None branch,
343
+ // and after the match if we return in the Some branch. If anyone knows how to work
344
+ // around this, *please do*.
345
+ None => Vacant ( VacantEntry { map : self_ptr, key : key, marker : ContravariantLifetime } ) ,
346
+ Some ( val) => Occupied ( OccupiedEntry { map : self_ptr, key : key, val : val } ) ,
347
+ }
348
+ }
335
349
}
336
350
337
351
impl < V : Clone > SmallIntMap < V > {
@@ -532,14 +546,90 @@ pub type Keys<'a, T> =
532
546
pub type Values < ' a , T > =
533
547
iter:: Map < ' static , ( uint , & ' a T ) , & ' a T , Entries < ' a , T > > ;
534
548
549
+ /// A view into a single occupied location in a SmallIntMap
550
+ pub struct OccupiedEntry < ' a , V : ' a > {
551
+ key : uint ,
552
+ val : & ' a mut V ,
553
+ // We only need this for `take`. Should never be null, and we'll only use it when
554
+ // we we'll never touch `val` again. Totally safe, just lame that we need this.
555
+ // The alternative would be doing the indexing on every op, which would make this API
556
+ // *worse* than useless. This way it's *only* useless.
557
+ map : * mut SmallIntMap < V > ,
558
+ }
559
+
560
+ /// A view into a single empty location in a SmallIntMap
561
+ pub struct VacantEntry < ' a , V : ' a > {
562
+ // See the FIXME in `entry` for why this mess happened
563
+ map : * mut SmallIntMap < V > ,
564
+ key : uint ,
565
+ marker : ContravariantLifetime < ' a > ,
566
+ }
567
+
568
+ /// A view into a single location in a map, which may be vacant or occupied
569
+ pub enum Entry < ' a , V : ' a > {
570
+ /// An occupied Entry
571
+ Occupied ( OccupiedEntry < ' a , V > ) ,
572
+ /// A vacant Entry
573
+ Vacant ( VacantEntry < ' a , V > ) ,
574
+ }
575
+
576
+ impl < ' a , V > OccupiedEntry < ' a , V > {
577
+ /// Gets a reference to the value in the entry
578
+ pub fn get ( & self ) -> & V {
579
+ & * self . val
580
+ }
581
+
582
+ /// Gets a mutable reference to the value in the entry
583
+ pub fn get_mut ( & mut self ) -> & mut V {
584
+ self . val
585
+ }
586
+
587
+ /// Converts the OccupiedEntry into a mutable reference to the value in the entry
588
+ /// with a lifetime bound to the map itself
589
+ pub fn into_mut ( self ) -> & ' a mut V {
590
+ self . val
591
+ }
592
+
593
+ /// Sets the value of the entry, and returns the entry's old value
594
+ pub fn set ( & mut self , mut value : V ) -> V {
595
+ swap ( & mut value, self . val ) ;
596
+ value
597
+ }
598
+
599
+ /// Takes the value out of the entry, and returns it
600
+ pub fn take ( self ) -> V {
601
+ // This is pretty much as effecient as this can be, short of storing *another* raw ptr
602
+ // to the option, so that we can `None` it out directly, and then decrement the map's
603
+ // length directly. That would be... awful.
604
+ unsafe {
605
+ ( * self . map ) . pop ( & self . key ) . unwrap ( )
606
+ }
607
+ }
608
+ }
609
+
610
+ impl < ' a , V > VacantEntry < ' a , V > {
611
+ /// Sets the value of the entry with the VacantEntry's key,
612
+ /// and returns a mutable reference to it
613
+ pub fn set ( self , value : V ) -> & ' a mut V {
614
+ // This is moderately inefficient because we do two indexing operations, where we could
615
+ // only do one. However insert handles all the growing and length logic for us,
616
+ // and this API is already pretty silly on SmallIntMap. Not worth a big refactor over.
617
+ //
618
+ // There isn't any clear way to avoid an `unwrap` of the underlying option, regardless.
619
+ let map = unsafe { & mut * self . map } ;
620
+ map. insert ( self . key , value) ;
621
+ map. find_mut ( & self . key ) . unwrap ( )
622
+ }
623
+ }
624
+
535
625
#[ cfg( test) ]
536
626
mod test_map {
537
627
use std:: prelude:: * ;
538
628
use vec:: Vec ;
539
629
use hash;
540
630
541
631
use { Map , MutableMap , Mutable , MutableSeq } ;
542
- use super :: SmallIntMap ;
632
+ use super :: { SmallIntMap , OccupiedEntry , VacantEntry } ;
543
633
544
634
#[ test]
545
635
fn test_find_mut ( ) {
@@ -901,6 +991,58 @@ mod test_map {
901
991
902
992
map[ 4 ] ;
903
993
}
994
+
995
+ #[ test]
996
+ fn test_entry ( ) {
997
+ let xs = [ ( 1 i, 10 i) , ( 2 , 20 ) , ( 3 , 30 ) , ( 4 , 40 ) , ( 5 , 50 ) , ( 6 , 60 ) ] ;
998
+
999
+ let mut map: SmallIntMap < int > = xs. iter ( ) . map ( |& x| x) . collect ( ) ;
1000
+
1001
+ // Existing key (insert)
1002
+ match map. entry ( 1 ) {
1003
+ Vacant ( _) => unreachable ! ( ) ,
1004
+ Occupied ( mut view) => {
1005
+ assert_eq ! ( view. get( ) , & 10 ) ;
1006
+ assert_eq ! ( view. set( 100 ) , 10 ) ;
1007
+ }
1008
+ }
1009
+ assert_eq ! ( map. find( & 1 ) . unwrap( ) , & 100 ) ;
1010
+ assert_eq ! ( map. len( ) , 6 ) ;
1011
+
1012
+
1013
+ // Existing key (update)
1014
+ match map. entry ( 2 ) {
1015
+ Vacant ( _) => unreachable ! ( ) ,
1016
+ Occupied ( mut view) => {
1017
+ let v = view. get_mut ( ) ;
1018
+ let new_v = ( * v) * 10 ;
1019
+ * v = new_v;
1020
+ }
1021
+ }
1022
+ assert_eq ! ( map. find( & 2 ) . unwrap( ) , & 200 ) ;
1023
+ assert_eq ! ( map. len( ) , 6 ) ;
1024
+
1025
+ // Existing key (take)
1026
+ match map. entry ( 3 ) {
1027
+ Vacant ( _) => unreachable ! ( ) ,
1028
+ Occupied ( view) => {
1029
+ assert_eq ! ( view. take( ) , 30 ) ;
1030
+ }
1031
+ }
1032
+ assert_eq ! ( map. find( & 3 ) , None ) ;
1033
+ assert_eq ! ( map. len( ) , 5 ) ;
1034
+
1035
+
1036
+ // Inexistent key (insert)
1037
+ match map. entry ( 10 ) {
1038
+ Occupied ( _) => unreachable ! ( ) ,
1039
+ Vacant ( view) => {
1040
+ assert_eq ! ( * view. set( 1000 ) , 1000 ) ;
1041
+ }
1042
+ }
1043
+ assert_eq ! ( map. find( & 10 ) . unwrap( ) , & 1000 ) ;
1044
+ assert_eq ! ( map. len( ) , 6 ) ;
1045
+ }
904
1046
}
905
1047
906
1048
#[ cfg( test) ]
0 commit comments