1use std::collections::HashMap;
22
23use super::{FourStateValue, StateCellId};
24
25pub type Site = (u64, u64);
28
29struct Layer {
31 mask: Vec<u64>,
33 value: FourStateValue,
35 sites: Vec<Site>,
37}
38
39impl Layer {
40 fn new(width_words: usize, value: FourStateValue) -> Self {
41 Layer {
42 mask: vec![0; width_words],
43 value,
44 sites: Vec::new(),
45 }
46 }
47
48 fn is_empty(&self) -> bool {
49 self.mask.iter().all(|&m| m == 0)
50 }
51}
52
53struct Forced {
54 driven: FourStateValue,
56 restores: bool,
59 assign: Option<Layer>,
61 force: Option<Layer>,
63}
64
65impl Forced {
66 fn visible(&self) -> FourStateValue {
69 let mut v = self.driven.clone();
70 for layer in [&self.assign, &self.force].into_iter().flatten() {
71 v = merge(&v, &layer.value, &layer.mask);
72 }
73 v
74 }
75}
76
77#[derive(Default)]
79pub struct ForceTable {
80 forced: HashMap<StateCellId, Forced>,
81 rows: HashMap<(StateCellId, u32), Forced>,
86 active_sites: HashMap<Site, usize>,
88 bypass: bool,
90}
91
92impl ForceTable {
93 pub(crate) fn filter(&mut self, cell: StateCellId, new: FourStateValue) -> FourStateValue {
96 if self.bypass {
97 return new;
98 }
99 match self.forced.get_mut(&cell) {
100 Some(e) => {
101 e.driven = new;
102 e.visible()
103 }
104 None => new,
105 }
106 }
107
108 pub(crate) fn filter_row(
110 &mut self,
111 cell: StateCellId,
112 at: u32,
113 new: FourStateValue,
114 ) -> FourStateValue {
115 if self.bypass {
116 return new;
117 }
118 match self.rows.get_mut(&(cell, at)) {
119 Some(e) => {
120 e.driven = new;
121 e.visible()
122 }
123 None => new,
124 }
125 }
126
127 pub(crate) fn contains(&self, cell: StateCellId) -> bool {
130 self.forced.contains_key(&cell)
131 }
132
133 pub(crate) fn driven_value(&self, cell: StateCellId) -> Option<FourStateValue> {
136 self.forced.get(&cell).map(|e| e.driven.clone())
137 }
138
139 pub(crate) fn is_empty(&self) -> bool {
141 self.forced.is_empty() && self.rows.is_empty()
142 }
143
144 #[allow(clippy::too_many_arguments)]
149 pub fn force(
150 &mut self,
151 cell: StateCellId,
152 value: FourStateValue,
153 mask: Vec<u64>,
154 restores: bool,
155 site: Site,
156 current: FourStateValue,
157 procedural: bool,
158 ) -> FourStateValue {
159 let e = self.forced.entry(cell).or_insert_with(|| Forced {
160 driven: current,
161 restores,
162 assign: None,
163 force: None,
164 });
165 apply_force(e, &mut self.active_sites, value, mask, site, procedural)
166 }
167
168 #[allow(clippy::too_many_arguments)]
170 pub fn force_row(
171 &mut self,
172 cell: StateCellId,
173 at: u32,
174 value: FourStateValue,
175 mask: Vec<u64>,
176 restores: bool,
177 site: Site,
178 current: FourStateValue,
179 procedural: bool,
180 ) -> FourStateValue {
181 let e = self.rows.entry((cell, at)).or_insert_with(|| Forced {
182 driven: current,
183 restores,
184 assign: None,
185 force: None,
186 });
187 apply_force(e, &mut self.active_sites, value, mask, site, procedural)
188 }
189
190 pub fn release(
197 &mut self,
198 cell: StateCellId,
199 mask: &[u64],
200 procedural: bool,
201 ) -> Option<FourStateValue> {
202 let e = self.forced.get_mut(&cell)?;
203 let out = apply_release(e, &mut self.active_sites, mask, procedural);
204 if e.assign.is_none() && e.force.is_none() {
205 self.forced.remove(&cell);
206 }
207 out
208 }
209
210 pub fn release_row(
212 &mut self,
213 cell: StateCellId,
214 at: u32,
215 mask: &[u64],
216 procedural: bool,
217 ) -> Option<FourStateValue> {
218 let e = self.rows.get_mut(&(cell, at))?;
219 let out = apply_release(e, &mut self.active_sites, mask, procedural);
220 if e.assign.is_none() && e.force.is_none() {
221 self.rows.remove(&(cell, at));
222 }
223 out
224 }
225
226 pub fn site_active(&self, site: Site) -> bool {
229 self.active_sites.contains_key(&site)
230 }
231
232 pub fn set_bypass(&mut self, on: bool) {
234 self.bypass = on;
235 }
236}
237
238fn apply_force(
241 e: &mut Forced,
242 active_sites: &mut HashMap<Site, usize>,
243 value: FourStateValue,
244 mask: Vec<u64>,
245 site: Site,
246 procedural: bool,
247) -> FourStateValue {
248 let slot = if procedural {
249 &mut e.assign
250 } else {
251 &mut e.force
252 };
253 let layer = slot.get_or_insert_with(|| Layer::new(mask.len(), value.clone()));
254 layer.value = merge(&layer.value, &value, &mask);
255 for (m, n) in layer.mask.iter_mut().zip(&mask) {
256 *m |= n;
257 }
258 if !layer.sites.contains(&site) {
259 layer.sites.push(site);
260 *active_sites.entry(site).or_insert(0) += 1;
261 }
262 e.visible()
263}
264
265fn apply_release(
269 e: &mut Forced,
270 active_sites: &mut HashMap<Site, usize>,
271 mask: &[u64],
272 procedural: bool,
273) -> Option<FourStateValue> {
274 let before = e.visible();
275 let slot = if procedural {
276 &mut e.assign
277 } else {
278 &mut e.force
279 };
280 let layer = slot.as_mut()?;
281 for (m, r) in layer.mask.iter_mut().zip(mask) {
282 *m &= !r;
283 }
284 let mut freed = Vec::new();
285 if layer.is_empty() {
286 freed = std::mem::take(&mut layer.sites);
287 *slot = None;
288 }
289 for site in freed {
290 if let Some(n) = active_sites.get_mut(&site) {
291 *n -= 1;
292 if *n == 0 {
293 active_sites.remove(&site);
294 }
295 }
296 }
297 if !e.restores {
300 e.driven = before.clone();
301 }
302 let after = e.visible();
303 (!same(&after, &before)).then_some(after)
304}
305
306fn same(a: &FourStateValue, b: &FourStateValue) -> bool {
308 match (a, b) {
309 (FourStateValue::Narrow(x), FourStateValue::Narrow(y)) => x == y,
310 (
311 FourStateValue::Wide { aval: xa, bval: xb },
312 FourStateValue::Wide { aval: ya, bval: yb },
313 ) => xa == ya && xb == yb,
314 _ => false,
315 }
316}
317
318fn merge(base: &FourStateValue, forced: &FourStateValue, mask: &[u64]) -> FourStateValue {
320 match (base, forced) {
321 (FourStateValue::Narrow(b), FourStateValue::Narrow(v)) => {
322 let m = u128::from(mask.first().copied().unwrap_or(0));
323 let m = m | (m << 64);
324 FourStateValue::Narrow((b & !m) | (v & m))
325 }
326 (
327 FourStateValue::Wide { aval: ba, bval: bb },
328 FourStateValue::Wide { aval: fa, bval: fb },
329 ) => {
330 let pick = |b: &[u64], f: &[u64]| -> Vec<u64> {
331 b.iter()
332 .enumerate()
333 .map(|(i, &w)| {
334 let m = mask.get(i).copied().unwrap_or(0);
335 (w & !m) | (f.get(i).copied().unwrap_or(0) & m)
336 })
337 .collect()
338 };
339 FourStateValue::Wide {
340 aval: pick(ba, fa),
341 bval: pick(bb, fb),
342 }
343 }
344 _ => base.clone(),
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use super::*;
351
352 #[test]
353 fn forced_bits_win_and_a_released_net_returns_to_its_driven_value() {
354 let mut t = ForceTable::default();
355 let cell = StateCellId(3);
356 let now = FourStateValue::Narrow(0x5);
357 let written = t.force(
358 cell,
359 FourStateValue::Narrow(0xA0),
360 vec![0xF0],
361 true,
362 (9, 7),
363 now,
364 false,
365 );
366 assert!(matches!(written, FourStateValue::Narrow(0xA5)));
367 assert!(t.site_active((9, 7)));
368 assert!(
369 !t.site_active((8, 7)),
370 "another instance's statement is not in effect"
371 );
372 assert!(matches!(
374 t.filter(cell, FourStateValue::Narrow(0x33)),
375 FourStateValue::Narrow(0xA3)
376 ));
377 assert!(matches!(
378 t.release(cell, &[0xF0], false),
379 Some(FourStateValue::Narrow(0x33))
380 ));
381 assert!(!t.site_active((9, 7)));
382 assert!(matches!(
383 t.filter(cell, FourStateValue::Narrow(0x44)),
384 FourStateValue::Narrow(0x44)
385 ));
386 }
387
388 #[test]
389 fn a_released_variable_keeps_its_value() {
390 let mut t = ForceTable::default();
391 let cell = StateCellId(4);
392 t.force(
393 cell,
394 FourStateValue::Narrow(9),
395 vec![0xF],
396 false,
397 (1, 1),
398 FourStateValue::Narrow(2),
399 false,
400 );
401 assert!(matches!(
402 t.filter(cell, FourStateValue::Narrow(7)),
403 FourStateValue::Narrow(9)
404 ));
405 assert!(t.release(cell, &[0xF], false).is_none());
406 assert!(matches!(
408 t.filter(cell, FourStateValue::Narrow(7)),
409 FourStateValue::Narrow(7)
410 ));
411 }
412
413 #[test]
418 fn force_overrides_assign_and_release_restores_it() {
419 let mut t = ForceTable::default();
420 let cell = StateCellId(5);
421 let n = |v: u128| FourStateValue::Narrow(v);
422 let assign = (1, 10);
423 let force = (1, 20);
424 assert!(matches!(
425 t.force(cell, n(3), vec![0xF], false, assign, n(1), true),
426 FourStateValue::Narrow(3)
427 ));
428 assert!(
429 matches!(t.filter(cell, n(8)), FourStateValue::Narrow(3)),
430 "assign beats writes"
431 );
432 assert!(matches!(
433 t.force(cell, n(5), vec![0xF], false, force, n(3), false),
434 FourStateValue::Narrow(5)
435 ));
436 assert!(matches!(
438 t.force(cell, n(6), vec![0xF], false, assign, n(5), true),
439 FourStateValue::Narrow(5)
440 ));
441 assert!(
442 matches!(
443 t.release(cell, &[0xF], false),
444 Some(FourStateValue::Narrow(6))
445 ),
446 "the assign shows through"
447 );
448 assert!(t.site_active(assign) && !t.site_active(force));
449 t.force(cell, n(9), vec![0xF], false, force, n(6), false);
451 assert!(t.release(cell, &[0xF], true).is_none());
452 assert!(t.release(cell, &[0xF], false).is_none(), "keeps 9");
453 assert!(
454 matches!(t.filter(cell, n(2)), FourStateValue::Narrow(2)),
455 "nothing holds it now"
456 );
457 }
458}