Simplify HashMap Bucket interface

* Store capacity_mask instead of capacity
* Move bucket index into RawBucket
* Bucket index is now always within [0..table_capacity)
* Clone RawTable using RawBucket
* Simplify iterators by moving logic into RawBuckets
* Make retain aware of the number of elements
This commit is contained in:
arthurprs 2017-03-15 23:26:27 +01:00
parent 5309a3e31d
commit f07ebd6097
2 changed files with 164 additions and 190 deletions

View file

@ -472,7 +472,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>)
}
// Now we've done all our shifting. Return the value we grabbed earlier.
(retkey, retval, gap.into_bucket().into_table())
(retkey, retval, gap.into_table())
}
/// Perform robin hood bucket stealing at the given `bucket`. You must
@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
mut key: K,
mut val: V)
-> FullBucketMut<'a, K, V> {
let start_index = bucket.index();
let size = bucket.table().size();
// Save the *starting point*.
let mut bucket = bucket.stash();
let raw_capacity = bucket.table().capacity();
// There can be at most `size - dib` buckets to displace, because
// in the worst case, there are `size` elements and we already are
// `displacement` buckets away from the initial one.
let idx_end = start_index + size - bucket.displacement();
let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity;
// Save the *starting point*.
let mut bucket = bucket.stash();
loop {
let (old_hash, old_key, old_val) = bucket.replace(hash, key, val);
@ -568,11 +568,8 @@ impl<K, V, S> HashMap<K, V, S>
// The caller should ensure that invariants by Robin Hood Hashing hold
// and that there's space in the underlying table.
fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) {
let raw_cap = self.raw_capacity();
let mut buckets = Bucket::new(&mut self.table, hash);
// note that buckets.index() keeps increasing
// even if the pointer wraps back to the first bucket.
let limit_bucket = buckets.index() + raw_cap;
let start_index = buckets.index();
loop {
// We don't need to compare hashes for value swap.
@ -585,7 +582,7 @@ impl<K, V, S> HashMap<K, V, S>
Full(b) => b.into_bucket(),
};
buckets.next();
debug_assert!(buckets.index() < limit_bucket);
debug_assert!(buckets.index() != start_index);
}
}
}
@ -1244,24 +1241,25 @@ impl<K, V, S> HashMap<K, V, S>
pub fn retain<F>(&mut self, mut f: F)
where F: FnMut(&K, &mut V) -> bool
{
if self.table.capacity() == 0 || self.table.size() == 0 {
if self.table.size() == 0 {
return;
}
let mut elems_left = self.table.size();
let mut bucket = Bucket::head_bucket(&mut self.table);
bucket.prev();
let tail = bucket.index();
loop {
let start_index = bucket.index();
while elems_left != 0 {
bucket = match bucket.peek() {
Full(mut full) => {
elems_left -= 1;
let should_remove = {
let (k, v) = full.read_mut();
!f(k, v)
};
if should_remove {
let prev_idx = full.index();
let prev_raw = full.raw();
let (_, _, t) = pop_internal(full);
Bucket::new_from(prev_raw, prev_idx, t)
Bucket::new_from(prev_raw, t)
} else {
full.into_bucket()
}
@ -1271,9 +1269,7 @@ impl<K, V, S> HashMap<K, V, S>
}
};
bucket.prev(); // reverse iteration
if bucket.index() == tail {
break;
}
debug_assert!(elems_left == 0 || bucket.index() != start_index);
}
}
}

View file

@ -113,7 +113,7 @@ impl TaggedHashUintPtr {
/// when the RawTable is created and is accessible with the `tag` and `set_tag`
/// functions.
pub struct RawTable<K, V> {
capacity: usize,
capacity_mask: usize,
size: usize,
hashes: TaggedHashUintPtr,
@ -125,10 +125,13 @@ pub struct RawTable<K, V> {
unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {}
// An unsafe view of a RawTable bucket
// Valid indexes are within [0..table_capacity)
pub struct RawBucket<K, V> {
hash: *mut HashUint,
hash_start: *mut HashUint,
// We use *const to ensure covariance with respect to K and V
pair: *const (K, V),
pair_start: *const (K, V),
idx: usize,
_marker: marker::PhantomData<(K, V)>,
}
@ -141,7 +144,6 @@ impl<K, V> Clone for RawBucket<K, V> {
pub struct Bucket<K, V, M> {
raw: RawBucket<K, V>,
idx: usize,
table: M,
}
@ -154,13 +156,11 @@ impl<K, V, M: Copy> Clone for Bucket<K, V, M> {
pub struct EmptyBucket<K, V, M> {
raw: RawBucket<K, V>,
idx: usize,
table: M,
}
pub struct FullBucket<K, V, M> {
raw: RawBucket<K, V>,
idx: usize,
table: M,
}
@ -232,13 +232,17 @@ fn can_alias_safehash_as_hash() {
assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>())
}
// RawBucket methods are unsafe as it's possible to
// make a RawBucket point to invalid memory using safe code.
impl<K, V> RawBucket<K, V> {
unsafe fn offset(self, count: isize) -> RawBucket<K, V> {
RawBucket {
hash: self.hash.offset(count),
pair: self.pair.offset(count),
_marker: marker::PhantomData,
}
unsafe fn hash(&self) -> *mut HashUint {
self.hash_start.offset(self.idx as isize)
}
unsafe fn pair(&self) -> *mut (K, V) {
self.pair_start.offset(self.idx as isize) as *mut (K, V)
}
unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) {
(self.hash(), self.pair())
}
}
@ -258,7 +262,7 @@ impl<K, V, M> FullBucket<K, V, M> {
}
/// Get the raw index.
pub fn index(&self) -> usize {
self.idx
self.raw.idx
}
/// Get the raw bucket.
pub fn raw(&self) -> RawBucket<K, V> {
@ -280,7 +284,7 @@ impl<K, V, M> EmptyBucket<K, V, M> {
impl<K, V, M> Bucket<K, V, M> {
/// Get the raw index.
pub fn index(&self) -> usize {
self.idx
self.raw.idx
}
/// get the table.
pub fn into_table(self) -> M {
@ -331,12 +335,11 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
Bucket::at_index(table, hash.inspect() as usize)
}
pub fn new_from(r: RawBucket<K, V>, i: usize, t: M)
pub fn new_from(r: RawBucket<K, V>, t: M)
-> Bucket<K, V, M>
{
Bucket {
raw: r,
idx: i,
table: t,
}
}
@ -346,18 +349,16 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
// This is an uncommon case though, so avoid it in release builds.
debug_assert!(table.capacity() > 0,
"Table should have capacity at this point");
let ib_index = ib_index & (table.capacity() - 1);
let ib_index = ib_index & table.capacity_mask;
Bucket {
raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) },
idx: ib_index,
raw: table.raw_bucket_at(ib_index),
table: table,
}
}
pub fn first(table: M) -> Bucket<K, V, M> {
Bucket {
raw: table.first_bucket_raw(),
idx: 0,
raw: table.raw_bucket_at(0),
table: table,
}
}
@ -401,48 +402,30 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
/// the appropriate types to call most of the other functions in
/// this module.
pub fn peek(self) -> BucketState<K, V, M> {
match unsafe { *self.raw.hash } {
match unsafe { *self.raw.hash() } {
EMPTY_BUCKET => {
Empty(EmptyBucket {
raw: self.raw,
idx: self.idx,
table: self.table,
})
}
_ => {
Full(FullBucket {
raw: self.raw,
idx: self.idx,
table: self.table,
})
}
}
}
/// Modifies the bucket pointer in place to make it point to the next slot.
/// Modifies the bucket in place to make it point to the next slot.
pub fn next(&mut self) {
self.idx += 1;
let range = self.table.capacity();
// This code is branchless thanks to a conditional move.
let dist = if self.idx & (range - 1) == 0 {
1 - range as isize
} else {
1
};
unsafe {
self.raw = self.raw.offset(dist);
}
self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask;
}
/// Modifies the bucket pointer in place to make it point to the previous slot.
/// Modifies the bucket in place to make it point to the previous slot.
pub fn prev(&mut self) {
let range = self.table.capacity();
let new_idx = self.idx.wrapping_sub(1) & (range - 1);
let dist = (new_idx as isize).wrapping_sub(self.idx as isize);
self.idx = new_idx;
unsafe {
self.raw = self.raw.offset(dist);
}
self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask;
}
}
@ -458,7 +441,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
pub fn into_bucket(self) -> Bucket<K, V, M> {
Bucket {
raw: self.raw,
idx: self.idx,
table: self.table,
}
}
@ -466,7 +448,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
pub fn gap_peek(self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
let gap = EmptyBucket {
raw: self.raw,
idx: self.idx,
table: (),
};
@ -494,15 +475,14 @@ impl<K, V, M> EmptyBucket<K, V, M>
/// Use `make_hash` to construct a `SafeHash` to pass to this function.
pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
unsafe {
*self.raw.hash = hash.inspect();
ptr::write(self.raw.pair as *mut (K, V), (key, value));
*self.raw.hash() = hash.inspect();
ptr::write(self.raw.pair(), (key, value));
self.table.borrow_table_mut().size += 1;
}
FullBucket {
raw: self.raw,
idx: self.idx,
table: self.table,
}
}
@ -510,15 +490,14 @@ impl<K, V, M> EmptyBucket<K, V, M>
/// Puts given key, remain value uninitialized.
/// It is only used for inplacement insertion.
pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> {
*self.raw.hash = hash.inspect();
let pair_mut = self.raw.pair as *mut (K, V);
ptr::write(&mut (*pair_mut).0, key);
*self.raw.hash() = hash.inspect();
let pair_ptr = self.raw.pair();
ptr::write(&mut (*pair_ptr).0, key);
self.table.borrow_table_mut().size += 1;
FullBucket {
raw: self.raw,
idx: self.idx,
table: self.table,
}
}
@ -536,7 +515,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
pub fn into_bucket(self) -> Bucket<K, V, M> {
Bucket {
raw: self.raw,
idx: self.idx,
table: self.table,
}
}
@ -546,7 +524,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
pub fn stash(self) -> FullBucket<K, V, Self> {
FullBucket {
raw: self.raw,
idx: self.idx,
table: self,
}
}
@ -560,17 +537,20 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
// Calculates the distance one has to travel when going from
// `hash mod capacity` onwards to `idx mod capacity`, wrapping around
// if the destination is not reached before the end of the table.
(self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1)
(self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask
}
#[inline]
pub fn hash(&self) -> SafeHash {
unsafe { SafeHash { hash: *self.raw.hash } }
unsafe { SafeHash { hash: *self.raw.hash() } }
}
/// Gets references to the key and value at a given index.
pub fn read(&self) -> (&K, &V) {
unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
unsafe {
let pair_ptr = self.raw.pair();
(&(*pair_ptr).0, &(*pair_ptr).1)
}
}
}
@ -586,11 +566,10 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
self.table.size -= 1;
unsafe {
*self.raw.hash = EMPTY_BUCKET;
let (k, v) = ptr::read(self.raw.pair);
*self.raw.hash() = EMPTY_BUCKET;
let (k, v) = ptr::read(self.raw.pair());
(EmptyBucket {
raw: self.raw,
idx: self.idx,
table: self.table,
},
k,
@ -604,9 +583,9 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
pub unsafe fn remove_key(&mut self) {
self.table.size -= 1;
*self.raw.hash = EMPTY_BUCKET;
let pair_mut = self.raw.pair as *mut (K, V);
ptr::drop_in_place(&mut (*pair_mut).0); // only drop key
*self.raw.hash() = EMPTY_BUCKET;
let pair_ptr = self.raw.pair();
ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key
}
}
@ -617,8 +596,8 @@ impl<K, V, M> FullBucket<K, V, M>
{
pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
unsafe {
let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v));
let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h);
let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v));
(old_hash, old_key, old_val)
}
@ -630,8 +609,10 @@ impl<K, V, M> FullBucket<K, V, M>
{
/// Gets mutable references to the key and value at a given index.
pub fn read_mut(&mut self) -> (&mut K, &mut V) {
let pair_mut = self.raw.pair as *mut (K, V);
unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
unsafe {
let pair_ptr = self.raw.pair();
(&mut (*pair_ptr).0, &mut (*pair_ptr).1)
}
}
}
@ -644,7 +625,10 @@ impl<'t, K, V, M> FullBucket<K, V, M>
/// in exchange for this, the returned references have a longer lifetime
/// than the references returned by `read()`.
pub fn into_refs(self) -> (&'t K, &'t V) {
unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
unsafe {
let pair_ptr = self.raw.pair();
(&(*pair_ptr).0, &(*pair_ptr).1)
}
}
}
@ -654,8 +638,10 @@ impl<'t, K, V, M> FullBucket<K, V, M>
/// This works similarly to `into_refs`, exchanging a bucket state
/// for mutable references into the table.
pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
let pair_mut = self.raw.pair as *mut (K, V);
unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
unsafe {
let pair_ptr = self.raw.pair();
(&mut (*pair_ptr).0, &mut (*pair_ptr).1)
}
}
}
@ -667,22 +653,23 @@ impl<K, V, M> GapThenFull<K, V, M>
&self.full
}
pub fn into_bucket(self) -> Bucket<K, V, M> {
self.full.into_bucket()
pub fn into_table(self) -> M {
self.full.into_table()
}
pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
unsafe {
*self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET);
ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1);
let (gap_hash, gap_pair) = self.gap.raw.hash_pair();
let (full_hash, full_pair) = self.full.raw.hash_pair();
*gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET);
ptr::copy_nonoverlapping(full_pair, gap_pair, 1);
}
let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full;
let FullBucket { raw: prev_raw, .. } = self.full;
match self.full.next().peek() {
Full(bucket) => {
self.gap.raw = prev_raw;
self.gap.idx = prev_idx;
self.full = bucket;
@ -761,7 +748,7 @@ impl<K, V> RawTable<K, V> {
if capacity == 0 {
return RawTable {
size: 0,
capacity: 0,
capacity_mask: capacity.wrapping_sub(1),
hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint),
marker: marker::PhantomData,
};
@ -801,25 +788,27 @@ impl<K, V> RawTable<K, V> {
let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
RawTable {
capacity: capacity,
capacity_mask: capacity.wrapping_sub(1),
size: 0,
hashes: TaggedHashUintPtr::new(hashes),
marker: marker::PhantomData,
}
}
fn first_bucket_raw(&self) -> RawBucket<K, V> {
let hashes_size = self.capacity * size_of::<HashUint>();
let pairs_size = self.capacity * size_of::<(K, V)>();
fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
let hashes_size = self.capacity() * size_of::<HashUint>();
let pairs_size = self.capacity() * size_of::<(K, V)>();
let buffer = self.hashes.ptr() as *mut u8;
let (pairs_offset, _, oflo) =
calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
debug_assert!(!oflo, "capacity overflow");
let buffer = self.hashes.ptr() as *mut u8;
unsafe {
RawBucket {
hash: self.hashes.ptr(),
pair: buffer.offset(pairs_offset as isize) as *const _,
hash_start: buffer as *mut HashUint,
pair_start: buffer.offset(pairs_offset as isize) as *const (K, V),
idx: index,
_marker: marker::PhantomData,
}
}
@ -837,7 +826,7 @@ impl<K, V> RawTable<K, V> {
/// The hashtable's capacity, similar to a vector's.
pub fn capacity(&self) -> usize {
self.capacity
self.capacity_mask.wrapping_add(1)
}
/// The number of elements ever `put` in the hashtable, minus the number
@ -848,8 +837,8 @@ impl<K, V> RawTable<K, V> {
fn raw_buckets(&self) -> RawBuckets<K, V> {
RawBuckets {
raw: self.first_bucket_raw(),
hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) },
raw: self.raw_bucket_at(0),
elems_left: self.size,
marker: marker::PhantomData,
}
}
@ -857,25 +846,23 @@ impl<K, V> RawTable<K, V> {
pub fn iter(&self) -> Iter<K, V> {
Iter {
iter: self.raw_buckets(),
elems_left: self.size(),
}
}
pub fn iter_mut(&mut self) -> IterMut<K, V> {
IterMut {
iter: self.raw_buckets(),
elems_left: self.size(),
_marker: marker::PhantomData,
}
}
pub fn into_iter(self) -> IntoIter<K, V> {
let RawBuckets { raw, hashes_end, .. } = self.raw_buckets();
let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
// Replace the marker regardless of lifetime bounds on parameters.
IntoIter {
iter: RawBuckets {
raw: raw,
hashes_end: hashes_end,
elems_left: elems_left,
marker: marker::PhantomData,
},
table: self,
@ -883,12 +870,12 @@ impl<K, V> RawTable<K, V> {
}
pub fn drain(&mut self) -> Drain<K, V> {
let RawBuckets { raw, hashes_end, .. } = self.raw_buckets();
let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
// Replace the marker regardless of lifetime bounds on parameters.
Drain {
iter: RawBuckets {
raw: raw,
hashes_end: hashes_end,
elems_left: elems_left,
marker: marker::PhantomData,
},
table: unsafe { Shared::new(self) },
@ -900,18 +887,16 @@ impl<K, V> RawTable<K, V> {
/// state and should only be used for dropping the table's remaining
/// entries. It's used in the implementation of Drop.
unsafe fn rev_drop_buckets(&mut self) {
let first_raw = self.first_bucket_raw();
let mut raw = first_raw.offset(self.capacity as isize);
// initialize the raw bucket past the end of the table
let mut raw = self.raw_bucket_at(self.capacity());
let mut elems_left = self.size;
while elems_left != 0 {
debug_assert!(raw.hash != first_raw.hash);
raw.idx -= 1;
raw = raw.offset(-1);
if *raw.hash != EMPTY_BUCKET {
if *raw.hash() != EMPTY_BUCKET {
elems_left -= 1;
ptr::drop_in_place(raw.pair as *mut (K, V));
ptr::drop_in_place(raw.pair());
}
}
}
@ -931,7 +916,7 @@ impl<K, V> RawTable<K, V> {
/// this interface is safe, it's not used outside this module.
struct RawBuckets<'a, K, V> {
raw: RawBucket<K, V>,
hashes_end: *mut HashUint,
elems_left: usize,
// Strictly speaking, this should be &'a (K,V), but that would
// require that K:'a, and we often use RawBuckets<'static...> for
@ -946,7 +931,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> {
fn clone(&self) -> RawBuckets<'a, K, V> {
RawBuckets {
raw: self.raw,
hashes_end: self.hashes_end,
elems_left: self.elems_left,
marker: marker::PhantomData,
}
}
@ -957,25 +942,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> {
type Item = RawBucket<K, V>;
fn next(&mut self) -> Option<RawBucket<K, V>> {
while self.raw.hash != self.hashes_end {
if self.elems_left == 0 {
return None;
}
loop {
unsafe {
// We are swapping out the pointer to a bucket and replacing
// it with the pointer to the next one.
let prev = ptr::replace(&mut self.raw, self.raw.offset(1));
if *prev.hash != EMPTY_BUCKET {
return Some(prev);
let item = self.raw;
self.raw.idx += 1;
if *item.hash() != EMPTY_BUCKET {
self.elems_left -= 1;
return Some(item);
}
}
}
}
None
fn size_hint(&self) -> (usize, Option<usize>) {
(self.elems_left, Some(self.elems_left))
}
}
impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> {
fn len(&self) -> usize {
self.elems_left
}
}
/// Iterator over shared references to entries in a table.
pub struct Iter<'a, K: 'a, V: 'a> {
iter: RawBuckets<'a, K, V>,
elems_left: usize,
}
unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {}
@ -986,16 +982,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> {
fn clone(&self) -> Iter<'a, K, V> {
Iter {
iter: self.iter.clone(),
elems_left: self.elems_left,
}
}
}
/// Iterator over mutable references to entries in a table.
pub struct IterMut<'a, K: 'a, V: 'a> {
iter: RawBuckets<'a, K, V>,
elems_left: usize,
// To ensure invariance with respect to V
_marker: marker::PhantomData<&'a mut V>,
}
@ -1009,7 +1002,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
pub fn iter(&self) -> Iter<K, V> {
Iter {
iter: self.iter.clone(),
elems_left: self.elems_left,
}
}
}
@ -1027,7 +1019,6 @@ impl<K, V> IntoIter<K, V> {
pub fn iter(&self) -> Iter<K, V> {
Iter {
iter: self.iter.clone(),
elems_left: self.table.size,
}
}
}
@ -1044,11 +1035,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {}
impl<'a, K, V> Drain<'a, K, V> {
pub fn iter(&self) -> Iter<K, V> {
unsafe {
Iter {
iter: self.iter.clone(),
elems_left: (**self.table).size,
}
Iter {
iter: self.iter.clone(),
}
}
}
@ -1057,19 +1045,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> {
type Item = (&'a K, &'a V);
fn next(&mut self) -> Option<(&'a K, &'a V)> {
self.iter.next().map(|bucket| {
self.elems_left -= 1;
unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) }
self.iter.next().map(|raw| unsafe {
let pair_ptr = raw.pair();
(&(*pair_ptr).0, &(*pair_ptr).1)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.elems_left, Some(self.elems_left))
self.iter.size_hint()
}
}
impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
fn len(&self) -> usize {
self.elems_left
self.iter.len()
}
}
@ -1077,20 +1066,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
self.iter.next().map(|bucket| {
self.elems_left -= 1;
let pair_mut = bucket.pair as *mut (K, V);
unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) }
self.iter.next().map(|raw| unsafe {
let pair_ptr = raw.pair();
(&(*pair_ptr).0, &mut (*pair_ptr).1)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.elems_left, Some(self.elems_left))
self.iter.size_hint()
}
}
impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
fn len(&self) -> usize {
self.elems_left
self.iter.len()
}
}
@ -1098,23 +1087,23 @@ impl<K, V> Iterator for IntoIter<K, V> {
type Item = (SafeHash, K, V);
fn next(&mut self) -> Option<(SafeHash, K, V)> {
self.iter.next().map(|bucket| {
self.iter.next().map(|raw| {
self.table.size -= 1;
unsafe {
let (k, v) = ptr::read(bucket.pair);
(SafeHash { hash: *bucket.hash }, k, v)
let (k, v) = ptr::read(raw.pair());
(SafeHash { hash: *raw.hash() }, k, v)
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.table.size();
(size, Some(size))
self.iter.size_hint()
}
}
impl<K, V> ExactSizeIterator for IntoIter<K, V> {
fn len(&self) -> usize {
self.table.size()
self.iter().len()
}
}
@ -1123,23 +1112,21 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
#[inline]
fn next(&mut self) -> Option<(SafeHash, K, V)> {
self.iter.next().map(|bucket| {
unsafe {
(*self.table.as_mut_ptr()).size -= 1;
let (k, v) = ptr::read(bucket.pair);
(SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v)
}
self.iter.next().map(|raw| unsafe {
(*self.table.as_mut_ptr()).size -= 1;
let (k, v) = ptr::read(raw.pair());
(SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = unsafe { (**self.table).size() };
(size, Some(size))
self.iter.size_hint()
}
}
impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
fn len(&self) -> usize {
unsafe { (**self.table).size() }
self.iter.len()
}
}
@ -1152,30 +1139,21 @@ impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
fn clone(&self) -> RawTable<K, V> {
unsafe {
let mut new_ht = RawTable::new_uninitialized(self.capacity());
let cap = self.capacity();
let mut new_ht = RawTable::new_uninitialized(cap);
{
let cap = self.capacity();
let mut new_buckets = Bucket::first(&mut new_ht);
let mut buckets = Bucket::first(self);
while buckets.index() != cap {
match buckets.peek() {
Full(full) => {
let (h, k, v) = {
let (k, v) = full.read();
(full.hash(), k.clone(), v.clone())
};
*new_buckets.raw.hash = h.inspect();
ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v));
}
Empty(..) => {
*new_buckets.raw.hash = EMPTY_BUCKET;
}
}
new_buckets.next();
buckets.next();
let mut new_buckets = new_ht.raw_bucket_at(0);
let mut buckets = self.raw_bucket_at(0);
while buckets.idx < cap {
*new_buckets.hash() = *buckets.hash();
if *new_buckets.hash() != EMPTY_BUCKET {
let pair_ptr = buckets.pair();
let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone());
ptr::write(new_buckets.pair(), kv);
}
};
buckets.idx += 1;
new_buckets.idx += 1;
}
new_ht.size = self.size();
@ -1186,7 +1164,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
fn drop(&mut self) {
if self.capacity == 0 {
if self.capacity() == 0 {
return;
}
@ -1202,8 +1180,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
}
}
let hashes_size = self.capacity * size_of::<HashUint>();
let pairs_size = self.capacity * size_of::<(K, V)>();
let hashes_size = self.capacity() * size_of::<HashUint>();
let pairs_size = self.capacity() * size_of::<(K, V)>();
let (align, _, size, oflo) = calculate_allocation(hashes_size,
align_of::<HashUint>(),
pairs_size,