use crate::reg::Reg;
use crate::{nid,nid::NID};
use crate::vid::VID;
use crate::vhl::{HiLoPart, HiLoBase};
pub trait CursorPlan : HiLoBase {
fn includes_leaf(&self, n:NID)->bool { n == nid::I }
fn includes_lo(&self, n:NID)->bool { n != nid::O }
}
#[derive(Debug)]
pub struct Cursor {
pub nvars: usize,
pub node: NID,
pub invert: bool,
pub nstack: Vec<NID>,
pub istack: Vec<bool>,
pub scope: Reg,
pub can_skip: Reg,
pub watch: Reg }
impl Cursor {
pub fn new(nvars:usize, node:NID)->Self {
Cursor {
nvars,
node,
invert: false, scope: Reg::new(nvars),
can_skip: Reg::new(nvars), watch: Reg::new(nvars), nstack: vec![],
istack: vec![]}}
pub fn new_with_watch(nvars:usize, node:NID, watch:Reg)->Self {
Self { watch, ..Self::new(nvars, node) }}
fn push_node(&mut self, node:NID) {
self.istack.push(self.invert);
self.nstack.push(self.node);
self.node = node;
self.invert = node.is_inv() && !node.is_const() }
fn pop_node(&mut self) {
assert!(!self.nstack.is_empty());
self.invert = self.istack.pop().expect("istack.pop() should have worked, as len>0");
self.node = self.nstack.pop().expect("nstack.pop() should have worked, as len>0"); }
pub fn step_up(&mut self)->NID {
self.pop_node();
self.node }
pub fn at_top(&self)->bool { self.nstack.is_empty() }
fn step_down(&mut self, base: &dyn CursorPlan, which:HiLoPart) {
let hl = base.get_hilo(self.node).expect("node not found for step_down");
self.push_node(hl.get_part(which)); }
pub fn put_step(&mut self, base:&dyn CursorPlan, val:bool) {
self.scope.var_put(self.node.vid(), val);
if val { self.step_down(base, HiLoPart::HiPart) }
else { self.step_down(base, HiLoPart::LoPart) }}
pub fn dontcares(&self)->Vec<usize> {
println!("self.can_skip = {:?}", self.can_skip);
println!("self.watch.= {:?}", self.watch);
let mut res = vec![];
for i in self.can_skip.hi_bits() {
if !self.watch.get(i) { res.push(i) }}
res }
pub fn cube(&self)->Vec<(VID,bool)> {
let mut res = vec![];
for i in 0..self.nvars {
if self.watch.get(i) || !self.can_skip.get(i) {
res.push((VID::var(i as u32), self.scope.get(i))) }}
res }
pub fn descend(&mut self, base: &dyn CursorPlan) {
while !self.node.is_const() {
let hl = base.get_hilo(self.node).expect("couldn't get_hilo");
let choice = !base.includes_lo(hl.lo);
self.put_step(base, choice) }}
pub fn var_get(&self)->bool {
self.scope.var_get(self.node.vid()) }
pub fn ascend(&mut self) {
let mut bv = self.node.vid();
while self.scope.var_get(bv) && !self.nstack.is_empty() {
bv = self.step_up().vid(); }}
pub fn clear_trailing_bits(&mut self) {
let bi = self.node.vid().var_ix();
for i in 0..bi { self.scope.put(i, false) }}
pub fn increment(&mut self) -> Option<usize> {
let len = self.scope.data.len();
for i in 0..len { self.scope.data[i] |= self.can_skip.data[i] & (!self.watch.data[i]); }
if let Some(zpos) = self.scope.increment() {
let vz = VID::var(zpos as u32);
while !self.nstack.is_empty()
&& !vz.is_below(&self.nstack[self.nstack.len()-1].vid()) {
self.pop_node(); }
Some(zpos) }
else { None }}}