Skip to content

Commit 531cc29

Browse files
stepanchegfacebook-github-bot
authored andcommitted
Switch VecMap to Vec2
Summary: Switch `VecMap` from `Vec<(Hash, K, V)>` to `Vec2<(K, V), Hash>`. See the following diff D40557486. Reviewed By: ndmitchell Differential Revision: D40647760 fbshipit-source-id: 92275d597614740fc98d06f091119248b01ee2f1
1 parent f0d1c23 commit 531cc29

File tree

2 files changed

+38
-31
lines changed

2 files changed

+38
-31
lines changed

starlark_map/src/vec_map/iter.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@
1515
* limitations under the License.
1616
*/
1717

18+
use core::slice;
19+
1820
use gazebo::prelude::Clone_;
1921

2022
use crate::iter::def_double_ended_iter;
2123
use crate::iter::def_iter;
22-
use crate::vec_map::Bucket;
24+
use crate::vec2;
2325
use crate::Hashed;
26+
use crate::StarlarkHashValue;
2427

2528
#[derive(Clone_)]
2629
pub(crate) struct Keys<'a, K: 'a, V: 'a> {
@@ -134,13 +137,13 @@ impl<'a, K: 'a, V: 'a> Iter<'a, K, V> {
134137

135138
#[derive(Clone_)]
136139
pub(crate) struct IterHashed<'a, K: 'a, V: 'a> {
137-
pub(crate) iter: std::slice::Iter<'a, Bucket<K, V>>,
140+
pub(crate) iter: vec2::iter::Iter<'a, (K, V), StarlarkHashValue>,
138141
}
139142

140143
impl<'a, K: 'a, V: 'a> IterHashed<'a, K, V> {
141144
#[inline]
142-
fn map(b: &'a Bucket<K, V>) -> (Hashed<&'a K>, &'a V) {
143-
(Hashed::new_unchecked(b.hash, &b.key), &b.value)
145+
fn map(((k, v), hash): (&'a (K, V), &'a StarlarkHashValue)) -> (Hashed<&'a K>, &'a V) {
146+
(Hashed::new_unchecked(*hash, k), v)
144147
}
145148
}
146149

@@ -162,13 +165,13 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterHashed<'a, K, V> {
162165
}
163166

164167
pub(crate) struct IterMut<'a, K: 'a, V: 'a> {
165-
pub(crate) iter: std::slice::IterMut<'a, Bucket<K, V>>,
168+
pub(crate) iter: slice::IterMut<'a, (K, V)>,
166169
}
167170

168171
impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
169172
#[inline]
170-
fn map(b: &mut Bucket<K, V>) -> (&K, &mut V) {
171-
(&b.key, &mut b.value)
173+
fn map((k, v): &mut (K, V)) -> (&K, &mut V) {
174+
(k, v)
172175
}
173176
}
174177

@@ -190,13 +193,13 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
190193
}
191194

192195
pub(crate) struct IntoIterHashed<K, V> {
193-
pub(crate) iter: std::vec::IntoIter<Bucket<K, V>>,
196+
pub(crate) iter: vec2::iter::IntoIter<(K, V), StarlarkHashValue>,
194197
}
195198

196199
impl<K, V> IntoIterHashed<K, V> {
197200
#[inline]
198-
fn map(b: Bucket<K, V>) -> (Hashed<K>, V) {
199-
(Hashed::new_unchecked(b.hash, b.key), b.value)
201+
fn map(((k, v), hash): ((K, V), StarlarkHashValue)) -> (Hashed<K>, V) {
202+
(Hashed::new_unchecked(hash, k), v)
200203
}
201204
}
202205

starlark_map/src/vec_map/mod.rs

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use gazebo::prelude::*;
2727
use crate::equivalent::Equivalent;
2828
use crate::hash_value::StarlarkHashValue;
2929
use crate::hashed::Hashed;
30+
pub(crate) use crate::vec2::Vec2;
3031
pub(crate) use crate::vec_map::iter::IntoIter;
3132
pub(crate) use crate::vec_map::iter::IntoIterHashed;
3233
pub(crate) use crate::vec_map::iter::Iter;
@@ -56,21 +57,21 @@ impl<K: Hash, V: Hash> Hash for Bucket<K, V> {
5657

5758
#[derive(Debug, Clone, Eq, PartialEq, Default_, Allocative)]
5859
pub(crate) struct VecMap<K, V> {
59-
buckets: Vec<Bucket<K, V>>,
60+
buckets: Vec2<(K, V), StarlarkHashValue>,
6061
}
6162

6263
impl<K, V> VecMap<K, V> {
6364
#[inline]
6465
pub(crate) const fn new() -> Self {
6566
VecMap {
66-
buckets: Vec::new(),
67+
buckets: Vec2::new(),
6768
}
6869
}
6970

7071
#[inline]
7172
pub(crate) fn with_capacity(n: usize) -> Self {
7273
VecMap {
73-
buckets: Vec::with_capacity(n),
74+
buckets: Vec2::with_capacity(n),
7475
}
7576
}
7677

@@ -95,9 +96,9 @@ impl<K, V> VecMap<K, V> {
9596
) -> Option<(usize, &K, &V)> {
9697
let mut i = 0;
9798
#[allow(clippy::explicit_counter_loop)] // we are paranoid about performance
98-
for b in &self.buckets {
99-
if b.hash == hash && eq(&b.key) {
100-
return Some((i, &b.key, &b.value));
99+
for ((k, v), b_hash) in &self.buckets {
100+
if *b_hash == hash && eq(k) {
101+
return Some((i, k, v));
101102
}
102103
i += 1;
103104
}
@@ -123,30 +124,28 @@ impl<K, V> VecMap<K, V> {
123124

124125
#[inline]
125126
pub(crate) fn get_index(&self, index: usize) -> Option<(&K, &V)> {
126-
self.buckets.get(index).map(|x| (&x.key, &x.value))
127+
let ((k, v), _hash) = self.buckets.get(index)?;
128+
Some((k, v))
127129
}
128130

129131
#[inline]
130132
pub(crate) unsafe fn get_unchecked(&self, index: usize) -> (Hashed<&K>, &V) {
131133
debug_assert!(index < self.buckets.len());
132-
let Bucket { hash, key, value } = self.buckets.get_unchecked(index);
134+
let ((key, value), hash) = self.buckets.get_unchecked(index);
133135
(Hashed::new_unchecked(*hash, key), value)
134136
}
135137

136138
#[inline]
137139
pub(crate) unsafe fn get_unchecked_mut(&mut self, index: usize) -> (Hashed<&K>, &mut V) {
138140
debug_assert!(index < self.buckets.len());
139-
let Bucket { hash, key, value } = self.buckets.get_unchecked_mut(index);
141+
let ((key, value), hash) = self.buckets.get_unchecked_mut(index);
140142
(Hashed::new_unchecked(*hash, key), value)
141143
}
142144

143145
#[inline]
144146
pub(crate) fn insert_hashed_unique_unchecked(&mut self, key: Hashed<K>, value: V) {
145-
self.buckets.push(Bucket {
146-
hash: key.hash(),
147-
key: key.into_key(),
148-
value,
149-
});
147+
let hash = key.hash();
148+
self.buckets.push((key.into_key(), value), hash);
150149
}
151150

152151
pub(crate) fn remove_hashed_entry<Q>(&mut self, key: Hashed<&Q>) -> Option<(K, V)>
@@ -163,13 +162,13 @@ impl<K, V> VecMap<K, V> {
163162

164163
#[inline]
165164
pub(crate) fn remove(&mut self, index: usize) -> (Hashed<K>, V) {
166-
let Bucket { hash, key, value } = self.buckets.remove(index);
165+
let ((key, value), hash) = self.buckets.remove(index);
167166
(Hashed::new_unchecked(hash, key), value)
168167
}
169168

170169
#[inline]
171170
pub(crate) fn pop(&mut self) -> Option<(Hashed<K>, V)> {
172-
let Bucket { hash, key, value } = self.buckets.pop()?;
171+
let ((key, value), hash) = self.buckets.pop()?;
173172
Some((Hashed::new_unchecked(hash, key), value))
174173
}
175174

@@ -237,22 +236,22 @@ impl<K, V> VecMap<K, V> {
237236
#[inline]
238237
pub(crate) fn iter_mut(&mut self) -> IterMut<K, V> {
239238
IterMut {
240-
iter: self.buckets.iter_mut(),
239+
iter: self.buckets.keys_mut().iter_mut(),
241240
}
242241
}
243242

244243
pub(crate) fn sort_keys(&mut self)
245244
where
246245
K: Ord,
247246
{
248-
self.buckets.sort_unstable_by(|a, b| a.key.cmp(&b.key));
247+
self.buckets.sort_by(|(a, _ah), (b, _bh)| a.0.cmp(&b.0));
249248
}
250249

251250
pub(crate) fn is_sorted_by_key(&self) -> bool
252251
where
253252
K: Ord,
254253
{
255-
self.buckets.windows(2).all(|w| w[0].key <= w[1].key)
254+
self.buckets.keys().windows(2).all(|w| w[0].0 <= w[1].0)
256255
}
257256

258257
/// Equal if entries are equal in the iterator order.
@@ -261,7 +260,10 @@ impl<K, V> VecMap<K, V> {
261260
K: PartialEq,
262261
V: PartialEq,
263262
{
264-
self.buckets.eq(&other.buckets)
263+
// We compare hashes before comparing keys and values because it is faster
264+
// (fewer branches, and no comparison of the rest it at lest one hash is different).
265+
self.buckets.values() == other.buckets.values()
266+
&& self.buckets.keys() == other.buckets.keys()
265267
}
266268

267269
/// Hash entries in the iterator order.
@@ -272,6 +274,8 @@ impl<K, V> VecMap<K, V> {
272274
K: Hash,
273275
V: Hash,
274276
{
275-
self.buckets.hash(state);
277+
for e in self.iter_hashed() {
278+
e.hash(state);
279+
}
276280
}
277281
}

0 commit comments

Comments
 (0)