Implement placement-in protocol for HashMap
· rust-lang/rust@584c798 (original) (raw)
`@@ -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
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 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 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 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
`}
`