Skip to content

Commit a883a57

Browse files
authored
Merge pull request #565 from ratmice/vacant_marking
Replace a misuse prone internal API with a better one.
2 parents 361316d + 4137927 commit a883a57

File tree

2 files changed

+100
-11
lines changed

2 files changed

+100
-11
lines changed

cfgrammar/src/lib/markmap.rs

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,41 @@ impl<'a, K: Ord + Clone, V> VacantEntry<'a, K, V> {
122122
}
123123
}
124124

125-
/// Inserts the key into the `MarkMap`.
126-
///
127-
/// If you want to insert a value into the `MarkMap` use `insert` or `insert_entry` instead.
128-
/// This function can be used if you want to mark a vacant key as `required` or `used`.
129-
pub fn occupied_entry(self) -> OccupiedEntry<'a, K, V> {
125+
/// Marks the key associated with this entry as required.
126+
pub fn mark_required(&mut self) {
130127
match self.pos {
131128
Ok(pos) => {
132-
self.map.contents[pos].2 = None;
133-
OccupiedEntry { pos, map: self.map }
129+
let repr = self.map.contents[pos].1;
130+
self.map.contents[pos].1 = repr | Mark::Required.repr();
134131
}
135132
Err(pos) => {
136-
self.map.contents.insert(pos, (self.key, 0, None));
137-
OccupiedEntry { pos, map: self.map }
133+
self.map
134+
.contents
135+
.insert(pos, (self.key.clone(), Mark::Required.repr(), None));
136+
self.pos = Ok(pos)
137+
}
138+
}
139+
}
140+
141+
/// Sets the merge behavior for the key associated with this entry.
142+
pub fn set_merge_behavior(&mut self, mb: MergeBehavior) {
143+
match self.pos {
144+
Ok(pos) => {
145+
let merge_reprs = Mark::MergeBehavior(MergeBehavior::MutuallyExclusive).repr()
146+
| Mark::MergeBehavior(MergeBehavior::Ours).repr()
147+
| Mark::MergeBehavior(MergeBehavior::Theirs).repr();
148+
let mut repr = self.map.contents[pos].1;
149+
// Zap just the MergeBehavior bits.
150+
repr ^= repr & merge_reprs;
151+
repr |= Mark::MergeBehavior(mb).repr();
152+
self.map.contents[pos].1 = repr;
153+
}
154+
Err(pos) => {
155+
self.map.contents.insert(
156+
pos,
157+
(self.key.clone(), Mark::MergeBehavior(mb).repr(), None),
158+
);
159+
self.pos = Ok(pos)
138160
}
139161
}
140162
}
@@ -208,6 +230,9 @@ pub struct OccupiedEntry<'a, K, V> {
208230
/// A view into a vacant entry in a `MarkMap`. It is part of the `Entry` enum.
209231
#[doc(hidden)]
210232
pub struct VacantEntry<'a, K, V> {
233+
// The values of the `pos` result imply:
234+
// * When `Ok(pos)` the key was found at `pos`, and it's value was `None`.
235+
// * When `Err(pos)` the key was not found at `pos`.
211236
pos: Result<usize, usize>,
212237
key: K,
213238
map: &'a mut MarkMap<K, V>,
@@ -905,4 +930,68 @@ mod test {
905930
vec![(&"a", &"mm"), (&"b", &"mm2"), (&"x", &"mm2")]
906931
);
907932
}
933+
934+
#[test]
935+
fn test_vacant_entry_required() {
936+
let mut mm = MarkMap::new();
937+
// To test the first case we want a marked key with no value associated to it.
938+
mm.mark_used(&"a");
939+
let e = mm.entry("a");
940+
match e {
941+
Entry::Occupied(_) => panic!("Expected unoccupied entry"),
942+
Entry::Vacant(mut e) => {
943+
e.mark_required();
944+
e.insert_entry("a");
945+
}
946+
}
947+
assert!(mm.is_required(&"a"));
948+
assert!(mm.is_used(&"a"));
949+
// For the second case we want an unmarked key with another key in it's binary search pos.
950+
mm.insert("c", "c");
951+
let e = mm.entry("b");
952+
match e {
953+
Entry::Occupied(_) => panic!("Expected unoccupied entry"),
954+
Entry::Vacant(mut e) => {
955+
e.mark_required();
956+
}
957+
}
958+
assert!(mm.is_required(&"b"));
959+
assert!(!mm.is_required(&"c"));
960+
}
961+
962+
#[test]
963+
fn test_vacant_entry_merge_behavior() {
964+
let mut mm = MarkMap::new();
965+
// To test the first case we want a marked key with no value associated to it.
966+
mm.mark_used(&"a");
967+
let mut mm2 = MarkMap::new();
968+
mm2.insert("a", "a2");
969+
mm2.insert("a", "c2");
970+
let e = mm.entry("a");
971+
match e {
972+
Entry::Occupied(_) => panic!("Expected unoccupied entry"),
973+
Entry::Vacant(mut e) => {
974+
e.set_merge_behavior(MergeBehavior::Ours);
975+
e.insert_entry("a1");
976+
}
977+
}
978+
assert_eq!(
979+
mm.get_mark(&"a"),
980+
Some(Mark::MergeBehavior(MergeBehavior::Ours).repr() | Mark::Used.repr())
981+
);
982+
// For the second case we want an unmarked key with another key in it's binary search pos.
983+
mm.insert("c", "c");
984+
let e = mm.entry("b");
985+
match e {
986+
Entry::Occupied(_) => panic!("Expected unoccupied entry"),
987+
Entry::Vacant(mut e) => {
988+
e.set_merge_behavior(MergeBehavior::Theirs);
989+
}
990+
}
991+
assert_eq!(
992+
mm.get_mark(&"b"),
993+
Some(Mark::MergeBehavior(MergeBehavior::Theirs).repr())
994+
);
995+
assert_eq!(mm.get_mark(&"c"), Some(0));
996+
}
908997
}

lrpar/src/lib/ctbuilder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ where
522522

523523
match header.entry("yacckind".to_string()) {
524524
Entry::Occupied(_) => unreachable!(),
525-
Entry::Vacant(v) => match self.yacckind {
525+
Entry::Vacant(mut v) => match self.yacckind {
526526
Some(YaccKind::Eco) => panic!("Eco compile-time grammar generation not supported."),
527527
Some(yk) => {
528528
let yk_value = Value::try_from(yk)?;
@@ -533,7 +533,7 @@ where
533533
o.set_merge_behavior(MergeBehavior::Ours);
534534
}
535535
None => {
536-
v.occupied_entry().mark_required();
536+
v.mark_required();
537537
}
538538
},
539539
}

0 commit comments

Comments
 (0)