Skip to content

Commit 5529396

Browse files
committed
refactor(basic): Improve performance of IndexedMap
Store both keys and values in the vector, so that it's possible to iterate over the entries without needing to lookup the value. This also removes the need for a custom KeysIterator.
1 parent e9deab8 commit 5529396

2 files changed

Lines changed: 39 additions & 72 deletions

File tree

Lines changed: 24 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
11
use std::collections::HashMap;
22
use std::hash::Hash;
3-
use std::slice::{Iter, IterMut};
43

54
/// A key-value map that can also access values by their insertion order.
65
#[derive(Debug)]
76
pub struct IndexedMap<K, V>
87
where
9-
K: Eq + Hash,
8+
K: Clone + Eq + Hash,
109
{
11-
values: Vec<V>,
10+
entries: Vec<(K, V)>,
1211
keys_to_indices: HashMap<K, usize>,
1312
}
1413

1514
impl<K, V> IndexedMap<K, V>
1615
where
17-
K: Eq + Hash,
16+
K: Clone + Eq + Hash,
1817
{
1918
pub fn new() -> Self {
2019
Self {
21-
values: vec![],
20+
entries: vec![],
2221
keys_to_indices: HashMap::new(),
2322
}
2423
}
2524

2625
pub fn insert(&mut self, key: K, value: V) {
2726
match self.keys_to_indices.get(&key) {
2827
Some(existing_index) => {
29-
self.values[*existing_index] = value;
28+
self.entries[*existing_index] = (key, value);
3029
}
3130
_ => {
32-
let index = self.values.len();
33-
self.values.push(value);
31+
let index = self.entries.len();
32+
self.entries.push((key.clone(), value));
3433
self.keys_to_indices.insert(key, index);
3534
}
3635
}
@@ -39,89 +38,52 @@ where
3938
pub fn get(&self, key: &K) -> Option<&V> {
4039
self.keys_to_indices
4140
.get(key)
42-
.and_then(|index| self.values.get(*index))
41+
.and_then(|index| self.get_by_index(*index))
4342
}
4443

4544
pub fn get_by_index(&self, index: usize) -> Option<&V> {
46-
self.values.get(index)
45+
self.entries.get(index).map(|(_, v)| v)
4746
}
4847

4948
pub fn get_by_index_mut(&mut self, index: usize) -> Option<&mut V> {
50-
self.values.get_mut(index)
49+
self.entries.get_mut(index).map(|(_, v)| v)
5150
}
5251

5352
pub fn get_or_create<F>(&mut self, key: K, creator: F) -> &mut V
5453
where
5554
F: FnOnce(&K) -> V,
5655
{
57-
match self.keys_to_indices.get(&key) {
58-
Some(existing_index) => self.values.get_mut(*existing_index).unwrap(),
56+
let opt_value = match self.keys_to_indices.get(&key) {
57+
Some(existing_index) => self.get_by_index_mut(*existing_index),
5958
_ => {
6059
let v = creator(&key);
6160
self.insert(key, v);
62-
self.values.last_mut().unwrap()
61+
self.entries.last_mut().map(|(_, v)| v)
6362
}
64-
}
63+
};
64+
// guaranteed to be present
65+
opt_value.unwrap()
6566
}
6667

67-
pub fn values(&self) -> Iter<'_, V> {
68-
self.values.iter()
68+
pub fn entries(&self) -> impl Iterator<Item = &(K, V)> {
69+
self.entries.iter()
6970
}
7071

71-
pub fn values_mut(&mut self) -> IterMut<'_, V> {
72-
self.values.iter_mut()
72+
pub fn values(&self) -> impl Iterator<Item = &V> {
73+
self.entries.iter().map(|(_, v)| v)
7374
}
7475

75-
pub fn keys(&self) -> impl Iterator<Item = &K> + '_ {
76-
KeysIterator::new(self)
76+
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
77+
self.entries.iter_mut().map(|(_, v)| v)
7778
}
7879

7980
pub fn len(&self) -> usize {
80-
self.values.len()
81+
self.entries.len()
8182
}
8283
}
8384

84-
impl<K: Eq + Hash, V> Default for IndexedMap<K, V> {
85+
impl<K: Clone + Eq + Hash, V> Default for IndexedMap<K, V> {
8586
fn default() -> Self {
8687
Self::new()
8788
}
8889
}
89-
90-
struct KeysIterator<'a, K, V>
91-
where
92-
K: Eq + Hash,
93-
{
94-
owner: &'a IndexedMap<K, V>,
95-
index: usize,
96-
}
97-
98-
impl<'a, K, V> KeysIterator<'a, K, V>
99-
where
100-
K: Eq + Hash,
101-
{
102-
pub fn new(owner: &'a IndexedMap<K, V>) -> Self {
103-
Self { owner, index: 0 }
104-
}
105-
}
106-
107-
impl<'a, K, V> Iterator for KeysIterator<'a, K, V>
108-
where
109-
K: Eq + Hash,
110-
{
111-
type Item = &'a K;
112-
113-
fn next(&mut self) -> Option<Self::Item> {
114-
if self.index < self.owner.len() {
115-
let result = self
116-
.owner
117-
.keys_to_indices
118-
.iter()
119-
.find(|(_, index)| **index == self.index)
120-
.map(|(key, _)| key);
121-
self.index += 1;
122-
result
123-
} else {
124-
None
125-
}
126-
}
127-
}

rusty_basic/src/interpreter/variables.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -204,21 +204,26 @@ impl Variables {
204204
pub fn calculate_var_ptr(&self, name: &Name) -> usize {
205205
debug_assert!(self.map.get(name).is_some());
206206
self.map
207-
.keys()
208-
.take_while(|k| *k != name)
209-
.map(|k| self.get_by_name(k).unwrap())
207+
.entries()
208+
.take_while(|(k, _)| k != name)
209+
.map(|(_, v)| &v.value)
210210
.map(Variant::byte_size)
211211
.sum()
212212
}
213213

214214
pub fn array_names(&self) -> impl Iterator<Item = &Name> {
215-
self.map.keys().filter(move |key| match self.map.get(*key) {
216-
Some(RuntimeVariableInfo {
217-
value: Variant::VArray(_),
218-
..
219-
}) => true,
220-
_ => false,
221-
})
215+
self.map
216+
.entries()
217+
.filter(move |(_, value)| {
218+
matches!(
219+
value,
220+
RuntimeVariableInfo {
221+
value: Variant::VArray(_),
222+
..
223+
}
224+
)
225+
})
226+
.map(|(key, _)| key)
222227
}
223228
}
224229

0 commit comments

Comments
 (0)