#![feature(test)]

extern crate bit_field;

use bit_field::*;

pub trait BitOper {
    const BIT_LEN: usize;
    fn get_b(&self, idx: usize) -> bool;
    fn set_b(&mut self, idx: usize, val: bool);
    fn toggle(&mut self, idx: usize);
}

pub trait BitArrayOper<T: BitOper> {
    fn get_blen(&self) -> usize;
    fn get_b(&self, idx: usize) -> bool;
    fn set_b(&mut self, idx: usize, val: bool);
    fn toggle(&mut self, idx: usize);
}

impl BitOper for u8 {
    const BIT_LEN: usize = std::mem::size_of::<Self>() as usize * 8;

    fn set_b(&mut self, idx: usize, val: bool) {
        assert!(idx < Self::BIT_LEN);
        if val {
            *self |= 1 << idx;
        } else {
            *self &= !(1 << idx);
        }
    }

    fn get_b(&self, idx: usize) -> bool {
        assert!(idx < Self::BIT_LEN);
        (self & 1 << idx) != 0
    }

    fn toggle(&mut self, idx: usize) {
        assert!(idx < Self::BIT_LEN);
        *self ^= 1 << idx;
    }
}

impl BitOper for u32 {
    const BIT_LEN: usize = std::mem::size_of::<Self>() as usize * 8;
    fn set_b(&mut self, idx: usize, val: bool) {
        assert!(idx < Self::BIT_LEN);
        if val {
            *self |= 1 << idx;
        } else {
            *self &= !(1 << idx);
        }
    }

    fn get_b(&self, idx: usize) -> bool {
        assert!(idx < Self::BIT_LEN);
        (self & 1 << idx) != 0
    }

    fn toggle(&mut self, idx: usize) {
        assert!(idx < Self::BIT_LEN);
        *self ^= 1 << idx;
    }
}

impl BitOper for u64 {
    const BIT_LEN: usize = std::mem::size_of::<Self>() as usize * 8;
    fn set_b(&mut self, idx: usize, val: bool) {
        assert!(idx < Self::BIT_LEN);
        if val {
            *self |= 1 << idx;
        } else {
            *self &= !(1 << idx);
        }
    }

    fn get_b(&self, idx: usize) -> bool {
        assert!(idx < Self::BIT_LEN);
        (self & 1 << idx) != 0
    }

    fn toggle(&mut self, idx: usize) {
        assert!(idx < Self::BIT_LEN);
        *self ^= 1 << idx;
    }
}

impl<T: BitOper> BitArrayOper<T> for [T] {
    fn get_blen(&self) -> usize {
        self.len() * T::BIT_LEN
    }

    fn get_b(&self, idx: usize) -> bool {
        self[idx / T::BIT_LEN].get_b(idx % T::BIT_LEN)
    }

    fn set_b(&mut self, idx: usize, val: bool) {
        self[idx / T::BIT_LEN].set_b(idx % T::BIT_LEN, val);
    }

    fn toggle(&mut self, idx: usize) {
        self[idx / T::BIT_LEN].toggle(idx % T::BIT_LEN);
    }
}

extern crate test;

use test::Bencher;

const LEN: usize = 256;

fn set_bitfield<T: BitField>(v: &mut Vec<T>) {
    for i in 0..v.len() * T::BIT_LENGTH {
        v.as_mut_slice().set_bit(i, true);;
    }
}

fn get_bitfield<T: BitField>(v: &Vec<T>) {
    for i in 0..v.len() * T::BIT_LENGTH {
        let _b = v.as_slice().get_bit(i);
    }
}

fn set_trivial<T: BitOper>(v: &mut Vec<T>) {
    for i in 0..v.len() * T::BIT_LEN {
        v.set_b(i, true);
    }
}

fn get_trivial<T: BitOper>(v: &Vec<T>) {
    for i in 0..v.len() * T::BIT_LEN {
        let _b = v.get_b(i);
    }
}

#[bench]
fn u8_set_bitfield(b: &mut Bencher) {
    let mut v = vec![0u8; LEN];
    b.iter(|| {
        set_bitfield(&mut v);
    });
}

#[bench]
fn u8_set_trivial(b: &mut Bencher) {
    let mut v = vec![0u8; LEN];

    b.iter(|| {
        set_trivial(&mut v);
    });
}

#[bench]
fn u8_get_bitfield(b: &mut Bencher) {
    let v = vec![1u8; LEN];
    b.iter(|| {
        get_bitfield(&v);
    });
}

#[bench]
fn u8_get_trivial(b: &mut Bencher) {
    let v = vec![1u8; LEN];
    b.iter(|| {
        get_trivial(&v);
    });
}

#[bench]
fn u32_set_bitfield(b: &mut Bencher) {
    let mut v = vec![0u32; LEN];
    b.iter(|| {
        set_bitfield(&mut v);
    });
}

#[bench]
fn u32_set_trivial(b: &mut Bencher) {
    let mut v = vec![0u32; LEN];

    b.iter(|| {
        set_trivial(&mut v);
    });
}

#[bench]
fn u32_get_bitfield(b: &mut Bencher) {
    let v = vec![1u32; LEN];
    b.iter(|| {
        get_bitfield(&v);
    });
}

#[bench]
fn u32_get_trivial(b: &mut Bencher) {
    let v = vec![1u32; LEN];
    b.iter(|| {
        get_trivial(&v);
    });
}

#[bench]
fn u64_set_bitfield(b: &mut Bencher) {
    let mut v = vec![0u64; LEN];
    b.iter(|| {
        set_bitfield(&mut v);
    });
}

#[bench]
fn u64_set_trivial(b: &mut Bencher) {
    let mut v = vec![0u64; LEN];

    b.iter(|| {
        set_trivial(&mut v);
    });
}

#[bench]
fn u64_get_bitfield(b: &mut Bencher) {
    let v = vec![1u64; LEN];
    b.iter(|| {
        get_bitfield(&v);
    });
}

#[bench]
fn u64_get_trivial(b: &mut Bencher) {
    let v = vec![1u64; LEN];
    b.iter(|| {
        get_trivial(&v);
    });
}
