1use std::cell::{Cell, RefCell};
22use std::collections::HashMap;
23
24use super::write::{ChangeResult, four_state_changed};
25use super::{FourStateValue, StateCellId};
26
27#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
30pub struct AliasWindow {
31 pub row: Option<u64>,
32 pub lo: u32,
33 pub width: u32,
34}
35
36#[derive(Clone, Copy, Debug)]
38pub(crate) struct ViewInfo {
39 pub root: StateCellId,
40 pub window: AliasWindow,
41}
42
43#[derive(Clone, Debug)]
46pub struct AliasChange {
47 pub cell: StateCellId,
48 pub old: FourStateValue,
49 pub new: FourStateValue,
50 pub no_edge: bool,
52}
53
54#[derive(Default)]
56pub(crate) struct ViewTable {
57 by_view: HashMap<StateCellId, ViewInfo>,
58 by_key: HashMap<(StateCellId, AliasWindow), StateCellId>,
59 of_root: HashMap<StateCellId, Vec<StateCellId>>,
60 pending: Vec<AliasChange>,
61 writing: Option<StateCellId>,
63}
64
65impl ViewTable {
66 pub(crate) fn existing(&self, root: StateCellId, window: AliasWindow) -> Option<StateCellId> {
67 self.by_key.get(&(root, window)).copied()
68 }
69
70 pub(crate) fn register(&mut self, view: StateCellId, root: StateCellId, window: AliasWindow) {
71 self.by_view.insert(view, ViewInfo { root, window });
72 self.by_key.insert((root, window), view);
73 self.of_root.entry(root).or_default().push(view);
74 }
75
76 pub(crate) fn info(&self, cell: StateCellId) -> Option<ViewInfo> {
77 self.by_view.get(&cell).copied()
78 }
79
80 pub(crate) fn begin_write(&mut self, view: StateCellId) {
81 self.writing = Some(view);
82 }
83
84 pub(crate) fn end_write(&mut self) {
85 self.writing = None;
86 }
87
88 pub(crate) fn take_pending(&mut self) -> Vec<AliasChange> {
89 std::mem::take(&mut self.pending)
90 }
91
92 fn note(&mut self, root: StateCellId, row: Option<u64>, result: &ChangeResult) {
95 let ViewTable {
96 by_view,
97 of_root,
98 pending,
99 writing,
100 ..
101 } = self;
102 if writing.is_some() {
103 pending.push(AliasChange {
104 cell: root,
105 old: result.old.clone(),
106 new: result.new.clone(),
107 no_edge: row.is_some(),
108 });
109 }
110 let Some(views) = of_root.get(&root) else {
111 return;
112 };
113 for &view in views {
114 if Some(view) == *writing {
115 continue;
116 }
117 let info = &by_view[&view];
118 if info.window.row != row {
119 continue;
120 }
121 let old = window_value(&result.old, info.window);
122 let new = window_value(&result.new, info.window);
123 if four_state_changed(&old, &new) {
124 pending.push(AliasChange {
125 cell: view,
126 old,
127 new,
128 no_edge: false,
129 });
130 }
131 }
132 }
133}
134
135#[derive(Default)]
138pub(crate) struct Views {
139 any: Cell<bool>,
140 table: RefCell<ViewTable>,
141}
142
143impl Views {
144 pub(crate) fn table(&self) -> std::cell::RefMut<'_, ViewTable> {
145 self.table.borrow_mut()
146 }
147
148 pub(crate) fn mark_any(&self) {
149 self.any.set(true);
150 }
151
152 pub(crate) fn info(&self, cell: StateCellId) -> Option<ViewInfo> {
153 if !self.any.get() {
154 return None;
155 }
156 self.table.borrow().info(cell)
157 }
158
159 #[inline]
160 pub(crate) fn note_change(&self, root: StateCellId, row: Option<u64>, result: &ChangeResult) {
161 if self.any.get() && result.changed {
162 self.table.borrow_mut().note(root, row, result);
163 }
164 }
165
166 pub(crate) fn take_pending(&self) -> Vec<AliasChange> {
167 if !self.any.get() {
168 return Vec::new();
169 }
170 self.table.borrow_mut().take_pending()
171 }
172}
173
174fn planes(v: &FourStateValue) -> (Vec<u64>, Vec<u64>) {
177 match v {
178 FourStateValue::Narrow(n) => (vec![*n as u64], vec![(*n >> 64) as u64]),
179 FourStateValue::Wide { aval, bval } => (
180 aval.iter().zip(bval).map(|(a, b)| a ^ b).collect(),
181 bval.clone(),
182 ),
183 }
184}
185
186fn extract_bits(src: &[u64], lo: u32, width: u32) -> Vec<u64> {
187 let n = width.div_ceil(64) as usize;
188 let mut out = Vec::with_capacity(n);
189 for i in 0..n {
190 let bit = lo as usize + 64 * i;
191 let (wi, sh) = (bit / 64, (bit % 64) as u32);
192 let mut w = src.get(wi).copied().unwrap_or(0) >> sh;
193 if sh != 0 {
194 w |= src.get(wi + 1).copied().unwrap_or(0) << (64 - sh);
195 }
196 out.push(w);
197 }
198 if !width.is_multiple_of(64)
199 && let Some(last) = out.last_mut()
200 {
201 *last &= (1u64 << (width % 64)) - 1;
202 }
203 out
204}
205
206fn insert_bits(dst: &mut [u64], lo: u32, width: u32, src: &[u64]) {
207 let n = width.div_ceil(64) as usize;
208 for i in 0..n {
209 let chunk = (width as usize - 64 * i).min(64) as u32;
210 let m = if chunk == 64 {
211 u64::MAX
212 } else {
213 (1u64 << chunk) - 1
214 };
215 let v = src.get(i).copied().unwrap_or(0) & m;
216 let bit = lo as usize + 64 * i;
217 let (wi, sh) = (bit / 64, (bit % 64) as u32);
218 dst[wi] = (dst[wi] & !(m << sh)) | (v << sh);
219 if sh != 0 && sh + chunk > 64 {
220 dst[wi + 1] = (dst[wi + 1] & !(m >> (64 - sh))) | (v >> (64 - sh));
221 }
222 }
223}
224
225pub fn window_value(root: &FourStateValue, window: AliasWindow) -> FourStateValue {
228 let (val, unk) = planes(root);
229 let val = extract_bits(&val, window.lo, window.width);
230 let unk = extract_bits(&unk, window.lo, window.width);
231 if window.width <= 64 {
232 FourStateValue::Narrow(u128::from(val[0]) | (u128::from(unk[0]) << 64))
233 } else {
234 FourStateValue::Wide {
235 aval: val.iter().zip(&unk).map(|(v, u)| v ^ u).collect(),
236 bval: unk,
237 }
238 }
239}
240
241pub fn splice_window(
243 root: &FourStateValue,
244 window: AliasWindow,
245 new: &FourStateValue,
246) -> FourStateValue {
247 let (mut val, mut unk) = planes(root);
248 let (nv, nu) = planes(new);
249 insert_bits(&mut val, window.lo, window.width, &nv);
250 insert_bits(&mut unk, window.lo, window.width, &nu);
251 match root {
252 FourStateValue::Narrow(_) => {
253 FourStateValue::Narrow(u128::from(val[0]) | (u128::from(unk[0]) << 64))
254 }
255 FourStateValue::Wide { .. } => FourStateValue::Wide {
256 aval: val.iter().zip(&unk).map(|(v, u)| v ^ u).collect(),
257 bval: unk,
258 },
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265
266 fn w(row: Option<u64>, lo: u32, width: u32) -> AliasWindow {
267 AliasWindow { row, lo, width }
268 }
269
270 #[test]
271 fn narrow_window_round_trips() {
272 let root = FourStateValue::Narrow(0x00AB_CDEF);
273 let win = w(None, 8, 8);
274 match window_value(&root, win) {
275 FourStateValue::Narrow(v) => assert_eq!(v, 0xCD),
276 other => panic!("{other:?}"),
277 }
278 match splice_window(&root, win, &FourStateValue::Narrow(0x12)) {
279 FourStateValue::Narrow(v) => assert_eq!(v, 0x00AB_12EF),
280 other => panic!("{other:?}"),
281 }
282 }
283
284 #[test]
285 fn unknown_bits_travel_with_the_window() {
286 let root = FourStateValue::Narrow(0x0000_0000_0000_0005 | (0xF0u128 << 64));
288 let win = w(None, 4, 4);
289 match window_value(&root, win) {
290 FourStateValue::Narrow(v) => assert_eq!(v, 0xF_u128 << 64),
291 other => panic!("{other:?}"),
292 }
293 }
294
295 #[test]
296 fn wide_window_straddling_a_word_boundary() {
297 let root = FourStateValue::Wide {
299 aval: vec![u64::MAX, u64::MAX],
300 bval: vec![0, 0],
301 };
302 let win = w(None, 60, 8);
303 match window_value(&root, win) {
304 FourStateValue::Narrow(v) => assert_eq!(v, 0xFF),
305 other => panic!("{other:?}"),
306 }
307 let cleared = splice_window(&root, win, &FourStateValue::Narrow(0));
308 match cleared {
309 FourStateValue::Wide { aval, bval } => {
310 assert_eq!(aval, vec![0x0FFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFF0]);
311 assert_eq!(bval, vec![0, 0]);
312 }
313 other => panic!("{other:?}"),
314 }
315 }
316
317 #[test]
318 fn window_wider_than_a_word_is_wide() {
319 let root = FourStateValue::Wide {
320 aval: vec![0x1111, 0x2222, 0x3333],
321 bval: vec![0, 0, 0],
322 };
323 match window_value(&root, w(None, 64, 100)) {
324 FourStateValue::Wide { aval, bval } => {
325 assert_eq!(aval, vec![0x2222, 0x3333 & 0xF_FFFF_FFFF]);
326 assert_eq!(bval, vec![0, 0]);
327 }
328 other => panic!("{other:?}"),
329 }
330 }
331}