Skip to main content

embed_collections/avl/
iter.rs

1use super::*;
2use crate::Pointer;
3use core::mem::MaybeUninit;
4use core::ptr::null;
5
6// TODO IntoIter
7
8pub struct AvlDrain<'a, P: Pointer, Tag>
9where
10    P::Target: AvlItem<Tag>,
11{
12    tree: &'a mut AvlTree<P, Tag>,
13    parent: *const P::Target,
14    dir: Option<AvlDirection>,
15}
16
17impl<'a, P: Pointer, Tag> AvlDrain<'a, P, Tag>
18where
19    P::Target: AvlItem<Tag>,
20{
21    #[inline]
22    pub(super) fn new(tree: &'a mut AvlTree<P, Tag>) -> Self {
23        Self { tree, parent: null(), dir: None }
24    }
25}
26
27unsafe impl<'a, P, Tag> Send for AvlDrain<'a, P, Tag>
28where
29    P: Pointer + Send,
30    P::Target: AvlItem<Tag>,
31{
32}
33
34impl<'a, P: Pointer, Tag> Iterator for AvlDrain<'a, P, Tag>
35where
36    P::Target: AvlItem<Tag>,
37{
38    type Item = P;
39
40    fn next(&mut self) -> Option<Self::Item> {
41        if self.tree.root.is_null() {
42            return None;
43        }
44
45        let mut node: *const P::Target;
46        let parent: *const P::Target;
47
48        if self.dir.is_none() && self.parent.is_null() {
49            // Initial call: find the leftmost node
50            let mut curr = self.tree.root;
51            while unsafe { !(*curr).get_node().left.is_null() } {
52                curr = unsafe { (*curr).get_node().left };
53            }
54            node = curr;
55        } else {
56            parent = self.parent;
57            if parent.is_null() {
58                // Should not happen if root was nulled
59                return None;
60            }
61
62            let child_dir = self.dir.unwrap();
63            // child_dir child of parent was just nulled in previous call?
64            // NO, we null it in THIS call.
65
66            if child_dir == AvlDirection::Right || unsafe { (*parent).get_node().right.is_null() } {
67                node = parent;
68            } else {
69                // Finished left, go to right sibling
70                node = unsafe { (*parent).get_node().right };
71                while unsafe { !(*node).get_node().left.is_null() } {
72                    node = unsafe { (*node).get_node().left };
73                }
74            }
75        }
76
77        // Goto check_right_side logic
78        if unsafe { !(*node).get_node().right.is_null() } {
79            // It has a right child, so we must yield that first (in post-order)
80            // Note: in AVL, if left is null, right must be a leaf.
81            node = unsafe { (*node).get_node().right };
82        }
83
84        // Determine next state
85        let next_parent = unsafe { (*node).get_node().parent };
86        if next_parent.is_null() {
87            self.tree.root = null();
88            self.parent = null();
89            self.dir = Some(AvlDirection::Left);
90        } else {
91            self.parent = next_parent;
92            self.dir = Some(self.tree.parent_direction(node, next_parent));
93            // Unlink from parent NOW
94            unsafe { (*next_parent).get_node().set_child(self.dir.unwrap(), null()) };
95        }
96
97        self.tree.count -= 1;
98        unsafe {
99            (*node).get_node().detach();
100            Some(P::from_raw(node))
101        }
102    }
103}
104
105pub struct AvlIter<'a, P, Tag>
106where
107    P: Pointer,
108    P::Target: AvlItem<Tag>,
109{
110    tree: &'a AvlTree<P, Tag>,
111    cur: Option<NonNull<P::Target>>,
112    dir: AvlDirection,
113    temp: MaybeUninit<P>,
114}
115
116/// A lending iterator for AvlTree
117///
118/// NOTE: If you use the [Iterator] interface (for iteration), you only get &P::Target.
119///
120/// you can use next_ref() to get &P
121impl<'a, P, Tag> AvlIter<'a, P, Tag>
122where
123    P: Pointer,
124    P::Target: AvlItem<Tag>,
125{
126    #[inline]
127    pub(crate) fn new(
128        tree: &'a AvlTree<P, Tag>, init: Option<NonNull<P::Target>>, dir: AvlDirection,
129    ) -> Self {
130        Self { tree, cur: init, dir, temp: MaybeUninit::uninit() }
131    }
132
133    /// Return a reference of P (you can P.clone() of P has Clone)
134    ///
135    /// NOTE: this is a lending iterator.
136    /// Unfortunately rust Iterator trait don't let us do this because of lifetime limitation
137    ///
138    /// # Example
139    ///
140    /// ```rust
141    /// use embed_collections::avl::{AvlTree, AvlItem, AvlNode};
142    /// use core::cell::UnsafeCell;
143    /// use core::cmp::Ordering;
144    /// extern crate alloc;
145    /// use alloc::sync::Arc;
146    ///
147    /// struct MyNode {
148    ///     value: i32,
149    ///     avl_node: UnsafeCell<AvlNode<MyNode, ()>>,
150    /// }
151    ///
152    /// unsafe impl AvlItem<()> for MyNode {
153    ///
154    ///     type Key = i32;
155    ///
156    ///     fn get_node(&self) -> &mut AvlNode<MyNode, ()> {
157    ///         unsafe { &mut *self.avl_node.get() }
158    ///     }
159    ///
160    ///     fn borrow_key(&self) -> &Self::Key {
161    ///         &self.value
162    ///     }
163    /// }
164    ///
165    /// let mut tree = AvlTree::<Arc<MyNode>, ()>::new();
166    ///
167    /// let new_node = | n: i32| {
168    ///     Arc::new(MyNode { value: n, avl_node: UnsafeCell::new(Default::default()) })
169    /// };
170    /// tree.add(new_node(1));
171    /// tree.add(new_node(2));
172    /// tree.add(new_node(3));
173    /// assert_eq!(tree.len(), 3);
174    ///
175    /// let mut iter = tree.iter_rev();
176    /// let mut all_nodes_rev = Vec::with_capacity(tree.len());
177    /// while let Some(node) = iter.next_ref() {
178    ///     all_nodes_rev.push(node.clone());
179    /// }
180    /// ```
181    #[inline]
182    pub fn next_ref(&mut self) -> Option<&P> {
183        let cur: NonNull<P::Target> = self.cur.take()?;
184        self.temp.write(unsafe { P::from_raw(cur.as_ptr()) });
185        let p = self.tree.walk_dir(cur, self.dir);
186        self.cur = p;
187        Some(unsafe { self.temp.assume_init_ref() })
188    }
189}
190
191unsafe impl<'a, P, Tag> Send for AvlIter<'a, P, Tag>
192where
193    P: Pointer + Send,
194    P::Target: AvlItem<Tag>,
195{
196}
197
198impl<'a, P, Tag> Iterator for AvlIter<'a, P, Tag>
199where
200    P: Pointer,
201    P::Target: AvlItem<Tag>,
202{
203    type Item = &'a P::Target;
204
205    fn next(&mut self) -> Option<Self::Item> {
206        let cur: NonNull<P::Target> = self.cur.take()?;
207        let p = self.tree.walk_dir(cur, self.dir);
208        self.cur = p;
209        Some(unsafe { cur.as_ref() })
210    }
211}