reliq 0.1.0

A portable library of primitive-like constructs.
Documentation
pub trait Key
where
    Self: ::core::fmt::Debug,
    Self: Default,
    Self: Clone,
    Self: Copy,
    Self: Eq,
    Self: ::core::hash::Hash {}

pub trait Val
where
    Self: ::core::fmt::Debug,
    Self: Default,
    Self: Clone,
    Self: Copy {}

pub trait Hasher
where
    Self: Default,
    Self: ::core::hash::Hasher {}

#[derive(Clone)]
pub struct Map<const A: usize, B, C, D = ::core::hash::SipHasher> 
where
    B: Key,
    C: Val,
    D: ::core::hash::Hasher {
    keys: [Option<B>; A],
    vals: [Option<C>; A],
    len: usize,
    hasher: ::core::marker::PhantomData<D>
}

impl<const A: usize, B, C, D> Map<A, B, C, D>
where
    B: Key,
    C: Val,
    D: Hasher {
    pub const fn len(&self) -> usize {
        self.len
    }

    pub const fn cap(&self) -> usize {
        A
    }

    pub const fn is_empty(&self) -> bool {
        self.len == 0
    }

    #[inline]
    pub fn get(&self, key: &B) -> Option<&C> {
        let mut position: usize = self.hash_index(key);
        for _ in 0..A {
            match &self.keys[position] {
                Some(k) if k == key => return self.vals[position].as_ref(),
                None => return None,
                _ => position = (position + 1) % A
            }
        }
        None
    }

    #[inline]
    pub fn insert(&mut self, key: B, data: C) -> Result<(), (B, C)> {
        if self.len >= A {
            return Err((key, data))
        }
        let mut position: usize = self.hash_index(&key);
        for _ in 0..A {
            match &self.keys[position] {
                Some(existing_key) if *existing_key == key => {
                    self.vals[position] = Some(data);
                    return Ok(())
                },
                None => {
                    self.keys[position] = Some(key);
                    self.vals[position] = Some(data);
                    self.len += 1;
                    return Ok(())
                },
                _ => position = (position + 1) % A
            }
        }
        Err((key, data))
    }

    #[inline]
    pub fn remove(&mut self, key: &B) -> Option<C> {
        let mut pos = self.hash_index(key);
        for _ in 0..A {
            match self.keys[pos] {
                Some(k) if k == *key => {
                    let old_val = self.vals[pos].take();
                    self.keys[pos] = None;
                    self.len -= 1;

                    // Reinsert subsequent cluster keys to avoid lookup holes
                    let mut next = (pos + 1) % A;
                    while let Some(k) = self.keys[next] {
                        let val = self.vals[next].take().unwrap();
                        self.keys[next] = None;
                        self.len -= 1;
                        self.insert(k, val).unwrap();
                        next = (next + 1) % A;
                    }
                    return old_val;
                }
                None => return None,
                _ => pos = (pos + 1) % A,
            }
        }
        None
    }

    #[inline]
    fn hash_index(&self, key: &B) -> usize {
        let mut hasher: D = D::default();
        key.hash(&mut hasher);
        (
            hasher.finish() as usize
        ) % A
    }
}

impl<const A: usize, B, C, D> Default for Map<A, B, C, D> 
where
    B: Key,
    C: Val,
    D: Hasher {
    #[inline]
    fn default() -> Self {
        Self {
            keys: [None; A],
            vals: [None; A],
            len: 0,
            hasher: ::core::marker::PhantomData
        }
    }
}