iceoryx2_bb_container/
flatmap.rs

1// Copyright (c) 2025 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 FlatMap is a data structure to store key-value pairs. Multiple variations of that container
14//! are available.
15//!
16//!  * [`FixedSizeFlatMap`](crate::flatmap::FixedSizeFlatMap), compile-time fixed-size flatmap
17//!    that is self-contained and shared-memory compatible.
18//!  * [`RelocatableFlatMap`](crate::flatmap::RelocatableFlatMap), run-time fixed-size flatmap that
19//!    is shared-memory compatible.
20//!  * [`FlatMap`](crate::flatmap::FlatMap), run-time fixed-size flatmap that is not shared-memory
21//!    compatible since the memory resides in the heap.
22//!
23//! # User Examples
24//!
25//! ```
26//! # extern crate iceoryx2_loggers;
27//!
28//! use iceoryx2_bb_container::flatmap::FixedSizeFlatMap;
29//!
30//! const CAPACITY: usize = 100;
31//! let mut map = FixedSizeFlatMap::<u8, u8, CAPACITY>::new();
32//! assert_eq!(map.insert(23, 4).is_ok(), true);
33//! assert_eq!(map.get(&23).unwrap(), 4);
34//! ```
35
36use crate::slotmap::FreeListEntry;
37use crate::slotmap::{MetaSlotMap, RelocatableSlotMap};
38use core::fmt::Debug;
39use core::mem::MaybeUninit;
40use iceoryx2_bb_concurrency::atomic::AtomicBool;
41use iceoryx2_bb_elementary::bump_allocator::BumpAllocator;
42use iceoryx2_bb_elementary::relocatable_ptr::GenericRelocatablePointer;
43use iceoryx2_bb_elementary::CallbackProgression;
44use iceoryx2_bb_elementary_traits::generic_pointer::GenericPointer;
45use iceoryx2_bb_elementary_traits::owning_pointer::GenericOwningPointer;
46pub use iceoryx2_bb_elementary_traits::relocatable_container::RelocatableContainer;
47use iceoryx2_bb_elementary_traits::{
48    placement_default::PlacementDefault, zero_copy_send::ZeroCopySend,
49};
50use iceoryx2_log::{fail, fatal_panic};
51
52/// Failures caused by insert()
53#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
54pub enum FlatMapError {
55    /// The FlatMap already contains the key that shall be inserted.
56    KeyAlreadyExists,
57    /// The FlatMap is full and cannot hold an additional key-value pair.
58    IsFull,
59}
60
61#[repr(C)]
62struct Entry<K: Eq, V: Clone> {
63    id: K,
64    value: V,
65}
66
67unsafe impl<K: Eq + ZeroCopySend, V: Clone + ZeroCopySend> ZeroCopySend for Entry<K, V> {}
68
69/// A runtime fixed-size, non-shared memory compatible [`FlatMap`]. The [`FlatMap`]s memory resides
70/// in the heap.
71pub type FlatMap<K, V> = MetaFlatMap<K, V, GenericOwningPointer>;
72
73/// A runtime fixed-size, shared-memory compatible [`RelocatableFlatMap`].
74pub type RelocatableFlatMap<K, V> = MetaFlatMap<K, V, GenericRelocatablePointer>;
75
76#[doc(hidden)]
77#[repr(C)]
78pub struct MetaFlatMap<K: Eq, V: Clone, Ptr: GenericPointer> {
79    map: MetaSlotMap<Entry<K, V>, Ptr>,
80    is_initialized: AtomicBool,
81}
82
83impl<K: Eq + Debug, V: Clone + Debug, Ptr: GenericPointer> Debug for MetaFlatMap<K, V, Ptr> {
84    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85        write!(
86            f,
87            "MetaFlatMap<{}, {}, {}> {{ len: {}, is_initialized: {} }}",
88            core::any::type_name::<K>(),
89            core::any::type_name::<V>(),
90            core::any::type_name::<Ptr>(),
91            self.len_impl(),
92            self.is_initialized
93                .load(core::sync::atomic::Ordering::Relaxed),
94        )
95    }
96}
97
98impl<K: Eq, V: Clone, Ptr: GenericPointer> MetaFlatMap<K, V, Ptr> {
99    #[inline(always)]
100    fn verify_init(&self, source: &str) {
101        debug_assert!(
102                self.is_initialized
103                    .load(core::sync::atomic::Ordering::Relaxed),
104                "From: MetaFlatMap<{}, {}>::{}, Undefined behavior - the object was not initialized with 'init' before.",
105                core::any::type_name::<K>(), core::any::type_name::<V>(), source
106            );
107    }
108
109    pub(crate) unsafe fn insert_impl<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
110        &mut self,
111        id: K,
112        value: V,
113        eq_func: &F,
114    ) -> Result<(), FlatMapError> {
115        self.verify_init("insert()");
116
117        let msg = "Unable to insert key-value pair into FlatMap";
118        let origin = "MetaFlatMap::insert_impl()";
119
120        let mut iter = self
121            .map
122            .iter_impl()
123            .skip_while(|kv| !__internal_eq_comparison_wrapper(&kv.1.id, &id, eq_func));
124        if iter.next().is_some() {
125            fail!(from origin, with FlatMapError::KeyAlreadyExists, "{msg} since the passed key already exists.");
126        }
127        if self.map.insert_impl(Entry { id, value }).is_none() {
128            fail!(from origin, with FlatMapError::IsFull, "{msg} since the FlatMap is full.");
129        }
130        Ok(())
131    }
132
133    pub(crate) unsafe fn get_impl<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
134        &self,
135        id: &K,
136        eq_func: &F,
137    ) -> Option<V> {
138        self.verify_init("get()");
139
140        self.get_ref_impl(id, eq_func).cloned()
141    }
142
143    pub(crate) unsafe fn get_ref_impl<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
144        &self,
145        id: &K,
146        eq_func: &F,
147    ) -> Option<&V> {
148        self.verify_init("get_ref()");
149
150        let mut iter = self
151            .map
152            .iter_impl()
153            .skip_while(|kv| !__internal_eq_comparison_wrapper(&kv.1.id, id, eq_func));
154        iter.next().map(|kv| &kv.1.value)
155    }
156
157    pub(crate) unsafe fn get_mut_ref_impl<F: Fn(*const u8, *const u8) -> bool>(
158        &mut self,
159        id: &K,
160        eq_func: &F,
161    ) -> Option<&mut V> {
162        self.verify_init("get_mut_ref()");
163
164        let slot_map_entry = self
165            .map
166            .iter_impl()
167            .find(|kv| __internal_eq_comparison_wrapper(&kv.1.id, id, eq_func))?;
168        self.map
169            .get_mut_impl(slot_map_entry.0)
170            .map(|flat_map_entry| &mut flat_map_entry.value)
171    }
172
173    pub(crate) unsafe fn remove_impl<F: Fn(*const u8, *const u8) -> bool>(
174        &mut self,
175        id: &K,
176        eq_func: &F,
177    ) -> Option<V> {
178        self.verify_init("remove()");
179
180        let mut iter = self
181            .map
182            .iter_impl()
183            .skip_while(|kv| !__internal_eq_comparison_wrapper(&kv.1.id, id, eq_func));
184        if let Some(kv) = iter.next() {
185            let key = kv.0;
186            self.map.remove_impl(key).map(|e| e.value)
187        } else {
188            None
189        }
190    }
191
192    pub(crate) fn is_empty_impl(&self) -> bool {
193        self.map.is_empty_impl()
194    }
195
196    pub(crate) fn is_full_impl(&self) -> bool {
197        self.map.is_full_impl()
198    }
199
200    pub(crate) unsafe fn contains_impl<F: Fn(*const u8, *const u8) -> bool>(
201        &self,
202        id: &K,
203        eq_func: &F,
204    ) -> bool {
205        self.verify_init("contains()");
206
207        self.get_ref_impl(id, eq_func).is_some()
208    }
209
210    pub(crate) fn len_impl(&self) -> usize {
211        self.map.len_impl()
212    }
213
214    pub(crate) unsafe fn list_keys_impl<F: FnMut(&K) -> CallbackProgression>(
215        &self,
216        mut callback: F,
217    ) {
218        for (_, kv) in self.map.iter_impl() {
219            if callback(&kv.id) == CallbackProgression::Stop {
220                break;
221            }
222        }
223    }
224}
225
226#[doc(hidden)]
227// This function is passed to functions that require a Fn(*const u8, *const u8) -> bool so it cannot be
228// unsafe. It is meant to be used only flatmap internal where the type, lhs and rhs are pointing to, is
229// known and valid.
230pub fn __internal_default_eq_comparison<T: Eq>(lhs: *const u8, rhs: *const u8) -> bool {
231    unsafe { *lhs.cast::<T>() == *rhs.cast::<T>() }
232}
233
234#[doc(hidden)]
235pub fn __internal_eq_comparison_wrapper<T: Eq, F: Fn(*const u8, *const u8) -> bool + ?Sized>(
236    lhs: &T,
237    rhs: &T,
238    eq_func: &F,
239) -> bool {
240    eq_func(
241        (lhs as *const T).cast::<u8>(),
242        (rhs as *const T).cast::<u8>(),
243    )
244}
245
246impl<K: Eq, V: Clone> FlatMap<K, V> {
247    /// Creates a new runtime-fixed size [`FlatMap`] on the heap with the given capacity.
248    pub fn new(capacity: usize) -> Self {
249        Self {
250            map: MetaSlotMap::new(capacity),
251            is_initialized: AtomicBool::new(true),
252        }
253    }
254
255    /// Inserts a new key-value pair into the [`FlatMap`]. On success, the method returns [`Ok`],
256    /// otherwise a [`FlatMapError`] describing the failure.
257    pub fn insert(&mut self, id: K, value: V) -> Result<(), FlatMapError> {
258        unsafe { self.insert_impl(id, value, &__internal_default_eq_comparison::<K>) }
259    }
260
261    #[doc(hidden)]
262    // Inserts a new key-value pair into the [`FlatMap`] using a provided equality compare
263    // function. On success, the method returns [`Ok`], otherwise a [`FlatMapError`] describing
264    // the failure.
265    //
266    // # Safety
267    //
268    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
269    //    [`FlatMap`] instance and from every process that uses the [`FlatMap`] instance
270    //
271    pub unsafe fn __internal_insert<F: Fn(*const u8, *const u8) -> bool>(
272        &mut self,
273        id: K,
274        value: V,
275        eq_func: &F,
276    ) -> Result<(), FlatMapError> {
277        self.insert_impl(id, value, eq_func)
278    }
279
280    /// Returns a copy of the value corresponding to the given key. If there is no such key,
281    /// [`None`] is returned.
282    pub fn get(&self, id: &K) -> Option<V> {
283        unsafe { self.get_impl(id, &__internal_default_eq_comparison::<K>) }
284    }
285
286    #[doc(hidden)]
287    // Returns a copy of the value corresponding to the given key using a provided equality compare
288    // function. If there is no such key, [`None`] is returned.
289    //
290    // # Safety
291    //
292    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
293    //    [`FlatMap`] instance and from every process that uses the [`FlatMap`] instance
294    //
295    pub unsafe fn __internal_get<F: Fn(*const u8, *const u8) -> bool>(
296        &self,
297        id: &K,
298        eq_func: &F,
299    ) -> Option<V> {
300        self.get_impl(id, eq_func)
301    }
302
303    /// Returns a reference to the value corresponding to the given key. If there is no such
304    /// key, [`None`] is returned.
305    pub fn get_ref(&self, id: &K) -> Option<&V> {
306        unsafe { self.get_ref_impl(id, &__internal_default_eq_comparison::<K>) }
307    }
308
309    #[doc(hidden)]
310    // Returns a reference to the value corresponding to the given key using a provided equality
311    // compare function. If there is no such key, [`None`] is returned.
312    //
313    // # Safety
314    //
315    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
316    //    [`FlatMap`] instance and from every process that uses the [`FlatMap`] instance
317    //
318    pub unsafe fn __internal_get_ref<F: Fn(*const u8, *const u8) -> bool>(
319        &self,
320        id: &K,
321        eq_func: &F,
322    ) -> Option<&V> {
323        self.get_ref_impl(id, eq_func)
324    }
325
326    /// Returns a mutable reference to the value corresponding to the given key. If there is
327    /// no such key, [`None`] is returned.
328    pub fn get_mut_ref(&mut self, id: &K) -> Option<&mut V> {
329        unsafe { self.get_mut_ref_impl(id, &__internal_default_eq_comparison::<K>) }
330    }
331
332    #[doc(hidden)]
333    // Returns a mutable reference to the value corresponding to the given key using a provided
334    // equality compare function. If there is no such key, [`None`] is returned.
335    //
336    // # Safety
337    //
338    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
339    //    [`FlatMap`] instance and from every process that uses the [`FlatMap`] instance
340    //
341    pub unsafe fn __internal_get_mut_ref<F: Fn(*const u8, *const u8) -> bool>(
342        &mut self,
343        id: &K,
344        eq_func: &F,
345    ) -> Option<&mut V> {
346        self.get_mut_ref_impl(id, eq_func)
347    }
348
349    /// Removes a key (`id`) from the [`FlatMap`], returning the Some(value) at the key if the key
350    /// was previously in the map or [`None`] otherwise.
351    pub fn remove(&mut self, id: &K) -> Option<V> {
352        unsafe { self.remove_impl(id, &__internal_default_eq_comparison::<K>) }
353    }
354
355    #[doc(hidden)]
356    // Removes a key (`id`) from the [`FlatMap`] using a provided equality compare function,
357    // returning the Some(value) at the key if the key was previously in the map or [`None`]
358    // otherwise.
359    //
360    // # Safety
361    //
362    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
363    //    [`FlatMap`] instance and from every process that uses the [`FlatMap`] instance
364    //
365    pub unsafe fn __internal_remove<F: Fn(*const u8, *const u8) -> bool>(
366        &mut self,
367        id: &K,
368        eq_func: &F,
369    ) -> Option<V> {
370        self.remove_impl(id, eq_func)
371    }
372
373    /// Returns true if the [`FlatMap`] is empty, otherwise false.
374    pub fn is_empty(&self) -> bool {
375        self.is_empty_impl()
376    }
377
378    /// Returns true if the [`FlatMap`] is full, otherwise false.
379    pub fn is_full(&self) -> bool {
380        self.is_full_impl()
381    }
382
383    /// Returns true if the [`FlatMap`] contains the given key, otherwise false.
384    pub fn contains(&self, id: &K) -> bool {
385        unsafe { self.contains_impl(id, &__internal_default_eq_comparison::<K>) }
386    }
387
388    #[doc(hidden)]
389    // Returns true if the [`FlatMap`] contains the given key using a provided equality
390    // compare function, otherwise false.
391    //
392    // # Safety
393    //
394    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
395    //    [`FlatMap`] instance and from every process that uses the [`FlatMap`] instance
396    //
397    pub unsafe fn __internal_contains<F: Fn(*const u8, *const u8) -> bool>(
398        &self,
399        id: &K,
400        eq_func: &F,
401    ) -> bool {
402        self.contains_impl(id, eq_func)
403    }
404
405    /// Returns the number of stored key-value pairs.
406    pub fn len(&self) -> usize {
407        self.len_impl()
408    }
409
410    /// Iterates over all keys of the map and calls the provided callback.
411    pub fn list_keys<F: FnMut(&K) -> CallbackProgression>(&self, callback: F) {
412        unsafe { self.list_keys_impl(callback) };
413    }
414}
415
416impl<K: Eq, V: Clone> RelocatableContainer for RelocatableFlatMap<K, V> {
417    unsafe fn new_uninit(capacity: usize) -> Self {
418        Self {
419            map: RelocatableSlotMap::new_uninit(capacity),
420            is_initialized: AtomicBool::new(false),
421        }
422    }
423
424    unsafe fn init<Allocator: iceoryx2_bb_elementary_traits::allocator::BaseAllocator>(
425        &mut self,
426        allocator: &Allocator,
427    ) -> Result<(), iceoryx2_bb_elementary_traits::allocator::AllocationError> {
428        if self
429            .is_initialized
430            .load(core::sync::atomic::Ordering::Relaxed)
431        {
432            fatal_panic!(from "RelocatableFlatMap::init()", "Memory already initialized. Initializing it twice may lead to undefined behavior.");
433        }
434        let msg = "Unable to initialize RelocatableFlatMap";
435        fail!(from "RelocatableFlatMap::init()", when self.map.init(allocator), "{msg} since the underlying RelocatableSlotMap could not be initialized.");
436        self.is_initialized
437            .store(true, core::sync::atomic::Ordering::Relaxed);
438        Ok(())
439    }
440
441    fn memory_size(capacity: usize) -> usize {
442        Self::const_memory_size(capacity)
443    }
444}
445
446unsafe impl<K: Eq + ZeroCopySend, V: Clone + ZeroCopySend> ZeroCopySend
447    for RelocatableFlatMap<K, V>
448{
449}
450
451impl<K: Eq, V: Clone> RelocatableFlatMap<K, V> {
452    /// Returns how much memory the [`RelocatableFlatMap`] will allocate from the allocator
453    /// in [`RelocatableFlatMap::init()`].
454    pub const fn const_memory_size(capacity: usize) -> usize {
455        RelocatableSlotMap::<Entry<K, V>>::const_memory_size(capacity)
456    }
457
458    /// Inserts a new key-value pair into the map. On success, the method returns [`Ok`],
459    /// otherwise a [`FlatMapError`] describing the failure.
460    ///
461    /// # Safety
462    ///
463    ///  * [`RelocatableFlatMap::init()`] must be called once before
464    ///
465    pub unsafe fn insert(&mut self, id: K, value: V) -> Result<(), FlatMapError> {
466        self.insert_impl(id, value, &__internal_default_eq_comparison::<K>)
467    }
468
469    #[doc(hidden)]
470    // Inserts a new key-value pair into the [`RelocatableFlatMap`] using a provided equality
471    // compare function. On success, the method returns [`Ok`], otherwise a [`FlatMapError`]
472    // describing the failure.
473    //
474    // # Safety
475    //
476    //  * [`RelocatableFlatMap::init()`] must be called once before
477    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
478    //    [`RelocatableFlatMap`] instance and from every process that uses the
479    //    [`RelocatableFlatMap`] instance
480    //
481    pub unsafe fn __internal_insert<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
482        &mut self,
483        id: K,
484        value: V,
485        eq_func: &F,
486    ) -> Result<(), FlatMapError> {
487        self.insert_impl(id, value, eq_func)
488    }
489
490    /// Returns a copy of the value corresponding to the given key. If there is no such key,
491    /// [`None`] is returned.
492    ///
493    /// # Safety
494    ///
495    ///  * [`RelocatableFlatMap::init()`] must be called once before
496    ///
497    pub unsafe fn get(&self, id: &K) -> Option<V> {
498        self.get_impl(id, &__internal_default_eq_comparison::<K>)
499    }
500
501    #[doc(hidden)]
502    // Returns a copy of the value corresponding to the given key using a provided equality compare
503    // function. If there is no such key, [`None`] is returned.
504    //
505    // # Safety
506    //
507    //  * [`RelocatableFlatMap::init()`] must be called once before
508    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
509    //    [`RelocatableFlatMap`] instance and from every process that uses the
510    //    [`RelocatableFlatMap`] instance
511    //
512    pub unsafe fn __internal_get<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
513        &self,
514        id: &K,
515        eq_func: &F,
516    ) -> Option<V> {
517        self.get_impl(id, eq_func)
518    }
519
520    /// Returns a reference to the value corresponding to the given key. If there is no such
521    /// key, [`None`] is returned.
522    ///
523    /// # Safety
524    ///
525    ///  * [`RelocatableFlatMap::init()`] must be called once before
526    ///
527    pub unsafe fn get_ref(&self, id: &K) -> Option<&V> {
528        self.get_ref_impl(id, &__internal_default_eq_comparison::<K>)
529    }
530
531    #[doc(hidden)]
532    // Returns a reference to the value corresponding to the given key using a provided equality
533    // compare function. If there is no such key, [`None`] is returned.
534    //
535    // # Safety
536    //
537    //  * [`RelocatableFlatMap::init()`] must be called once before
538    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
539    //    [`RelocatableFlatMap`] instance and from every process that uses the [`RelocatableFlatMap`]
540    //    instance
541    //
542    pub unsafe fn __internal_get_ref<F: Fn(*const u8, *const u8) -> bool>(
543        &self,
544        id: &K,
545        eq_func: &F,
546    ) -> Option<&V> {
547        self.get_ref_impl(id, eq_func)
548    }
549
550    /// Returns a mutable reference to the value corresponding to the given key. If there is
551    /// no such key, [`None`] is returned.
552    ///
553    /// # Safety
554    ///
555    ///  * [`RelocatableFlatMap::init()`] must be called once before
556    ///
557    pub unsafe fn get_mut_ref(&mut self, id: &K) -> Option<&mut V> {
558        self.get_mut_ref_impl(id, &__internal_default_eq_comparison::<K>)
559    }
560
561    #[doc(hidden)]
562    // Returns a mutable reference to the value corresponding to the given key using a provided
563    // equality compare function. If there is no such key, [`None`] is returned.
564    //
565    // # Safety
566    //
567    //  * [`RelocatableFlatMap::init()`] must be called once before
568    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
569    //    [`RelocatableFlatMap`] instance and from every process that uses the
570    //    [`RelocatableFlatMap`] instance
571    //
572    pub unsafe fn __internal_get_mut_ref<F: Fn(*const u8, *const u8) -> bool>(
573        &mut self,
574        id: &K,
575        eq_func: &F,
576    ) -> Option<&mut V> {
577        self.get_mut_ref_impl(id, eq_func)
578    }
579
580    /// Removes a key (`id`) from the map, returning the Some(value) at the key if the key
581    /// was previously in the map or [`None`] otherwise.
582    /// # Safety
583    ///
584    ///  * [`RelocatableFlatMap::init()`] must be called once before
585    ///
586    pub unsafe fn remove(&mut self, id: &K) -> Option<V> {
587        self.remove_impl(id, &__internal_default_eq_comparison::<K>)
588    }
589
590    #[doc(hidden)]
591    // Removes a key (`id`) from the [`RelocatableFlatMap`] using a provided equality compare
592    // function, returning the Some(value) at the key if the key was previously in the map or
593    // [`None`] otherwise.
594    //
595    // # Safety
596    //
597    //  * [`RelocatableFlatMap::init()`] must be called once before
598    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
599    //    [`RelocatableFlatMap`] instance and from every process that uses the
600    //    [`RelocatableFlatMap`] instance
601    //
602    pub unsafe fn __internal_remove<F: Fn(*const u8, *const u8) -> bool>(
603        &mut self,
604        id: &K,
605        eq_func: &F,
606    ) -> Option<V> {
607        self.remove_impl(id, eq_func)
608    }
609
610    /// Returns true if the map is empty, otherwise false.
611    pub fn is_empty(&self) -> bool {
612        self.map.is_empty()
613    }
614
615    /// Returns true if the map is full, otherwise false.
616    pub fn is_full(&self) -> bool {
617        self.map.is_full()
618    }
619
620    /// Returns true if the map contains the given key, otherwise false.
621    ///
622    /// # Safety
623    ///
624    ///  * [`RelocatableFlatMap::init()`] must be called once before
625    ///
626    pub unsafe fn contains(&self, id: &K) -> bool {
627        self.contains_impl(id, &__internal_default_eq_comparison::<K>)
628    }
629
630    #[doc(hidden)]
631    // Returns true if the [`RelocatableFlatMap`] contains the given key using a provided equality
632    // compare function, otherwise false.
633    //
634    // # Safety
635    //
636    //  * [`RelocatableFlatMap::init()`] must be called once before
637    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
638    //    [`RelocatableFlatMap`] instance and from every process that uses the
639    //    [`RelocatableFlatMap`] instance
640    //
641    pub unsafe fn __internal_contains<F: Fn(*const u8, *const u8) -> bool>(
642        &self,
643        id: &K,
644        eq_func: &F,
645    ) -> bool {
646        self.contains_impl(id, eq_func)
647    }
648
649    /// Returns the number of stored key-value pairs.
650    pub fn len(&self) -> usize {
651        self.map.len()
652    }
653
654    /// Iterates over all keys of the map and calls the provided callback.
655    pub fn list_keys<F: FnMut(&K) -> CallbackProgression>(&self, callback: F) {
656        unsafe { self.list_keys_impl(callback) };
657    }
658}
659
660/// A compile-time fixed-size, shared-memory compatible [`FixedSizeFlatMap`].
661#[repr(C)]
662pub struct FixedSizeFlatMap<K: Eq, V: Clone, const CAPACITY: usize> {
663    map: RelocatableFlatMap<K, V>,
664    _idx_to_data: MaybeUninit<[usize; CAPACITY]>,
665    _idx_to_data_free_list: MaybeUninit<[FreeListEntry; CAPACITY]>,
666    _data: MaybeUninit<[Option<Entry<K, V>>; CAPACITY]>,
667    _data_next_free_index: MaybeUninit<[usize; CAPACITY]>,
668}
669
670unsafe impl<K: Eq + ZeroCopySend, V: Clone + ZeroCopySend, const CAPACITY: usize> ZeroCopySend
671    for FixedSizeFlatMap<K, V, CAPACITY>
672{
673}
674
675impl<K: Eq, V: Clone, const CAPACITY: usize> PlacementDefault for FixedSizeFlatMap<K, V, CAPACITY> {
676    unsafe fn placement_default(ptr: *mut Self) {
677        let map_ptr = core::ptr::addr_of_mut!((*ptr).map);
678        map_ptr.write(unsafe { RelocatableFlatMap::new_uninit(CAPACITY) });
679        let allocator = BumpAllocator::new((*ptr)._idx_to_data.as_mut_ptr().cast());
680        (*ptr)
681            .map
682            .init(&allocator)
683            .expect("All required memory is preallocated.");
684    }
685}
686
687impl<K: Eq, V: Clone, const CAPACITY: usize> Default for FixedSizeFlatMap<K, V, CAPACITY> {
688    fn default() -> Self {
689        Self::new()
690    }
691}
692
693impl<K: Eq + Debug, V: Clone + Debug, const CAPACITY: usize> Debug
694    for FixedSizeFlatMap<K, V, CAPACITY>
695{
696    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
697        write!(
698            f,
699            "MetaFlatMap<{}, {}, {}> {{ {:?} }}",
700            core::any::type_name::<K>(),
701            core::any::type_name::<V>(),
702            CAPACITY,
703            self.map
704        )
705    }
706}
707
708impl<K: Eq, V: Clone, const CAPACITY: usize> FixedSizeFlatMap<K, V, CAPACITY> {
709    /// Creates a new [`FixedSizeFlatMap`]
710    pub fn new() -> Self {
711        let mut new_self = Self {
712            map: unsafe { RelocatableFlatMap::new_uninit(CAPACITY) },
713            _idx_to_data: MaybeUninit::uninit(),
714            _idx_to_data_free_list: MaybeUninit::uninit(),
715            _data: MaybeUninit::uninit(),
716            _data_next_free_index: MaybeUninit::uninit(),
717        };
718        let allocator = BumpAllocator::new(new_self._idx_to_data.as_mut_ptr().cast());
719        unsafe {
720            new_self
721                .map
722                .init(&allocator)
723                .expect("All required memory is preallocated.")
724        };
725        new_self
726    }
727
728    /// Inserts a new key-value pair into the [`FixedSizeFlatMap`]. On success, the method returns [`Ok`],
729    /// otherwise a [`FlatMapError`] describing the failure.
730    pub fn insert(&mut self, id: K, value: V) -> Result<(), FlatMapError> {
731        unsafe { self.map.insert(id, value) }
732    }
733
734    #[doc(hidden)]
735    // Inserts a new key-value pair into the [`FixedSizeFlatMap`] using a provided equality compare
736    // function. On success, the method returns [`Ok`], otherwise a [`FlatMapError`] describing the
737    // failure.
738    //
739    // # Safety
740    //
741    //  * eq_func must be the same for every call to insert/get*/remove/contains for the [`FixedSizeFlatMap`]
742    //    instance and from every process that uses the [`FixedSizeFlatMap`] instance
743    //
744    pub unsafe fn __internal_insert<F: Fn(*const u8, *const u8) -> bool>(
745        &mut self,
746        id: K,
747        value: V,
748        eq_func: &F,
749    ) -> Result<(), FlatMapError> {
750        self.map.__internal_insert(id, value, eq_func)
751    }
752
753    /// Returns a copy of the value corresponding to the given key. If there is no such key,
754    /// [`None`] is returned.
755    pub fn get(&self, id: &K) -> Option<V> {
756        unsafe { self.map.get(id) }
757    }
758
759    #[doc(hidden)]
760    // Returns a copy of the value corresponding to the given key using a provided equality compare
761    // function. If there is no such key, [`None`] is returned.
762    //
763    // # Safety
764    //
765    //  * eq_func must be the same for every call to insert/get*/remove/contains for the [`FixedSizeFlatMap`]
766    //    instance and from every process that uses the [`FixedSizeFlatMap`] instance
767    //
768    pub unsafe fn __internal_get<F: Fn(*const u8, *const u8) -> bool>(
769        &self,
770        id: &K,
771        eq_func: &F,
772    ) -> Option<V> {
773        self.map.__internal_get(id, eq_func)
774    }
775
776    /// Returns a reference to the value corresponding to the given key. If there is no such
777    /// key, [`None`] is returned.
778    pub fn get_ref(&self, id: &K) -> Option<&V> {
779        unsafe { self.map.get_ref(id) }
780    }
781
782    #[doc(hidden)]
783    // Returns a reference to the value corresponding to the given key using a provided equality
784    // compare function. If there is no such key, [`None`] is returned.
785    //
786    // # Safety
787    //
788    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
789    //    [`FixedSizeFlatMap`] instance and from every process that uses the [`FixedSizeFlatMap`]
790    //    instance
791    //
792    pub unsafe fn __internal_get_ref<F: Fn(*const u8, *const u8) -> bool>(
793        &self,
794        id: &K,
795        eq_func: &F,
796    ) -> Option<&V> {
797        self.map.__internal_get_ref(id, eq_func)
798    }
799
800    /// Returns a mutable reference to the value corresponding to the given key. If there is
801    /// no such key, [`None`] is returned.
802    pub fn get_mut_ref(&mut self, id: &K) -> Option<&mut V> {
803        unsafe { self.map.get_mut_ref(id) }
804    }
805
806    #[doc(hidden)]
807    // Returns a mutable reference to the value corresponding to the given key using a provided
808    // equality compare function. If there is no such key, [`None`] is returned.
809    //
810    // # Safety
811    //
812    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
813    //    [`FixedSizeFlatMap`] instance and from every process that uses the
814    //    [`FixedSizeFlatMap`] instance
815    //
816    pub unsafe fn __internal_get_mut_ref<F: Fn(*const u8, *const u8) -> bool>(
817        &mut self,
818        id: &K,
819        eq_func: &F,
820    ) -> Option<&mut V> {
821        self.map.__internal_get_mut_ref(id, eq_func)
822    }
823
824    /// Removes a key (`id`) from the [`FixedSizeFlatMap`], returning the Some(value) at the key
825    /// if the key was previously in the map or [`None`] otherwise.
826    pub fn remove(&mut self, id: &K) -> Option<V> {
827        unsafe { self.map.remove(id) }
828    }
829
830    #[doc(hidden)]
831    // Removes a key (`id`) from the [`FixedSizeFlatMap`] using a provided equality compare
832    // function, returning the Some(value) at the key if the key was previously in the map or
833    // [`None`] otherwise.
834    //
835    // # Safety
836    //
837    //  * eq_func must be the same for every call to insert/get*/remove/contains for the
838    //    [`FixedSizeFlatMap`] instance and from every process that uses the
839    //    [`FixedSizeFlatMap`] instance
840    //
841    pub unsafe fn __internal_remove<F: Fn(*const u8, *const u8) -> bool>(
842        &mut self,
843        id: &K,
844        eq_func: &F,
845    ) -> Option<V> {
846        self.map.__internal_remove(id, eq_func)
847    }
848
849    /// Returns true if the [`FixedSizeFlatMap`] is empty, otherwise false.
850    pub fn is_empty(&self) -> bool {
851        self.map.is_empty()
852    }
853
854    /// Returns true if the [`FixedSizeFlatMap`] is full, otherwise false.
855    pub fn is_full(&self) -> bool {
856        self.map.is_full()
857    }
858
859    /// Returns true if the [`FixedSizeFlatMap`] contains the given key, otherwise false.
860    pub fn contains(&self, id: &K) -> bool {
861        unsafe { self.map.contains(id) }
862    }
863
864    #[doc(hidden)]
865    // Returns true if the [`FixedSizeFlatMap`] contains the given key using a provided equality
866    // compare function, otherwise false.
867    //
868    // # Safety
869    //
870    //  * eq_func must be the same for every call to insert/get*/remove/contains for the [`FixedSizeFlatMap`]
871    //    instance and from every process that uses the [`FixedSizeFlatMap`] instance
872    //
873    pub unsafe fn __internal_contains<F: Fn(*const u8, *const u8) -> bool>(
874        &self,
875        id: &K,
876        eq_func: &F,
877    ) -> bool {
878        self.map.__internal_contains(id, eq_func)
879    }
880
881    /// Returns the number of stored key-value pairs.
882    pub fn len(&self) -> usize {
883        self.map.len()
884    }
885
886    /// Iterates over all keys of the map and calls the provided callback.
887    pub fn list_keys<F: FnMut(&K) -> CallbackProgression>(&self, callback: F) {
888        unsafe { self.map.list_keys_impl(callback) };
889    }
890}