Add tests and fixes for double ended map range iterator

This commit is contained in:
Andrew Jeffery 2022-05-05 16:51:16 +01:00
parent 7d5eaa0b7f
commit 28a61f2dcd
4 changed files with 351 additions and 1 deletions

View file

@ -476,6 +476,325 @@ fn range_iter_map() {
);
}
#[test]
fn map_range_back_and_forth_single() {
let mut doc = AutoCommit::new();
let actor = doc.get_actor().clone();
doc.put(ROOT, "1", "a").unwrap();
doc.put(ROOT, "2", "b").unwrap();
doc.put(ROOT, "3", "c").unwrap();
let mut range_all = doc.map_range(ROOT, ..);
assert_eq!(
range_all.next(),
Some(("1", "a".into(), ExId::Id(1, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "b".into(), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc.map_range(ROOT, ..);
assert_eq!(
range_all.next(),
Some(("1", "a".into(), ExId::Id(1, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(
range_all.next(),
Some(("2", Value::str("b"), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc.map_range(ROOT, ..);
assert_eq!(
range_all.next(),
Some(("1", "a".into(), ExId::Id(1, actor.clone(), 0)))
);
assert_eq!(
range_all.next(),
Some(("2", "b".into(), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(
range_all.next(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc.map_range(ROOT, ..);
assert_eq!(
range_all.next_back(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "b".into(), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("1", "a".into(), ExId::Id(1, actor, 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
}
#[test]
fn map_range_back_and_forth_double() {
let mut doc1 = AutoCommit::new();
doc1.set_actor(ActorId::from([0]));
doc1.put(ROOT, "1", "a").unwrap();
doc1.put(ROOT, "2", "b").unwrap();
doc1.put(ROOT, "3", "c").unwrap();
// actor 2 should win in all conflicts here
let mut doc2 = AutoCommit::new();
doc1.set_actor(ActorId::from([1]));
let actor2 = doc2.get_actor().clone();
doc2.put(ROOT, "1", "aa").unwrap();
doc2.put(ROOT, "2", "bb").unwrap();
doc2.put(ROOT, "3", "cc").unwrap();
doc1.merge(&mut doc2).unwrap();
let mut range_all = doc1.map_range(ROOT, ..);
assert_eq!(
range_all.next(),
Some(("1", "aa".into(), ExId::Id(1, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc1.map_range(ROOT, ..);
assert_eq!(
range_all.next(),
Some(("1", "aa".into(), ExId::Id(1, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(
range_all.next(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc1.map_range(ROOT, ..);
assert_eq!(
range_all.next(),
Some(("1", "aa".into(), ExId::Id(1, actor2.clone(), 1)))
);
assert_eq!(
range_all.next(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(
range_all.next(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc1.map_range(ROOT, ..);
assert_eq!(
range_all.next_back(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("1", "aa".into(), ExId::Id(1, actor2, 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
}
#[test]
fn map_range_at_back_and_forth_single() {
let mut doc = AutoCommit::new();
let actor = doc.get_actor().clone();
doc.put(ROOT, "1", "a").unwrap();
doc.put(ROOT, "2", "b").unwrap();
doc.put(ROOT, "3", "c").unwrap();
let heads = doc.get_heads();
let mut range_all = doc.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next(),
Some(("1", "a".into(), ExId::Id(1, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "b".into(), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next(),
Some(("1", "a".into(), ExId::Id(1, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(
range_all.next(),
Some(("2", Value::str("b"), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next(),
Some(("1", "a".into(), ExId::Id(1, actor.clone(), 0)))
);
assert_eq!(
range_all.next(),
Some(("2", "b".into(), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(
range_all.next(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next_back(),
Some(("3", "c".into(), ExId::Id(3, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "b".into(), ExId::Id(2, actor.clone(), 0)))
);
assert_eq!(
range_all.next_back(),
Some(("1", "a".into(), ExId::Id(1, actor, 0)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
}
#[test]
fn map_range_at_back_and_forth_double() {
let mut doc1 = AutoCommit::new();
doc1.set_actor(ActorId::from([0]));
doc1.put(ROOT, "1", "a").unwrap();
doc1.put(ROOT, "2", "b").unwrap();
doc1.put(ROOT, "3", "c").unwrap();
// actor 2 should win in all conflicts here
let mut doc2 = AutoCommit::new();
doc1.set_actor(ActorId::from([1]));
let actor2 = doc2.get_actor().clone();
doc2.put(ROOT, "1", "aa").unwrap();
doc2.put(ROOT, "2", "bb").unwrap();
doc2.put(ROOT, "3", "cc").unwrap();
doc1.merge(&mut doc2).unwrap();
let heads = doc1.get_heads();
let mut range_all = doc1.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next(),
Some(("1", "aa".into(), ExId::Id(1, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc1.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next(),
Some(("1", "aa".into(), ExId::Id(1, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(
range_all.next(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc1.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next(),
Some(("1", "aa".into(), ExId::Id(1, actor2.clone(), 1)))
);
assert_eq!(
range_all.next(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(
range_all.next(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
let mut range_all = doc1.map_range_at(ROOT, .., &heads);
assert_eq!(
range_all.next_back(),
Some(("3", "cc".into(), ExId::Id(3, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("2", "bb".into(), ExId::Id(2, actor2.clone(), 1)))
);
assert_eq!(
range_all.next_back(),
Some(("1", "aa".into(), ExId::Id(1, actor2, 1)))
);
assert_eq!(range_all.next_back(), None);
assert_eq!(range_all.next(), None);
}
#[test]
fn insert_at_index() {
let mut doc = AutoCommit::new();

View file

@ -98,7 +98,7 @@ pub(crate) enum QueryResult {
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct Index {
/// The map of visible elements to the number of operations targetting them.
/// The map of visible keys to the number of visible operations for that key.
pub(crate) visible: HashMap<Key, usize, FxBuildHasher>,
/// Set of opids found in this node and below.
pub(crate) ops: HashSet<OpId, FxBuildHasher>,

View file

@ -74,6 +74,7 @@ impl<'a, R: RangeBounds<String>> DoubleEndedIterator for MapRange<'a, R> {
for i in (self.index..self.index_back).rev() {
let op = self.root_child.get(i)?;
self.index_back -= 1;
if Some(op.key) != self.last_key_back && op.visible() {
self.last_key_back = Some(op.key);
let prop = match op.key {
@ -85,6 +86,21 @@ impl<'a, R: RangeBounds<String>> DoubleEndedIterator for MapRange<'a, R> {
}
}
}
// we're now overlapping the index and index_back so try and take the result from the next query
if let Some((prop, a, b)) = self.next_result.take() {
let last_prop = match self.last_key_back {
None => None,
Some(Key::Map(u)) => Some(self.meta.props.get(u).as_str()),
Some(Key::Seq(_)) => None,
};
// we can only use this result if we haven't ended in the prop's state (to account for
// conflicts).
if Some(prop) != last_prop {
return Some((prop, a, b));
}
}
None
}
}

View file

@ -99,6 +99,21 @@ impl<'a, R: RangeBounds<String>> DoubleEndedIterator for MapRangeAt<'a, R> {
}
}
}
// we're now overlapping the index and index_back so try and take the result from the next query
if let Some((prop, a, b)) = self.next_result.take() {
let last_prop = match self.last_key_back {
None => None,
Some(Key::Map(u)) => Some(self.meta.props.get(u).as_str()),
Some(Key::Seq(_)) => None,
};
// we can only use this result if we haven't ended in the prop's state (to account for
// conflicts).
if Some(prop) != last_prop {
return Some((prop, a, b));
}
}
None
}
}