use crate::error::{CIndexMapError, MapErrorKind};
use crate::util::mem_cmp;
use core::alloc::Layout;
use core::fmt::Debug;
use core::ptr;
#[derive(Debug)]
pub struct CIndexMap<K, V> {
key_layout: Layout,
val_layout: Layout,
keys: *mut K,
values: *mut V,
cap: isize,
pos: isize,
}
impl<K, V> CIndexMap<K, V> {
pub fn new() -> CIndexMap<K, V> {
if size_of::<K>() == 0 || size_of::<V>() == 0 {
panic!("Cannot initialize CIndexMap with ZSTs!");
}
let key_layout = unsafe {
Layout::from_size_align(size_of::<K>() * 1, align_of::<K>()).unwrap()
};
let val_layout = unsafe {
Layout::from_size_align(size_of::<V>() * 1, align_of::<V>()).unwrap()
};
let key_ptr = unsafe {
std::alloc::alloc(key_layout)
} as *mut K;
let val_ptr = unsafe {
std::alloc::alloc(val_layout)
} as *mut V;
CIndexMap {
key_layout,
val_layout,
keys: key_ptr,
values: val_ptr,
cap: 1,
pos: -1,
}
}
pub fn insert(&mut self, key: K, value: V) -> crate::result::Result<()> {
if (self.pos + 1) >= self.cap {
let new_cap = self.cap + 2;
let new_key_ptr = unsafe {
std::alloc::realloc(
self.keys as *mut u8,
self.key_layout,
size_of::<K>() * (new_cap as usize),
) as *mut K
};
let new_val_ptr = unsafe {
std::alloc::realloc(
self.values as *mut u8,
self.val_layout,
size_of::<V>() * (new_cap as usize),
) as *mut V
};
if (new_val_ptr == ptr::null_mut()) || (new_key_ptr == ptr::null_mut()) {
return Err(CIndexMapError::new(
MapErrorKind::AllocationError,
"Error when attempting to allocate map memory."
));
} else {
self.keys = new_key_ptr;
self.values = new_val_ptr;
self.cap = new_cap;
}
}
self.pos += 1;
unsafe {
self.keys.offset(self.pos).write(key);
self.values.offset(self.pos).write(value);
}
Ok(())
}
pub fn remove(&mut self, index: usize) -> crate::result::Result<()> {
if index > (self.pos as usize) {
Err(
CIndexMapError::new(
MapErrorKind::AccessError,
"Attempted to access a map index that surpasses the bounds of the current map."
)
)
} else {
unsafe {
ptr::copy(
self.keys.offset((index as isize) + 1),
self.keys.offset(index as isize),
(self.pos as usize - index),
);
ptr::copy(
self.values.offset((index as isize) + 1),
self.values.offset(index as isize),
self.pos as usize - index,
);
}
self.pos -= 1;
Ok(())
}
}
pub fn index(&self, index: usize) -> crate::result::Result<&K> {
if index > (self.pos as usize) {
Err(
CIndexMapError::new(
MapErrorKind::AccessError,
"Attempted to access a map index that surpasses the bounds of the current map."
)
)
} else {
unsafe {
Ok(
&*self.keys.offset(index as isize)
)
}
}
}
pub fn get_no_peq(&self, key: K) -> Option<&V> {
let key_ptr = ptr::from_ref(&key);
let mut i = 0;
unsafe {
while i <= self.pos {
let cmp = mem_cmp(key_ptr as *const u8, self.keys.offset(i) as *const u8, size_of::<K>());
match cmp {
None => { return Some(&*self.values.offset(i)); }
Some(_) => {}
}
i += 1;
}
}
None
}
}
impl<K: PartialEq, V> CIndexMap<K, V> {
pub fn get(&self, key: K) -> Option<&V> {
unsafe {
for i in 0..(self.pos + 1) {
if *self.keys.add(i as usize) == key {
return Some(&*self.values.add(i as usize));
}
}
};
None
}
pub fn contains_key(&self, key: K) -> bool {
unsafe {
for i in 0..(self.pos + 1) {
if *self.keys.add(i as usize) == key {
return true;
}
}
};
false
}
}
impl<K, V: PartialEq> CIndexMap<K, V> {
pub fn contains_value(&self, value: V) -> bool {
unsafe {
for i in 0..(self.pos + 1) {
if *self.values.add(i as usize) == value {
return true;
}
}
};
false
}
}