Skip to main content

steel_core/java_block_pos_set/
tree.rs

1use std::cmp::Ordering;
2use steel_utils::BlockPos;
3
4use super::{EMPTY, EqualHashOrder, JavaBlockPosSet, UNTREEIFY_THRESHOLD, spread};
5
6pub(super) struct Links {
7    pub(super) parent: u32,
8    pub(super) left: u32,
9    pub(super) right: u32,
10    pub(super) prev: u32,
11    pub(super) red: bool,
12}
13
14impl Links {
15    const EMPTY: Self = Self {
16        parent: EMPTY,
17        left: EMPTY,
18        right: EMPTY,
19        prev: EMPTY,
20        red: false,
21    };
22}
23
24impl JavaBlockPosSet {
25    pub(super) fn tree_root(&self, mut node: u32) -> u32 {
26        while self.links(node).parent != EMPTY {
27            node = self.links(node).parent;
28        }
29        node
30    }
31
32    pub(super) fn links(&self, node: u32) -> &Links {
33        &self.trees[&node]
34    }
35
36    pub(super) fn links_mut(&mut self, node: u32) -> &mut Links {
37        match self.trees.get_mut(&node) {
38            Some(links) => links,
39            None => panic!("tree bin entry has no tree links"),
40        }
41    }
42
43    fn reset_links(&mut self, node: u32) {
44        self.trees.insert(node, Links::EMPTY);
45    }
46
47    pub(super) fn find_in_tree(&self, mut node: u32, hash: i32, pos: BlockPos) -> bool {
48        while node != EMPTY {
49            let entry = &self.entries[node as usize];
50            let links = self.links(node);
51            let node_hash = spread(entry.pos);
52            match hash.cmp(&node_hash) {
53                Ordering::Less => node = links.left,
54                Ordering::Greater => node = links.right,
55                Ordering::Equal => {
56                    if entry.pos == pos || self.find_in_tree(links.right, hash, pos) {
57                        return true;
58                    }
59                    node = links.left;
60                }
61            }
62        }
63        false
64    }
65
66    fn goes_left(&self, node: u32, parent: u32) -> bool {
67        let hash = spread(self.entries[node as usize].pos);
68        let parent_hash = spread(self.entries[parent as usize].pos);
69        if hash != parent_hash {
70            return hash < parent_hash;
71        }
72        match self.equal_hash_order {
73            EqualHashOrder::Insertion => node < parent,
74            EqualHashOrder::Coordinates => {
75                let pos = self.entries[node as usize].pos;
76                let parent_pos = self.entries[parent as usize].pos;
77                (pos.y(), pos.z(), pos.x()) < (parent_pos.y(), parent_pos.z(), parent_pos.x())
78            }
79        }
80    }
81
82    fn attach(&mut self, root: u32, node: u32) -> u32 {
83        let mut parent = root;
84        loop {
85            let left = self.goes_left(node, parent);
86            let child = if left {
87                self.links(parent).left
88            } else {
89                self.links(parent).right
90            };
91            if child != EMPTY {
92                parent = child;
93                continue;
94            }
95            self.links_mut(node).parent = parent;
96            if left {
97                self.links_mut(parent).left = node;
98            } else {
99                self.links_mut(parent).right = node;
100            }
101            return parent;
102        }
103    }
104
105    pub(super) fn split_tree(&mut self, index: usize, head: u32, bit: usize) {
106        let mut counts = [0; 2];
107        let mut current = head;
108        while current != EMPTY {
109            let next = self.entries[current as usize].next;
110            let side =
111                usize::from(spread(self.entries[current as usize].pos) as u32 as usize & bit != 0);
112            let target = index + side * bit;
113            let bucket = self.buckets[target];
114            self.links_mut(current).prev = if bucket.head == EMPTY {
115                EMPTY
116            } else {
117                bucket.tail
118            };
119            self.append(target, current);
120            counts[side] += 1;
121            current = next;
122        }
123        for side in 0..2 {
124            if counts[side] <= UNTREEIFY_THRESHOLD {
125                // Untreeification preserves the split list's linked order.
126                continue;
127            }
128            let target = index + side * bit;
129            self.buckets[target].tail = EMPTY;
130            // Java keeps an unsplit tree's shape.
131            if counts[1 - side] != 0 {
132                self.treeify(target);
133            }
134        }
135    }
136
137    pub(super) fn treeify(&mut self, bucket: usize) {
138        let mut node = self.buckets[bucket].head;
139        let mut root = EMPTY;
140        let mut prev = EMPTY;
141        while node != EMPTY {
142            self.reset_links(node);
143            self.links_mut(node).prev = prev;
144            if root == EMPTY {
145                root = node;
146            } else {
147                self.attach(root, node);
148                root = self.balance_insertion(root, node);
149            }
150            prev = node;
151            node = self.entries[node as usize].next;
152        }
153        self.buckets[bucket].tail = EMPTY;
154        self.move_root_to_front(bucket, root);
155    }
156
157    pub(super) fn insert_tree(&mut self, bucket: usize, node: u32) {
158        self.reset_links(node);
159        let root = self.tree_root(self.buckets[bucket].head);
160        let parent = self.attach(root, node);
161        let next = self.entries[parent as usize].next;
162        self.entries[parent as usize].next = node;
163        self.entries[node as usize].next = next;
164        self.links_mut(node).prev = parent;
165        if next != EMPTY {
166            self.links_mut(next).prev = node;
167        }
168        let root = self.balance_insertion(root, node);
169        self.move_root_to_front(bucket, root);
170    }
171
172    fn move_root_to_front(&mut self, bucket: usize, root: u32) {
173        debug_assert_eq!(self.links(root).parent, EMPTY);
174        let first = self.buckets[bucket].head;
175        if root == first {
176            return;
177        }
178        let next = self.entries[root as usize].next;
179        let prev = self.links(root).prev;
180        if next != EMPTY {
181            self.links_mut(next).prev = prev;
182        }
183        if prev != EMPTY {
184            self.entries[prev as usize].next = next;
185        }
186        self.links_mut(first).prev = root;
187        self.entries[root as usize].next = first;
188        self.links_mut(root).prev = EMPTY;
189        self.buckets[bucket].head = root;
190    }
191
192    // Both rotations change only the tree; iteration still follows next/prev.
193    pub(super) fn rotate(&mut self, mut root: u32, node: u32, left: bool) -> u32 {
194        let pivot = if left {
195            self.links(node).right
196        } else {
197            self.links(node).left
198        };
199        let inner = if left {
200            self.links(pivot).left
201        } else {
202            self.links(pivot).right
203        };
204        if left {
205            self.links_mut(node).right = inner;
206        } else {
207            self.links_mut(node).left = inner;
208        }
209        if inner != EMPTY {
210            self.links_mut(inner).parent = node;
211        }
212        let parent = self.links(node).parent;
213        self.links_mut(pivot).parent = parent;
214        if parent == EMPTY {
215            root = pivot;
216            self.links_mut(pivot).red = false;
217        } else if self.links(parent).left == node {
218            self.links_mut(parent).left = pivot;
219        } else {
220            self.links_mut(parent).right = pivot;
221        }
222        if left {
223            self.links_mut(pivot).left = node;
224        } else {
225            self.links_mut(pivot).right = node;
226        }
227        self.links_mut(node).parent = pivot;
228        root
229    }
230
231    fn balance_insertion(&mut self, mut root: u32, mut node: u32) -> u32 {
232        self.links_mut(node).red = true;
233        loop {
234            let mut parent = self.links(node).parent;
235            if parent == EMPTY {
236                self.links_mut(node).red = false;
237                return node;
238            }
239            let mut grandparent = self.links(parent).parent;
240            if !self.links(parent).red || grandparent == EMPTY {
241                return root;
242            }
243            let left = parent == self.links(grandparent).left;
244            let uncle = if left {
245                self.links(grandparent).right
246            } else {
247                self.links(grandparent).left
248            };
249            if uncle != EMPTY && self.links(uncle).red {
250                self.links_mut(uncle).red = false;
251                self.links_mut(parent).red = false;
252                self.links_mut(grandparent).red = true;
253                node = grandparent;
254                continue;
255            }
256            let inner = if left {
257                self.links(parent).right
258            } else {
259                self.links(parent).left
260            };
261            if node == inner {
262                node = parent;
263                root = self.rotate(root, node, left);
264                parent = self.links(node).parent;
265                grandparent = self.links(parent).parent;
266            }
267            self.links_mut(parent).red = false;
268            if grandparent != EMPTY {
269                self.links_mut(grandparent).red = true;
270                root = self.rotate(root, grandparent, !left);
271            }
272        }
273    }
274}