1use crate::{EntityAlloc, IEntityAllocID, PtrID, alloc::IEntityAllocatable};
2use std::{
3 cell::Cell,
4 error::Error,
5 fmt::{Debug, Display},
6 iter::Rev,
7};
8
9pub struct EntityListHead<E: IEntityAllocatable>(pub Option<PtrID<E>>, pub Option<PtrID<E>>);
10
11impl<E: IEntityAllocatable> Clone for EntityListHead<E> {
12 #[inline]
13 fn clone(&self) -> Self {
14 Self(self.0, self.1)
15 }
16}
17impl<E: IEntityAllocatable> Copy for EntityListHead<E> {}
18impl<E: IEntityAllocatable> EntityListHead<E> {
19 #[inline]
20 pub fn none() -> Self {
21 Self(None, None)
22 }
23
24 fn get_prev_ptr(&self) -> Option<PtrID<E>> {
25 self.0
26 }
27 fn get_next_ptr(&self) -> Option<PtrID<E>> {
28 self.1
29 }
30 pub fn get_prev_id(&self) -> Option<E::PtrID> {
31 self.0.map(E::PtrID::from)
32 }
33 pub fn get_next_id(&self) -> Option<E::PtrID> {
34 self.1.map(E::PtrID::from)
35 }
36
37 fn prev_ptr(self, prev: Option<PtrID<E>>) -> Self {
38 Self(prev, self.1)
39 }
40 fn next_ptr(self, next: Option<PtrID<E>>) -> Self {
41 Self(self.0, next)
42 }
43 pub fn next_id(self, next: Option<E::PtrID>) -> Self {
44 Self(self.0, next.map(E::ptr_of_id))
45 }
46 pub fn prev_id(self, prev: Option<E::PtrID>) -> Self {
47 Self(prev.map(E::ptr_of_id), self.1)
48 }
49}
50
51mod list_util {
52 pub(super) struct RingList;
53 pub(super) struct LinkList;
54}
55
56trait RawListNodeOps<E: IEntityAllocatable, KindT> {
57 fn get_prev_ptr(&self) -> Option<PtrID<E>>;
58 fn get_next_ptr(&self) -> Option<PtrID<E>>;
59 fn set_prev_ptr(&self, prev: Option<PtrID<E>>);
60 fn set_next_ptr(&self, next: Option<PtrID<E>>);
61}
62
63pub enum EntityListError<E: IEntityAllocatable> {
64 EmptyList,
65 ListBroken,
66 NodeIsSentinel,
67 RepeatedNode,
68 RepeatedList,
69 SelfNotAttached(PtrID<E>),
70 ItemFalselyAttached(PtrID<E>),
71 ItemFalselyDetached(PtrID<E>),
72}
73impl<E: IEntityAllocatable> Debug for EntityListError<E> {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 use EntityListError::*;
76 match self {
77 EmptyList => write!(f, "EmptyList"),
78 ListBroken => write!(f, "ListBroken"),
79 NodeIsSentinel => write!(f, "NodeIsSentinel"),
80 RepeatedNode => write!(f, "RepeatedNode"),
81 RepeatedList => write!(f, "RepeatedList"),
82 SelfNotAttached(id) => {
83 write!(f, "SelfNotAttached({id:?})")
84 }
85 ItemFalselyAttached(id) => {
86 write!(f, "ItemFalselyAttached({id:?})")
87 }
88 ItemFalselyDetached(id) => {
89 write!(f, "ItemFalselyDetached({id:?})")
90 }
91 }
92 }
93}
94impl<E: IEntityAllocatable> Clone for EntityListError<E> {
95 fn clone(&self) -> Self {
96 use EntityListError::*;
97 match self {
98 EmptyList => EmptyList,
99 ListBroken => ListBroken,
100 NodeIsSentinel => NodeIsSentinel,
101 RepeatedNode => RepeatedNode,
102 RepeatedList => RepeatedList,
103 SelfNotAttached(id) => SelfNotAttached(*id),
104 ItemFalselyAttached(id) => ItemFalselyAttached(*id),
105 ItemFalselyDetached(id) => ItemFalselyDetached(*id),
106 }
107 }
108}
109impl<E: IEntityAllocatable> Copy for EntityListError<E> {}
110impl<E: IEntityAllocatable> Display for EntityListError<E> {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 write!(f, "{self:?}")
113 }
114}
115impl<E: IEntityAllocatable> Error for EntityListError<E> {}
116
117pub type PtrListRes<E, T = ()> = Result<T, EntityListError<E>>;
118
119pub trait IEntityListNode: Sized + IEntityAllocatable {
120 fn load_head(&self) -> EntityListHead<Self>;
121 fn store_head(&self, head: EntityListHead<Self>);
122 fn is_sentinel(&self) -> bool;
123 fn new_sentinel() -> Self;
124 fn on_push_next(
125 curr: Self::PtrID,
126 next: Self::PtrID,
127 alloc: &EntityAlloc<Self>,
128 ) -> PtrListRes<Self>;
129 fn on_push_prev(
130 curr: Self::PtrID,
131 prev: Self::PtrID,
132 alloc: &EntityAlloc<Self>,
133 ) -> PtrListRes<Self>;
134 fn on_unplug(curr: Self::PtrID, alloc: &EntityAlloc<Self>) -> PtrListRes<Self>;
135
136 #[inline]
137 fn get_prev_id(&self) -> Option<Self::PtrID> {
138 self.load_head().get_prev_id()
139 }
140 #[inline]
141 fn get_next_id(&self) -> Option<Self::PtrID> {
142 self.load_head().get_next_id()
143 }
144
145 #[inline]
146 fn set_prev_id(&self, prev: Option<Self::PtrID>) {
147 self.store_head(self.load_head().prev_id(prev));
148 }
149 #[inline]
150 fn set_next_id(&self, next: Option<Self::PtrID>) {
151 self.store_head(self.load_head().next_id(next));
152 }
153
154 #[inline]
155 fn is_attached(&self) -> bool {
156 let EntityListHead(prev, next) = self.load_head();
157 assert!(
158 self.is_sentinel() || prev.is_some() == next.is_some(),
159 "ptrlist node is corrupted"
160 );
161 prev.is_some() || next.is_some()
162 }
163
164 fn comes_before(
165 curr: Self::PtrID,
166 other: Self::PtrID,
167 alloc: &EntityAlloc<Self>,
168 ) -> PtrListRes<Self> {
169 let mut node = Self::ptr_of_id(curr);
170 while let Some(next) = node.deref(alloc).get_next_ptr() {
171 if next == other.into() {
172 return Ok(());
173 }
174 node = next;
175 }
176 Err(EntityListError::ListBroken)
177 }
178}
179impl<E: IEntityListNode> RawListNodeOps<E, list_util::LinkList> for E {
180 fn get_prev_ptr(&self) -> Option<PtrID<E>> {
181 self.load_head().get_prev_ptr()
182 }
183 fn get_next_ptr(&self) -> Option<PtrID<E>> {
184 self.load_head().get_next_ptr()
185 }
186 fn set_prev_ptr(&self, prev: Option<PtrID<E>>) {
187 self.store_head(self.load_head().prev_ptr(prev))
188 }
189 fn set_next_ptr(&self, next: Option<PtrID<E>>) {
190 self.store_head(self.load_head().next_ptr(next))
191 }
192}
193
194pub struct EntityListRange<E: IEntityListNode> {
199 pub start: E::PtrID,
200 pub end: Option<E::PtrID>,
201}
202
203impl<E: IEntityListNode> EntityListRange<E> {
204 #[inline]
205 pub fn is_empty(&self) -> bool {
206 Some(self.start) == self.end
207 }
208
209 pub fn iter<'alloc>(&self, alloc: &'alloc EntityAlloc<E>) -> EntityListReadIter<'alloc, E> {
210 EntityListReadIter {
211 alloc,
212 curr: Some(E::ptr_of_id(self.start)),
213 end: self.end.map(E::ptr_of_id),
214 }
215 }
216}
217
218pub struct EntityList<E: IEntityListNode> {
219 pub head: PtrID<E>,
220 pub tail: PtrID<E>,
221 pub len: Cell<usize>,
222}
223
224impl<E: IEntityListNode> EntityList<E> {
225 pub fn new(alloc: &EntityAlloc<E>) -> Self {
228 let head = alloc.allocate(E::new_sentinel());
229 let tail = alloc.allocate(E::new_sentinel());
230 head.deref(alloc).set_next_ptr(Some(tail));
231 tail.deref(alloc).set_prev_ptr(Some(head));
232 Self {
233 head,
234 tail,
235 len: Cell::new(0),
236 }
237 }
238
239 #[inline]
241 pub fn len(&self) -> usize {
242 self.len.get()
243 }
244 #[inline]
246 pub fn is_empty(&self) -> bool {
247 self.len.get() == 0
248 }
249
250 #[inline]
252 pub fn get_front_id(&self, alloc: &EntityAlloc<E>) -> Option<E::PtrID> {
253 self.get_front_ptr(alloc).map(E::id_of_ptr)
254 }
255 #[inline]
257 pub fn get_back_id(&self, alloc: &EntityAlloc<E>) -> Option<E::PtrID> {
258 self.get_back_ptr(alloc).map(E::id_of_ptr)
259 }
260 fn get_front_ptr(&self, alloc: &EntityAlloc<E>) -> Option<PtrID<E>> {
261 let next = self.head.deref(alloc).get_next_ptr()?;
262 if next == self.tail { None } else { Some(next) }
263 }
264 fn get_back_ptr(&self, alloc: &EntityAlloc<E>) -> Option<PtrID<E>> {
265 let prev = self.tail.deref(alloc).get_prev_ptr()?;
266 if prev == self.head { None } else { Some(prev) }
267 }
268
269 pub fn node_add_next(
274 &self,
275 node: E::PtrID,
276 new_node: E::PtrID,
277 alloc: &EntityAlloc<E>,
278 ) -> PtrListRes<E> {
279 if node == new_node {
280 return Err(EntityListError::RepeatedNode);
281 }
282 let node_ptr = node.into();
283 let new_node_ptr = new_node.into();
284 if node_ptr == self.tail {
286 return Err(EntityListError::NodeIsSentinel);
287 }
288 E::on_push_next(node, new_node, alloc)?;
289
290 let node_obj = node_ptr.deref(alloc);
291 let new_node_obj = new_node_ptr.deref(alloc);
292 assert!(node_obj.is_attached(), "Cannot add next to a detached node");
293 assert!(
294 !new_node_obj.is_attached(),
295 "Cannot add a node that is already attached"
296 );
297
298 let orig_next = node_obj.get_next_ptr();
299 new_node_obj.store_head(EntityListHead(Some(node_ptr), orig_next));
300 node_obj.set_next_ptr(Some(new_node_ptr));
301 if let Some(orig_next) = orig_next {
302 orig_next.deref(alloc).set_prev_ptr(Some(new_node_ptr));
303 }
304 self.len.set(self.len.get() + 1);
305 Ok(())
306 }
307
308 pub fn node_add_prev(
313 &self,
314 node: E::PtrID,
315 new_node: E::PtrID,
316 alloc: &EntityAlloc<E>,
317 ) -> PtrListRes<E> {
318 if node == new_node {
319 return Err(EntityListError::RepeatedNode);
320 }
321 E::on_push_prev(node, new_node, alloc)?;
322 let node_ptr = node.into();
324 let new_node_ptr = new_node.into();
325 if node_ptr == self.head {
326 return Err(EntityListError::NodeIsSentinel);
327 }
328 let node_obj = node_ptr.deref(alloc);
329 let new_node_obj = new_node_ptr.deref(alloc);
330
331 assert!(node_obj.is_attached(), "Cannot add prev to a detached node");
332 assert!(
333 !new_node_obj.is_attached(),
334 "Cannot add a node that is already attached"
335 );
336 let orig_prev = node_obj.get_prev_ptr();
337 new_node_obj.store_head(EntityListHead(orig_prev, Some(node_ptr)));
338 node_obj.set_prev_ptr(Some(new_node_ptr));
339 if let Some(orig_prev) = orig_prev {
340 orig_prev.deref(alloc).set_next_ptr(Some(new_node_ptr));
341 }
342 self.len.set(self.len.get() + 1);
343 Ok(())
344 }
345 pub fn node_unplug(&self, node: E::PtrID, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
346 let node_ptr = node.into();
347 if node_ptr == self.head || node_ptr == self.tail {
348 return Err(EntityListError::NodeIsSentinel);
349 }
350 E::on_unplug(node, alloc)?;
351 let node_obj = node_ptr.deref(alloc);
352 assert!(node_obj.is_attached(), "Cannot unplug a detached node");
353
354 let prev = node_obj.get_prev_ptr().ok_or(EntityListError::ListBroken)?;
355 let next = node_obj.get_next_ptr().ok_or(EntityListError::ListBroken)?;
356 prev.deref(alloc).set_next_ptr(Some(next));
357 next.deref(alloc).set_prev_ptr(Some(prev));
358 node_obj.store_head(EntityListHead(None, None));
359 self.len.set(self.len.get() - 1);
360 Ok(())
361 }
362
363 #[inline]
364 pub fn push_back_id(&self, new_node: E::PtrID, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
365 self.node_add_prev(E::id_of_ptr(self.tail), new_node, alloc)
366 }
367 #[inline]
368 pub fn push_front_id(&self, new_node: E::PtrID, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
369 self.node_add_next(E::id_of_ptr(self.head), new_node, alloc)
370 }
371 #[inline]
372 pub fn push_back_val(&self, val: E, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
373 self.push_back_id(E::PtrID::from(alloc.allocate(val)), alloc)
374 }
375 #[inline]
376 pub fn push_front_val(&self, val: E, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
377 self.push_front_id(E::PtrID::from(alloc.allocate(val)), alloc)
378 }
379
380 pub fn pop_back(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, E::PtrID> {
381 let back_id = self.get_back_id(alloc).ok_or(EntityListError::EmptyList)?;
382 self.node_unplug(back_id, alloc)?;
383 Ok(back_id)
384 }
385 pub fn pop_front(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, E::PtrID> {
386 let front_id = self.get_front_id(alloc).ok_or(EntityListError::EmptyList)?;
387 self.node_unplug(front_id, alloc)?;
388 Ok(front_id)
389 }
390
391 pub fn foreach(&self, alloc: &EntityAlloc<E>, mut f: impl FnMut(E::PtrID, &E) -> bool) -> bool {
392 let mut node_opt = self.get_front_ptr(alloc);
393 let mut count = 0;
394 while let Some(node) = node_opt {
395 let node_obj = node.deref(alloc);
396 if !f(E::id_of_ptr(node), node_obj) {
397 return false;
398 }
399 node_opt = node_obj.get_next_ptr();
400 if node_opt == Some(self.tail) {
401 assert_eq!(count, self.len(), "Broken list detected in foreach");
402 return true;
403 }
404 count += 1;
405 }
406 unreachable!("Broken list {self:p} detected in foreach after {count} nodes");
407 }
408 pub fn forall_with_sentinel(
409 &self,
410 alloc: &EntityAlloc<E>,
411 mut f: impl FnMut(E::PtrID, &E) -> bool,
412 ) -> bool {
413 let mut node_opt = Some(self.head);
414 let mut count = 0;
415 while let Some(node) = node_opt {
416 let node_obj = node.deref(alloc);
417 if !f(E::PtrID::from(node), node_obj) {
418 return false;
419 }
420 node_opt = node_obj.get_next_ptr();
421 count += 1;
422 }
423 assert_eq!(
424 count,
425 self.len() + 2,
426 "Broken list {self:p} detected in forall_with_sentinel after {count} nodes"
427 );
428 true
429 }
430
431 pub fn get_range(&self, alloc: &EntityAlloc<E>) -> EntityListRange<E> {
432 let Some(start) = self.head.deref(alloc).get_next_id() else {
433 panic!("EntityList corrupted: head has no next");
434 };
435 EntityListRange {
436 start,
437 end: Some(E::id_of_ptr(self.tail)),
438 }
439 }
440 pub fn get_range_with_sentinels(&self) -> EntityListRange<E> {
442 EntityListRange {
443 start: E::id_of_ptr(self.head),
444 end: None,
445 }
446 }
447
448 pub fn iter<'alloc>(
449 &'alloc self,
450 alloc: &'alloc EntityAlloc<E>,
451 ) -> EntityListReadIter<'alloc, E> {
452 EntityListReadIter {
453 alloc,
454 curr: self.head.deref(alloc).get_next_ptr(),
455 end: Some(self.tail),
456 }
457 }
458 pub fn iter_with_sentinels<'alloc>(
459 &'alloc self,
460 alloc: &'alloc EntityAlloc<E>,
461 ) -> EntityListReadIter<'alloc, E> {
462 EntityListReadIter {
463 alloc,
464 curr: Some(self.head),
465 end: None,
466 }
467 }
468}
469
470pub struct EntityListReadIter<'alloc, E: IEntityListNode> {
471 alloc: &'alloc EntityAlloc<E>,
472 curr: Option<PtrID<E>>,
473 end: Option<PtrID<E>>,
474}
475impl<'alloc, E: IEntityListNode> Iterator for EntityListReadIter<'alloc, E> {
476 type Item = (E::PtrID, &'alloc E);
477
478 fn next(&mut self) -> Option<Self::Item> {
479 let curr_ptr = self.curr?;
480 if Some(curr_ptr) == self.end {
481 return None;
482 }
483 let curr_obj = curr_ptr.deref(self.alloc);
484 self.curr = curr_obj.get_next_ptr();
485 Some((E::id_of_ptr(curr_ptr), curr_obj))
486 }
487}
488
489pub trait IEntityRingListNode: Sized + IEntityAllocatable {
491 fn load_head(&self) -> EntityListHead<Self>;
492 fn store_head(&self, head: EntityListHead<Self>);
493 fn is_sentinel(&self) -> bool;
494 fn new_sentinel() -> Self;
495
496 fn ring_list_node_dispose(&self, alloc: &EntityAlloc<Self>) {
497 self.detach(alloc)
498 .expect("Failed to detach node during disposal");
499 }
500 fn on_self_unplug(&self, self_id: Self::PtrID, alloc: &EntityAlloc<Self>);
501
502 #[inline]
503 fn get_prev_id(&self) -> Option<Self::PtrID> {
504 self.load_head().get_prev_id()
505 }
506 #[doc(hidden)]
507 fn get_prev_ptr(&self) -> Option<PtrID<Self>> {
508 self.load_head().get_prev_ptr()
509 }
510 #[inline]
511 fn get_next_id(&self) -> Option<Self::PtrID> {
512 self.load_head().get_next_id()
513 }
514 #[doc(hidden)]
515 fn get_next_ptr(&self) -> Option<PtrID<Self>> {
516 self.load_head().get_next_ptr()
517 }
518 #[inline]
519 fn set_prev_id(&self, prev: Option<Self::PtrID>) {
520 self.store_head(self.load_head().prev_id(prev));
521 }
522 #[doc(hidden)]
523 fn set_prev_ptr(&self, prev: Option<PtrID<Self>>) {
524 self.store_head(self.load_head().prev_ptr(prev));
525 }
526 #[inline]
527 fn set_next_id(&self, next: Option<Self::PtrID>) {
528 self.store_head(self.load_head().next_id(next));
529 }
530 #[doc(hidden)]
531 fn set_next_ptr(&self, next: Option<PtrID<Self>>) {
532 self.store_head(self.load_head().next_ptr(next));
533 }
534
535 #[inline]
536 fn is_attached(&self) -> bool {
537 let EntityListHead(prev, next) = self.load_head();
538 assert_eq!(prev.is_some(), next.is_some(), "ptrlist node is corrupted");
539 prev.is_some() || next.is_some()
540 }
541 fn detach(&self, alloc: &EntityAlloc<Self>) -> PtrListRes<Self> {
542 if self.is_sentinel() {
543 return Err(EntityListError::NodeIsSentinel);
544 }
545 let EntityListHead(Some(prev), Some(next)) = self.load_head() else {
546 return Ok(());
548 };
549 prev.deref(alloc).set_next_ptr(Some(next));
550 next.deref(alloc).set_prev_ptr(Some(prev));
551 self.store_head(EntityListHead(None, None));
552 Ok(())
553 }
554}
555impl<E: IEntityRingListNode> RawListNodeOps<E, list_util::RingList> for E {
556 fn get_prev_ptr(&self) -> Option<PtrID<E>> {
557 self.load_head().get_prev_ptr()
558 }
559 fn get_next_ptr(&self) -> Option<PtrID<E>> {
560 self.load_head().get_next_ptr()
561 }
562 fn set_prev_ptr(&self, prev: Option<PtrID<E>>) {
563 self.store_head(self.load_head().prev_ptr(prev))
564 }
565 fn set_next_ptr(&self, next: Option<PtrID<E>>) {
566 self.store_head(self.load_head().next_ptr(next))
567 }
568}
569
570impl<E: IEntityRingListNode> PtrID<E> {
571 pub fn detach(self, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
572 self.deref(alloc).detach(alloc)
573 }
574}
575
576pub struct EntityRingList<E: IEntityRingListNode> {
578 pub sentinel: E::PtrID,
579}
580
581impl<E: IEntityRingListNode> EntityRingList<E> {
582 pub fn new(alloc: &EntityAlloc<E>) -> Self {
583 let sentinel = alloc.allocate(E::new_sentinel());
584 let head = Some(sentinel);
585 sentinel.deref(alloc).store_head(EntityListHead(head, head));
586 Self {
587 sentinel: E::id_of_ptr(sentinel),
588 }
589 }
590 pub fn len(&self, alloc: &EntityAlloc<E>) -> usize {
591 let mut count = 0;
592 self.foreach(alloc, |_, _| {
593 count += 1;
594 true
595 });
596 count
597 }
598 pub fn front_id(&self, alloc: &EntityAlloc<E>) -> Option<E::PtrID> {
599 let sentinel = E::ptr_of_id(self.sentinel);
600 let next = sentinel.deref(alloc).get_next_id()?;
601 if next == self.sentinel {
602 None
603 } else {
604 Some(next)
605 }
606 }
607 pub fn back_id(&self, alloc: &EntityAlloc<E>) -> Option<E::PtrID> {
608 let sentinel = E::ptr_of_id(self.sentinel);
609 let prev = sentinel.deref(alloc).get_prev_id()?;
610 if prev == self.sentinel {
611 None
612 } else {
613 Some(prev)
614 }
615 }
616
617 pub fn is_empty(&self, alloc: &EntityAlloc<E>) -> bool {
618 const ERRMSG: &str = "ring list corrupted when checking is_empty";
619 let sentinel = E::ptr_of_id(self.sentinel);
620 let sentinel_obj = sentinel.deref(alloc);
621 let next = sentinel_obj.get_next_ptr().expect(ERRMSG);
622 next == sentinel
623 }
624 pub fn is_single(&self, alloc: &EntityAlloc<E>) -> bool {
625 const ERRMSG: &str = "ring list corrupted when checking is_single";
626 let sentinel = E::ptr_of_id(self.sentinel);
627 let sentinel_obj = sentinel.deref(alloc);
628 let next = sentinel_obj.get_next_ptr().expect(ERRMSG);
629 let prev = sentinel_obj.get_prev_ptr().expect(ERRMSG);
630 next == prev && next != sentinel
631 }
632 pub fn is_multiple(&self, alloc: &EntityAlloc<E>) -> bool {
633 const ERRMSG: &str = "ring list corrupted when checking is_multiple";
634 let sentinel = E::ptr_of_id(self.sentinel);
635 let sentinel_obj = sentinel.deref(alloc);
636 let next = sentinel_obj.get_next_ptr().expect(ERRMSG);
637 let prev = sentinel_obj.get_prev_ptr().expect(ERRMSG);
638 next != prev
639 }
640 pub fn foreach(
641 &self,
642 alloc: &EntityAlloc<E>,
643 mut pred: impl FnMut(E::PtrID, &E) -> bool,
644 ) -> bool {
645 let sentinel = E::ptr_of_id(self.sentinel);
646 let mut node_opt = sentinel.deref(alloc).get_next_ptr();
647 let mut count = 0;
648 while let Some(node_ptr) = node_opt {
649 if node_ptr == sentinel {
650 return true;
651 }
652 let node_obj = node_ptr.deref(alloc);
653 if !pred(E::id_of_ptr(node_ptr), node_obj) {
654 return false;
655 }
656 node_opt = node_obj.get_next_ptr();
657 count += 1;
658 }
659 panic!("Broken ring list detected after {count} iterations");
660 }
661 pub fn forall_with_sentinel(
662 &self,
663 alloc: &EntityAlloc<E>,
664 mut pred: impl FnMut(E::PtrID, &E) -> bool,
665 ) -> bool {
666 let mut node_opt = Some(self.sentinel);
667 let mut count = 0;
668 while let Some(node_id) = node_opt {
669 let node_ptr = E::ptr_of_id(node_id);
670 let node_obj = node_ptr.deref(alloc);
671 if !pred(node_id, node_obj) {
672 return false;
673 }
674 node_opt = node_obj.get_next_id();
675 if node_opt == Some(self.sentinel) {
676 return true;
677 }
678 count += 1;
679 }
680 panic!("Broken ring list detected after {count} iterations");
681 }
682 pub fn contains(&self, node: E::PtrID, alloc: &EntityAlloc<E>) -> bool {
683 self.foreach(alloc, |id, _| id == node)
684 }
685 #[inline]
687 pub fn clone_view(&self) -> Self {
688 Self {
689 sentinel: self.sentinel,
690 }
691 }
692 pub fn iter<'alloc>(
693 &'alloc self,
694 alloc: &'alloc EntityAlloc<E>,
695 ) -> EntityRingListReadIter<'alloc, E> {
696 let sentinel = E::ptr_of_id(self.sentinel);
697 let Some(curr) = sentinel.deref(alloc).get_next_ptr() else {
698 panic!("ring list corrupted when creating iterator");
699 };
700 EntityRingListReadIter { alloc, curr }
701 }
702 pub fn back_iter<'alloc>(
703 &'alloc self,
704 alloc: &'alloc EntityAlloc<E>,
705 ) -> Rev<EntityRingListReadIter<'alloc, E>> {
706 let sentinel = E::ptr_of_id(self.sentinel);
707 let Some(curr) = sentinel.deref(alloc).get_prev_ptr() else {
708 panic!("ring list corrupted when creating back iterator");
709 };
710 EntityRingListReadIter { alloc, curr }.rev()
711 }
712
713 pub fn push_back_id(&self, new_node: E::PtrID, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
715 const ERRMSG: &str = "Broken ring detected during push_back";
716
717 let new_node = E::ptr_of_id(new_node);
719 let sentinel = E::ptr_of_id(self.sentinel);
720 let sentinel_obj = sentinel.deref(alloc);
721
722 let prev = sentinel_obj.get_prev_ptr().expect(ERRMSG);
723 assert!(!new_node.deref(alloc).is_attached());
725 new_node
726 .deref(alloc)
727 .store_head(EntityListHead(Some(prev), Some(sentinel)));
728 sentinel_obj.set_prev_ptr(Some(new_node));
729 prev.deref(alloc).set_next_ptr(Some(new_node));
730 Ok(())
731 }
732
733 pub fn move_all_to(
738 &self,
739 other: &EntityRingList<E>,
740 alloc: &EntityAlloc<E>,
741 mut on_move: impl FnMut(E::PtrID),
742 ) -> PtrListRes<E> {
743 if self.sentinel == other.sentinel {
744 return Ok(());
745 }
746 let mut cur = self.front_id(alloc).map(E::ptr_of_id);
747 while let Some(ptr) = cur {
748 let next = ptr.deref(alloc).get_next_ptr();
749 ptr.detach(alloc)?;
750
751 let id = E::id_of_ptr(ptr);
752 other.push_back_id(id, alloc)?;
753 on_move(id);
754 cur = match next {
755 Some(n) if !n.deref(alloc).is_sentinel() => Some(n),
756 _ => None,
757 };
758 }
759 Ok(())
760 }
761 pub fn move_to_if(
763 &self,
764 other: &EntityRingList<E>,
765 alloc: &EntityAlloc<E>,
766 mut predicate: impl FnMut(E::PtrID, &E) -> bool,
767 mut on_move: impl FnMut(E::PtrID),
768 ) -> PtrListRes<E> {
769 if self.sentinel == other.sentinel {
770 return Ok(());
771 }
772 let mut cur = self.front_id(alloc).map(E::ptr_of_id);
773 while let Some(ptr) = cur {
774 let next = ptr.deref(alloc).get_next_ptr();
775 let id = E::PtrID::from(ptr);
776 let obj = ptr.deref(alloc);
777 if predicate(id, obj) {
778 ptr.detach(alloc)?;
779 other.push_back_id(id, alloc)?;
780 on_move(id);
781 }
782 cur = match next {
783 Some(n) if !n.deref(alloc).is_sentinel() => Some(n),
784 _ => None,
785 };
786 }
787 Ok(())
788 }
789
790 pub fn clean(&self, alloc: &EntityAlloc<E>) {
792 let sentinel = E::ptr_of_id(self.sentinel);
793 let mut node = sentinel.deref(alloc).get_next_ptr();
794 let mut count = 0;
795 while let Some(node_ptr) = node {
796 if node_ptr == sentinel {
797 let head = EntityListHead(Some(sentinel), Some(sentinel));
798 sentinel.deref(alloc).store_head(head);
799 return;
800 }
801 let next = node_ptr.deref(alloc).get_next_ptr();
802 let node_obj = node_ptr.deref(alloc);
803 node_obj.store_head(EntityListHead(None, None));
804 node_obj.on_self_unplug(E::id_of_ptr(node_ptr), alloc);
805 node = next;
806 count += 1;
807 }
808 panic!("Broken ring list detected during clean after {count} iterations");
809 }
810
811 pub fn pop_back(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, E::PtrID> {
812 let back_id = self.back_id(alloc).ok_or(EntityListError::EmptyList)?;
813 let back_ptr = E::ptr_of_id(back_id);
814 back_ptr.detach(alloc)?;
815 back_ptr.deref(alloc).on_self_unplug(back_id, alloc);
816 Ok(back_id)
817 }
818 pub fn pop_front(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, PtrID<E>> {
819 let front_id = self.front_id(alloc).ok_or(EntityListError::EmptyList)?;
820 let front_ptr = E::ptr_of_id(front_id);
821 front_ptr.detach(alloc)?;
822 front_ptr.deref(alloc).on_self_unplug(front_id, alloc);
823 Ok(front_ptr)
824 }
825}
826
827pub struct EntityRingListReadIter<'alloc, E: IEntityRingListNode> {
828 alloc: &'alloc EntityAlloc<E>,
829 curr: PtrID<E>,
830}
831
832impl<'alloc, E: IEntityRingListNode> Iterator for EntityRingListReadIter<'alloc, E> {
833 type Item = (E::PtrID, &'alloc E);
834
835 fn next(&mut self) -> Option<Self::Item> {
836 let curr_ptr = self.curr;
837 let curr_obj = curr_ptr.deref(self.alloc);
838 if curr_obj.is_sentinel() {
839 return None;
840 }
841 let Some(next_ptr) = curr_obj.get_next_ptr() else {
842 panic!("Broken ring list detected during iteration");
843 };
844 if next_ptr == curr_ptr {
845 return None;
846 }
847 self.curr = next_ptr;
848 Some((E::id_of_ptr(curr_ptr), curr_obj))
849 }
850}
851impl<'alloc, E: IEntityRingListNode> DoubleEndedIterator for EntityRingListReadIter<'alloc, E> {
852 fn next_back(&mut self) -> Option<Self::Item> {
853 let curr_ptr = self.curr;
854 let curr_obj = curr_ptr.deref(self.alloc);
855 if curr_obj.is_sentinel() {
856 return None;
857 }
858 let Some(prev_ptr) = curr_obj.get_prev_ptr() else {
859 panic!("Broken ring list detected during back iteration");
860 };
861 if prev_ptr == curr_ptr {
862 return None;
863 }
864 self.curr = prev_ptr;
865 Some((E::id_of_ptr(curr_ptr), curr_obj))
866 }
867}