Skip to content

Commit cde2f7d

Browse files
authored
Merge pull request #61 from mlodato517/implement-keys-and-values-iterators
Adds keys and values iterators
2 parents a3e36ea + 61c6642 commit cde2f7d

File tree

3 files changed

+144
-11
lines changed

3 files changed

+144
-11
lines changed

src/read/read_ref.rs

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,27 @@ where
3535
/// refresh will block waiting on this reader to finish.
3636
pub fn iter(&self) -> ReadGuardIter<'_, K, V, S> {
3737
ReadGuardIter {
38-
iter: Some(self.guard.data.iter()),
38+
iter: self.guard.data.iter(),
39+
}
40+
}
41+
42+
/// Iterate over all keys in the map.
43+
///
44+
/// Be careful with this function! While the iteration is ongoing, any writer that tries to
45+
/// refresh will block waiting on this reader to finish.
46+
pub fn keys(&self) -> KeysIter<'_, K, V, S> {
47+
KeysIter {
48+
iter: self.guard.data.iter(),
49+
}
50+
}
51+
52+
/// Iterate over all value sets in the map.
53+
///
54+
/// Be careful with this function! While the iteration is ongoing, any writer that tries to
55+
/// refresh will block waiting on this reader to finish.
56+
pub fn values(&self) -> ValuesIter<'_, K, V, S> {
57+
ValuesIter {
58+
iter: self.guard.data.iter(),
3959
}
4060
}
4161

@@ -157,9 +177,7 @@ where
157177
V: Eq + Hash,
158178
S: BuildHasher,
159179
{
160-
iter: Option<
161-
<&'rg crate::inner::MapImpl<K, Values<ManuallyDrop<V>, S>, S> as IntoIterator>::IntoIter,
162-
>,
180+
iter: <&'rg crate::inner::MapImpl<K, Values<ManuallyDrop<V>, S>, S> as IntoIterator>::IntoIter,
163181
}
164182

165183
impl<'rg, K, V, S> Iterator for ReadGuardIter<'rg, K, V, S>
@@ -170,8 +188,52 @@ where
170188
{
171189
type Item = (&'rg K, &'rg Values<V, S>);
172190
fn next(&mut self) -> Option<Self::Item> {
173-
self.iter
174-
.as_mut()
175-
.and_then(|iter| iter.next().map(|(k, v)| (k, v.user_friendly())))
191+
self.iter.next().map(|(k, v)| (k, v.user_friendly()))
192+
}
193+
}
194+
195+
/// An [`Iterator`] over keys.
196+
#[derive(Debug)]
197+
pub struct KeysIter<'rg, K, V, S>
198+
where
199+
K: Eq + Hash,
200+
V: Eq + Hash,
201+
S: BuildHasher,
202+
{
203+
iter: <&'rg crate::inner::MapImpl<K, Values<ManuallyDrop<V>, S>, S> as IntoIterator>::IntoIter,
204+
}
205+
206+
impl<'rg, K, V, S> Iterator for KeysIter<'rg, K, V, S>
207+
where
208+
K: Eq + Hash,
209+
V: Eq + Hash,
210+
S: BuildHasher,
211+
{
212+
type Item = &'rg K;
213+
fn next(&mut self) -> Option<Self::Item> {
214+
self.iter.next().map(|(k, _)| k)
215+
}
216+
}
217+
218+
/// An [`Iterator`] over value sets.
219+
#[derive(Debug)]
220+
pub struct ValuesIter<'rg, K, V, S>
221+
where
222+
K: Eq + Hash,
223+
V: Eq + Hash,
224+
S: BuildHasher,
225+
{
226+
iter: <&'rg crate::inner::MapImpl<K, Values<ManuallyDrop<V>, S>, S> as IntoIterator>::IntoIter,
227+
}
228+
229+
impl<'rg, K, V, S> Iterator for ValuesIter<'rg, K, V, S>
230+
where
231+
K: Eq + Hash,
232+
V: Eq + Hash,
233+
S: BuildHasher,
234+
{
235+
type Item = &'rg Values<V, S>;
236+
fn next(&mut self) -> Option<Self::Item> {
237+
self.iter.next().map(|(_, v)| v.user_friendly())
176238
}
177239
}

tests/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,45 @@ fn map_into() {
593593
assert!(copy[&2].contains(&"c"));
594594
}
595595

596+
#[test]
597+
fn keys() {
598+
let (r, mut w) = evmap::new();
599+
w.insert(1, "a");
600+
w.insert(1, "b");
601+
w.insert(2, "c");
602+
w.refresh();
603+
w.insert(1, "x");
604+
605+
let mut keys = r.read().unwrap().keys().copied().collect::<Vec<_>>();
606+
keys.sort();
607+
608+
assert_eq!(keys, vec![1, 2]);
609+
}
610+
611+
#[test]
612+
fn values() {
613+
let (r, mut w) = evmap::new();
614+
w.insert(1, "a");
615+
w.insert(1, "b");
616+
w.insert(2, "c");
617+
w.refresh();
618+
w.insert(1, "x");
619+
620+
let mut values = r
621+
.read()
622+
.unwrap()
623+
.values()
624+
.map(|value_bag| {
625+
let mut inner_items = value_bag.iter().copied().collect::<Vec<_>>();
626+
inner_items.sort();
627+
inner_items
628+
})
629+
.collect::<Vec<Vec<_>>>();
630+
values.sort_by_key(|value_vec| value_vec.len());
631+
632+
assert_eq!(values, vec![vec!["c"], vec!["a", "b"]]);
633+
}
634+
596635
#[test]
597636
#[cfg_attr(miri, ignore)]
598637
fn clone_churn() {

tests/quick.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn insert_empty(insert: Vec<u8>, remove: Vec<u8>) -> bool {
6262
w.refresh();
6363
let elements = &set(&insert) - &set(&remove);
6464
r.len() == elements.len()
65-
&& r.map_into::<_, Vec<()>, _>(|_, _| ()).len() == elements.len()
65+
&& r.read().iter().map(|r| r.keys()).flatten().count() == elements.len()
6666
&& elements.iter().all(|k| r.get(k).is_some())
6767
}
6868

@@ -137,14 +137,13 @@ where
137137
S: BuildHasher,
138138
{
139139
assert_eq!(a.len(), b.len());
140-
let keys = a.map_into::<_, Vec<K>, _>(|k, _| k.clone());
141-
for key in &keys {
140+
for key in a.read().iter().map(|r| r.keys()).flatten() {
142141
assert!(b.contains_key(key), "b does not contain {:?}", key);
143142
}
144143
for key in b.keys() {
145144
assert!(a.get(key).is_some(), "a does not contain {:?}", key);
146145
}
147-
for key in &keys {
146+
for key in a.read().iter().map(|r| r.keys()).flatten() {
148147
let mut ev_map_values: Vec<V> = a.get(key).unwrap().iter().copied().collect();
149148
ev_map_values.sort();
150149
let mut map_values = b[key].clone();
@@ -230,3 +229,36 @@ fn operations_string(ops: Vec<Op<Alphabet, i8>>) -> bool {
230229
w.refresh();
231230
assert_maps_equivalent(&r, &write_ref)
232231
}
232+
233+
#[quickcheck]
234+
fn keys_values(ops: Large<Vec<Op<i8, i8>>>) -> bool {
235+
let (r, mut w) = evmap::new();
236+
let mut write_ref = HashMap::new();
237+
let mut read_ref = HashMap::new();
238+
do_ops(&ops, &mut w, &mut write_ref, &mut read_ref);
239+
240+
if let Some(read_guard) = r.read() {
241+
let (r_visit, mut w_visit) = evmap::new();
242+
for (k, v_set) in read_guard.keys().zip(read_guard.values()) {
243+
assert!(read_guard[k].iter().all(|v| v_set.contains(v)));
244+
assert!(v_set.iter().all(|v| read_guard[k].contains(v)));
245+
246+
assert!(!r_visit.contains_key(k));
247+
248+
// If the value set is empty, we still need to add the key.
249+
// But we need to add the key with an empty value bag.
250+
// Just add something and then remove the value, but leave the bag.
251+
if v_set.is_empty() {
252+
w_visit.insert(*k, 0);
253+
w_visit.remove_value(*k, 0);
254+
} else {
255+
for value in v_set {
256+
w_visit.insert(*k, *value);
257+
}
258+
}
259+
w_visit.refresh();
260+
}
261+
assert_eq!(r_visit.len(), read_ref.len());
262+
}
263+
true
264+
}

0 commit comments

Comments
 (0)