mtb_entity_slab/container/
ring_list.rs1use crate::{
10 EntityListError, EntityListIter, EntityListNodeHead, EntityListRange, EntityListRes,
11 IBasicEntityListID, IDBoundAlloc, container::list_base::NodeOps,
12};
13
14pub trait IEntityRingListNodeID: IBasicEntityListID {
16 fn obj_detach(obj: &Self::ObjectT, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self> {
18 if Self::obj_is_sentinel(obj) {
19 return Err(EntityListError::NodeIsSentinel);
20 }
21 let (Some(prev), Some(next)) = Self::obj_load_head(obj).into_id() else {
22 return Ok(());
24 };
25 prev.set_next_id(alloc, Some(next));
26 next.set_prev_id(alloc, Some(prev));
27 Self::obj_store_head(obj, EntityListNodeHead::none());
28 Ok(())
29 }
30
31 fn detach(self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self> {
38 self.on_unplug(alloc)?;
39 Self::obj_detach(self.deref_alloc(alloc), alloc)
40 }
41}
42
43pub struct EntityRingList<I: IEntityRingListNodeID> {
49 pub sentinel: I,
51}
52
53impl<I: IEntityRingListNodeID> EntityRingList<I> {
54 pub fn new(alloc: &IDBoundAlloc<I>) -> Self {
56 let sentinel = I::new_sentinel(alloc);
57 I::obj_store_head(
58 sentinel.deref_alloc(alloc),
59 EntityListNodeHead {
60 prev: Some(sentinel),
61 next: Some(sentinel),
62 },
63 );
64 Self { sentinel }
65 }
66 pub fn front_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
68 let next = self.sentinel.get_next_id(alloc)?;
69 if next == self.sentinel {
70 None
71 } else {
72 Some(next)
73 }
74 }
75 pub fn back_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
77 let prev = self.sentinel.get_prev_id(alloc)?;
78 if prev == self.sentinel {
79 None
80 } else {
81 Some(prev)
82 }
83 }
84 pub fn is_empty(&self, alloc: &IDBoundAlloc<I>) -> bool {
86 self.front_id(alloc).is_none()
87 }
88 pub fn is_single(&self, alloc: &IDBoundAlloc<I>) -> bool {
90 let sentinel = self.sentinel.deref_alloc(alloc);
91 let head = I::obj_load_head(sentinel);
92 let (Some(prev), Some(next)) = head.into_id() else {
93 return false;
94 };
95 prev == next && prev != self.sentinel
96 }
97 pub fn is_multiple(&self, alloc: &IDBoundAlloc<I>) -> bool {
99 let sentinel = self.sentinel.deref_alloc(alloc);
100 let head = I::obj_load_head(sentinel);
101 let (Some(prev), Some(next)) = head.into_id() else {
102 return false;
103 };
104 prev != next
105 }
106
107 pub fn foreach(
113 &self,
114 alloc: &IDBoundAlloc<I>,
115 mut pred: impl FnMut(I, &I::ObjectT) -> bool,
116 ) -> bool {
117 let mut curr = self.sentinel.get_next_id(alloc);
118 let mut count = 0;
119 while let Some(node_id) = curr {
120 if node_id == self.sentinel {
121 return true;
122 }
123 let node_obj = node_id.deref_alloc(alloc);
124 if !pred(node_id, node_obj) {
125 return false;
126 }
127 curr = node_id.get_next_id(alloc);
128 count += 1;
129 }
130 panic!("Broken ring list detected after {count} nodes");
131 }
132
133 pub fn forall_with_sentinel(
139 &self,
140 alloc: &IDBoundAlloc<I>,
141 mut pred: impl FnMut(I, &I::ObjectT) -> bool,
142 ) -> bool {
143 let mut curr = Some(self.sentinel);
144 let mut count = 0;
145 while let Some(node_id) = curr {
146 let node_obj = node_id.deref_alloc(alloc);
147 if !pred(node_id, node_obj) {
148 return false;
149 }
150 curr = node_id.get_next_id(alloc);
151 count += 1;
152 if curr == Some(self.sentinel) {
153 return true;
154 }
155 }
156 panic!("Broken ring list detected after {count} nodes");
157 }
158
159 pub fn len(&self, alloc: &IDBoundAlloc<I>) -> usize {
164 let mut len = 0;
165 self.foreach(alloc, |_, _| {
166 len += 1;
167 true
168 });
169 len
170 }
171 pub fn contains(&self, node: I, alloc: &IDBoundAlloc<I>) -> bool {
173 !self.foreach(alloc, |id, _| id != node)
174 }
175
176 #[inline]
178 #[deprecated = "Use 'get_range' instead of cloning the view"]
179 pub fn clone_view(&self) -> Self {
180 Self {
181 sentinel: self.sentinel,
182 }
183 }
184
185 pub fn get_range(&self, alloc: &IDBoundAlloc<I>) -> EntityListRange<I> {
187 EntityListRange {
188 start: self
189 .sentinel
190 .get_next_id(alloc)
191 .expect("Broken ring list detected in get_range()"),
192 end: Some(self.sentinel),
193 }
194 }
195
196 pub fn push_back(&self, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
198 const ERRMSG: &str = "Broken ring detected during push_back";
199
200 let sentinel_obj = self.sentinel.deref_alloc(alloc);
201 let prev = I::obj_get_prev_id(sentinel_obj).expect(ERRMSG);
202 if prev == new_node {
203 return Err(EntityListError::RepeatedNode);
204 }
205 if new_node.is_attached(alloc) {
206 return Err(EntityListError::ItemFalselyAttached(new_node));
207 }
208 let new_node_obj = new_node.deref_alloc(alloc);
210 I::obj_store_head(
211 new_node_obj,
212 EntityListNodeHead::from_id(prev, self.sentinel),
213 );
214 prev.set_next_id(alloc, Some(new_node));
216 self.sentinel.set_prev_id(alloc, Some(new_node));
217 Ok(())
218 }
219
220 pub fn pop_back(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
222 let back_id = self.back_id(alloc).ok_or(EntityListError::EmptyList)?;
223 back_id.detach(alloc)?;
224 Ok(back_id)
225 }
226 pub fn pop_front(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
228 let front_id = self.front_id(alloc).ok_or(EntityListError::EmptyList)?;
229 front_id.detach(alloc)?;
230 Ok(front_id)
231 }
232
233 pub fn move_all_to(
235 &self,
236 other: &Self,
237 alloc: &IDBoundAlloc<I>,
238 mut on_move: impl FnMut(I),
239 ) -> EntityListRes<I> {
240 if self.sentinel == other.sentinel {
241 return Ok(());
242 }
243 loop {
244 let node = match self.pop_front(alloc) {
245 Ok(n) => n,
246 Err(EntityListError::EmptyList) => break Ok(()),
247 Err(e) => break Err(e),
248 };
249 other.push_back(node, alloc)?;
250 on_move(node);
251 }
252 }
253
254 pub fn move_to_if(
256 &self,
257 other: &Self,
258 alloc: &IDBoundAlloc<I>,
259 mut pred: impl FnMut(I, &I::ObjectT) -> bool,
260 mut on_move: impl FnMut(I),
261 ) -> EntityListRes<I> {
262 if self.sentinel == other.sentinel {
263 return Err(EntityListError::RepeatedList);
264 }
265 let mut curr = self.sentinel;
266 loop {
267 let Some(next) = curr.get_next_id(alloc) else {
268 break;
269 };
270 if next == self.sentinel {
271 return Ok(());
272 }
273 let next_obj = next.deref_alloc(alloc);
274 if !pred(next, next_obj) {
275 curr = next;
276 continue;
277 }
278 next.detach(alloc)?;
279 other.push_back(next, alloc)?;
280 on_move(next);
281 }
282 Err(EntityListError::ListBroken)
283 }
284
285 pub fn clean(&self, alloc: &IDBoundAlloc<I>) {
287 let mut count = 0;
288 let err = loop {
289 match self.pop_front(alloc) {
290 Ok(_) => count += 1,
291 Err(EntityListError::EmptyList) => return,
292 Err(e) => break e,
293 };
294 };
295 panic!("Broken ring list detected after removing {count} nodes: {err}");
296 }
297
298 pub fn iter<'a>(&self, alloc: &'a IDBoundAlloc<I>) -> EntityListIter<'a, I> {
300 let next_node = self
301 .sentinel
302 .get_next_id(alloc)
303 .expect("Broken ring list detected in iter()");
304 EntityListIter {
305 alloc,
306 curr: Some(next_node),
307 end: Some(self.sentinel),
308 }
309 }
310}