Skip to content

Commit 04ae392

Browse files
authored
Merge pull request #552 from ratmice/markmap_merge_many
Fix bug with `merge_from` when a markmap had many keys.
2 parents 152316b + abf41bd commit 04ae392

1 file changed

Lines changed: 59 additions & 17 deletions

File tree

cfgrammar/src/lib/markmap.rs

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -369,19 +369,19 @@ impl<K: Ord + Clone, V> MarkMap<K, V> {
369369
/// For the behavior of exclusive or mark the behavior as also `Mark::Required`, then after merge call `missing()`
370370
/// to check all required values.
371371
#[doc(hidden)]
372-
pub fn merge_from(&mut self, other: Self) -> Result<(), MergeError<K, Box<V>>> {
373-
for (their_key, their_mark, their_val) in other.contents {
372+
pub fn merge_from(&mut self, mut other: Self) -> Result<(), MergeError<K, Box<V>>> {
373+
for (their_key, their_mark, their_val) in other.contents.drain(..) {
374374
let pos = self.contents.binary_search_by(|x| x.0.cmp(&their_key));
375375
match pos {
376376
Ok(pos) => {
377-
let (_, my_mark, my_val) = &self.contents[pos];
377+
let (_, my_mark, my_val) = &mut self.contents[pos];
378378
let theirs_mark = Mark::MergeBehavior(MergeBehavior::Theirs).repr();
379379
let ours_mark = Mark::MergeBehavior(MergeBehavior::Ours).repr();
380380
let exclusive_mark =
381381
Mark::MergeBehavior(MergeBehavior::MutuallyExclusive).repr();
382-
let merge_behavior = (my_mark & exclusive_mark)
383-
| (my_mark & ours_mark)
384-
| (my_mark & theirs_mark);
382+
let merge_behavior = (*my_mark & exclusive_mark)
383+
| (*my_mark & ours_mark)
384+
| (*my_mark & theirs_mark);
385385
if merge_behavior == exclusive_mark || merge_behavior == 0 {
386386
// If only clippy could convince me and the borrow checker this is actually unnecessary.
387387
#[allow(clippy::unnecessary_unwrap)]
@@ -391,18 +391,13 @@ impl<K: Ord + Clone, V> MarkMap<K, V> {
391391
Box::new(their_val.unwrap()),
392392
));
393393
} else if my_val.is_none() {
394-
self.contents[pos].2 = their_val;
395-
return Ok(());
394+
*my_val = their_val;
396395
}
397-
}
398-
if merge_behavior == theirs_mark && their_val.is_some() {
399-
self.contents[pos].2 = their_val;
400-
return Ok(());
401-
}
402-
403-
if merge_behavior == ours_mark && my_val.is_none() {
404-
self.contents[pos].2 = their_val;
405-
return Ok(());
396+
} else if merge_behavior == theirs_mark && their_val.is_some()
397+
|| merge_behavior == ours_mark && my_val.is_none()
398+
{
399+
*my_mark = their_mark;
400+
*my_val = their_val;
406401
}
407402
}
408403
Err(pos) => {
@@ -457,6 +452,12 @@ impl<K: Ord + Clone, V> MarkMap<K, V> {
457452
}
458453
ret
459454
}
455+
456+
/// Returns an `Iterator` over all the keys of the `MarkMap`.
457+
#[doc(hidden)]
458+
pub fn keys(&self) -> Keys<'_, K, V> {
459+
Keys { pos: 0, map: self }
460+
}
460461
}
461462

462463
/// Iterator over the owned keys and values of a `MarkMap`.
@@ -509,6 +510,30 @@ impl<'a, K, V> IntoIterator for &'a MarkMap<K, V> {
509510
}
510511
}
511512

513+
/// Iterator over references to keys and values of a `MarkMap`.
514+
#[doc(hidden)]
515+
pub struct Keys<'a, K, V> {
516+
pos: usize,
517+
map: &'a MarkMap<K, V>,
518+
}
519+
520+
impl<'a, K, V> Iterator for Keys<'a, K, V> {
521+
type Item = &'a K;
522+
523+
fn next(&mut self) -> Option<Self::Item> {
524+
loop {
525+
if self.pos >= self.map.contents.len() {
526+
return None;
527+
}
528+
let pos = self.pos;
529+
self.pos += 1;
530+
if self.map.contents[pos].2.is_some() {
531+
return Some(&self.map.contents[pos].0);
532+
}
533+
}
534+
}
535+
}
536+
512537
#[cfg(test)]
513538
mod test {
514539
use super::*;
@@ -828,4 +853,21 @@ mod test {
828853
assert!(mm.is_required(&"a"));
829854
assert!(mm.is_used(&"a"));
830855
}
856+
857+
#[test]
858+
fn test_merge_many() {
859+
let mut mm = MarkMap::new();
860+
mm.insert("a", ());
861+
mm.insert("b", ());
862+
863+
let mut mm2 = MarkMap::new();
864+
mm2.insert("x", ());
865+
mm2.insert("y", ());
866+
867+
mm.merge_from(mm2).unwrap();
868+
assert_eq!(
869+
mm.keys().cloned().collect::<Vec<_>>(),
870+
vec!["a", "b", "x", "y"]
871+
);
872+
}
831873
}

0 commit comments

Comments
 (0)