1
1
use crate :: { Equivalent , TryReserveError } ;
2
- use alloc:: borrow:: ToOwned ;
3
2
use core:: hash:: { BuildHasher , Hash } ;
4
3
use core:: iter:: { Chain , FusedIterator } ;
5
4
use core:: ops:: { BitAnd , BitAndAssign , BitOr , BitOrAssign , BitXor , BitXorAssign , Sub , SubAssign } ;
6
5
use core:: { fmt, mem} ;
7
- use map:: { equivalent_key , make_hash, make_hasher } ;
6
+ use map:: make_hash;
8
7
9
8
use super :: map:: { self , HashMap , Keys } ;
10
9
use crate :: raw:: { Allocator , Global , RawExtractIf } ;
@@ -911,45 +910,12 @@ where
911
910
/// ```
912
911
#[ cfg_attr( feature = "inline-more" , inline) ]
913
912
pub fn get_or_insert ( & mut self , value : T ) -> & T {
914
- // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
915
- // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
916
- self . map
917
- . raw_entry_mut ( )
918
- . from_key ( & value)
919
- . or_insert ( value, ( ) )
920
- . 0
921
- }
922
-
923
- /// Inserts an owned copy of the given `value` into the set if it is not
924
- /// present, then returns a reference to the value in the set.
925
- ///
926
- /// # Examples
927
- ///
928
- /// ```
929
- /// use hashbrown::HashSet;
930
- ///
931
- /// let mut set: HashSet<String> = ["cat", "dog", "horse"]
932
- /// .iter().map(|&pet| pet.to_owned()).collect();
933
- ///
934
- /// assert_eq!(set.len(), 3);
935
- /// for &pet in &["cat", "dog", "fish"] {
936
- /// let value = set.get_or_insert_owned(pet);
937
- /// assert_eq!(value, pet);
938
- /// }
939
- /// assert_eq!(set.len(), 4); // a new "fish" was inserted
940
- /// ```
941
- #[ inline]
942
- pub fn get_or_insert_owned < Q > ( & mut self , value : & Q ) -> & T
943
- where
944
- Q : Hash + Equivalent < T > + ToOwned < Owned = T > + ?Sized ,
945
- {
946
- // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
947
- // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
948
- self . map
949
- . raw_entry_mut ( )
950
- . from_key ( value)
951
- . or_insert_with ( || ( value. to_owned ( ) , ( ) ) )
952
- . 0
913
+ let hash = make_hash ( & self . map . hash_builder , & value) ;
914
+ let bucket = match self . map . find_or_find_insert_slot ( hash, & value) {
915
+ Ok ( bucket) => bucket,
916
+ Err ( slot) => unsafe { self . map . table . insert_in_slot ( hash, slot, ( value, ( ) ) ) } ,
917
+ } ;
918
+ unsafe { & bucket. as_ref ( ) . 0 }
953
919
}
954
920
955
921
/// Inserts a value computed from `f` into the set if the given `value` is
@@ -970,19 +936,29 @@ where
970
936
/// }
971
937
/// assert_eq!(set.len(), 4); // a new "fish" was inserted
972
938
/// ```
939
+ ///
940
+ /// The following example will panic because the new value doesn't match.
941
+ ///
942
+ /// ```should_panic
943
+ /// let mut set = hashbrown::HashSet::new();
944
+ /// set.get_or_insert_with("rust", |_| String::new());
945
+ /// ```
973
946
#[ cfg_attr( feature = "inline-more" , inline) ]
974
947
pub fn get_or_insert_with < Q , F > ( & mut self , value : & Q , f : F ) -> & T
975
948
where
976
949
Q : Hash + Equivalent < T > + ?Sized ,
977
950
F : FnOnce ( & Q ) -> T ,
978
951
{
979
- // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
980
- // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
981
- self . map
982
- . raw_entry_mut ( )
983
- . from_key ( value)
984
- . or_insert_with ( || ( f ( value) , ( ) ) )
985
- . 0
952
+ let hash = make_hash ( & self . map . hash_builder , value) ;
953
+ let bucket = match self . map . find_or_find_insert_slot ( hash, value) {
954
+ Ok ( bucket) => bucket,
955
+ Err ( slot) => {
956
+ let new = f ( value) ;
957
+ assert ! ( value. equivalent( & new) , "new value is not equivalent" ) ;
958
+ unsafe { self . map . table . insert_in_slot ( hash, slot, ( new, ( ) ) ) }
959
+ }
960
+ } ;
961
+ unsafe { & bucket. as_ref ( ) . 0 }
986
962
}
987
963
988
964
/// Gets the given value's corresponding entry in the set for in-place manipulation.
@@ -1157,11 +1133,7 @@ where
1157
1133
#[ cfg_attr( feature = "inline-more" , inline) ]
1158
1134
pub fn replace ( & mut self , value : T ) -> Option < T > {
1159
1135
let hash = make_hash ( & self . map . hash_builder , & value) ;
1160
- match self . map . table . find_or_find_insert_slot (
1161
- hash,
1162
- equivalent_key ( & value) ,
1163
- make_hasher ( & self . map . hash_builder ) ,
1164
- ) {
1136
+ match self . map . find_or_find_insert_slot ( hash, & value) {
1165
1137
Ok ( bucket) => Some ( mem:: replace ( unsafe { & mut bucket. as_mut ( ) . 0 } , value) ) ,
1166
1138
Err ( slot) => {
1167
1139
unsafe {
@@ -1607,15 +1579,17 @@ where
1607
1579
/// ```
1608
1580
fn bitxor_assign ( & mut self , rhs : & HashSet < T , S , A > ) {
1609
1581
for item in rhs {
1610
- let entry = self . map . raw_entry_mut ( ) . from_key ( item) ;
1611
- match entry {
1612
- map:: RawEntryMut :: Occupied ( e) => {
1613
- e. remove ( ) ;
1614
- }
1615
- map:: RawEntryMut :: Vacant ( e) => {
1616
- e. insert ( item. to_owned ( ) , ( ) ) ;
1617
- }
1618
- } ;
1582
+ let hash = make_hash ( & self . map . hash_builder , item) ;
1583
+ match self . map . find_or_find_insert_slot ( hash, item) {
1584
+ Ok ( bucket) => unsafe {
1585
+ self . map . table . remove ( bucket) ;
1586
+ } ,
1587
+ Err ( slot) => unsafe {
1588
+ self . map
1589
+ . table
1590
+ . insert_in_slot ( hash, slot, ( item. clone ( ) , ( ) ) ) ;
1591
+ } ,
1592
+ }
1619
1593
}
1620
1594
}
1621
1595
}
@@ -2598,7 +2572,7 @@ fn assert_covariance() {
2598
2572
2599
2573
#[ cfg( test) ]
2600
2574
mod test_set {
2601
- use super :: HashSet ;
2575
+ use super :: { make_hash , Equivalent , HashSet } ;
2602
2576
use crate :: DefaultHashBuilder ;
2603
2577
use std:: vec:: Vec ;
2604
2578
@@ -3072,4 +3046,57 @@ mod test_set {
3072
3046
assert_eq ! ( HashSet :: <u32 >:: new( ) . allocation_size( ) , 0 ) ;
3073
3047
assert ! ( HashSet :: <u32 >:: with_capacity( 1 ) . allocation_size( ) > core:: mem:: size_of:: <u32 >( ) ) ;
3074
3048
}
3049
+
3050
+ #[ test]
3051
+ fn duplicate_insert ( ) {
3052
+ let mut set = HashSet :: new ( ) ;
3053
+ set. insert ( 1 ) ;
3054
+ set. get_or_insert_with ( & 1 , |_| 1 ) ;
3055
+ set. get_or_insert_with ( & 1 , |_| 1 ) ;
3056
+ assert ! ( [ 1 ] . iter( ) . eq( set. iter( ) ) ) ;
3057
+ }
3058
+
3059
+ #[ test]
3060
+ #[ should_panic]
3061
+ fn some_invalid_equivalent ( ) {
3062
+ use core:: hash:: { Hash , Hasher } ;
3063
+ struct Invalid {
3064
+ count : u32 ,
3065
+ other : u32 ,
3066
+ }
3067
+
3068
+ struct InvalidRef {
3069
+ count : u32 ,
3070
+ other : u32 ,
3071
+ }
3072
+
3073
+ impl PartialEq for Invalid {
3074
+ fn eq ( & self , other : & Self ) -> bool {
3075
+ self . count == other. count && self . other == other. other
3076
+ }
3077
+ }
3078
+ impl Eq for Invalid { }
3079
+
3080
+ impl Equivalent < Invalid > for InvalidRef {
3081
+ fn equivalent ( & self , key : & Invalid ) -> bool {
3082
+ self . count == key. count && self . other == key. other
3083
+ }
3084
+ }
3085
+ impl Hash for Invalid {
3086
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
3087
+ self . count . hash ( state) ;
3088
+ }
3089
+ }
3090
+ impl Hash for InvalidRef {
3091
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
3092
+ self . count . hash ( state) ;
3093
+ }
3094
+ }
3095
+ let mut set: HashSet < Invalid > = HashSet :: new ( ) ;
3096
+ let key = InvalidRef { count : 1 , other : 1 } ;
3097
+ let value = Invalid { count : 1 , other : 2 } ;
3098
+ if make_hash ( set. hasher ( ) , & key) == make_hash ( set. hasher ( ) , & value) {
3099
+ set. get_or_insert_with ( & key, |_| value) ;
3100
+ }
3101
+ }
3075
3102
}
0 commit comments