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}