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

`}

`