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
use crate::{
    BitUtil, 
    Ordering
};

#[allow(non_snake_case)]
#[derive(Debug, Clone, Copy)]
pub struct BitProto {
    pub(crate) MASK: usize,
    pub(crate) BITS: usize,
    pub(crate) MAX_CAPACITY: usize
}

impl BitProto {
    pub(crate) const MAX_TRUE_CAP: usize = (usize::MAX / usize::BITS as usize);
    pub(crate) const MAX_TRUE_BITS: usize = Self::MAX_TRUE_CAP * usize::BITS as usize;

    #[inline(always)]
    pub const fn create(bit_width: usize) -> Self {
        if bit_width == 0 {
            panic!("bit_width cannot be 0 (use a zero-typed Vec instead)");
        }
        if bit_width > usize::BITS as usize {
            panic!("bit_width cannot be greater than usize::BITS");
        }
        let mask = if bit_width == usize::BITS as usize {
            usize::MAX
        } else {
            (1 << bit_width) - 1
        };
        Self {
            MASK: mask,
            BITS: bit_width,
            MAX_CAPACITY: Self::MAX_TRUE_BITS / bit_width,
        }
    }

    #[inline(always)]
    pub const fn idx_proxy(proto: BitProto, bitwise_idx: usize) -> IdxProxy {
        let total_bits = bitwise_idx * proto.BITS;
        let (real_idx, first_offset) = match BitUtil::USIZE_BITS {
            64 => (total_bits >> 6, total_bits & 0b_00111111),
            32 => (total_bits >> 5, total_bits & 0b_00011111),
            16 => (total_bits >> 4, total_bits & 0b_00001111),
            _ => (total_bits / BitUtil::USIZE_BITS, total_bits % BitUtil::USIZE_BITS)
        };
        let second_offset = BitUtil::USIZE_BITS - first_offset;
        let first_mask = proto.MASK << first_offset;
        let second_mask = BitUtil::right_shift_discard_if_ubits(proto.MASK, second_offset);
        IdxProxy {
            bitwise_idx,
            real_idx,
            first_offset,
            first_mask,
            second_offset,
            second_mask
        }
    }

    #[inline(always)]
    pub(crate) const fn calc_block_count_from_bitwise_count(proto: BitProto, bitwise_count: usize) -> usize {
        let total_bits = bitwise_count * proto.BITS;
        let (real_count, bit_offset) = match BitUtil::USIZE_BITS {
            64 => (total_bits >> 6, total_bits & 0b_00111111),
            32 => (total_bits >> 5, total_bits & 0b_00011111),
            16 => (total_bits >> 4, total_bits & 0b_00001111),
            _ => (total_bits / BitUtil::USIZE_BITS, total_bits % BitUtil::USIZE_BITS)
        };
        real_count + BitUtil::one_if_val_isnt_zero(bit_offset)
    }

    #[inline(always)]
    pub(crate) fn calc_bitwise_count_from_block_count(proto: BitProto, block_count: usize) -> usize {
        BitUtil::calc_total_bits_in_num_usize(block_count) / proto.BITS
    }
}

#[derive(Clone, Copy, Debug)]
pub struct IdxProxy {
    pub(crate) bitwise_idx: usize,
    pub(crate) real_idx: usize,
    pub(crate) first_offset: usize,
    pub(crate) first_mask: usize,
    pub(crate) second_offset: usize,
    pub(crate) second_mask: usize
}

impl IdxProxy {
    #[inline(always)]
    pub fn idx(&self) -> usize {
        self.bitwise_idx
    }
}

impl Ord for IdxProxy {
    #[inline(always)]
    fn cmp(&self, other: &Self) -> Ordering {
        self.bitwise_idx.cmp(&other.bitwise_idx)
    }
}

impl PartialOrd<Self> for IdxProxy {
    #[inline(always)]
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq<Self> for IdxProxy {
    #[inline(always)]
    fn eq(&self, other: &Self) -> bool {
        self.bitwise_idx == other.bitwise_idx
    }
}
impl Eq for IdxProxy {}