@@ -19,7 +19,8 @@ use core::default::Default;
1919use core:: fmt;
2020use core:: iter;
2121use core:: iter:: { Enumerate , FilterMap } ;
22- use core:: mem:: replace;
22+ use core:: mem:: { replace, swap} ;
23+ use core:: kinds:: marker:: ContravariantLifetime ;
2324
2425use { Mutable , Map , MutableMap , MutableSeq } ;
2526use { vec, slice} ;
@@ -295,6 +296,19 @@ impl<V> SmallIntMap<V> {
295296 v. map ( |v| ( i, v) )
296297 } )
297298 }
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+ }
298312}
299313
300314impl < V : Clone > SmallIntMap < V > {
@@ -494,14 +508,90 @@ pub type Keys<'a, T> =
494508pub type Values < ' a , T > =
495509 iter:: Map < ' static , ( uint , & ' a T ) , & ' a T , Entries < ' a , T > > ;
496510
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+
497587#[ cfg( test) ]
498588mod test_map {
499589 use std:: prelude:: * ;
500590 use vec:: Vec ;
501591 use hash;
502592
503593 use { Map , MutableMap , Mutable , MutableSeq } ;
504- use super :: SmallIntMap ;
594+ use super :: { SmallIntMap , Occupied , Vacant } ;
505595
506596 #[ test]
507597 fn test_find_mut ( ) {
@@ -863,6 +953,58 @@ mod test_map {
863953
864954 map[ 4 ] ;
865955 }
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+ }
8661008}
8671009
8681010#[ cfg( test) ]
0 commit comments