Skip to main content

iceoryx2_bb_container/
slotmap.rs

1// Copyright (c) 2024 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13//! A SlotMap is a container that has a static unique key for every stored value. Adding or
14//! removing values to the SlotMap do not change the unique key of the remaining values.
15//! Multiple variationes of that container are available.
16//!
17//!  * [`SlotMap`](crate::slotmap::SlotMap), run-time fixed-size slotmap that is not shared-memory
18//!    compatible since the memory resides in the heap.
19//!  * [`FixedSizeSlotMap`](crate::slotmap::FixedSizeSlotMap), compile-time fixed-size slotmap that
20//!    is self-contained and shared-memory compatible.
21//!  * [`RelocatableSlotMap`](crate::slotmap::RelocatableSlotMap), run-time fixed-size slotmap that
22//!    is shared-memory compatible.
23//!
24//! The SlotMap shall satisfy the following requirements:
25//!
26//!  * A new element can be inserted with a max runtime of `O(1)`
27//!  * A new element can be inserted at a user-provided key with a max runtime of `O(1)`
28//!  * An element can be removed by providing the corresponding key with a max runtime of `O(1)`
29//!  * One can iterate over all elements of the SlotMap.
30//!
31//! The SlotMap is the perfect container when elements shall be added, removed and accesses quickly
32//! but iteration is allowed to be slow.
33//!
34//! # User Examples
35//!
36//! ```
37//! # extern crate iceoryx2_bb_loggers;
38//!
39//! use iceoryx2_bb_container::slotmap::FixedSizeSlotMap;
40//!
41//! const CAPACITY: usize = 123;
42//! let mut slotmap = FixedSizeSlotMap::<u64, CAPACITY>::new();
43//!
44//! let key = slotmap.insert(78181).unwrap();
45//!
46//! println!("value: {:?}", slotmap.get(key));
47//! ```
48
49use 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/// A key of a [`SlotMap`], [`RelocatableSlotMap`] or [`FixedSizeSlotMap`] that identifies a
69/// value.
70#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
71pub struct SlotMapKey(usize);
72
73impl SlotMapKey {
74    /// Creates a new [`SlotMapKey`] with the specified value.
75    pub fn new(value: usize) -> Self {
76        Self(value)
77    }
78
79    /// Returns the underlying value of the [`SlotMapKey`].
80    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
92/// A runtime fixed-size, non-shared memory compatible [`SlotMap`]. The [`SlotMap`]s memory resides
93/// in the heap.
94pub type SlotMap<T> = MetaSlotMap<T, GenericOwningPointer>;
95
96/// A runtime fixed-size, shared-memory compatible [`RelocatableSlotMap`].
97pub type RelocatableSlotMap<T> = MetaSlotMap<T, GenericRelocatablePointer>;
98
99const INVALID: usize = usize::MAX;
100
101#[doc(hidden)]
102/// The iterator of a [`SlotMap`], [`RelocatableSlotMap`] or [`FixedSizeSlotMap`].
103pub 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    /// Creates a new runtime-fixed size [`SlotMap`] on the heap with the given capacity.
409    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    /// Returns the [`Iter`]ator to iterate over all entries.
424    pub fn iter(&self) -> OwningIter<'_, T> {
425        unsafe { self.iter_impl() }
426    }
427
428    /// Returns `true` if the provided `key` is contained, otherwise `false`.
429    pub fn contains(&self, key: SlotMapKey) -> bool {
430        unsafe { self.contains_impl(key) }
431    }
432
433    /// Returns a reference to the value stored under the given key. If there is no such key,
434    /// [`None`] is returned.
435    pub fn get(&self, key: SlotMapKey) -> Option<&T> {
436        unsafe { self.get_impl(key) }
437    }
438
439    /// Returns a mutable reference to the value stored under the given key. If there is no
440    /// such key, [`None`] is returned.
441    pub fn get_mut(&mut self, key: SlotMapKey) -> Option<&mut T> {
442        unsafe { self.get_mut_impl(key) }
443    }
444
445    /// Insert a value and returns the corresponding [`SlotMapKey`]. If the container is full
446    /// [`None`] is returned.
447    pub fn insert(&mut self, value: T) -> Option<SlotMapKey> {
448        unsafe { self.insert_impl(value) }
449    }
450
451    /// Insert a value at the specified [`SlotMapKey`] and returns true.  If the provided key
452    /// is out-of-bounds it returns `false` and adds nothing. If there is already a value
453    /// stored at the `key`s index, the value is overridden with the provided value.
454    pub fn insert_at(&mut self, key: SlotMapKey, value: T) -> bool {
455        unsafe { self.insert_at_impl(key, value) }
456    }
457
458    /// Removes a value at the specified [`SlotMapKey`]. If there was no value corresponding
459    /// to the [`SlotMapKey`] it returns None, otherwise Some(value).
460    pub fn remove(&mut self, key: SlotMapKey) -> Option<T> {
461        unsafe { self.remove_impl(key) }
462    }
463
464    /// Returns the [`SlotMapKey`] that will be used when the user calls
465    /// [`SlotMap::insert()`]. If the [`SlotMap`] is full it returns [`None`].
466    pub fn next_free_key(&self) -> Option<SlotMapKey> {
467        unsafe { self.next_free_key_impl() }
468    }
469
470    /// Returns the number of stored values.
471    pub fn len(&self) -> usize {
472        self.len_impl()
473    }
474
475    /// Returns the capacity.
476    pub fn capacity(&self) -> usize {
477        self.capacity_impl()
478    }
479
480    /// Returns true if the container is empty, otherwise false.
481    pub fn is_empty(&self) -> bool {
482        self.is_empty_impl()
483    }
484
485    /// Returns true if the container is full, otherwise false.
486    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    /// Returns how many memory the [`RelocatableSlotMap`] will allocate from the allocator
495    /// in [`RelocatableSlotMap::init()`].
496    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    /// Returns the [`Iter`]ator to iterate over all entries.
504    ///
505    /// # Safety
506    ///
507    ///  * [`RelocatableSlotMap::init()`] must be called once before
508    ///
509    pub unsafe fn iter(&self) -> RelocatableIter<'_, T> {
510        unsafe { self.iter_impl() }
511    }
512
513    /// Returns `true` if the provided `key` is contained, otherwise `false`.
514    ///
515    /// # Safety
516    ///
517    ///  * [`RelocatableSlotMap::init()`] must be called once before
518    ///
519    pub unsafe fn contains(&self, key: SlotMapKey) -> bool {
520        unsafe { self.contains_impl(key) }
521    }
522
523    /// Returns a reference to the value stored under the given key. If there is no such key,
524    /// [`None`] is returned.
525    ///
526    /// # Safety
527    ///
528    ///  * [`RelocatableSlotMap::init()`] must be called once before
529    ///
530    pub unsafe fn get(&self, key: SlotMapKey) -> Option<&T> {
531        unsafe { self.get_impl(key) }
532    }
533
534    /// Returns a mutable reference to the value stored under the given key. If there is no
535    /// such key, [`None`] is returned.
536    ///
537    /// # Safety
538    ///
539    ///  * [`RelocatableSlotMap::init()`] must be called once before
540    ///
541    pub unsafe fn get_mut(&mut self, key: SlotMapKey) -> Option<&mut T> {
542        unsafe { self.get_mut_impl(key) }
543    }
544
545    /// Insert a value and returns the corresponding [`SlotMapKey`]. If the container is full
546    /// [`None`] is returned.
547    ///
548    /// # Safety
549    ///
550    ///  * [`RelocatableSlotMap::init()`] must be called once before
551    ///
552    pub unsafe fn insert(&mut self, value: T) -> Option<SlotMapKey> {
553        unsafe { self.insert_impl(value) }
554    }
555
556    /// Insert a value at the specified [`SlotMapKey`] and returns true.  If the provided key
557    /// is out-of-bounds it returns `false` and adds nothing. If there is already a value
558    /// stored at the `key`s index, the value is overridden with the provided value.
559    ///
560    /// # Safety
561    ///
562    ///  * [`RelocatableSlotMap::init()`] must be called once before
563    ///
564    pub unsafe fn insert_at(&mut self, key: SlotMapKey, value: T) -> bool {
565        unsafe { self.insert_at_impl(key, value) }
566    }
567
568    /// Removes a value at the specified [`SlotMapKey`]. If there was no value corresponding
569    /// to the [`SlotMapKey`] it returns None, otherwise Some(value).
570    ///
571    /// # Safety
572    ///
573    ///  * [`RelocatableSlotMap::init()`] must be called once before
574    ///
575    pub unsafe fn remove(&mut self, key: SlotMapKey) -> Option<T> {
576        unsafe { self.remove_impl(key) }
577    }
578
579    /// Returns the [`SlotMapKey`] that will be used when the user calls
580    /// [`SlotMap::insert()`]. If the [`SlotMap`] is full it returns [`None`].
581    ///
582    /// # Safety
583    ///
584    ///  * [`RelocatableSlotMap::init()`] must be called once before
585    ///
586    pub unsafe fn next_free_key(&self) -> Option<SlotMapKey> {
587        unsafe { self.next_free_key_impl() }
588    }
589
590    /// Returns the number of stored values.
591    pub fn len(&self) -> usize {
592        self.len_impl()
593    }
594
595    /// Returns the capacity.
596    pub fn capacity(&self) -> usize {
597        self.capacity_impl()
598    }
599
600    /// Returns true if the container is empty, otherwise false.
601    pub fn is_empty(&self) -> bool {
602        self.is_empty_impl()
603    }
604
605    /// Returns true if the container is full, otherwise false.
606    pub fn is_full(&self) -> bool {
607        self.is_full_impl()
608    }
609}
610
611/// A compile-time fixed-size, shared memory compatible [`FixedSizeSlotMap`].
612#[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    /// Creates a new empty [`FixedSizeSlotMap`].
662    pub fn new() -> Self {
663        Self::default()
664    }
665
666    /// Returns the [`RelocatableIter`]ator to iterate over all entries.
667    pub fn iter(&self) -> RelocatableIter<'_, T> {
668        unsafe { self.state.iter_impl() }
669    }
670
671    /// Returns `true` if the provided `key` is contained, otherwise `false`.
672    pub fn contains(&self, key: SlotMapKey) -> bool {
673        unsafe { self.state.contains_impl(key) }
674    }
675
676    /// Returns a reference to the value stored under the given key. If there is no such key,
677    /// [`None`] is returned.
678    pub fn get(&self, key: SlotMapKey) -> Option<&T> {
679        unsafe { self.state.get_impl(key) }
680    }
681
682    /// Returns a mutable reference to the value stored under the given key. If there is no
683    /// such key, [`None`] is returned.
684    pub fn get_mut(&mut self, key: SlotMapKey) -> Option<&mut T> {
685        unsafe { self.state.get_mut_impl(key) }
686    }
687
688    /// Insert a value and returns the corresponding [`SlotMapKey`]. If the container is full
689    /// [`None`] is returned.
690    pub fn insert(&mut self, value: T) -> Option<SlotMapKey> {
691        unsafe { self.state.insert_impl(value) }
692    }
693
694    /// Insert a value at the specified [`SlotMapKey`] and returns true.  If the provided key
695    /// is out-of-bounds it returns `false` and adds nothing. If there is already a value
696    /// stored at the `key`s index, the value is overridden with the provided value.
697    pub fn insert_at(&mut self, key: SlotMapKey, value: T) -> bool {
698        unsafe { self.state.insert_at_impl(key, value) }
699    }
700
701    /// Removes a value at the specified [`SlotMapKey`]. If there was no value corresponding
702    /// to the [`SlotMapKey`] it returns None, otherwise Some(value).
703    pub fn remove(&mut self, key: SlotMapKey) -> Option<T> {
704        unsafe { self.state.remove_impl(key) }
705    }
706
707    /// Returns the [`SlotMapKey`] that will be used when the user calls
708    /// [`SlotMap::insert()`]. If the [`SlotMap`] is full it returns [`None`].
709    pub fn next_free_key(&self) -> Option<SlotMapKey> {
710        unsafe { self.state.next_free_key_impl() }
711    }
712
713    /// Returns the number of stored values.
714    pub fn len(&self) -> usize {
715        self.state.len_impl()
716    }
717
718    /// Returns the capacity.
719    pub fn capacity(&self) -> usize {
720        self.state.capacity_impl()
721    }
722
723    /// Returns true if the container is empty, otherwise false.
724    pub fn is_empty(&self) -> bool {
725        self.state.is_empty_impl()
726    }
727
728    /// Returns true if the container is full, otherwise false.
729    pub fn is_full(&self) -> bool {
730        self.state.is_full_impl()
731    }
732}