use crate::slotmap::FreeListEntry;
use crate::slotmap::{MetaSlotMap, RelocatableSlotMap};
use core::fmt::Debug;
use core::mem::MaybeUninit;
use iceoryx2_bb_concurrency::atomic::AtomicBool;
use iceoryx2_bb_elementary::CallbackProgression;
use iceoryx2_bb_elementary::bump_allocator::BumpAllocator;
use iceoryx2_bb_elementary::relocatable_ptr::GenericRelocatablePointer;
use iceoryx2_bb_elementary_traits::generic_pointer::GenericPointer;
use iceoryx2_bb_elementary_traits::owning_pointer::GenericOwningPointer;
pub use iceoryx2_bb_elementary_traits::relocatable_container::RelocatableContainer;
use iceoryx2_bb_elementary_traits::{
placement_default::PlacementDefault, zero_copy_send::ZeroCopySend,
};
use iceoryx2_log::{fail, fatal_panic};
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub enum FlatMapError {
KeyAlreadyExists,
IsFull,
}
#[repr(C)]
struct Entry<K: Eq, V: Clone> {
id: K,
value: V,
}
unsafe impl<K: Eq + ZeroCopySend, V: Clone + ZeroCopySend> ZeroCopySend for Entry<K, V> {}
pub type FlatMap<K, V> = MetaFlatMap<K, V, GenericOwningPointer>;
pub type RelocatableFlatMap<K, V> = MetaFlatMap<K, V, GenericRelocatablePointer>;
#[doc(hidden)]
#[repr(C)]
pub struct MetaFlatMap<K: Eq, V: Clone, Ptr: GenericPointer> {
map: MetaSlotMap<Entry<K, V>, Ptr>,
is_initialized: AtomicBool,
}
impl<K: Eq + Debug, V: Clone + Debug, Ptr: GenericPointer> Debug for MetaFlatMap<K, V, Ptr> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"MetaFlatMap<{}, {}, {}> {{ len: {}, is_initialized: {} }}",
core::any::type_name::<K>(),
core::any::type_name::<V>(),
core::any::type_name::<Ptr>(),
self.len_impl(),
self.is_initialized
.load(core::sync::atomic::Ordering::Relaxed),
)
}
}
impl<K: Eq, V: Clone, Ptr: GenericPointer> MetaFlatMap<K, V, Ptr> {
#[inline(always)]
fn verify_init(&self, source: &str) {
debug_assert!(
self.is_initialized
.load(core::sync::atomic::Ordering::Relaxed),
"From: MetaFlatMap<{}, {}>::{}, Undefined behavior - the object was not initialized with 'init' before.",
core::any::type_name::<K>(),
core::any::type_name::<V>(),
source
);
}
pub(crate) unsafe fn insert_impl<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
&mut self,
id: K,
value: V,
eq_func: &F,
) -> Result<(), FlatMapError> {
self.verify_init("insert()");
let msg = "Unable to insert key-value pair into FlatMap";
let origin = "MetaFlatMap::insert_impl()";
let mut iter = unsafe { self.map.iter_impl() }
.skip_while(|kv| !__internal_eq_comparison_wrapper(&kv.1.id, &id, eq_func));
if iter.next().is_some() {
fail!(from origin, with FlatMapError::KeyAlreadyExists, "{msg} since the passed key already exists.");
}
if unsafe { self.map.insert_impl(Entry { id, value }) }.is_none() {
fail!(from origin, with FlatMapError::IsFull, "{msg} since the FlatMap is full.");
}
Ok(())
}
pub(crate) unsafe fn get_impl<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
&self,
id: &K,
eq_func: &F,
) -> Option<V> {
self.verify_init("get()");
unsafe { self.get_ref_impl(id, eq_func).cloned() }
}
pub(crate) unsafe fn get_ref_impl<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
&self,
id: &K,
eq_func: &F,
) -> Option<&V> {
self.verify_init("get_ref()");
let mut iter = unsafe { self.map.iter_impl() }
.skip_while(|kv| !__internal_eq_comparison_wrapper(&kv.1.id, id, eq_func));
iter.next().map(|kv| &kv.1.value)
}
pub(crate) unsafe fn get_mut_ref_impl<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<&mut V> {
self.verify_init("get_mut_ref()");
let slot_map_entry = unsafe { self.map.iter_impl() }
.find(|kv| __internal_eq_comparison_wrapper(&kv.1.id, id, eq_func))?;
unsafe { self.map.get_mut_impl(slot_map_entry.0) }
.map(|flat_map_entry| &mut flat_map_entry.value)
}
pub(crate) unsafe fn remove_impl<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<V> {
self.verify_init("remove()");
let mut iter = unsafe { self.map.iter_impl() }
.skip_while(|kv| !__internal_eq_comparison_wrapper(&kv.1.id, id, eq_func));
if let Some(kv) = iter.next() {
let key = kv.0;
unsafe { self.map.remove_impl(key) }.map(|e| e.value)
} else {
None
}
}
pub(crate) fn is_empty_impl(&self) -> bool {
self.map.is_empty_impl()
}
pub(crate) fn is_full_impl(&self) -> bool {
self.map.is_full_impl()
}
pub(crate) unsafe fn contains_impl<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> bool {
self.verify_init("contains()");
unsafe { self.get_ref_impl(id, eq_func).is_some() }
}
pub(crate) fn len_impl(&self) -> usize {
self.map.len_impl()
}
pub(crate) unsafe fn list_keys_impl<F: FnMut(&K) -> CallbackProgression>(
&self,
mut callback: F,
) {
for (_, kv) in unsafe { self.map.iter_impl() } {
if callback(&kv.id) == CallbackProgression::Stop {
break;
}
}
}
}
#[doc(hidden)]
pub fn __internal_default_eq_comparison<T: Eq>(lhs: *const u8, rhs: *const u8) -> bool {
unsafe { *lhs.cast::<T>() == *rhs.cast::<T>() }
}
#[doc(hidden)]
pub fn __internal_eq_comparison_wrapper<T: Eq, F: Fn(*const u8, *const u8) -> bool + ?Sized>(
lhs: &T,
rhs: &T,
eq_func: &F,
) -> bool {
eq_func(
(lhs as *const T).cast::<u8>(),
(rhs as *const T).cast::<u8>(),
)
}
impl<K: Eq, V: Clone> FlatMap<K, V> {
pub fn new(capacity: usize) -> Self {
Self {
map: MetaSlotMap::new(capacity),
is_initialized: AtomicBool::new(true),
}
}
pub fn insert(&mut self, id: K, value: V) -> Result<(), FlatMapError> {
unsafe { self.insert_impl(id, value, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_insert<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: K,
value: V,
eq_func: &F,
) -> Result<(), FlatMapError> {
unsafe { self.insert_impl(id, value, eq_func) }
}
pub fn get(&self, id: &K) -> Option<V> {
unsafe { self.get_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_get<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> Option<V> {
unsafe { self.get_impl(id, eq_func) }
}
pub fn get_ref(&self, id: &K) -> Option<&V> {
unsafe { self.get_ref_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_get_ref<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> Option<&V> {
unsafe { self.get_ref_impl(id, eq_func) }
}
pub fn get_mut_ref(&mut self, id: &K) -> Option<&mut V> {
unsafe { self.get_mut_ref_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_get_mut_ref<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<&mut V> {
unsafe { self.get_mut_ref_impl(id, eq_func) }
}
pub fn remove(&mut self, id: &K) -> Option<V> {
unsafe { self.remove_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_remove<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<V> {
unsafe { self.remove_impl(id, eq_func) }
}
pub fn is_empty(&self) -> bool {
self.is_empty_impl()
}
pub fn is_full(&self) -> bool {
self.is_full_impl()
}
pub fn contains(&self, id: &K) -> bool {
unsafe { self.contains_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_contains<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> bool {
unsafe { self.contains_impl(id, eq_func) }
}
pub fn len(&self) -> usize {
self.len_impl()
}
pub fn list_keys<F: FnMut(&K) -> CallbackProgression>(&self, callback: F) {
unsafe { self.list_keys_impl(callback) };
}
}
impl<K: Eq, V: Clone> RelocatableContainer for RelocatableFlatMap<K, V> {
unsafe fn new_uninit(capacity: usize) -> Self {
Self {
map: unsafe { RelocatableSlotMap::new_uninit(capacity) },
is_initialized: AtomicBool::new(false),
}
}
unsafe fn init<Allocator: iceoryx2_bb_elementary_traits::allocator::BaseAllocator>(
&mut self,
allocator: &Allocator,
) -> Result<(), iceoryx2_bb_elementary_traits::allocator::AllocationError> {
if self
.is_initialized
.load(core::sync::atomic::Ordering::Relaxed)
{
fatal_panic!(from "RelocatableFlatMap::init()", "Memory already initialized. Initializing it twice may lead to undefined behavior.");
}
let msg = "Unable to initialize RelocatableFlatMap";
fail!(from "RelocatableFlatMap::init()", when unsafe {self.map.init(allocator)}, "{msg} since the underlying RelocatableSlotMap could not be initialized.");
self.is_initialized
.store(true, core::sync::atomic::Ordering::Relaxed);
Ok(())
}
fn memory_size(capacity: usize) -> usize {
Self::const_memory_size(capacity)
}
}
unsafe impl<K: Eq + ZeroCopySend, V: Clone + ZeroCopySend> ZeroCopySend
for RelocatableFlatMap<K, V>
{
}
impl<K: Eq, V: Clone> RelocatableFlatMap<K, V> {
pub const fn const_memory_size(capacity: usize) -> usize {
RelocatableSlotMap::<Entry<K, V>>::const_memory_size(capacity)
}
pub unsafe fn insert(&mut self, id: K, value: V) -> Result<(), FlatMapError> {
unsafe { self.insert_impl(id, value, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_insert<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
&mut self,
id: K,
value: V,
eq_func: &F,
) -> Result<(), FlatMapError> {
unsafe { self.insert_impl(id, value, eq_func) }
}
pub unsafe fn get(&self, id: &K) -> Option<V> {
unsafe { self.get_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_get<F: Fn(*const u8, *const u8) -> bool + ?Sized>(
&self,
id: &K,
eq_func: &F,
) -> Option<V> {
unsafe { self.get_impl(id, eq_func) }
}
pub unsafe fn get_ref(&self, id: &K) -> Option<&V> {
unsafe { self.get_ref_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_get_ref<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> Option<&V> {
unsafe { self.get_ref_impl(id, eq_func) }
}
pub unsafe fn get_mut_ref(&mut self, id: &K) -> Option<&mut V> {
unsafe { self.get_mut_ref_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_get_mut_ref<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<&mut V> {
unsafe { self.get_mut_ref_impl(id, eq_func) }
}
pub unsafe fn remove(&mut self, id: &K) -> Option<V> {
unsafe { self.remove_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_remove<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<V> {
unsafe { self.remove_impl(id, eq_func) }
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn is_full(&self) -> bool {
self.map.is_full()
}
pub unsafe fn contains(&self, id: &K) -> bool {
unsafe { self.contains_impl(id, &__internal_default_eq_comparison::<K>) }
}
#[doc(hidden)]
pub unsafe fn __internal_contains<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> bool {
unsafe { self.contains_impl(id, eq_func) }
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn list_keys<F: FnMut(&K) -> CallbackProgression>(&self, callback: F) {
unsafe { self.list_keys_impl(callback) };
}
}
#[repr(C)]
pub struct FixedSizeFlatMap<K: Eq, V: Clone, const CAPACITY: usize> {
map: RelocatableFlatMap<K, V>,
_idx_to_data: MaybeUninit<[usize; CAPACITY]>,
_idx_to_data_free_list: MaybeUninit<[FreeListEntry; CAPACITY]>,
_data: MaybeUninit<[Option<Entry<K, V>>; CAPACITY]>,
_data_next_free_index: MaybeUninit<[usize; CAPACITY]>,
}
unsafe impl<K: Eq + ZeroCopySend, V: Clone + ZeroCopySend, const CAPACITY: usize> ZeroCopySend
for FixedSizeFlatMap<K, V, CAPACITY>
{
}
impl<K: Eq, V: Clone, const CAPACITY: usize> PlacementDefault for FixedSizeFlatMap<K, V, CAPACITY> {
unsafe fn placement_default(ptr: *mut Self) {
unsafe {
let map_ptr = core::ptr::addr_of_mut!((*ptr).map);
map_ptr.write(RelocatableFlatMap::new_uninit(CAPACITY));
let allocator = BumpAllocator::new((*ptr)._idx_to_data.as_mut_ptr().cast());
(*ptr)
.map
.init(&allocator)
.expect("All required memory is preallocated.");
}
}
}
impl<K: Eq, V: Clone, const CAPACITY: usize> Default for FixedSizeFlatMap<K, V, CAPACITY> {
fn default() -> Self {
Self::new()
}
}
impl<K: Eq + Debug, V: Clone + Debug, const CAPACITY: usize> Debug
for FixedSizeFlatMap<K, V, CAPACITY>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"MetaFlatMap<{}, {}, {}> {{ {:?} }}",
core::any::type_name::<K>(),
core::any::type_name::<V>(),
CAPACITY,
self.map
)
}
}
impl<K: Eq, V: Clone, const CAPACITY: usize> FixedSizeFlatMap<K, V, CAPACITY> {
pub fn new() -> Self {
let mut new_self = Self {
map: unsafe { RelocatableFlatMap::new_uninit(CAPACITY) },
_idx_to_data: MaybeUninit::uninit(),
_idx_to_data_free_list: MaybeUninit::uninit(),
_data: MaybeUninit::uninit(),
_data_next_free_index: MaybeUninit::uninit(),
};
let allocator = BumpAllocator::new(new_self._idx_to_data.as_mut_ptr().cast());
unsafe {
new_self
.map
.init(&allocator)
.expect("All required memory is preallocated.")
};
new_self
}
pub fn insert(&mut self, id: K, value: V) -> Result<(), FlatMapError> {
unsafe { self.map.insert(id, value) }
}
#[doc(hidden)]
pub unsafe fn __internal_insert<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: K,
value: V,
eq_func: &F,
) -> Result<(), FlatMapError> {
unsafe { self.map.__internal_insert(id, value, eq_func) }
}
pub fn get(&self, id: &K) -> Option<V> {
unsafe { self.map.get(id) }
}
#[doc(hidden)]
pub unsafe fn __internal_get<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> Option<V> {
unsafe { self.map.__internal_get(id, eq_func) }
}
pub fn get_ref(&self, id: &K) -> Option<&V> {
unsafe { self.map.get_ref(id) }
}
#[doc(hidden)]
pub unsafe fn __internal_get_ref<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> Option<&V> {
unsafe { self.map.__internal_get_ref(id, eq_func) }
}
pub fn get_mut_ref(&mut self, id: &K) -> Option<&mut V> {
unsafe { self.map.get_mut_ref(id) }
}
#[doc(hidden)]
pub unsafe fn __internal_get_mut_ref<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<&mut V> {
unsafe { self.map.__internal_get_mut_ref(id, eq_func) }
}
pub fn remove(&mut self, id: &K) -> Option<V> {
unsafe { self.map.remove(id) }
}
#[doc(hidden)]
pub unsafe fn __internal_remove<F: Fn(*const u8, *const u8) -> bool>(
&mut self,
id: &K,
eq_func: &F,
) -> Option<V> {
unsafe { self.map.__internal_remove(id, eq_func) }
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn is_full(&self) -> bool {
self.map.is_full()
}
pub fn contains(&self, id: &K) -> bool {
unsafe { self.map.contains(id) }
}
#[doc(hidden)]
pub unsafe fn __internal_contains<F: Fn(*const u8, *const u8) -> bool>(
&self,
id: &K,
eq_func: &F,
) -> bool {
unsafe { self.map.__internal_contains(id, eq_func) }
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn list_keys<F: FnMut(&K) -> CallbackProgression>(&self, callback: F) {
unsafe { self.map.list_keys_impl(callback) };
}
}