solverforge_solver/heuristic/move/
arena.rs1use std::fmt::Debug;
8use std::mem::MaybeUninit;
9use std::ptr;
10
11pub struct MoveArena<M> {
50 storage: Vec<MaybeUninit<M>>,
52 len: usize,
54 taken: Option<usize>,
56}
57
58impl<M> MoveArena<M> {
59 #[inline]
61 pub fn new() -> Self {
62 Self {
63 storage: Vec::new(),
64 len: 0,
65 taken: None,
66 }
67 }
68
69 #[inline]
71 pub fn with_capacity(capacity: usize) -> Self {
72 Self {
73 storage: Vec::with_capacity(capacity),
74 len: 0,
75 taken: None,
76 }
77 }
78
79 #[inline]
83 pub fn reset(&mut self) {
84 for i in 0..self.len {
86 if self.taken != Some(i) {
87 unsafe {
88 ptr::drop_in_place(self.storage[i].as_mut_ptr());
89 }
90 }
91 }
92 self.len = 0;
93 self.taken = None;
94 }
95
96 #[inline]
98 pub fn push(&mut self, m: M) {
99 if self.len < self.storage.len() {
100 self.storage[self.len] = MaybeUninit::new(m);
102 } else {
103 self.storage.push(MaybeUninit::new(m));
105 }
106 self.len += 1;
107 }
108
109 #[inline]
111 pub fn len(&self) -> usize {
112 self.len
113 }
114
115 #[inline]
117 pub fn is_empty(&self) -> bool {
118 self.len == 0
119 }
120
121 #[inline]
123 pub fn iter(&self) -> impl Iterator<Item = &M> {
124 self.storage[..self.len]
125 .iter()
126 .map(|slot| unsafe { slot.assume_init_ref() })
127 }
128
129 #[inline]
131 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut M> {
132 self.storage[..self.len]
133 .iter_mut()
134 .map(|slot| unsafe { slot.assume_init_mut() })
135 }
136
137 #[inline]
139 pub fn get(&self, index: usize) -> Option<&M> {
140 if index < self.len {
141 Some(unsafe { self.storage[index].assume_init_ref() })
142 } else {
143 None
144 }
145 }
146
147 #[inline]
172 pub fn take(&mut self, index: usize) -> M {
173 assert!(index < self.len, "index out of bounds");
174 assert!(self.taken.is_none(), "move already taken this step");
175 self.taken = Some(index);
176 unsafe { self.storage[index].assume_init_read() }
177 }
178
179 #[inline]
181 pub fn extend<I: IntoIterator<Item = M>>(&mut self, iter: I) {
182 for m in iter {
183 self.push(m);
184 }
185 }
186
187 #[inline]
189 pub fn capacity(&self) -> usize {
190 self.storage.capacity()
191 }
192}
193
194impl<M> Default for MoveArena<M> {
195 fn default() -> Self {
196 Self::new()
197 }
198}
199
200impl<M: Debug> Debug for MoveArena<M> {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 f.debug_struct("MoveArena")
203 .field("len", &self.len)
204 .field("capacity", &self.storage.capacity())
205 .finish()
206 }
207}
208
209impl<M> Drop for MoveArena<M> {
210 fn drop(&mut self) {
211 for i in 0..self.len {
213 if self.taken != Some(i) {
214 unsafe {
215 ptr::drop_in_place(self.storage[i].as_mut_ptr());
216 }
217 }
218 }
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn test_arena_basic() {
228 let mut arena: MoveArena<i32> = MoveArena::new();
229 assert!(arena.is_empty());
230
231 arena.push(1);
232 arena.push(2);
233 arena.push(3);
234
235 assert_eq!(arena.len(), 3);
236 assert_eq!(arena.get(0), Some(&1));
237 assert_eq!(arena.get(1), Some(&2));
238 assert_eq!(arena.get(2), Some(&3));
239 assert_eq!(arena.get(3), None);
240 }
241
242 #[test]
243 fn test_arena_reset() {
244 let mut arena: MoveArena<i32> = MoveArena::new();
245 arena.push(1);
246 arena.push(2);
247 arena.push(3);
248
249 let capacity_before = arena.capacity();
250
251 arena.reset();
252
253 assert!(arena.is_empty());
254 assert_eq!(arena.len(), 0);
255 assert_eq!(arena.capacity(), capacity_before);
257 }
258
259 #[test]
260 fn test_arena_reuse_after_reset() {
261 let mut arena: MoveArena<i32> = MoveArena::new();
262
263 arena.push(1);
265 arena.push(2);
266 assert_eq!(arena.len(), 2);
267
268 arena.reset();
269
270 arena.push(10);
272 arena.push(20);
273 arena.push(30);
274 assert_eq!(arena.len(), 3);
275 assert_eq!(arena.get(0), Some(&10));
276 assert_eq!(arena.get(1), Some(&20));
277 assert_eq!(arena.get(2), Some(&30));
278 }
279
280 #[test]
281 fn test_arena_iter() {
282 let mut arena: MoveArena<i32> = MoveArena::new();
283 arena.push(1);
284 arena.push(2);
285 arena.push(3);
286
287 let collected: Vec<_> = arena.iter().copied().collect();
288 assert_eq!(collected, vec![1, 2, 3]);
289 }
290
291 #[test]
292 fn test_arena_extend() {
293 let mut arena: MoveArena<i32> = MoveArena::new();
294 arena.extend(vec![1, 2, 3]);
295 assert_eq!(arena.len(), 3);
296
297 let collected: Vec<_> = arena.iter().copied().collect();
298 assert_eq!(collected, vec![1, 2, 3]);
299 }
300
301 #[test]
302 fn test_arena_with_capacity() {
303 let arena: MoveArena<i32> = MoveArena::with_capacity(100);
304 assert!(arena.is_empty());
305 assert!(arena.capacity() >= 100);
306 }
307
308 #[test]
309 fn test_arena_take() {
310 let mut arena: MoveArena<String> = MoveArena::new();
311 arena.push("a".to_string());
312 arena.push("b".to_string());
313 arena.push("c".to_string());
314
315 let taken = arena.take(1);
316 assert_eq!(taken, "b");
317
318 arena.reset();
320 assert!(arena.is_empty());
321
322 arena.push("x".to_string());
324 let taken = arena.take(0);
325 assert_eq!(taken, "x");
326 }
327
328 #[test]
329 #[should_panic(expected = "move already taken")]
330 fn test_arena_double_take_panics() {
331 let mut arena: MoveArena<i32> = MoveArena::new();
332 arena.push(1);
333 arena.push(2);
334 arena.take(0);
335 arena.take(1); }
337}