cranpose_core/node_marks.rs
1//! A small value for each applier node, kept in the applier's dense node
2//! order: one walk over the tree reads and sets a node's mark with the two
3//! array reads that find its storage, where a hash set hashed the id and
4//! probed its groups.
5
6use crate::{MemoryApplier, NodeId, collections::map::HashMap};
7
8/// Marks on the nodes of one [`MemoryApplier`], for one walk over its tree.
9///
10/// A mark is a byte; an unmarked node reads `0`. Marks stay until
11/// [`NodeMarks::reset`], and only a walk that leaves the applier's tree as it
12/// is may keep them: a node stored again in another place loses its mark.
13///
14/// ```
15/// use cranpose_core::{MemoryApplier, NodeId, NodeMarks};
16///
17/// let applier = MemoryApplier::new();
18/// let mut marks = NodeMarks::default();
19/// marks.reset(&applier);
20/// assert_eq!(marks.get(&applier, NodeId(7)), 0);
21/// marks.set(&applier, NodeId(7), 2);
22/// assert_eq!(marks.get(&applier, NodeId(7)), 2);
23/// ```
24#[derive(Clone, Default)]
25pub struct NodeMarks {
26 dense: Vec<u8>,
27 elsewhere: HashMap<NodeId, u8>,
28}
29
30impl NodeMarks {
31 /// Unmarks every node, with room for every node `applier` holds now.
32 pub fn reset(&mut self, applier: &MemoryApplier) {
33 self.dense.clear();
34 self.dense.resize(applier.state.nodes.len(), 0);
35 self.elsewhere.clear();
36 }
37
38 /// The mark of `id`: `0` while it has none.
39 #[inline]
40 pub fn get(&self, applier: &MemoryApplier, id: NodeId) -> u8 {
41 self.mark_at(MarkPlace::of(applier, id))
42 }
43
44 /// Adds the bits of `mark` to `id`'s mark, finding its storage once,
45 /// and returns the mark it had.
46 ///
47 /// ```
48 /// use cranpose_core::{MemoryApplier, NodeId, NodeMarks};
49 ///
50 /// let applier = MemoryApplier::new();
51 /// let mut marks = NodeMarks::default();
52 /// marks.reset(&applier);
53 /// assert_eq!(marks.add(&applier, NodeId(7), 1), 0);
54 /// assert_eq!(marks.add(&applier, NodeId(7), 2), 1);
55 /// assert_eq!(marks.get(&applier, NodeId(7)), 3);
56 /// ```
57 #[inline]
58 pub fn add(&mut self, applier: &MemoryApplier, id: NodeId, mark: u8) -> u8 {
59 let entry = self.entry_at(MarkPlace::of(applier, id));
60 let had = *entry;
61 *entry |= mark;
62 had
63 }
64
65 /// Adds the bits of `mark` to `id`'s mark and those of `ancestor_mark`
66 /// to the mark of each node above it, from its parent up to the first
67 /// that had them. Each node's storage is found once.
68 pub fn add_with_ancestors(
69 &mut self,
70 applier: &MemoryApplier,
71 id: NodeId,
72 mark: u8,
73 ancestor_mark: u8,
74 ) {
75 let mut place = MarkPlace::of(applier, id);
76 *self.entry_at(place) |= mark;
77 while let Some(parent) = applier.parent_at(place) {
78 place = MarkPlace::of(applier, parent);
79 let entry = self.entry_at(place);
80 let had = *entry;
81 *entry |= ancestor_mark;
82 if had & ancestor_mark == ancestor_mark {
83 break;
84 }
85 }
86 }
87
88 /// Marks `id` with `mark`.
89 #[inline]
90 pub fn set(&mut self, applier: &MemoryApplier, id: NodeId, mark: u8) {
91 *self.entry_at(MarkPlace::of(applier, id)) = mark;
92 }
93
94 #[inline]
95 pub(crate) fn mark_at(&self, place: MarkPlace) -> u8 {
96 match place {
97 MarkPlace::Dense(slot) => self.dense.get(slot).copied().unwrap_or(0),
98 MarkPlace::Elsewhere(id) => self.elsewhere.get(&id).copied().unwrap_or(0),
99 }
100 }
101
102 #[inline]
103 pub(crate) fn entry_at(&mut self, place: MarkPlace) -> &mut u8 {
104 match place {
105 MarkPlace::Dense(slot) if slot < self.dense.len() => &mut self.dense[slot],
106 _ => self.grown_entry_at(place),
107 }
108 }
109
110 // The entry of a node stored past the room `reset` made, or kept apart.
111 #[cold]
112 #[inline(never)]
113 fn grown_entry_at(&mut self, place: MarkPlace) -> &mut u8 {
114 match place {
115 MarkPlace::Dense(slot) => {
116 self.dense.resize(slot + 1, 0);
117 &mut self.dense[slot]
118 }
119 MarkPlace::Elsewhere(id) => self.elsewhere.entry(id).or_insert(0),
120 }
121 }
122}
123
124// Where a node's mark is kept, and its node in the applier: the node's
125// dense storage slot, or its id for a node kept apart.
126#[derive(Clone, Copy)]
127pub(crate) enum MarkPlace {
128 Dense(usize),
129 Elsewhere(NodeId),
130}
131
132impl MarkPlace {
133 #[inline]
134 pub(crate) fn of(applier: &MemoryApplier, id: NodeId) -> Self {
135 applier
136 .resolve_node_index(id)
137 .map_or(Self::Elsewhere(id), Self::Dense)
138 }
139}