primitivemap 0.1.0

blazing fast [Integer -> T: Copy] map
Documentation
extern crate smallvec;

pub mod bucket;
pub mod hash;
pub mod kv;

use std::marker::PhantomData;

pub use bucket::{ArrayBucket, ArrayBucketList, Bucket, BucketList, SmallVecBucket,
                 SmallVecBucketList};
pub use hash::{DefaultHasher, Hash, Hasher};
pub use kv::{Key, Value};

pub struct PrimitiveMap<
    K: Key,
    V: Value,
    B: Bucket<K, V>,
    BL: BucketList<K, V, Bucket = B>,
    H: Hasher<K>,
> {
    buckets: BL,
    _marker: PhantomData<(K, V, B, H)>,
}

impl<K, V, B, BL, H> PrimitiveMap<K, V, B, BL, H>
where
    K: Key,
    V: Value,
    B: Bucket<K, V>,
    BL: BucketList<K, V, Bucket = B>,
    H: Hasher<K>,
{
    pub fn custom(buckets: BL, _hasher: H) -> Self {
        PrimitiveMap {
            buckets,
            _marker: PhantomData,
        }
    }

    pub fn insert(&mut self, key: K, value: V) {
        let addr = self.get_addr(key);
        let bucket = self.buckets.get_mut(addr);
        bucket.push(key, value)
    }

    pub fn get(&self, key: K) -> Option<V> {
        let addr = self.get_addr(key);
        let bucket = &self.buckets.get(addr);
        bucket.get(key)
    }

    fn get_addr(&self, key: K) -> usize {
        let hash = H::hash(key);
        H::compress(hash, self.buckets.len())
    }
}

impl<K, V> PrimitiveMap<K, V, SmallVecBucket<K, V>, SmallVecBucketList<K, V>, DefaultHasher<K>>
where
    K: Key,
    V: Value,
    DefaultHasher<K>: Hasher<K>,
{
    pub fn dynamic() -> Self {
        PrimitiveMap::custom(SmallVecBucketList::empty(), DefaultHasher::default())
    }
}

impl<K, V> PrimitiveMap<K, V, ArrayBucket<K, V>, ArrayBucketList<K, V>, DefaultHasher<K>>
where
    K: Key,
    V: Value,
    DefaultHasher<K>: Hasher<K>,
{
    pub fn fixed() -> Self {
        PrimitiveMap::custom(ArrayBucketList::empty(), DefaultHasher::default())
    }
}

impl<K, V, H> PrimitiveMap<K, V, SmallVecBucket<K, V>, SmallVecBucketList<K, V>, H>
where
    K: Key,
    V: Value,
    H: Hasher<K>,
{
    pub fn dynamic_with_hasher(hasher: H) -> Self {
        PrimitiveMap::custom(SmallVecBucketList::empty(), hasher)
    }
}

impl<K, V, H> PrimitiveMap<K, V, ArrayBucket<K, V>, ArrayBucketList<K, V>, H>
where
    K: Key,
    V: Value,
    H: Hasher<K>,
{
    pub fn fixed_with_hasher(hasher: H) -> Self {
        PrimitiveMap::custom(ArrayBucketList::empty(), hasher)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn create_dynamic() {
        <PrimitiveMap<u8, u32, _, _, _>>::dynamic();
    }

    #[test]
    fn create_fixed() {
        <PrimitiveMap<u8, u32, _, _, _>>::fixed();
    }

    #[test]
    fn default_hasher() {
        <PrimitiveMap<u8, u8, _, _, _>>::dynamic();
        <PrimitiveMap<u16, u8, _, _, _>>::dynamic();
        <PrimitiveMap<u32, u8, _, _, _>>::dynamic();
        <PrimitiveMap<u64, u8, _, _, _>>::dynamic();
        <PrimitiveMap<usize, u8, _, _, _>>::dynamic();
        <PrimitiveMap<i8, u8, _, _, _>>::dynamic();
        <PrimitiveMap<i16, u8, _, _, _>>::dynamic();
        <PrimitiveMap<i32, u8, _, _, _>>::dynamic();
    }

    #[test]
    fn insert_dynamic() {
        let mut map = PrimitiveMap::dynamic();
        map.insert(0u8, 10u32);
    }

    #[test]
    fn insert_fixed() {
        let mut map: PrimitiveMap<_, _, _, _, DefaultHasher<_>> = PrimitiveMap::fixed();
        map.insert(0u16, 10u32);
    }

    #[test]
    fn get_empty_dynamic() {
        let map = PrimitiveMap::dynamic();
        assert_eq!(map.get(0u32), None::<u32>);
    }

    #[test]
    fn get_empty_fixed() {
        let map = PrimitiveMap::fixed();
        assert_eq!(map.get(0u32), None::<u32>);
    }

    #[test]
    fn insert_and_get_dynamic() {
        let mut map = PrimitiveMap::dynamic();
        map.insert(0i8, 10u32);
        assert_eq!(map.get(0i8), Some(10u32));
    }

    #[test]
    fn insert_and_get_fixed() {
        let mut map = PrimitiveMap::fixed();
        map.insert(0i16, 10u32);
        assert_eq!(map.get(0i16), Some(10u32));
    }

    #[test]
    fn insert_saturate_buckets_dynamic() {
        let mut map = PrimitiveMap::dynamic();
        for i in 0..10000 {
            map.insert(i, 10u32);
        }
    }
}