1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use crate::word::Word;

/// Abstracts over writing bits to a buffer.
pub trait Write {
    /// Clears the buffer.
    fn start_write(&mut self);
    /// Returns the written bytes.
    fn finish_write(&mut self) -> &[u8];
    /// Writes a bit.
    fn write_bit(&mut self, v: bool);
    /// Writes up to 64 bits. The index of `word`'s most significant 1 must be < `bits`.
    /// `bits` must be in range `0..=64`.
    fn write_bits(&mut self, word: Word, bits: usize);
    /// Writes bytes.
    fn write_bytes(&mut self, bytes: &[u8]);
}

#[cfg(all(test, not(miri)))]
mod tests {
    use super::*;
    use crate::bit_buffer::BitBuffer;
    use crate::word_buffer::WordBuffer;
    use paste::paste;
    use test::{black_box, Bencher};

    // How many times each benchmark calls the function.
    const TIMES: usize = 1000;

    #[bench]
    fn bench_vec(b: &mut Bencher) {
        let mut vec = vec![];
        b.iter(|| {
            let vec = black_box(&mut vec);
            vec.clear();
            for _ in 0..TIMES {
                vec.push(black_box(0b10101u8))
            }
            black_box(vec);
        });
    }

    fn bench_write_bit<T: Write + Default>(b: &mut Bencher) {
        let mut buf = T::default();
        b.iter(|| {
            let buf = black_box(&mut buf);
            buf.start_write();
            for _ in 0..TIMES {
                buf.write_bit(black_box(true))
            }
        });
    }

    fn bench_write_bytes<T: Write + Default>(b: &mut Bencher, bytes: usize) {
        let v = vec![123u8; bytes];
        let mut buf = T::default();
        b.iter(|| {
            let buf = black_box(&mut buf);
            buf.start_write();
            buf.write_bit(true); // Make write_bytes unaligned.
            for _ in 0..TIMES {
                buf.write_bytes(black_box(v.as_slice()))
            }
        });
    }

    fn bench_write_bits<T: Write + Default>(b: &mut Bencher, bits: usize) {
        let v = Word::MAX >> (Word::BITS as usize - bits);
        let mut buf = T::default();
        b.iter(|| {
            let buf = black_box(&mut buf);
            buf.start_write();
            for _ in 0..TIMES {
                buf.write_bits(black_box(v), black_box(bits))
            }
        });
    }

    macro_rules! bench_write_bits {
        ($name:ident, $T:ty, $n:literal) => {
            paste! {
                #[bench]
                fn [<bench_ $name _write_bits_ $n>](b: &mut Bencher) {
                    bench_write_bits::<$T>(b, $n);
                }
            }
        };
    }

    macro_rules! bench_write_bytes {
        ($name:ident, $T:ty, $n:literal) => {
            paste! {
                #[bench]
                fn [<bench_ $name _write_bytes_ $n>](b: &mut Bencher) {
                    bench_write_bytes::<$T>(b, $n);
                }
            }
        };
    }

    macro_rules! bench_write {
        ($name:ident, $T:ty) => {
            paste! {
                #[bench]
                fn [<bench_ $name _write_bit1>](b: &mut Bencher) {
                    bench_write_bit::<$T>(b);
                }
            }

            bench_write_bits!($name, $T, 5);
            bench_write_bits!($name, $T, 41);
            bench_write_bytes!($name, $T, 1);
            bench_write_bytes!($name, $T, 10);
            bench_write_bytes!($name, $T, 100);
            bench_write_bytes!($name, $T, 1000);
        };
    }

    bench_write!(bit_buffer, BitBuffer);
    bench_write!(word_buffer, WordBuffer);
}