1use crate::queue::MetaQueue;
50use crate::vec::MetaVec;
51use crate::{queue::RelocatableQueue, vec::RelocatableVec};
52use core::mem::MaybeUninit;
53use iceoryx2_bb_concurrency::atomic::AtomicBool;
54use iceoryx2_bb_derive_macros::ZeroCopySend;
55use iceoryx2_bb_elementary::bump_allocator::BumpAllocator;
56use iceoryx2_bb_elementary::relocatable_ptr::GenericRelocatablePointer;
57use iceoryx2_bb_elementary_traits::generic_pointer::GenericPointer;
58use iceoryx2_bb_elementary_traits::non_null::NonNullCompat;
59use iceoryx2_bb_elementary_traits::owning_pointer::GenericOwningPointer;
60use iceoryx2_bb_elementary_traits::placement_default::PlacementDefault;
61pub use iceoryx2_bb_elementary_traits::relocatable_container::RelocatableContainer;
62use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
63use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
64use iceoryx2_log::{fail, fatal_panic};
65
66use core::ptr::NonNull;
67
68#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
71pub struct SlotMapKey(usize);
72
73impl SlotMapKey {
74 pub fn new(value: usize) -> Self {
76 Self(value)
77 }
78
79 pub fn value(&self) -> usize {
81 self.0
82 }
83}
84
85#[repr(C)]
86#[derive(Debug, Clone, Copy, ZeroCopySend)]
87pub(crate) struct FreeListEntry {
88 previous: usize,
89 next: usize,
90}
91
92pub type SlotMap<T> = MetaSlotMap<T, GenericOwningPointer>;
95
96pub type RelocatableSlotMap<T> = MetaSlotMap<T, GenericRelocatablePointer>;
98
99const INVALID: usize = usize::MAX;
100
101#[doc(hidden)]
102pub struct Iter<'slotmap, T, Ptr: GenericPointer> {
104 slotmap: &'slotmap MetaSlotMap<T, Ptr>,
105 key: SlotMapKey,
106}
107
108#[doc(hidden)]
109pub type OwningIter<'slotmap, T> = Iter<'slotmap, T, GenericOwningPointer>;
110#[doc(hidden)]
111pub type RelocatableIter<'slotmap, T> = Iter<'slotmap, T, GenericRelocatablePointer>;
112
113impl<'slotmap, T, Ptr: GenericPointer> Iterator for Iter<'slotmap, T, Ptr> {
114 type Item = (SlotMapKey, &'slotmap T);
115
116 fn next(&mut self) -> Option<Self::Item> {
117 if let Some((next_key, value)) = self.slotmap.next_available_key_after(self.key) {
118 self.key.0 = next_key.0 + 1;
119 Some((next_key, value))
120 } else {
121 None
122 }
123 }
124}
125
126#[doc(hidden)]
127#[repr(C)]
128#[derive(Debug)]
129pub struct MetaSlotMap<T, Ptr: GenericPointer> {
130 idx_to_data: MetaVec<usize, Ptr>,
131 idx_to_data_free_list: MetaVec<FreeListEntry, Ptr>,
132 data: MetaVec<Option<T>, Ptr>,
133 data_next_free_index: MetaQueue<usize, Ptr>,
134 idx_to_data_free_list_head: usize,
135 is_initialized: AtomicBool,
136 len: usize,
137}
138
139impl<T: Abandonable, Ptr: GenericPointer> Abandonable for MetaSlotMap<T, Ptr> {
140 unsafe fn abandon_in_place(mut this: NonNull<Self>) {
141 let this = unsafe { this.as_mut() };
142 for element in this.data.iter_mut().flatten() {
143 unsafe { T::abandon_in_place(NonNull::iox2_from_mut(element)) };
144 }
145 }
146}
147
148impl<T, Ptr: GenericPointer> MetaSlotMap<T, Ptr> {
149 #[inline(always)]
150 fn verify_init(&self, source: &str) {
151 debug_assert!(
152 self.is_initialized
153 .load(core::sync::atomic::Ordering::Relaxed),
154 "From: MetaSlotMap<{}>::{}, Undefined behavior - the object was not initialized with 'init' before.",
155 core::any::type_name::<T>(),
156 source
157 );
158 }
159
160 fn next_available_key_after(&self, start: SlotMapKey) -> Option<(SlotMapKey, &T)> {
161 let idx_to_data = &self.idx_to_data;
162
163 for n in start.0..idx_to_data.len() {
164 let data_idx = self.idx_to_data[n];
165 if data_idx != INVALID {
166 return Some((
167 SlotMapKey(n),
168 self.data[data_idx].as_ref().expect(
169 "By contract, data contains a value when idx_to_data contains a value",
170 ),
171 ));
172 }
173 }
174
175 None
176 }
177
178 pub(crate) unsafe fn initialize_data_structures(&mut self) {
179 let capacity = self.capacity_impl();
180 for n in 0..capacity {
181 unsafe {
182 self.idx_to_data.push_impl(INVALID);
183 self.data.push_impl(None);
184 self.data_next_free_index.push_impl(n);
185 }
186 let previous = if n == 0 { INVALID } else { n - 1 };
187 let next = if n < capacity - 1 { n + 1 } else { INVALID };
188 unsafe {
189 self.idx_to_data_free_list
190 .push_impl(FreeListEntry { previous, next });
191 }
192 }
193 }
194
195 pub(crate) unsafe fn iter_impl(&self) -> Iter<'_, T, Ptr> {
196 self.verify_init("iter()");
197 Iter {
198 slotmap: self,
199 key: SlotMapKey(0),
200 }
201 }
202
203 pub(crate) unsafe fn contains_impl(&self, key: SlotMapKey) -> bool {
204 self.verify_init("contains()");
205 self.idx_to_data[key.0] != INVALID
206 }
207
208 pub(crate) unsafe fn get_impl(&self, key: SlotMapKey) -> Option<&T> {
209 self.verify_init("get()");
210 match self.idx_to_data[key.0] {
211 INVALID => None,
212 n => Some(self.data[n].as_ref().expect(
213 "data and idx_to_data correspond and this value must be always available.",
214 )),
215 }
216 }
217
218 pub(crate) unsafe fn get_mut_impl(&mut self, key: SlotMapKey) -> Option<&mut T> {
219 self.verify_init("get_mut()");
220 match self.idx_to_data[key.0] {
221 INVALID => None,
222 n => Some(self.data[n].as_mut().expect(
223 "data and idx_to_data correspond and this value must be always available.",
224 )),
225 }
226 }
227
228 unsafe fn acquire_next_free_index(&mut self) -> Option<usize> {
229 if self.idx_to_data_free_list_head == INVALID {
230 return None;
231 }
232
233 let free_idx = self.idx_to_data_free_list_head;
234 let next = self.idx_to_data_free_list[free_idx].next;
235
236 if next != INVALID {
237 self.idx_to_data_free_list[next].previous = INVALID;
238 }
239 self.idx_to_data_free_list_head = next;
240 Some(free_idx)
241 }
242
243 unsafe fn claim_index(&mut self, idx: usize) {
244 if idx >= self.capacity_impl() {
245 return;
246 }
247
248 let entry = self.idx_to_data_free_list[idx];
249 if entry.previous != INVALID {
250 self.idx_to_data_free_list[entry.previous].next = entry.next;
251 }
252 if entry.next != INVALID {
253 self.idx_to_data_free_list[entry.next].previous = entry.previous;
254 }
255 self.idx_to_data_free_list[idx].next = INVALID;
256 self.idx_to_data_free_list[idx].previous = INVALID;
257 }
258
259 unsafe fn release_free_index(&mut self, idx: usize) {
260 if self.idx_to_data_free_list_head != INVALID {
261 self.idx_to_data_free_list[self.idx_to_data_free_list_head].previous = idx;
262 }
263
264 self.idx_to_data_free_list[idx] = FreeListEntry {
265 previous: INVALID,
266 next: self.idx_to_data_free_list_head,
267 };
268
269 self.idx_to_data_free_list_head = idx;
270 }
271
272 pub(crate) unsafe fn insert_impl(&mut self, value: T) -> Option<SlotMapKey> {
273 self.verify_init("insert()");
274
275 unsafe {
276 self.acquire_next_free_index().map(|key| {
277 let key = SlotMapKey(key);
278 self.store_value(key, value);
279 key
280 })
281 }
282 }
283
284 pub(crate) unsafe fn insert_at_impl(&mut self, key: SlotMapKey, value: T) -> bool {
285 self.verify_init("insert_at()");
286 unsafe {
287 self.claim_index(key.value());
288 self.store_value(key, value)
289 }
290 }
291
292 pub(crate) unsafe fn store_value(&mut self, key: SlotMapKey, value: T) -> bool {
293 self.verify_init("store()");
294 if key.0 > self.capacity_impl() {
295 return false;
296 }
297
298 let data_idx = self.idx_to_data[key.0];
299 if data_idx != INVALID {
300 self.data[data_idx] = Some(value);
301 } else {
302 let n = unsafe { self.data_next_free_index.pop_impl() }.expect(
303 "data and idx_to_data correspond and there must be always a free index available.",
304 );
305 self.idx_to_data[key.0] = n;
306 self.data[n] = Some(value);
307 self.len += 1;
308 }
309
310 true
311 }
312
313 pub(crate) unsafe fn remove_impl(&mut self, key: SlotMapKey) -> Option<T> {
314 self.verify_init("remove()");
315 if key.0 > self.idx_to_data.len() {
316 return None;
317 }
318
319 let data_idx = self.idx_to_data[key.0];
320 if data_idx != INVALID {
321 let ret = self.data[data_idx].take();
322 let push_result = unsafe { self.data_next_free_index.push_impl(data_idx) };
323 debug_assert!(push_result);
324 unsafe { self.release_free_index(key.0) };
325 self.idx_to_data[key.0] = INVALID;
326 self.len -= 1;
327 ret
328 } else {
329 None
330 }
331 }
332
333 pub(crate) unsafe fn next_free_key_impl(&self) -> Option<SlotMapKey> {
334 self.verify_init("next_free_key()");
335 if self.idx_to_data_free_list_head == INVALID {
336 return None;
337 }
338
339 Some(SlotMapKey::new(self.idx_to_data_free_list_head))
340 }
341
342 pub(crate) fn len_impl(&self) -> usize {
343 self.len
344 }
345
346 pub(crate) fn capacity_impl(&self) -> usize {
347 self.idx_to_data.capacity()
348 }
349
350 pub(crate) fn is_empty_impl(&self) -> bool {
351 self.len_impl() == 0
352 }
353
354 pub(crate) fn is_full_impl(&self) -> bool {
355 self.len_impl() == self.capacity_impl()
356 }
357}
358
359impl<T> RelocatableContainer for RelocatableSlotMap<T> {
360 unsafe fn new_uninit(capacity: usize) -> Self {
361 Self {
362 len: 0,
363 idx_to_data_free_list_head: 0,
364 idx_to_data: unsafe { RelocatableVec::new_uninit(capacity) },
365 idx_to_data_free_list: unsafe { RelocatableVec::new_uninit(capacity) },
366 data: unsafe { RelocatableVec::new_uninit(capacity) },
367 data_next_free_index: unsafe { RelocatableQueue::new_uninit(capacity) },
368 is_initialized: AtomicBool::new(false),
369 }
370 }
371
372 unsafe fn init<Allocator: iceoryx2_bb_elementary_traits::allocator::BaseAllocator>(
373 &mut self,
374 allocator: &Allocator,
375 ) -> Result<(), iceoryx2_bb_elementary_traits::allocator::AllocationError> {
376 if self
377 .is_initialized
378 .load(core::sync::atomic::Ordering::Relaxed)
379 {
380 fatal_panic!(from "RelocatableSlotMap::init()", "Memory already initialized. Initializing it twice may lead to undefined behavior.");
381 }
382 let msg = "Unable to initialize RelocatableSlotMap";
383 fail!(from "RelocatableSlotMap::init()",
384 when unsafe {self.idx_to_data.init(allocator)},
385 "{msg} since the underlying idx_to_data vector could not be initialized.");
386 fail!(from "RelocatableSlotMap::init()",
387 when unsafe {self.idx_to_data_free_list.init(allocator)},
388 "{msg} since the underlying idx_to_data_free_list vec could not be initialized.");
389 fail!(from "RelocatableSlotMap::init()",
390 when unsafe {self.data.init(allocator)},
391 "{msg} since the underlying data vector could not be initialized.");
392 fail!(from "RelocatableSlotMap::init()",
393 when unsafe {self.data_next_free_index.init(allocator)},
394 "{msg} since the underlying data_next_free_index queue could not be initialized.");
395
396 unsafe { self.initialize_data_structures() };
397 self.is_initialized
398 .store(true, core::sync::atomic::Ordering::Relaxed);
399 Ok(())
400 }
401
402 fn memory_size(capacity: usize) -> usize {
403 Self::const_memory_size(capacity)
404 }
405}
406
407impl<T> SlotMap<T> {
408 pub fn new(capacity: usize) -> Self {
410 let mut new_self = Self {
411 len: 0,
412 idx_to_data_free_list_head: 0,
413 idx_to_data: MetaVec::new(capacity),
414 idx_to_data_free_list: MetaVec::new(capacity),
415 data: MetaVec::new(capacity),
416 data_next_free_index: MetaQueue::new(capacity),
417 is_initialized: AtomicBool::new(true),
418 };
419 unsafe { new_self.initialize_data_structures() };
420 new_self
421 }
422
423 pub fn iter(&self) -> OwningIter<'_, T> {
425 unsafe { self.iter_impl() }
426 }
427
428 pub fn contains(&self, key: SlotMapKey) -> bool {
430 unsafe { self.contains_impl(key) }
431 }
432
433 pub fn get(&self, key: SlotMapKey) -> Option<&T> {
436 unsafe { self.get_impl(key) }
437 }
438
439 pub fn get_mut(&mut self, key: SlotMapKey) -> Option<&mut T> {
442 unsafe { self.get_mut_impl(key) }
443 }
444
445 pub fn insert(&mut self, value: T) -> Option<SlotMapKey> {
448 unsafe { self.insert_impl(value) }
449 }
450
451 pub fn insert_at(&mut self, key: SlotMapKey, value: T) -> bool {
455 unsafe { self.insert_at_impl(key, value) }
456 }
457
458 pub fn remove(&mut self, key: SlotMapKey) -> Option<T> {
461 unsafe { self.remove_impl(key) }
462 }
463
464 pub fn next_free_key(&self) -> Option<SlotMapKey> {
467 unsafe { self.next_free_key_impl() }
468 }
469
470 pub fn len(&self) -> usize {
472 self.len_impl()
473 }
474
475 pub fn capacity(&self) -> usize {
477 self.capacity_impl()
478 }
479
480 pub fn is_empty(&self) -> bool {
482 self.is_empty_impl()
483 }
484
485 pub fn is_full(&self) -> bool {
487 self.is_full_impl()
488 }
489}
490
491unsafe impl<T: ZeroCopySend> ZeroCopySend for RelocatableSlotMap<T> {}
492
493impl<T> RelocatableSlotMap<T> {
494 pub const fn const_memory_size(capacity: usize) -> usize {
497 RelocatableVec::<usize>::const_memory_size(capacity)
498 + RelocatableVec::<FreeListEntry>::const_memory_size(capacity)
499 + RelocatableVec::<Option<T>>::const_memory_size(capacity)
500 + RelocatableQueue::<usize>::const_memory_size(capacity)
501 }
502
503 pub unsafe fn iter(&self) -> RelocatableIter<'_, T> {
510 unsafe { self.iter_impl() }
511 }
512
513 pub unsafe fn contains(&self, key: SlotMapKey) -> bool {
520 unsafe { self.contains_impl(key) }
521 }
522
523 pub unsafe fn get(&self, key: SlotMapKey) -> Option<&T> {
531 unsafe { self.get_impl(key) }
532 }
533
534 pub unsafe fn get_mut(&mut self, key: SlotMapKey) -> Option<&mut T> {
542 unsafe { self.get_mut_impl(key) }
543 }
544
545 pub unsafe fn insert(&mut self, value: T) -> Option<SlotMapKey> {
553 unsafe { self.insert_impl(value) }
554 }
555
556 pub unsafe fn insert_at(&mut self, key: SlotMapKey, value: T) -> bool {
565 unsafe { self.insert_at_impl(key, value) }
566 }
567
568 pub unsafe fn remove(&mut self, key: SlotMapKey) -> Option<T> {
576 unsafe { self.remove_impl(key) }
577 }
578
579 pub unsafe fn next_free_key(&self) -> Option<SlotMapKey> {
587 unsafe { self.next_free_key_impl() }
588 }
589
590 pub fn len(&self) -> usize {
592 self.len_impl()
593 }
594
595 pub fn capacity(&self) -> usize {
597 self.capacity_impl()
598 }
599
600 pub fn is_empty(&self) -> bool {
602 self.is_empty_impl()
603 }
604
605 pub fn is_full(&self) -> bool {
607 self.is_full_impl()
608 }
609}
610
611#[repr(C)]
613#[derive(Debug)]
614pub struct FixedSizeSlotMap<T, const CAPACITY: usize> {
615 state: RelocatableSlotMap<T>,
616 _idx_to_data: MaybeUninit<[usize; CAPACITY]>,
617 _idx_to_data_free_list: MaybeUninit<[FreeListEntry; CAPACITY]>,
618 _data: MaybeUninit<[Option<T>; CAPACITY]>,
619 _data_next_free_index: MaybeUninit<[usize; CAPACITY]>,
620}
621
622unsafe impl<T: ZeroCopySend, const CAPACITY: usize> ZeroCopySend for FixedSizeSlotMap<T, CAPACITY> {}
623
624impl<T, const CAPACITY: usize> PlacementDefault for FixedSizeSlotMap<T, CAPACITY> {
625 unsafe fn placement_default(ptr: *mut Self) {
626 unsafe {
627 let state_ptr = core::ptr::addr_of_mut!((*ptr).state);
628 state_ptr.write(RelocatableSlotMap::new_uninit(CAPACITY));
629 let allocator = BumpAllocator::new((*ptr)._idx_to_data.as_mut_ptr().cast());
630 (*ptr)
631 .state
632 .init(&allocator)
633 .expect("All required memory is preallocated.");
634 }
635 }
636}
637
638impl<T, const CAPACITY: usize> Default for FixedSizeSlotMap<T, CAPACITY> {
639 fn default() -> Self {
640 let mut new_self = Self {
641 _idx_to_data: MaybeUninit::uninit(),
642 _idx_to_data_free_list: MaybeUninit::uninit(),
643 _data: MaybeUninit::uninit(),
644 _data_next_free_index: MaybeUninit::uninit(),
645 state: unsafe { RelocatableSlotMap::new_uninit(CAPACITY) },
646 };
647
648 let allocator = BumpAllocator::new(new_self._idx_to_data.as_mut_ptr().cast());
649 unsafe {
650 new_self
651 .state
652 .init(&allocator)
653 .expect("All required memory is preallocated.")
654 };
655
656 new_self
657 }
658}
659
660impl<T, const CAPACITY: usize> FixedSizeSlotMap<T, CAPACITY> {
661 pub fn new() -> Self {
663 Self::default()
664 }
665
666 pub fn iter(&self) -> RelocatableIter<'_, T> {
668 unsafe { self.state.iter_impl() }
669 }
670
671 pub fn contains(&self, key: SlotMapKey) -> bool {
673 unsafe { self.state.contains_impl(key) }
674 }
675
676 pub fn get(&self, key: SlotMapKey) -> Option<&T> {
679 unsafe { self.state.get_impl(key) }
680 }
681
682 pub fn get_mut(&mut self, key: SlotMapKey) -> Option<&mut T> {
685 unsafe { self.state.get_mut_impl(key) }
686 }
687
688 pub fn insert(&mut self, value: T) -> Option<SlotMapKey> {
691 unsafe { self.state.insert_impl(value) }
692 }
693
694 pub fn insert_at(&mut self, key: SlotMapKey, value: T) -> bool {
698 unsafe { self.state.insert_at_impl(key, value) }
699 }
700
701 pub fn remove(&mut self, key: SlotMapKey) -> Option<T> {
704 unsafe { self.state.remove_impl(key) }
705 }
706
707 pub fn next_free_key(&self) -> Option<SlotMapKey> {
710 unsafe { self.state.next_free_key_impl() }
711 }
712
713 pub fn len(&self) -> usize {
715 self.state.len_impl()
716 }
717
718 pub fn capacity(&self) -> usize {
720 self.state.capacity_impl()
721 }
722
723 pub fn is_empty(&self) -> bool {
725 self.state.is_empty_impl()
726 }
727
728 pub fn is_full(&self) -> bool {
730 self.state.is_full_impl()
731 }
732}