mtb_entity_slab/container/
entity_list.rs1use std::cell::Cell;
22
23use crate::{
24 EntityListError, EntityListIter, EntityListNodeHead, EntityListRange, EntityListRes,
25 IBasicEntityListID, IDBoundAlloc, container::list_base::NodeOps,
26};
27
28pub trait IEntityListNodeID: IBasicEntityListID {
36 fn comes_before(self, latter: Self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self, bool> {
38 let mut node = self;
39 while let Some(next) = node.get_next_id(alloc) {
40 if next == latter {
41 return Ok(true);
42 }
43 node = next;
44 }
45 if node.is_sentinel(alloc) {
46 Ok(false)
47 } else {
48 Err(EntityListError::ListBroken)
49 }
50 }
51}
52
53pub struct EntityList<I: IEntityListNodeID> {
66 pub head: I,
68 pub tail: I,
70 pub len: Cell<usize>,
72}
73
74impl<I: IEntityListNodeID> EntityList<I> {
75 pub fn new(alloc: &IDBoundAlloc<I>) -> Self {
78 let head = I::new_sentinel(alloc);
79 let tail = I::new_sentinel(alloc);
80 head.set_next_id(alloc, Some(tail));
81 tail.set_prev_id(alloc, Some(head));
82 Self {
83 head,
84 tail,
85 len: Cell::new(0),
86 }
87 }
88
89 #[inline]
91 pub fn len(&self) -> usize {
92 self.len.get()
93 }
94 #[inline]
96 pub fn is_empty(&self) -> bool {
97 self.len() == 0
98 }
99
100 #[inline]
102 pub fn get_front_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
103 let next = self.head.get_next_id(alloc)?;
104 if next == self.tail { None } else { Some(next) }
105 }
106 #[inline]
108 pub fn get_back_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
109 let prev = self.tail.get_prev_id(alloc)?;
110 if prev == self.head { None } else { Some(prev) }
111 }
112
113 pub fn node_add_next(&self, node: I, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
123 if node == new_node {
124 return Err(EntityListError::RepeatedNode);
125 }
126 if node == self.tail {
127 return Err(EntityListError::NodeIsSentinel);
128 }
129 node.on_push_next(new_node, alloc)?;
130
131 let node_obj = node.deref_alloc(alloc);
132 let new_node_obj = new_node.deref_alloc(alloc);
133
134 debug_assert!(
135 I::obj_is_attached(node_obj),
136 "Cannot add next to a detached node"
137 );
138 debug_assert!(
139 !I::obj_is_attached(new_node_obj),
140 "Cannot add a node that is already attached"
141 );
142
143 let Some(old_next) = I::obj_get_next_id(node_obj) else {
144 return Err(EntityListError::ListBroken);
145 };
146 I::obj_set_next_id(node_obj, Some(new_node));
147 I::obj_store_head(new_node_obj, EntityListNodeHead::from_id(node, old_next));
148 old_next.set_prev_id(alloc, Some(new_node));
149 self.len.set(self.len.get() + 1);
150 Ok(())
151 }
152
153 pub fn node_add_prev(&self, node: I, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
163 if node == new_node {
164 return Err(EntityListError::RepeatedNode);
165 }
166 if node == self.head {
167 return Err(EntityListError::NodeIsSentinel);
168 }
169 node.on_push_prev(new_node, alloc)?;
170
171 let node_obj = node.deref_alloc(alloc);
172 let new_node_obj = new_node.deref_alloc(alloc);
173
174 debug_assert!(
175 I::obj_is_attached(node_obj),
176 "Cannot add prev to a detached node"
177 );
178 debug_assert!(
179 !I::obj_is_attached(new_node_obj),
180 "Cannot add a node that is already attached"
181 );
182
183 let Some(old_prev) = I::obj_get_prev_id(node_obj) else {
184 return Err(EntityListError::ListBroken);
185 };
186 NodeOps::obj_set_prev_id(node_obj, Some(new_node));
187 I::obj_store_head(new_node_obj, EntityListNodeHead::from_id(old_prev, node));
188 old_prev.set_next_id(alloc, Some(new_node));
189 self.len.set(self.len.get() + 1);
190 Ok(())
191 }
192
193 pub fn node_unplug(&self, node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
200 if node == self.head || node == self.tail {
201 return Err(EntityListError::NodeIsSentinel);
202 }
203 node.on_unplug(alloc)?;
204
205 let node_obj = node.deref_alloc(alloc);
206
207 debug_assert!(
208 I::obj_is_attached(node_obj),
209 "Cannot unplug a detached node"
210 );
211
212 let Some(prev) = I::obj_get_prev_id(node_obj) else {
213 return Err(EntityListError::ListBroken);
214 };
215 let Some(next) = I::obj_get_next_id(node_obj) else {
216 return Err(EntityListError::ListBroken);
217 };
218 prev.set_next_id(alloc, Some(next));
219 next.set_prev_id(alloc, Some(prev));
220 I::obj_store_head(node_obj, EntityListNodeHead::none());
221 self.len.set(self.len.get() - 1);
222 Ok(())
223 }
224
225 #[inline]
227 pub fn push_back_id(&self, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
228 self.node_add_prev(self.tail, new_node, alloc)
229 }
230
231 #[inline]
233 pub fn push_front_id(&self, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
234 self.node_add_next(self.head, new_node, alloc)
235 }
236
237 pub fn pop_back(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
239 let back_id = self.get_back_id(alloc).ok_or(EntityListError::EmptyList)?;
240 self.node_unplug(back_id, alloc)?;
241 Ok(back_id)
242 }
243
244 pub fn pop_front(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
246 let front_id = self.get_front_id(alloc).ok_or(EntityListError::EmptyList)?;
247 self.node_unplug(front_id, alloc)?;
248 Ok(front_id)
249 }
250
251 pub fn get_range(&self, alloc: &IDBoundAlloc<I>) -> EntityListRange<I> {
253 EntityListRange {
254 start: self.head.get_next_id(alloc).unwrap(),
255 end: Some(self.tail),
256 }
257 }
258 pub fn get_range_with_sentinels(&self) -> EntityListRange<I> {
260 EntityListRange {
261 start: self.head,
262 end: None,
263 }
264 }
265
266 pub fn iter<'alloc>(&self, alloc: &'alloc IDBoundAlloc<I>) -> EntityListIter<'alloc, I> {
268 EntityListIter::new(self.get_range(alloc), alloc)
269 }
270 pub fn iter_with_sentinels<'alloc>(
272 &self,
273 alloc: &'alloc IDBoundAlloc<I>,
274 ) -> EntityListIter<'alloc, I> {
275 EntityListIter::new(self.get_range_with_sentinels(), alloc)
276 }
277
278 pub fn forall_with_sentinel(
280 &self,
281 alloc: &IDBoundAlloc<I>,
282 mut f: impl FnMut(I, &I::ObjectT) -> EntityListRes<I>,
283 ) -> EntityListRes<I, ()> {
284 let mut curr = self.head;
285 loop {
286 f(curr, curr.deref_alloc(alloc))?;
287 if curr == self.tail {
288 break;
289 }
290 let next = curr.get_next_id(alloc).ok_or(EntityListError::ListBroken)?;
291 curr = next;
292 }
293 Ok(())
294 }
295}