use crate::{
Mapping,
internal::{arena::ArenaId, debug_expect_unchecked, id::ClauseId},
solver::clause::{Literal, WatchedLiterals},
};
#[derive(Default)]
pub(crate) struct WatchMap {
map: Mapping<Literal, ClauseId>,
}
impl WatchMap {
#[cfg(feature = "diagnostics")]
pub fn len(&self) -> usize {
self.map.len()
}
#[cfg(feature = "diagnostics")]
pub fn size_in_bytes(&self) -> usize {
self.map.size_in_bytes()
}
pub(crate) fn start_watching(&mut self, clause: &mut WatchedLiterals, clause_id: ClauseId) {
for (watch_index, watched_literal) in clause.watched_literals.into_iter().enumerate() {
let current_head = self.map.get(watched_literal).copied();
clause.next_watches[watch_index] = current_head;
self.map.insert(watched_literal, clause_id);
}
}
pub fn cursor<'a>(
&'a mut self,
watches: &'a mut [Option<WatchedLiterals>],
literal: Literal,
) -> Option<WatchMapCursor<'a>> {
let clause_id = *self.map.get(literal)?;
let watched_literal = watches[clause_id.to_usize()]
.as_ref()
.expect("no watches found for clause");
let watch_index = if watched_literal.watched_literals[0] == literal {
0
} else {
debug_assert_eq!(
watched_literal.watched_literals[1], literal,
"the clause is not actually watching the literal"
);
1
};
Some(WatchMapCursor {
watch_map: self,
watches,
literal,
previous: None,
current: WatchNode {
clause_id,
watch_index,
},
})
}
}
struct WatchNode {
clause_id: ClauseId,
watch_index: usize,
}
pub struct WatchMapCursor<'a> {
watch_map: &'a mut WatchMap,
watches: &'a mut [Option<WatchedLiterals>],
literal: Literal,
previous: Option<WatchNode>,
current: WatchNode,
}
impl WatchMapCursor<'_> {
pub fn next(mut self) -> Option<Self> {
let next = self.next_node()?;
self.previous = Some(self.current);
self.current = next;
Some(self)
}
fn next_node(&self) -> Option<WatchNode> {
let current_watch = self.watched_literals();
let next_clause_id = current_watch.next_watches[self.current.watch_index]?;
let next_watch = self.watches[next_clause_id.to_usize()]
.as_ref()
.expect("watches are missing");
let next_clause_watch_index = if next_watch.watched_literals[0] == self.literal {
0
} else {
debug_assert_eq!(
next_watch.watched_literals[1], self.literal,
"the clause is not actually watching the literal"
);
1
};
Some(WatchNode {
clause_id: next_clause_id,
watch_index: next_clause_watch_index,
})
}
pub fn clause_id(&self) -> ClauseId {
self.current.clause_id
}
pub fn watched_literals(&self) -> &WatchedLiterals {
unsafe {
debug_expect_unchecked(
self.watches[self.current.clause_id.to_usize()].as_ref(),
"clause is not watching literals",
)
}
}
pub fn watch_index(&self) -> usize {
self.current.watch_index
}
pub fn update(mut self, new_watch: Literal) -> Option<Self> {
debug_assert_ne!(
new_watch, self.literal,
"cannot update watch to the same literal"
);
let clause_idx = self.current.clause_id.to_usize();
let next_node = self.next_node();
if let Some(previous) = &self.previous {
let previous_watches = unsafe {
debug_expect_unchecked(
self.watches[previous.clause_id.to_usize()].as_mut(),
"previous clause has no watches",
)
};
previous_watches.next_watches[previous.watch_index] =
next_node.as_ref().map(|node| node.clause_id);
} else if let Some(next_clause_id) = next_node.as_ref().map(|node| node.clause_id) {
self.watch_map.map.insert(self.literal, next_clause_id);
} else {
self.watch_map.map.unset(self.literal);
}
let watch = unsafe {
debug_expect_unchecked(
self.watches[clause_idx].as_mut(),
"clause is not watching literals",
)
};
watch.watched_literals[self.current.watch_index] = new_watch;
let previous_clause_id = self.watch_map.map.insert(new_watch, self.current.clause_id);
watch.next_watches[self.current.watch_index] = previous_clause_id;
self.current = next_node?;
Some(self)
}
}