Skip to main content

orx_selfref_col/references/
array_left_most.rs

1use super::{
2    NodePtr,
3    iter::{ArrayLeftMostPtrIter, ArrayLeftMostPtrIterMut},
4    refs::Refs,
5};
6use crate::variant::Variant;
7use core::fmt::Debug;
8
9/// A constant number of left-aligned references.
10///
11/// It differs from [`RefsArray`] due to its additional requirement that:
12/// * all Some references are to the left of all None references.
13///
14/// [`RefsArray`]: crate::RefsArray
15pub struct RefsArrayLeftMost<const N: usize, V>
16where
17    V: Variant,
18{
19    array: [Option<NodePtr<V>>; N],
20    len: usize,
21}
22
23impl<const N: usize, V: Variant> Clone for RefsArrayLeftMost<N, V> {
24    fn clone(&self) -> Self {
25        Self {
26            array: self.array,
27            len: self.len,
28        }
29    }
30}
31
32impl<const N: usize, V: Variant> Debug for RefsArrayLeftMost<N, V> {
33    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34        f.debug_tuple("RefsArrayLeftMost")
35            .field(&self.array)
36            .finish()
37    }
38}
39
40impl<const N: usize, V> Refs for RefsArrayLeftMost<N, V>
41where
42    V: Variant,
43{
44    #[inline(always)]
45    fn empty() -> Self {
46        Self {
47            array: [const { None }; N],
48            len: 0,
49        }
50    }
51
52    #[inline(always)]
53    fn is_empty(&self) -> bool {
54        self.len == 0
55    }
56
57    #[inline(always)]
58    fn clear(&mut self) {
59        self.array
60            .iter_mut()
61            .take(self.len)
62            .for_each(|x| _ = x.take());
63        self.len = 0;
64    }
65
66    #[inline(always)]
67    fn remove_at(&mut self, ref_idx: usize) {
68        self.array[ref_idx] = None;
69        for i in (ref_idx + 1)..self.len {
70            self.array[i - 1] = self.array[i].take();
71        }
72        self.len -= 1;
73    }
74
75    #[inline(always)]
76    fn remove(&mut self, ptr: usize) -> Option<usize> {
77        let x = self.array.iter().enumerate().find(|x| match x.1 {
78            Some(x) => unsafe { x.ptr() as usize == ptr },
79            None => false,
80        });
81        match x {
82            Some((ref_idx, _)) => {
83                self.remove_at(ref_idx);
84                Some(ref_idx)
85            }
86            None => None,
87        }
88    }
89}
90
91impl<const N: usize, V: Variant> RefsArrayLeftMost<N, V> {
92    /// Returns the number of references.
93    pub fn len(&self) -> usize {
94        self.len
95    }
96
97    /// Returns true if the number of references is zero.
98    pub fn is_empty(&self) -> bool {
99        self.len == 0
100    }
101
102    /// Returns a reference to the node pointer at the `ref_idx` position of the references array.
103    pub fn get(&self, ref_idx: usize) -> Option<NodePtr<V>> {
104        match ref_idx < N {
105            true => self.array[ref_idx],
106            false => None,
107        }
108    }
109
110    /// Returns the optional node pointers as a slice such that:
111    /// * length of the slice is equal to `self.len()`,
112    /// * all elements of the slice are of `Some` variant, and hence,
113    /// * can be safely unwrapped to access the node pointer.
114    pub fn as_slice(&self) -> &[Option<NodePtr<V>>] {
115        &self.array[..self.len]
116    }
117
118    /// Creates an iterator over node pointers of the references collection.
119    pub fn iter(&self) -> ArrayLeftMostPtrIter<'_, V> {
120        let slice = &self.array[..self.len];
121        ArrayLeftMostPtrIter::new(slice.iter())
122    }
123
124    /// Creates a mutable iterator over node pointers of the references collection.
125    pub fn iter_mut(&mut self) -> ArrayLeftMostPtrIterMut<'_, V> {
126        let slice = &mut self.array[..self.len];
127        ArrayLeftMostPtrIterMut::new(slice.iter_mut())
128    }
129
130    /// Returns whether or not the collection has room for another reference.
131    pub fn has_room(&self) -> bool {
132        self.len < N
133    }
134
135    /// Pushes the node references to the end of the references collection.
136    ///
137    /// # Panics
138    ///
139    /// Panics if the array already has `N` references; i.e., when `self.has_room()` is false.
140    pub fn push(&mut self, node_ptr: NodePtr<V>) {
141        self.assert_has_room_for::<1>();
142        self.array[self.len] = Some(node_ptr);
143        self.len += 1;
144    }
145
146    /// Inserts the reference with the given `node_ptr` to the given `position` of the references collection.
147    pub fn insert(&mut self, position: usize, node_ptr: NodePtr<V>) {
148        for q in (position..self.len).rev() {
149            self.array[q + 1] = self.array[q];
150        }
151        self.array[position] = Some(node_ptr);
152        self.len += 1;
153    }
154
155    /// Inserts the reference with the given `node_ptr` just before the given `pivot_ptr` the reference if it exists;
156    /// and returns the position that the new reference is inserted to.
157    ///
158    /// Does nothing leaving the children unchanged if the `pivot_ptr` reference does not exists, and returns None.
159    pub fn push_before(&mut self, pivot_ptr: NodePtr<V>, node_ptr: NodePtr<V>) -> Option<usize> {
160        self.assert_has_room_for::<1>();
161        let position = self.iter().position(|x| *x == pivot_ptr);
162        if let Some(p) = position {
163            self.insert(p, node_ptr);
164        }
165        position
166    }
167
168    /// Inserts the reference with the given `node_ptr` just after the given `pivot_ptr` the reference if it exists;
169    /// and returns the position that the new reference is inserted to.
170    ///
171    /// Does nothing leaving the children unchanged if the `pivot_ptr` reference does not exists, and returns None.
172    pub fn push_after(&mut self, pivot_ptr: NodePtr<V>, node_ptr: NodePtr<V>) -> Option<usize> {
173        self.assert_has_room_for::<1>();
174        let position = self.iter().position(|x| *x == pivot_ptr);
175        if let Some(p) = position {
176            self.insert(p + 1, node_ptr);
177        }
178        position
179    }
180
181    /// Replaces the node reference `old_node_ptr` with the `new_node_ptr` and returns
182    /// the position of the reference.
183    ///
184    /// Does nothing and returns None if the `old_node_ptr` is absent.
185    pub fn replace_with(
186        &mut self,
187        old_node_ptr: NodePtr<V>,
188        new_node_ptr: NodePtr<V>,
189    ) -> Option<usize> {
190        let position = self.iter().position(|x| *x == old_node_ptr);
191        if let Some(p) = position {
192            self.array[p] = Some(new_node_ptr);
193        }
194        position
195    }
196
197    /// If both pointers `ptr_a` and `ptr_b` exist as children, this method swaps their positions
198    /// and returns `(pos_a, pos_b)` where `pos_a` (`pos_b`) is the original (before the swap) position
199    /// of the child `ptr_a` (`ptr_b`).
200    ///
201    /// Does nothing and returns None if either of the pointers is absent.
202    pub fn swap(&mut self, ptr_a: NodePtr<V>, ptr_b: NodePtr<V>) -> Option<(usize, usize)> {
203        let (pos_a, pos_b) = {
204            let mut a = None;
205            let mut b = None;
206            for (i, x) in self.array[..self.len].iter().enumerate() {
207                match *x {
208                    x if x == Some(ptr_a) => {
209                        a = Some(i);
210                        if b.is_some() {
211                            break;
212                        }
213                    }
214                    x if x == Some(ptr_b) => {
215                        b = Some(i);
216                        if a.is_some() {
217                            break;
218                        }
219                    }
220                    _ => {}
221                }
222            }
223            match (a, b) {
224                (Some(a), Some(b)) => Some((a, b)),
225                _ => None,
226            }
227        }?;
228        self.array[pos_a] = Some(ptr_b);
229        self.array[pos_b] = Some(ptr_a);
230        Some((pos_a, pos_b))
231    }
232
233    // helpers
234    fn assert_has_room_for<const P: usize>(&self) {
235        assert!(
236            self.len + P <= N,
237            "Pushing the {}-th reference to array-backed references with maximum of {} elements.",
238            N + P,
239            N
240        );
241    }
242}