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