superbit/simhash/
bitarray.rs1use core::{
5 cmp::Ordering,
6 fmt,
7 hash::{Hash, Hasher},
8 ops::*,
9};
10use num_traits::{One, Zero};
11
12#[derive(Clone, Copy)]
13pub struct BitArray<const LANES: usize> {
14 lanes: [u64; LANES],
15}
16impl<const LANES: usize> Default for BitArray<LANES> {
17 fn default() -> Self {
18 Self {
19 lanes: [0u64; LANES],
20 }
21 }
22}
23
24impl<const L: usize> fmt::Debug for BitArray<L> {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write!(f, "BitArray<{}×64>(…)", L)
29 }
30}
31impl<const L: usize> PartialEq for BitArray<L> {
32 fn eq(&self, o: &Self) -> bool {
33 self.lanes == o.lanes
34 }
35}
36impl<const L: usize> Eq for BitArray<L> {}
37impl<const L: usize> PartialOrd for BitArray<L> {
38 fn partial_cmp(&self, o: &Self) -> Option<Ordering> {
39 Some(self.lanes.cmp(&o.lanes))
40 }
41}
42impl<const L: usize> Hash for BitArray<L> {
43 fn hash<H: Hasher>(&self, st: &mut H) {
44 for &x in &self.lanes {
45 st.write_u64(x)
46 }
47 }
48}
49
50impl<const L: usize> Add for BitArray<L> {
53 type Output = Self;
54 fn add(self, _: Self) -> Self {
55 self
56 }
57}
58impl<const L: usize> Mul for BitArray<L> {
59 type Output = Self;
60 fn mul(self, _: Self) -> Self {
61 self
62 }
63}
64
65impl<const L: usize> Zero for BitArray<L> {
66 fn zero() -> Self {
67 Self { lanes: [0; L] }
68 }
69 fn is_zero(&self) -> bool {
70 self.lanes.iter().all(|&x| x == 0)
71 }
72}
73impl<const L: usize> One for BitArray<L> {
74 fn one() -> Self {
75 let mut a = [0u64; L];
76 a[0] = 1;
77 Self { lanes: a }
78 }
79}
80
81macro_rules! impl_bin {
84 ($Trait:ident,$func:ident,$op:tt) => {
85 impl<const L: usize> $Trait for BitArray<L>{
86 type Output = Self;
87 fn $func(mut self, rhs:Self)->Self{
88 for (a,b) in self.lanes.iter_mut().zip(rhs.lanes){ *a = *a $op b }
89 self
90 }
91 }
92 impl<const L: usize> $Trait<&Self> for BitArray<L>{
93 type Output = Self;
94 fn $func(self, rhs:&Self)->Self{ self.$func(*rhs) }
95 }
96 };
97}
98impl_bin!(BitOr, bitor , |);
99impl_bin!(BitAnd, bitand, &);
100impl_bin!(BitXor, bitxor, ^);
101
102impl<const L: usize> Not for BitArray<L> {
103 type Output = Self;
104 fn not(mut self) -> Self {
105 for x in &mut self.lanes {
106 *x = !*x
107 }
108 self
109 }
110}
111impl<const L: usize> BitOrAssign for BitArray<L> {
112 fn bitor_assign(&mut self, rhs: Self) {
113 for (a, b) in self.lanes.iter_mut().zip(rhs.lanes) {
114 *a |= b;
115 }
116 }
117}
118
119impl<const L: usize> ShlAssign<usize> for BitArray<L> {
122 fn shl_assign(&mut self, n: usize) {
123 let words = n / 64;
124 let bits = n % 64;
125 if words > 0 {
126 for i in (0..L).rev() {
127 self.lanes[i] = if i >= words { self.lanes[i - words] } else { 0 };
128 }
129 }
130 if bits > 0 {
131 for i in (0..L).rev() {
132 self.lanes[i] <<= bits;
133 if i > 0 {
134 self.lanes[i] |= self.lanes[i - 1] >> (64 - bits);
135 }
136 }
137 }
138 }
139}
140impl<const L: usize> Shl<usize> for BitArray<L> {
141 type Output = Self;
142 fn shl(mut self, n: usize) -> Self {
143 self <<= n;
144 self
145 }
146}
147
148impl<const L: usize> ShrAssign<usize> for BitArray<L> {
149 fn shr_assign(&mut self, n: usize) {
150 let words = n / 64;
151 let bits = n % 64;
152 if words > 0 {
153 for i in 0..L {
154 self.lanes[i] = if i + words < L {
155 self.lanes[i + words]
156 } else {
157 0
158 };
159 }
160 }
161 if bits > 0 {
162 for i in 0..L {
163 self.lanes[i] >>= bits;
164 if i + 1 < L {
165 self.lanes[i] |= self.lanes[i + 1] << (64 - bits);
166 }
167 }
168 }
169 }
170}
171impl<const L: usize> Shr<usize> for BitArray<L> {
172 type Output = Self;
173 fn shr(mut self, n: usize) -> Self {
174 self >>= n;
175 self
176 }
177}
178
179impl<const L: usize> super::SimHashBits for BitArray<L> {
180 fn count_ones(self) -> usize {
181 self.lanes.iter().map(|x| x.count_ones() as usize).sum()
182 }
183 fn to_u32_high_bits(self) -> u32 {
184 (self.lanes[L - 1] >> 32) as u32
185 }
186 fn to_u64_high_bits(self) -> u64 {
187 self.lanes[L - 1]
188 }
189 fn hamming_distance(&self, r: &Self) -> usize {
190 self.lanes
191 .iter()
192 .zip(r.lanes)
193 .map(|(a, b)| (a ^ b).count_ones() as usize)
194 .sum()
195 }
196 fn bit_length() -> usize {
197 L * 64
198 }
199}