@@ -467,6 +467,34 @@ where
467
467
pub fn values_mut ( & mut self ) -> impl Iterator < Item = & mut V > {
468
468
self . iter_mut ( ) . map ( |( _, v) | v)
469
469
}
470
+
471
+ /// Returns an entry for the corresponding key
472
+ /// ```
473
+ /// use heapless::linear_map;
474
+ /// use heapless::LinearMap;
475
+ /// let mut map = LinearMap::<_, _, 16>::new();
476
+ /// if let linear_map::Entry::Vacant(v) = map.entry("a") {
477
+ /// v.insert(1).unwrap();
478
+ /// }
479
+ /// if let linear_map::Entry::Occupied(mut o) = map.entry("a") {
480
+ /// println!("found {}", *o.get()); // Prints 1
481
+ /// o.insert(2);
482
+ /// }
483
+ /// // Prints 2
484
+ /// println!("val: {}", *map.get("a").unwrap());
485
+ /// ```
486
+ pub fn entry ( & mut self , key : K ) -> Entry < ' _ , K , V , S > {
487
+ let idx = self
488
+ . keys ( )
489
+ . enumerate ( )
490
+ . find ( |& ( _, k) | * k. borrow ( ) == key)
491
+ . map ( |( idx, _) | idx) ;
492
+
493
+ match idx {
494
+ Some ( idx) => Entry :: Occupied ( OccupiedEntry { idx, map : self } ) ,
495
+ None => Entry :: Vacant ( VacantEntry { key, map : self } ) ,
496
+ }
497
+ }
470
498
}
471
499
472
500
impl < K , V , Q , S : LinearMapStorage < K , V > + ?Sized > ops:: Index < & ' _ Q > for LinearMapInner < K , V , S >
@@ -635,11 +663,111 @@ where
635
663
{
636
664
}
637
665
666
+ /// A view into an entry in the map
667
+ pub enum Entry < ' a , K , V , S : LinearMapStorage < K , V > + ?Sized > {
668
+ /// The entry corresponding to the key `K` exists in the map
669
+ Occupied ( OccupiedEntry < ' a , K , V , S > ) ,
670
+ /// The entry corresponding to the key `K` does not exist in the map
671
+ Vacant ( VacantEntry < ' a , K , V , S > ) ,
672
+ }
673
+
674
+ /// An occupied entry which can be manipulated
675
+ pub struct OccupiedEntry < ' a , K , V , S : LinearMapStorage < K , V > + ?Sized > {
676
+ // SAFETY: `idx` must not be modified after construction, and
677
+ // the size of `map` must not be changed.
678
+ idx : usize ,
679
+ map : & ' a mut LinearMapInner < K , V , S > ,
680
+ }
681
+
682
+ impl < ' a , K , V , S : LinearMapStorage < K , V > + ?Sized > OccupiedEntry < ' a , K , V , S >
683
+ where
684
+ K : Eq ,
685
+ {
686
+ /// Gets a reference to the key that this entity corresponds to
687
+ pub fn key ( & self ) -> & K {
688
+ // SAFETY: Valid idx from OccupiedEntry construction
689
+ let ( k, _v) = unsafe { self . map . buffer . get_unchecked ( self . idx ) } ;
690
+ k
691
+ }
692
+
693
+ /// Removes this entry from the map and yields its corresponding key and value
694
+ pub fn remove_entry ( self ) -> ( K , V ) {
695
+ // SAFETY: Valid idx from OccupiedEntry construction
696
+ unsafe { self . map . buffer . swap_remove_unchecked ( self . idx ) }
697
+ }
698
+
699
+ /// Removes this entry from the map and yields its corresponding key and value
700
+ pub fn remove ( self ) -> V {
701
+ self . remove_entry ( ) . 1
702
+ }
703
+
704
+ /// Gets a reference to the value associated with this entry
705
+ pub fn get ( & self ) -> & V {
706
+ // SAFETY: Valid idx from OccupiedEntry construction
707
+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked ( self . idx ) } ;
708
+ v
709
+ }
710
+
711
+ /// Gets a mutable reference to the value associated with this entry
712
+ pub fn get_mut ( & mut self ) -> & mut V {
713
+ // SAFETY: Valid idx from OccupiedEntry construction
714
+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked_mut ( self . idx ) } ;
715
+ v
716
+ }
717
+
718
+ /// Consumes this entry and yields a reference to the underlying value
719
+ pub fn into_mut ( self ) -> & ' a mut V {
720
+ // SAFETY: Valid idx from OccupiedEntry construction
721
+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked_mut ( self . idx ) } ;
722
+ v
723
+ }
724
+
725
+ /// Overwrites the underlying map's value with this entry's value
726
+ pub fn insert ( self , value : V ) -> V {
727
+ // SAFETY: Valid idx from OccupiedEntry construction
728
+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked_mut ( self . idx ) } ;
729
+ mem:: replace ( v, value)
730
+ }
731
+ }
732
+
733
+ /// A view into an empty slot in the underlying map
734
+ pub struct VacantEntry < ' a , K , V , S : LinearMapStorage < K , V > + ?Sized > {
735
+ key : K ,
736
+ map : & ' a mut LinearMapInner < K , V , S > ,
737
+ }
738
+
739
+ impl < ' a , K , V , S : LinearMapStorage < K , V > + ?Sized > VacantEntry < ' a , K , V , S >
740
+ where
741
+ K : Eq ,
742
+ {
743
+ /// Get the key associated with this entry
744
+ pub fn key ( & self ) -> & K {
745
+ & self . key
746
+ }
747
+
748
+ /// Consumes this entry to yield to key associated with it
749
+ pub fn into_key ( self ) -> K {
750
+ self . key
751
+ }
752
+
753
+ /// Inserts this entry into to underlying map, yields a mutable reference to the inserted value.
754
+ /// If the map is at capacity the value is returned instead.
755
+ pub fn insert ( self , value : V ) -> Result < & ' a mut V , V > {
756
+ self . map
757
+ . buffer
758
+ . push ( ( self . key , value) )
759
+ . map_err ( |( _k, v) | v) ?;
760
+ let idx = self . map . buffer . len ( ) - 1 ;
761
+ let r = & mut self . map . buffer [ idx] ;
762
+ Ok ( & mut r. 1 )
763
+ }
764
+ }
765
+
638
766
#[ cfg( test) ]
639
767
mod test {
640
768
use static_assertions:: assert_not_impl_any;
641
769
642
- use super :: { LinearMap , LinearMapView } ;
770
+ use super :: { Entry , LinearMap , LinearMapView } ;
643
771
644
772
// Ensure a `LinearMap` containing `!Send` keys stays `!Send` itself.
645
773
assert_not_impl_any ! ( LinearMap <* const ( ) , ( ) , 4 >: Send ) ;
@@ -752,4 +880,124 @@ mod test {
752
880
let map: LinearMap < usize , f32 , 4 > = Default :: default ( ) ;
753
881
assert_eq ! ( map, map) ;
754
882
}
883
+
884
+ // tests that use this constant take too long to run under miri, specially on CI, with a map of
885
+ // this size so make the map smaller when using miri
886
+ #[ cfg( not( miri) ) ]
887
+ const MAP_SLOTS : usize = 4096 ;
888
+ #[ cfg( miri) ]
889
+ const MAP_SLOTS : usize = 64 ;
890
+ fn almost_filled_map ( ) -> LinearMap < usize , usize , MAP_SLOTS > {
891
+ let mut almost_filled = LinearMap :: new ( ) ;
892
+ for i in 1 ..MAP_SLOTS {
893
+ almost_filled. insert ( i, i) . unwrap ( ) ;
894
+ }
895
+ almost_filled
896
+ }
897
+
898
+ #[ test]
899
+ fn entry_find ( ) {
900
+ let key = 0 ;
901
+ let value = 0 ;
902
+ let mut src = almost_filled_map ( ) ;
903
+ let entry = src. entry ( key) ;
904
+ match entry {
905
+ Entry :: Occupied ( _) => {
906
+ panic ! ( "Found entry without inserting" ) ;
907
+ }
908
+ Entry :: Vacant ( v) => {
909
+ assert_eq ! ( & key, v. key( ) ) ;
910
+ assert_eq ! ( key, v. into_key( ) ) ;
911
+ }
912
+ }
913
+ src. insert ( key, value) . unwrap ( ) ;
914
+ let entry = src. entry ( key) ;
915
+ match entry {
916
+ Entry :: Occupied ( mut o) => {
917
+ assert_eq ! ( & key, o. key( ) ) ;
918
+ assert_eq ! ( & value, o. get( ) ) ;
919
+ assert_eq ! ( & value, o. get_mut( ) ) ;
920
+ assert_eq ! ( & value, o. into_mut( ) ) ;
921
+ }
922
+ Entry :: Vacant ( _) => {
923
+ panic ! ( "Entry not found" ) ;
924
+ }
925
+ }
926
+ }
927
+
928
+ #[ test]
929
+ fn entry_vacant_insert ( ) {
930
+ let key = 0 ;
931
+ let value = 0 ;
932
+ let mut src = almost_filled_map ( ) ;
933
+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
934
+ let entry = src. entry ( key) ;
935
+ match entry {
936
+ Entry :: Occupied ( _) => {
937
+ panic ! ( "Entry found when empty" ) ;
938
+ }
939
+ Entry :: Vacant ( v) => {
940
+ assert_eq ! ( value, * v. insert( value) . unwrap( ) ) ;
941
+ }
942
+ } ;
943
+ assert_eq ! ( value, * src. get( & key) . unwrap( ) ) ;
944
+ }
945
+
946
+ #[ test]
947
+ fn entry_occupied_insert ( ) {
948
+ let key = 0 ;
949
+ let value = 0 ;
950
+ let value2 = 5 ;
951
+ let mut src = almost_filled_map ( ) ;
952
+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
953
+ src. insert ( key, value) . unwrap ( ) ;
954
+ let entry = src. entry ( key) ;
955
+ match entry {
956
+ Entry :: Occupied ( o) => {
957
+ assert_eq ! ( value, o. insert( value2) ) ;
958
+ }
959
+ Entry :: Vacant ( _) => {
960
+ panic ! ( "Entry not found" ) ;
961
+ }
962
+ } ;
963
+ assert_eq ! ( value2, * src. get( & key) . unwrap( ) ) ;
964
+ }
965
+
966
+ #[ test]
967
+ fn entry_remove_entry ( ) {
968
+ let key = 0 ;
969
+ let value = 0 ;
970
+ let mut src = almost_filled_map ( ) ;
971
+ src. insert ( key, value) . unwrap ( ) ;
972
+ assert_eq ! ( MAP_SLOTS , src. len( ) ) ;
973
+ let entry = src. entry ( key) ;
974
+ match entry {
975
+ Entry :: Occupied ( o) => {
976
+ assert_eq ! ( ( key, value) , o. remove_entry( ) ) ;
977
+ }
978
+ Entry :: Vacant ( _) => {
979
+ panic ! ( "Entry not found" )
980
+ }
981
+ } ;
982
+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
983
+ }
984
+
985
+ #[ test]
986
+ fn entry_remove ( ) {
987
+ let key = 0 ;
988
+ let value = 0 ;
989
+ let mut src = almost_filled_map ( ) ;
990
+ src. insert ( key, value) . unwrap ( ) ;
991
+ assert_eq ! ( MAP_SLOTS , src. len( ) ) ;
992
+ let entry = src. entry ( key) ;
993
+ match entry {
994
+ Entry :: Occupied ( o) => {
995
+ assert_eq ! ( value, o. remove( ) ) ;
996
+ }
997
+ Entry :: Vacant ( _) => {
998
+ panic ! ( "Entry not found" ) ;
999
+ }
1000
+ } ;
1001
+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
1002
+ }
755
1003
}
0 commit comments