@@ -19,8 +19,9 @@ use fmt::{self, Debug};
19
19
use hash:: { Hash , Hasher , BuildHasher , SipHasher13 } ;
20
20
use iter:: { FromIterator , FusedIterator } ;
21
21
use mem:: { self , replace} ;
22
- use ops:: { Deref , Index } ;
22
+ use ops:: { Deref , Index , InPlace , Place , Placer } ;
23
23
use rand:: { self , Rng } ;
24
+ use ptr;
24
25
25
26
use super :: table:: { self , Bucket , EmptyBucket , FullBucket , FullBucketMut , RawTable , SafeHash } ;
26
27
use super :: table:: BucketState :: { Empty , Full } ;
@@ -483,7 +484,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
483
484
mut hash : SafeHash ,
484
485
mut key : K ,
485
486
mut val : V )
486
- -> & ' a mut V {
487
+ -> FullBucketMut < ' a , K , V > {
487
488
let start_index = bucket. index ( ) ;
488
489
let size = bucket. table ( ) . size ( ) ;
489
490
// Save the *starting point*.
@@ -515,7 +516,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
515
516
// bucket, which is a FullBucket on top of a
516
517
// FullBucketMut, into just one FullBucketMut. The "table"
517
518
// refers to the inner FullBucketMut in this context.
518
- return bucket. into_table ( ) . into_mut_refs ( ) . 1 ;
519
+ return bucket. into_table ( ) ;
519
520
}
520
521
Full ( bucket) => bucket,
521
522
} ;
@@ -1818,6 +1819,80 @@ impl<'a, K, V> fmt::Debug for Drain<'a, K, V>
1818
1819
}
1819
1820
}
1820
1821
1822
+ /// A place for insertion to a `Entry`.
1823
+ ///
1824
+ /// See [`HashMap::entry`](struct.HashMap.html#method.entry) for details.
1825
+ #[ must_use = "places do nothing unless written to with `<-` syntax" ]
1826
+ #[ unstable( feature = "collection_placement" ,
1827
+ reason = "struct name and placement protocol is subject to change" ,
1828
+ issue = "30172" ) ]
1829
+ pub struct EntryPlace < ' a , K : ' a , V : ' a > {
1830
+ bucket : FullBucketMut < ' a , K , V > ,
1831
+ }
1832
+
1833
+ #[ unstable( feature = "collection_placement" ,
1834
+ reason = "struct name and placement protocol is subject to change" ,
1835
+ issue = "30172" ) ]
1836
+ impl < ' a , K : ' a + Debug , V : ' a + Debug > Debug for EntryPlace < ' a , K , V > {
1837
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
1838
+ f. debug_struct ( "EntryPlace" )
1839
+ . field ( "key" , self . bucket . read ( ) . 0 )
1840
+ . field ( "value" , self . bucket . read ( ) . 1 )
1841
+ . finish ( )
1842
+ }
1843
+ }
1844
+
1845
+ #[ unstable( feature = "collection_placement" ,
1846
+ reason = "struct name and placement protocol is subject to change" ,
1847
+ issue = "30172" ) ]
1848
+ impl < ' a , K , V > Drop for EntryPlace < ' a , K , V > {
1849
+ fn drop ( & mut self ) {
1850
+ // Inplacement insertion failed. Only key need to drop.
1851
+ // The value is failed to insert into map.
1852
+ unsafe { self . bucket . remove_key ( ) } ;
1853
+ }
1854
+ }
1855
+
1856
+ #[ unstable( feature = "collection_placement" ,
1857
+ reason = "placement protocol is subject to change" ,
1858
+ issue = "30172" ) ]
1859
+ impl < ' a , K , V > Placer < V > for Entry < ' a , K , V > {
1860
+ type Place = EntryPlace < ' a , K , V > ;
1861
+
1862
+ fn make_place ( self ) -> EntryPlace < ' a , K , V > {
1863
+ let b = match self {
1864
+ Occupied ( mut o) => {
1865
+ unsafe { ptr:: drop_in_place ( o. elem . read_mut ( ) . 1 ) ; }
1866
+ o. elem
1867
+ }
1868
+ Vacant ( v) => {
1869
+ unsafe { v. insert_key ( ) }
1870
+ }
1871
+ } ;
1872
+ EntryPlace { bucket : b }
1873
+ }
1874
+ }
1875
+
1876
+ #[ unstable( feature = "collection_placement" ,
1877
+ reason = "placement protocol is subject to change" ,
1878
+ issue = "30172" ) ]
1879
+ impl < ' a , K , V > Place < V > for EntryPlace < ' a , K , V > {
1880
+ fn pointer ( & mut self ) -> * mut V {
1881
+ self . bucket . read_mut ( ) . 1
1882
+ }
1883
+ }
1884
+
1885
+ #[ unstable( feature = "collection_placement" ,
1886
+ reason = "placement protocol is subject to change" ,
1887
+ issue = "30172" ) ]
1888
+ impl < ' a , K , V > InPlace < V > for EntryPlace < ' a , K , V > {
1889
+ type Owner = ( ) ;
1890
+
1891
+ unsafe fn finalize ( self ) {
1892
+ mem:: forget ( self ) ;
1893
+ }
1894
+ }
1895
+
1821
1896
impl < ' a , K , V > Entry < ' a , K , V > {
1822
1897
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1823
1898
/// Ensures a value is in the entry by inserting the default if empty, and returns
@@ -2108,7 +2183,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
2108
2183
/// ```
2109
2184
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
2110
2185
pub fn insert ( self , value : V ) -> & ' a mut V {
2111
- match self . elem {
2186
+ let b = match self . elem {
2112
2187
NeqElem ( mut bucket, disp) => {
2113
2188
if disp >= DISPLACEMENT_THRESHOLD {
2114
2189
bucket. table_mut ( ) . set_tag ( true ) ;
@@ -2119,7 +2194,28 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
2119
2194
if disp >= DISPLACEMENT_THRESHOLD {
2120
2195
bucket. table_mut ( ) . set_tag ( true ) ;
2121
2196
}
2122
- bucket. put ( self . hash , self . key , value) . into_mut_refs ( ) . 1
2197
+ bucket. put ( self . hash , self . key , value)
2198
+ } ,
2199
+ } ;
2200
+ b. into_mut_refs ( ) . 1
2201
+ }
2202
+
2203
+ // Only used for InPlacement insert. Avoid unnecessary value copy.
2204
+ // The value remains uninitialized.
2205
+ unsafe fn insert_key ( self ) -> FullBucketMut < ' a , K , V > {
2206
+ match self . elem {
2207
+ NeqElem ( mut bucket, disp) => {
2208
+ if disp >= DISPLACEMENT_THRESHOLD {
2209
+ bucket. table_mut ( ) . set_tag ( true ) ;
2210
+ }
2211
+ let uninit = mem:: uninitialized ( ) ;
2212
+ robin_hood ( bucket, disp, self . hash , self . key , uninit)
2213
+ } ,
2214
+ NoElem ( mut bucket, disp) => {
2215
+ if disp >= DISPLACEMENT_THRESHOLD {
2216
+ bucket. table_mut ( ) . set_tag ( true ) ;
2217
+ }
2218
+ bucket. put_key ( self . hash , self . key )
2123
2219
} ,
2124
2220
}
2125
2221
}
@@ -2392,6 +2488,7 @@ mod test_map {
2392
2488
use super :: RandomState ;
2393
2489
use cell:: RefCell ;
2394
2490
use rand:: { thread_rng, Rng } ;
2491
+ use panic;
2395
2492
2396
2493
#[ test]
2397
2494
fn test_zero_capacities ( ) {
@@ -3265,4 +3362,57 @@ mod test_map {
3265
3362
}
3266
3363
panic ! ( "Adaptive early resize failed" ) ;
3267
3364
}
3365
+
3366
+ #[ test]
3367
+ fn test_placement_in ( ) {
3368
+ let mut map = HashMap :: new ( ) ;
3369
+ map. extend ( ( 0 ..10 ) . map ( |i| ( i, i) ) ) ;
3370
+
3371
+ map. entry ( 100 ) <- 100 ;
3372
+ assert_eq ! ( map[ & 100 ] , 100 ) ;
3373
+
3374
+ map. entry ( 0 ) <- 10 ;
3375
+ assert_eq ! ( map[ & 0 ] , 10 ) ;
3376
+
3377
+ assert_eq ! ( map. len( ) , 11 ) ;
3378
+ }
3379
+
3380
+ #[ test]
3381
+ fn test_placement_panic ( ) {
3382
+ let mut map = HashMap :: new ( ) ;
3383
+ map. extend ( ( 0 ..10 ) . map ( |i| ( i, i) ) ) ;
3384
+
3385
+ fn mkpanic ( ) -> usize { panic ! ( ) }
3386
+
3387
+ // modify existing key
3388
+ // when panic happens, previous key is removed.
3389
+ let _ = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || { map. entry ( 0 ) <- mkpanic ( ) ; } ) ) ;
3390
+ assert_eq ! ( map. len( ) , 9 ) ;
3391
+ assert ! ( !map. contains_key( & 0 ) ) ;
3392
+
3393
+ // add new key
3394
+ let _ = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || { map. entry ( 100 ) <- mkpanic ( ) ; } ) ) ;
3395
+ assert_eq ! ( map. len( ) , 9 ) ;
3396
+ assert ! ( !map. contains_key( & 100 ) ) ;
3397
+ }
3398
+
3399
+ #[ test]
3400
+ fn test_placement_drop ( ) {
3401
+ // correctly drop
3402
+ struct TestV < ' a > ( & ' a mut bool ) ;
3403
+ impl < ' a > Drop for TestV < ' a > {
3404
+ fn drop ( & mut self ) {
3405
+ if !* self . 0 { panic ! ( "value double drop!" ) ; } // no double drop
3406
+ * self . 0 = false ;
3407
+ }
3408
+ }
3409
+
3410
+ fn makepanic < ' a > ( ) -> TestV < ' a > { panic ! ( ) }
3411
+
3412
+ let mut can_drop = true ;
3413
+ let mut hm = HashMap :: new ( ) ;
3414
+ hm. insert ( 0 , TestV ( & mut can_drop) ) ;
3415
+ let _ = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || { hm. entry ( 0 ) <- makepanic ( ) ; } ) ) ;
3416
+ assert_eq ! ( hm. len( ) , 0 ) ;
3417
+ }
3268
3418
}
0 commit comments