@@ -19,8 +19,9 @@ use fmt::{self, Debug};
1919use hash:: { Hash , Hasher , BuildHasher , SipHasher13 } ;
2020use iter:: { FromIterator , FusedIterator } ;
2121use mem:: { self , replace} ;
22- use ops:: { Deref , Index } ;
22+ use ops:: { Deref , Index , InPlace , Place , Placer } ;
2323use rand:: { self , Rng } ;
24+ use ptr;
2425
2526use super :: table:: { self , Bucket , EmptyBucket , FullBucket , FullBucketMut , RawTable , SafeHash } ;
2627use super :: table:: BucketState :: { Empty , Full } ;
@@ -483,7 +484,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
483484 mut hash : SafeHash ,
484485 mut key : K ,
485486 mut val : V )
486- -> & ' a mut V {
487+ -> FullBucketMut < ' a , K , V > {
487488 let start_index = bucket. index ( ) ;
488489 let size = bucket. table ( ) . size ( ) ;
489490 // Save the *starting point*.
@@ -515,7 +516,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
515516 // bucket, which is a FullBucket on top of a
516517 // FullBucketMut, into just one FullBucketMut. The "table"
517518 // refers to the inner FullBucketMut in this context.
518- return bucket. into_table ( ) . into_mut_refs ( ) . 1 ;
519+ return bucket. into_table ( ) ;
519520 }
520521 Full ( bucket) => bucket,
521522 } ;
@@ -1818,6 +1819,80 @@ impl<'a, K, V> fmt::Debug for Drain<'a, K, V>
18181819 }
18191820}
18201821
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+
18211896impl < ' a , K , V > Entry < ' a , K , V > {
18221897 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
18231898 /// 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> {
21082183 /// ```
21092184 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
21102185 pub fn insert ( self , value : V ) -> & ' a mut V {
2111- match self . elem {
2186+ let b = match self . elem {
21122187 NeqElem ( mut bucket, disp) => {
21132188 if disp >= DISPLACEMENT_THRESHOLD {
21142189 bucket. table_mut ( ) . set_tag ( true ) ;
@@ -2119,7 +2194,28 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
21192194 if disp >= DISPLACEMENT_THRESHOLD {
21202195 bucket. table_mut ( ) . set_tag ( true ) ;
21212196 }
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 )
21232219 } ,
21242220 }
21252221 }
@@ -2392,6 +2488,7 @@ mod test_map {
23922488 use super :: RandomState ;
23932489 use cell:: RefCell ;
23942490 use rand:: { thread_rng, Rng } ;
2491+ use panic;
23952492
23962493 #[ test]
23972494 fn test_zero_capacities ( ) {
@@ -3265,4 +3362,57 @@ mod test_map {
32653362 }
32663363 panic ! ( "Adaptive early resize failed" ) ;
32673364 }
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+ }
32683418}
0 commit comments