diff --git a/src/lib.rs b/src/lib.rs index a08eb0ff..7953eaec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,7 +107,7 @@ impl From> for HashValue { } /// `Pos` is stored in the `indices` array and it points to the index of a -/// `Bucket` in self.entries. +/// `Bucket` in self.core.entries. /// /// Pos can be interpreted either as a 64-bit index, or as a 32-bit index and /// a 32-bit hash. @@ -290,12 +290,18 @@ impl ShortHashProxy /// ``` #[derive(Clone)] pub struct OrderMap { + core: OrderMapCore, + hash_builder: S, +} + +// core of the map that does not depend on S +#[derive(Clone)] +struct OrderMapCore { mask: usize, /// indices are the buckets. indices.len() == raw capacity indices: Box<[Pos]>, /// entries is a dense vec of entries in their order. entries.len() == len entries: Vec>, - hash_builder: S, } #[derive(Copy, Clone, Debug)] @@ -305,6 +311,18 @@ struct Bucket { value: V, } +impl Bucket { + // field accessors -- used for `f` instead of closures in `.map(f)` + fn key_ref(&self) -> &K { &self.key } + fn value_ref(&self) -> &V { &self.value } + fn value_mut(&mut self) -> &mut V { &mut self.value } + fn key(self) -> K { self.key } + fn key_value(self) -> (K, V) { (self.key, self.value) } + fn refs(&self) -> (&K, &V) { (&self.key, &self.value) } + fn ref_mut(&mut self) -> (&K, &mut V) { (&self.key, &mut self.value) } + fn muts(&mut self) -> (&mut K, &mut V) { (&mut self.key, &mut self.value) } +} + #[inline(always)] fn desired_pos(mask: usize, hash: HashValue) -> usize { hash.0 & mask @@ -336,15 +354,15 @@ impl fmt::Debug for OrderMap return Ok(()); } try!(writeln!(f, "")); - for (i, index) in enumerate(&*self.indices) { + for (i, index) in enumerate(&*self.core.indices) { try!(write!(f, "{}: {:?}", i, index)); if let Some(pos) = index.pos() { - let hash = self.entries[pos].hash; - let key = &self.entries[pos].key; - let desire = desired_pos(self.mask, hash); + let hash = self.core.entries[pos].hash; + let key = &self.core.entries[pos].key; + let desire = desired_pos(self.core.mask, hash); try!(write!(f, ", desired={}, probe_distance={}, key={:?}", desire, - probe_distance(self.mask, hash, i), + probe_distance(self.core.mask, hash, i), key)); } try!(writeln!(f, "")); @@ -352,7 +370,7 @@ impl fmt::Debug for OrderMap try!(writeln!(f, "cap={}, raw_cap={}, entries.cap={}", self.capacity(), self.raw_capacity(), - self.entries.capacity())); + self.core.entries.capacity())); Ok(()) } } @@ -407,18 +425,22 @@ impl OrderMap { if n == 0 { OrderMap { - mask: 0, - indices: Box::new([]), - entries: Vec::new(), + core: OrderMapCore { + mask: 0, + indices: Box::new([]), + entries: Vec::new(), + }, hash_builder: hash_builder, } } else { let raw = to_raw_capacity(n); let raw_cap = max(raw.next_power_of_two(), 8); OrderMap { - mask: raw_cap.wrapping_sub(1), - indices: vec![Pos::none(); raw_cap].into_boxed_slice(), - entries: Vec::with_capacity(usable_capacity(raw_cap)), + core: OrderMapCore { + mask: raw_cap.wrapping_sub(1), + indices: vec![Pos::none(); raw_cap].into_boxed_slice(), + entries: Vec::with_capacity(usable_capacity(raw_cap)), + }, hash_builder: hash_builder, } } @@ -427,7 +449,7 @@ impl OrderMap /// Return the number of key-value pairs in the map. /// /// Computes in **O(1)** time. - pub fn len(&self) -> usize { self.entries.len() } + pub fn len(&self) -> usize { self.core.len() } /// Returns true if the map contains no elements. /// @@ -448,6 +470,23 @@ impl OrderMap &self.hash_builder } + /// Computes in **O(1)** time. + pub fn capacity(&self) -> usize { + self.core.capacity() + } + + #[inline] + fn size_class_is_64bit(&self) -> bool { + self.core.size_class_is_64bit() + } + + #[inline(always)] + fn raw_capacity(&self) -> usize { + self.core.raw_capacity() + } +} + +impl OrderMapCore { // Return whether we need 32 or 64 bits to specify a bucket or entry index #[cfg(not(feature = "test_low_transition_point"))] fn size_class_is_64bit(&self) -> bool { @@ -465,15 +504,10 @@ impl OrderMap fn raw_capacity(&self) -> usize { self.indices.len() } - - /// Computes in **O(1)** time. - pub fn capacity(&self) -> usize { - usable_capacity(self.raw_capacity()) - } } /// Trait for the "size class". Either u32 or u64 depending on the index -/// size needed to address an entry's indes in self.entries. +/// size needed to address an entry's indes in self.core.entries. trait Size { fn is_64_bit() -> bool; fn is_same_size() -> bool { @@ -526,17 +560,14 @@ macro_rules! dispatch_32_vs_64 { /// Entry for an existing key-value pair or a vacant location to /// insert one. -/// -/// FIXME: Remove dependence on the `S` parameter -/// (to match HashMap). -pub enum Entry<'a, K: 'a, V: 'a, S: 'a = RandomState> { +pub enum Entry<'a, K: 'a, V: 'a> { /// Existing slot with equivalent key. - Occupied(OccupiedEntry<'a, K, V, S>), + Occupied(OccupiedEntry<'a, K, V>), /// Vacant slot (no equivalent key in the map). - Vacant(VacantEntry<'a, K, V, S>), + Vacant(VacantEntry<'a, K, V>), } -impl<'a, K, V, S> Entry<'a, K, V, S> { +impl<'a, K, V> Entry<'a, K, V> { /// Computes in **O(1)** time (amortized average). pub fn or_insert(self, default: V) -> &'a mut V { match self { @@ -571,14 +602,14 @@ impl<'a, K, V, S> Entry<'a, K, V, S> { } } -pub struct OccupiedEntry<'a, K: 'a, V: 'a, S: 'a = RandomState> { - map: &'a mut OrderMap, +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + map: &'a mut OrderMapCore, key: K, probe: usize, index: usize, } -impl<'a, K, V, S> OccupiedEntry<'a, K, V, S> { +impl<'a, K, V> OccupiedEntry<'a, K, V> { pub fn key(&self) -> &K { &self.key } pub fn get(&self) -> &V { &self.map.entries[self.index].value @@ -610,14 +641,14 @@ impl<'a, K, V, S> OccupiedEntry<'a, K, V, S> { } -pub struct VacantEntry<'a, K: 'a, V: 'a, S: 'a = RandomState> { - map: &'a mut OrderMap, +pub struct VacantEntry<'a, K: 'a, V: 'a> { + map: &'a mut OrderMapCore, key: K, hash: HashValue, probe: usize, } -impl<'a, K, V, S> VacantEntry<'a, K, V, S> { +impl<'a, K, V> VacantEntry<'a, K, V> { pub fn key(&self) -> &K { &self.key } pub fn into_key(self) -> K { self.key } /// Return the index where the key-value pair will be inserted. @@ -645,61 +676,19 @@ impl OrderMap where K: Hash + Eq, S: BuildHasher, { - // Warning, this is a code duplication zone Entry is not yet finished - fn entry_phase_1(&mut self, key: K) -> Entry + // FIXME: reduce duplication (compare with insert) + fn entry_phase_1(&mut self, key: K) -> Entry where Sz: Size { let hash = hash_elem_using(&self.hash_builder, &key); - let mut probe = desired_pos(self.mask, hash); - let mut dist = 0; - debug_assert!(self.len() < self.raw_capacity()); - probe_loop!(probe < self.indices.len(), { - if let Some((i, hash_proxy)) = self.indices[probe].resolve::() { - let entry_hash = hash_proxy.get_short_hash(&self.entries, i); - // if existing element probed less than us, swap - let their_dist = probe_distance(self.mask, entry_hash.into_hash(), probe); - if their_dist < dist { - // robin hood: steal the spot if it's better for us - return Entry::Vacant(VacantEntry { - map: self, - hash: hash, - key: key, - probe: probe, - }); - } else if entry_hash == hash && self.entries[i].key == key { - return Entry::Occupied(OccupiedEntry { - map: self, - key: key, - probe: probe, - index: i, - }); - } - } else { - // empty bucket, insert here - return Entry::Vacant(VacantEntry { - map: self, - hash: hash, - key: key, - probe: probe, - }); - } - dist += 1; - }); + self.core.entry_phase_1::(hash, key) } /// Remove all key-value pairs in the map, while preserving its capacity. /// /// Computes in **O(n)** time. pub fn clear(&mut self) { - self.entries.clear(); - self.clear_indices(); - } - - // clear self.indices to the same state as "no elements" - fn clear_indices(&mut self) { - for pos in self.indices.iter_mut() { - *pos = Pos::none(); - } + self.core.clear(); } /// Reserve capacity for `additional` more key-value pairs. @@ -720,117 +709,7 @@ impl OrderMap where Sz: Size { let hash = hash_elem_using(&self.hash_builder, &key); - let mut probe = desired_pos(self.mask, hash); - let mut dist = 0; - let insert_kind; - debug_assert!(self.len() < self.raw_capacity()); - probe_loop!(probe < self.indices.len(), { - let pos = &mut self.indices[probe]; - if let Some((i, hash_proxy)) = pos.resolve::() { - let entry_hash = hash_proxy.get_short_hash(&self.entries, i); - // if existing element probed less than us, swap - let their_dist = probe_distance(self.mask, entry_hash.into_hash(), probe); - if their_dist < dist { - // robin hood: steal the spot if it's better for us - let index = self.entries.len(); - insert_kind = Inserted::RobinHood { - probe: probe, - old_pos: Pos::with_hash::(index, hash), - }; - break; - } else if entry_hash == hash && self.entries[i].key == key { - return Inserted::Swapped { - prev_value: replace(&mut self.entries[i].value, value), - }; - } - } else { - // empty bucket, insert here - let index = self.entries.len(); - *pos = Pos::with_hash::(index, hash); - insert_kind = Inserted::Done; - break; - } - dist += 1; - }); - self.entries.push(Bucket { hash: hash, key: key, value: value }); - insert_kind - } - - fn first_allocation(&mut self) { - debug_assert_eq!(self.len(), 0); - let raw_cap = 8usize; - self.mask = raw_cap.wrapping_sub(1); - self.indices = vec![Pos::none(); raw_cap].into_boxed_slice(); - self.entries = Vec::with_capacity(usable_capacity(raw_cap)); - } - - #[inline(never)] - // `Sz` is *current* Size class, before grow - fn double_capacity(&mut self) - where Sz: Size - { - debug_assert!(self.raw_capacity() == 0 || self.len() > 0); - if self.raw_capacity() == 0 { - return self.first_allocation(); - } - - // find first ideally placed element -- start of cluster - let mut first_ideal = 0; - for (i, index) in enumerate(&*self.indices) { - if let Some(pos) = index.pos() { - if 0 == probe_distance(self.mask, self.entries[pos].hash, i) { - first_ideal = i; - break; - } - } - } - - // visit the entries in an order where we can simply reinsert them - // into self.indices without any bucket stealing. - let new_raw_cap = self.indices.len() * 2; - let old_indices = replace(&mut self.indices, vec![Pos::none(); new_raw_cap].into_boxed_slice()); - self.mask = new_raw_cap.wrapping_sub(1); - - // `Sz` is the old size class, and either u32 or u64 is the new - for &pos in &old_indices[first_ideal..] { - dispatch_32_vs_64!(self.reinsert_entry_in_order::(pos)); - } - - for &pos in &old_indices[..first_ideal] { - dispatch_32_vs_64!(self.reinsert_entry_in_order::(pos)); - } - let more = self.capacity() - self.len(); - self.entries.reserve_exact(more); - } - - // write to self.indices - // read from self.entries at `pos` - // - // reinserting rewrites all `Pos` entries anyway. This handles transitioning - // from u32 to u64 size class if needed by using the two type parameters. - fn reinsert_entry_in_order(&mut self, pos: Pos) - where SzNew: Size, - SzOld: Size, - { - if let Some((i, hash_proxy)) = pos.resolve::() { - // only if the size class is conserved can we use the short hash - let entry_hash = if SzOld::is_same_size::() { - hash_proxy.get_short_hash(&self.entries, i).into_hash() - } else { - self.entries[i].hash - }; - // find first empty bucket and insert there - let mut probe = desired_pos(self.mask, entry_hash); - probe_loop!(probe < self.indices.len(), { - if let Some(_) = self.indices[probe].resolve::() { - /* nothing */ - } else { - // empty bucket, insert here - self.indices[probe] = Pos::with_hash::(i, entry_hash); - return; - } - }); - } + self.core.insert_phase_1::(hash, key, value) } fn reserve_one(&mut self) { @@ -838,6 +717,11 @@ impl OrderMap dispatch_32_vs_64!(self.double_capacity()); } } + fn double_capacity(&mut self) + where Sz: Size, + { + self.core.double_capacity::(); + } /// Insert a key-value pair in the map. /// @@ -859,7 +743,7 @@ impl OrderMap Inserted::Swapped { prev_value } => Some(prev_value), Inserted::Done => None, Inserted::RobinHood { probe, old_pos } => { - self.insert_phase_2::(probe, old_pos); + self.core.insert_phase_2::(probe, old_pos); None } } @@ -868,7 +752,7 @@ impl OrderMap Inserted::Swapped { prev_value } => Some(prev_value), Inserted::Done => None, Inserted::RobinHood { probe, old_pos } => { - self.insert_phase_2::(probe, old_pos); + self.core.insert_phase_2::(probe, old_pos); None } } @@ -879,7 +763,7 @@ impl OrderMap /// in-place manipulation. /// /// Computes in **O(1)** time (amortized average). - pub fn entry(&mut self, key: K) -> Entry { + pub fn entry(&mut self, key: K) -> Entry { self.reserve_one(); dispatch_32_vs_64!(self.entry_phase_1(key)) } @@ -888,28 +772,28 @@ impl OrderMap /// Return an iterator over the key-value pairs of the map, in their order pub fn iter(&self) -> Iter { Iter { - iter: self.entries.iter() + iter: self.core.entries.iter() } } /// Return an iterator over the key-value pairs of the map, in their order pub fn iter_mut(&mut self) -> IterMut { IterMut { - iter: self.entries.iter_mut() + iter: self.core.entries.iter_mut() } } /// Return an iterator over the keys of the map, in their order pub fn keys(&self) -> Keys { Keys { - iter: self.entries.iter() + iter: self.core.entries.iter() } } /// Return an iterator over the values of the map, in their order pub fn values(&self) -> Values { Values { - iter: self.entries.iter() + iter: self.core.entries.iter() } } @@ -917,7 +801,7 @@ impl OrderMap /// in their order pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { - iter: self.entries.iter_mut() + iter: self.core.entries.iter_mut() } } @@ -945,7 +829,7 @@ impl OrderMap where Q: Hash + Equivalent, { if let Some((_, found)) = self.find(key) { - let entry = &self.entries[found]; + let entry = &self.core.entries[found]; Some((found, &entry.key, &entry.value)) } else { None @@ -971,7 +855,7 @@ impl OrderMap { if self.len() == 0 { return None; } let h = hash_elem_using(&self.hash_builder, key); - self.find_using(h, move |entry| { Q::equivalent(key, &entry.key) }) + self.core.find_using(h, move |entry| { Q::equivalent(key, &entry.key) }) } /// NOTE: Same as .swap_remove @@ -1014,7 +898,7 @@ impl OrderMap None => return None, Some(t) => t, }; - let (k, v) = self.remove_found(probe, found); + let (k, v) = self.core.remove_found(probe, found); Some((found, k, v)) } @@ -1022,7 +906,7 @@ impl OrderMap /// /// Computes in **O(1)** time (average). pub fn pop(&mut self) -> Option<(K, V)> { - self.pop_impl() + self.core.pop_impl() } /// Scan through each key-value pair in the map and keep those where the @@ -1041,37 +925,14 @@ impl OrderMap fn retain_mut(&mut self, keep: F) where F: FnMut(&mut K, &mut V) -> bool, { - dispatch_32_vs_64!(self.retain_in_order_impl::(keep)); + dispatch_32_vs_64!(self.retain_mut_sz::<_>(keep)); } - fn retain_in_order_impl(&mut self, mut keep: F) + fn retain_mut_sz(&mut self, keep: F) where F: FnMut(&mut K, &mut V) -> bool, Sz: Size, { - // Like Vec::retain in self.entries; for each removed key-value pair, - // we clear its corresponding spot in self.indices, and run the - // usual backward shift in self.indices. - let len = self.entries.len(); - let mut n_deleted = 0; - for i in 0..len { - let will_keep; - let hash; - { - let ent = &mut self.entries[i]; - hash = ent.hash; - will_keep = keep(&mut ent.key, &mut ent.value); - }; - let probe = find_existing_entry_at::(&self.indices, hash, self.mask, i); - if !will_keep { - n_deleted += 1; - self.indices[probe] = Pos::none(); - self.backward_shift_after_removal::(probe); - } else if n_deleted > 0 { - self.indices[probe].set_pos::(i - n_deleted); - self.entries.swap(i - n_deleted, i); - } - } - self.entries.truncate(len - n_deleted); + self.core.retain_in_order_impl::(keep); } /// Sort the map’s key-value pairs by the default ordering of the keys. @@ -1080,7 +941,7 @@ impl OrderMap pub fn sort_keys(&mut self) where K: Ord, { - self.sort_by(|k1, _, k2, _| Ord::cmp(k1, k2)) + self.core.sort_by(key_cmp) } /// Sort the map’s key-value pairs in place using the comparison @@ -1091,37 +952,10 @@ impl OrderMap /// /// Computes in **O(n log n + c)** time and **O(n)** space where *n* is /// the length of the map and *c* the capacity. The sort is stable. - pub fn sort_by(&mut self, mut compare: F) + pub fn sort_by(&mut self, compare: F) where F: FnMut(&K, &V, &K, &V) -> Ordering, { - // Temporarily use the hash field in a bucket to store the old index. - // Save the old hash values in `side_index`. Then we can sort - // `self.entries` in place. - let mut side_index = Vec::from_iter(enumerate(&mut self.entries).map(|(i, elt)| { - replace(&mut elt.hash, HashValue(i)).get() - })); - - self.entries.sort_by(move |ei, ej| compare(&ei.key, &ei.value, &ej.key, &ej.value)); - - // Write back the hash values from side_index and fill `side_index` with - // a mapping from the old to the new index instead. - for (i, ent) in enumerate(&mut self.entries) { - let old_index = ent.hash.get(); - ent.hash = HashValue(replace(&mut side_index[old_index], i)); - } - - // Apply new index to self.indices - dispatch_32_vs_64!(self => apply_new_index(&mut self.indices, &side_index)); - - fn apply_new_index(indices: &mut [Pos], new_index: &[usize]) - where Sz: Size - { - for pos in indices { - if let Some((i, _)) = pos.resolve::() { - pos.set_pos::(new_index[i]); - } - } - } + self.core.sort_by(compare) } /// Sort the key-value pairs of the map and return a by value iterator of @@ -1131,21 +965,27 @@ impl OrderMap pub fn sorted_by(mut self, mut cmp: F) -> IntoIter where F: FnMut(&K, &V, &K, &V) -> Ordering { - self.entries.sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + self.core.entries.sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); self.into_iter() } /// Clears the `OrderMap`, returning all key-value pairs as a drain iterator. /// Keeps the allocated memory for reuse. pub fn drain(&mut self, range: RangeFull) -> Drain { - self.clear_indices(); + self.core.clear_indices(); Drain { - iter: self.entries.drain(range), + iter: self.core.entries.drain(range), } } } +fn key_cmp(k1: &K, _v1: &V, k2: &K, _v2: &V) -> Ordering + where K: Ord +{ + Ord::cmp(k1, k2) +} + impl OrderMap { /// Get a key-value pair by index /// @@ -1153,7 +993,7 @@ impl OrderMap { /// /// Computes in **O(1)** time. pub fn get_index(&self, index: usize) -> Option<(&K, &V)> { - self.entries.get(index).map(|ent| (&ent.key, &ent.value)) + self.core.entries.get(index).map(Bucket::refs) } /// Get a key-value pair by index @@ -1162,7 +1002,7 @@ impl OrderMap { /// /// Computes in **O(1)** time. pub fn get_index_mut(&mut self, index: usize) -> Option<(&mut K, &mut V)> { - self.entries.get_mut(index).map(|ent| (&mut ent.key, &mut ent.value)) + self.core.entries.get_mut(index).map(Bucket::muts) } /// Remove the key-value pair by index @@ -1171,13 +1011,13 @@ impl OrderMap { /// /// Computes in **O(1)** time (average). pub fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { - let (probe, found) = match self.entries.get(index) - .map(|e| self.find_existing_entry(e)) + let (probe, found) = match self.core.entries.get(index) + .map(|e| self.core.find_existing_entry(e)) { None => return None, Some(t) => t, }; - Some(self.remove_found(probe, found)) + Some(self.core.remove_found(probe, found)) } } @@ -1187,7 +1027,102 @@ impl OrderMap { // using Hash + Eq at all in these methods. // // However, we should probably not let this show in the public API or docs. -impl OrderMap { +impl OrderMapCore { + fn len(&self) -> usize { self.entries.len() } + + fn capacity(&self) -> usize { + usable_capacity(self.raw_capacity()) + } + + fn clear(&mut self) { + self.entries.clear(); + self.clear_indices(); + } + + // clear self.indices to the same state as "no elements" + fn clear_indices(&mut self) { + for pos in self.indices.iter_mut() { + *pos = Pos::none(); + } + } + + fn first_allocation(&mut self) { + debug_assert_eq!(self.len(), 0); + let raw_cap = 8usize; + self.mask = raw_cap.wrapping_sub(1); + self.indices = vec![Pos::none(); raw_cap].into_boxed_slice(); + self.entries = Vec::with_capacity(usable_capacity(raw_cap)); + } + + #[inline(never)] + // `Sz` is *current* Size class, before grow + fn double_capacity(&mut self) + where Sz: Size + { + debug_assert!(self.raw_capacity() == 0 || self.len() > 0); + if self.raw_capacity() == 0 { + return self.first_allocation(); + } + + // find first ideally placed element -- start of cluster + let mut first_ideal = 0; + for (i, index) in enumerate(&*self.indices) { + if let Some(pos) = index.pos() { + if 0 == probe_distance(self.mask, self.entries[pos].hash, i) { + first_ideal = i; + break; + } + } + } + + // visit the entries in an order where we can simply reinsert them + // into self.indices without any bucket stealing. + let new_raw_cap = self.indices.len() * 2; + let old_indices = replace(&mut self.indices, vec![Pos::none(); new_raw_cap].into_boxed_slice()); + self.mask = new_raw_cap.wrapping_sub(1); + + // `Sz` is the old size class, and either u32 or u64 is the new + for &pos in &old_indices[first_ideal..] { + dispatch_32_vs_64!(self.reinsert_entry_in_order::(pos)); + } + + for &pos in &old_indices[..first_ideal] { + dispatch_32_vs_64!(self.reinsert_entry_in_order::(pos)); + } + let more = self.capacity() - self.len(); + self.entries.reserve_exact(more); + } + + // write to self.indices + // read from self.entries at `pos` + // + // reinserting rewrites all `Pos` entries anyway. This handles transitioning + // from u32 to u64 size class if needed by using the two type parameters. + fn reinsert_entry_in_order(&mut self, pos: Pos) + where SzNew: Size, + SzOld: Size, + { + if let Some((i, hash_proxy)) = pos.resolve::() { + // only if the size class is conserved can we use the short hash + let entry_hash = if SzOld::is_same_size::() { + hash_proxy.get_short_hash(&self.entries, i).into_hash() + } else { + self.entries[i].hash + }; + // find first empty bucket and insert there + let mut probe = desired_pos(self.mask, entry_hash); + probe_loop!(probe < self.indices.len(), { + if let Some(_) = self.indices[probe].resolve::() { + /* nothing */ + } else { + // empty bucket, insert here + self.indices[probe] = Pos::with_hash::(i, entry_hash); + return; + } + }); + } + } + fn pop_impl(&mut self) -> Option<(K, V)> { let (probe, found) = match self.entries.last() .map(|e| self.find_existing_entry(e)) @@ -1199,6 +1134,94 @@ impl OrderMap { Some(self.remove_found(probe, found)) } + // FIXME: reduce duplication (compare with insert) + fn entry_phase_1(&mut self, hash: HashValue, key: K) -> Entry + where Sz: Size, + K: Eq, + { + let mut probe = desired_pos(self.mask, hash); + let mut dist = 0; + debug_assert!(self.len() < self.raw_capacity()); + probe_loop!(probe < self.indices.len(), { + if let Some((i, hash_proxy)) = self.indices[probe].resolve::() { + let entry_hash = hash_proxy.get_short_hash(&self.entries, i); + // if existing element probed less than us, swap + let their_dist = probe_distance(self.mask, entry_hash.into_hash(), probe); + if their_dist < dist { + // robin hood: steal the spot if it's better for us + return Entry::Vacant(VacantEntry { + map: self, + hash: hash, + key: key, + probe: probe, + }); + } else if entry_hash == hash && self.entries[i].key == key { + return Entry::Occupied(OccupiedEntry { + map: self, + key: key, + probe: probe, + index: i, + }); + } + } else { + // empty bucket, insert here + return Entry::Vacant(VacantEntry { + map: self, + hash: hash, + key: key, + probe: probe, + }); + } + dist += 1; + }); + } + + // First phase: Look for the preferred location for key. + // + // We will know if `key` is already in the map, before we need to insert it. + // When we insert they key, it might be that we need to continue displacing + // entries (robin hood hashing), in which case Inserted::RobinHood is returned + fn insert_phase_1(&mut self, hash: HashValue, key: K, value: V) -> Inserted + where Sz: Size, + K: Eq, + { + let mut probe = desired_pos(self.mask, hash); + let mut dist = 0; + let insert_kind; + debug_assert!(self.len() < self.raw_capacity()); + probe_loop!(probe < self.indices.len(), { + let pos = &mut self.indices[probe]; + if let Some((i, hash_proxy)) = pos.resolve::() { + let entry_hash = hash_proxy.get_short_hash(&self.entries, i); + // if existing element probed less than us, swap + let their_dist = probe_distance(self.mask, entry_hash.into_hash(), probe); + if their_dist < dist { + // robin hood: steal the spot if it's better for us + let index = self.entries.len(); + insert_kind = Inserted::RobinHood { + probe: probe, + old_pos: Pos::with_hash::(index, hash), + }; + break; + } else if entry_hash == hash && self.entries[i].key == key { + return Inserted::Swapped { + prev_value: replace(&mut self.entries[i].value, value), + }; + } + } else { + // empty bucket, insert here + let index = self.entries.len(); + *pos = Pos::with_hash::(index, hash); + insert_kind = Inserted::Done; + break; + } + dist += 1; + }); + self.entries.push(Bucket { hash: hash, key: key, value: value }); + insert_kind + } + + /// phase 2 is post-insert where we forward-shift `Pos` in the indices. fn insert_phase_2(&mut self, mut probe: usize, mut old_pos: Pos) where Sz: Size @@ -1315,6 +1338,68 @@ impl OrderMap { }); } + fn retain_in_order_impl(&mut self, mut keep: F) + where F: FnMut(&mut K, &mut V) -> bool, + Sz: Size, + { + // Like Vec::retain in self.entries; for each removed key-value pair, + // we clear its corresponding spot in self.indices, and run the + // usual backward shift in self.indices. + let len = self.entries.len(); + let mut n_deleted = 0; + for i in 0..len { + let will_keep; + let hash; + { + let ent = &mut self.entries[i]; + hash = ent.hash; + will_keep = keep(&mut ent.key, &mut ent.value); + }; + let probe = find_existing_entry_at::(&self.indices, hash, self.mask, i); + if !will_keep { + n_deleted += 1; + self.indices[probe] = Pos::none(); + self.backward_shift_after_removal::(probe); + } else if n_deleted > 0 { + self.indices[probe].set_pos::(i - n_deleted); + self.entries.swap(i - n_deleted, i); + } + } + self.entries.truncate(len - n_deleted); + } + + fn sort_by(&mut self, mut compare: F) + where F: FnMut(&K, &V, &K, &V) -> Ordering, + { + // Temporarily use the hash field in a bucket to store the old index. + // Save the old hash values in `side_index`. Then we can sort + // `self.entries` in place. + let mut side_index = Vec::from_iter(enumerate(&mut self.entries).map(|(i, elt)| { + replace(&mut elt.hash, HashValue(i)).get() + })); + + self.entries.sort_by(move |ei, ej| compare(&ei.key, &ei.value, &ej.key, &ej.value)); + + // Write back the hash values from side_index and fill `side_index` with + // a mapping from the old to the new index instead. + for (i, ent) in enumerate(&mut self.entries) { + let old_index = ent.hash.get(); + ent.hash = HashValue(replace(&mut side_index[old_index], i)); + } + + // Apply new index to self.indices + dispatch_32_vs_64!(self => apply_new_index(&mut self.indices, &side_index)); + + fn apply_new_index(indices: &mut [Pos], new_index: &[usize]) + where Sz: Size + { + for pos in indices { + if let Some((i, _)) = pos.resolve::() { + pos.set_pos::(new_index[i]); + } + } + } + } } /// Find, in the indices, an entry that already exists at a known position @@ -1352,12 +1437,12 @@ pub struct Keys<'a, K: 'a, V: 'a> { impl<'a, K, V> Iterator for Keys<'a, K, V> { type Item = &'a K; - iterator_methods!(|entry| &entry.key); + iterator_methods!(Bucket::key_ref); } impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> { fn next_back(&mut self) -> Option<&'a K> { - self.iter.next_back().map(|ent| &ent.key) + self.iter.next_back().map(Bucket::key_ref) } } @@ -1374,12 +1459,12 @@ pub struct Values<'a, K: 'a, V: 'a> { impl<'a, K, V> Iterator for Values<'a, K, V> { type Item = &'a V; - iterator_methods!(|ent| &ent.value); + iterator_methods!(Bucket::value_ref); } impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { fn next_back(&mut self) -> Option { - self.iter.next_back().map(|ent| &ent.value) + self.iter.next_back().map(Bucket::value_ref) } } @@ -1396,12 +1481,12 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; - iterator_methods!(|ent| &mut ent.value); + iterator_methods!(Bucket::value_mut); } impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> { fn next_back(&mut self) -> Option { - self.iter.next_back().map(|ent| &mut ent.value) + self.iter.next_back().map(Bucket::value_mut) } } @@ -1418,12 +1503,12 @@ pub struct Iter<'a, K: 'a, V: 'a> { impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); - iterator_methods!(|e| (&e.key, &e.value)); + iterator_methods!(Bucket::refs); } impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> { fn next_back(&mut self) -> Option { - self.iter.next_back().map(|e| (&e.key, &e.value)) + self.iter.next_back().map(Bucket::refs) } } @@ -1440,12 +1525,12 @@ pub struct IterMut<'a, K: 'a, V: 'a> { impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); - iterator_methods!(|e| (&e.key, &mut e.value)); + iterator_methods!(Bucket::ref_mut); } impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> { fn next_back(&mut self) -> Option { - self.iter.next_back().map(|e| (&e.key, &mut e.value)) + self.iter.next_back().map(Bucket::ref_mut) } } @@ -1462,12 +1547,12 @@ pub struct IntoIter { impl Iterator for IntoIter { type Item = (K, V); - iterator_methods!(|entry| (entry.key, entry.value)); + iterator_methods!(Bucket::key_value); } impl<'a, K, V> DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { - self.iter.next_back().map(|entry| (entry.key, entry.value)) + self.iter.next_back().map(Bucket::key_value) } } @@ -1484,11 +1569,11 @@ pub struct Drain<'a, K, V> where K: 'a, V: 'a { impl<'a, K, V> Iterator for Drain<'a, K, V> { type Item = (K, V); - iterator_methods!(|bucket| (bucket.key, bucket.value)); + iterator_methods!(Bucket::key_value); } impl<'a, K, V> DoubleEndedIterator for Drain<'a, K, V> { - double_ended_iterator_methods!(|bucket| (bucket.key, bucket.value)); + double_ended_iterator_methods!(Bucket::key_value); } @@ -1522,7 +1607,7 @@ impl IntoIterator for OrderMap type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { - iter: self.entries.into_iter(), + iter: self.core.entries.into_iter(), } } } diff --git a/src/mutable_keys.rs b/src/mutable_keys.rs index 32c8b2e5..1d34f073 100644 --- a/src/mutable_keys.rs +++ b/src/mutable_keys.rs @@ -57,7 +57,7 @@ impl MutableKeys for OrderMap where Q: Hash + Equivalent, { if let Some((_, found)) = self.find(key) { - let entry = &mut self.entries[found]; + let entry = &mut self.core.entries[found]; Some((found, &mut entry.key, &mut entry.value)) } else { None diff --git a/src/set.rs b/src/set.rs index 6a7fd36c..0312fe1a 100644 --- a/src/set.rs +++ b/src/set.rs @@ -409,12 +409,12 @@ pub struct IntoIter { impl Iterator for IntoIter { type Item = T; - iterator_methods!(|entry| entry.key); + iterator_methods!(Bucket::key); } impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { - self.iter.next_back().map(|entry| entry.key) + self.iter.next_back().map(Bucket::key) } } @@ -432,12 +432,12 @@ pub struct Iter<'a, T: 'a> { impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; - iterator_methods!(|entry| &entry.key); + iterator_methods!(Bucket::key_ref); } impl<'a, T> DoubleEndedIterator for Iter<'a, T> { fn next_back(&mut self) -> Option { - self.iter.next_back().map(|entry| &entry.key) + self.iter.next_back().map(Bucket::key_ref) } } @@ -454,11 +454,11 @@ pub struct Drain<'a, T: 'a> { impl<'a, T> Iterator for Drain<'a, T> { type Item = T; - iterator_methods!(|bucket| bucket.key); + iterator_methods!(Bucket::key); } impl<'a, T> DoubleEndedIterator for Drain<'a, T> { - double_ended_iterator_methods!(|bucket| bucket.key); + double_ended_iterator_methods!(Bucket::key); } impl<'a, T, S> IntoIterator for &'a OrderSet