orx_selfref_col/references/
array_left_most.rs

1use super::{
2    iter::{ArrayLeftMostPtrIter, ArrayLeftMostPtrIterMut},
3    refs::Refs,
4    NodePtr,
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.clone(),
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) => 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].as_ref(),
106            false => None,
107        }
108    }
109
110    /// Creates an iterator over node pointers of the references collection.
111    pub fn iter(&self) -> ArrayLeftMostPtrIter<V> {
112        let slice = &self.array[..self.len];
113        ArrayLeftMostPtrIter::new(slice.iter())
114    }
115
116    /// Creates a mutable iterator over node pointers of the references collection.
117    pub fn iter_mut(&mut self) -> ArrayLeftMostPtrIterMut<V> {
118        let slice = &mut self.array[..self.len];
119        ArrayLeftMostPtrIterMut::new(slice.iter_mut())
120    }
121
122    /// Returns whether or not the collection has room for another reference.
123    pub fn has_room(&self) -> bool {
124        self.len < N
125    }
126
127    /// Pushes the node references to the end of the references collection.
128    ///
129    /// # Panics
130    ///
131    /// Panics if the array already has `N` references; i.e., when `self.has_room()` is false.
132    pub fn push(&mut self, node_ptr: NodePtr<V>) {
133        self.assert_has_room_for::<1>();
134        self.array[self.len] = Some(node_ptr);
135        self.len += 1;
136    }
137
138    /// Inserts the reference with the given `node_ptr` to the given `position` of the references collection.
139    pub fn insert(&mut self, position: usize, node_ptr: NodePtr<V>) {
140        for q in (position..self.len).rev() {
141            self.array[q + 1] = self.array[q].clone();
142        }
143        self.array[position] = Some(node_ptr);
144        self.len += 1;
145    }
146
147    /// Inserts the reference with the given `node_ptr` just before the given `pivot_ptr` the reference if it exists;
148    /// and returns the position that the new reference is inserted to.
149    ///
150    /// Does nothing leaving the children unchanged if the `pivot_ptr` reference does not exists, and returns None.
151    pub fn push_before(&mut self, pivot_ptr: &NodePtr<V>, node_ptr: NodePtr<V>) -> Option<usize> {
152        self.assert_has_room_for::<1>();
153        let position = self.iter().position(|x| x == pivot_ptr);
154        if let Some(p) = position {
155            self.insert(p, node_ptr);
156        }
157        position
158    }
159
160    /// Inserts the reference with the given `node_ptr` just after the given `pivot_ptr` the reference if it exists;
161    /// and returns the position that the new reference is inserted to.
162    ///
163    /// Does nothing leaving the children unchanged if the `pivot_ptr` reference does not exists, and returns None.
164    pub fn push_after(&mut self, pivot_ptr: &NodePtr<V>, node_ptr: NodePtr<V>) -> Option<usize> {
165        self.assert_has_room_for::<1>();
166        let position = self.iter().position(|x| x == pivot_ptr);
167        if let Some(p) = position {
168            self.insert(p + 1, node_ptr);
169        }
170        position
171    }
172
173    /// Replaces the node reference `old_node_ptr` with the `new_node_ptr` and returns
174    /// the position of the reference.
175    ///
176    /// Does nothing and returns None if the `old_node_ptr` is absent.
177    pub fn replace_with(
178        &mut self,
179        old_node_ptr: &NodePtr<V>,
180        new_node_ptr: NodePtr<V>,
181    ) -> Option<usize> {
182        let position = self.iter().position(|x| x == old_node_ptr);
183        if let Some(p) = position {
184            self.array[p] = Some(new_node_ptr);
185        }
186        position
187    }
188
189    // helpers
190    fn assert_has_room_for<const P: usize>(&self) {
191        assert!(
192            self.len + P <= N,
193            "Pushing the {}-th reference to array-backed references with maximum of {} elements.",
194            N + P,
195            N
196        );
197    }
198}