1use crate::bit_util::ceil;
21
22pub fn set_bits(
34 write_data: &mut [u8],
35 data: &[u8],
36 offset_write: usize,
37 offset_read: usize,
38 len: usize,
39) -> usize {
40 assert!(
41 offset_write
42 .checked_add(len)
43 .expect("operation will overflow write buffer")
44 <= write_data.len() * 8
45 );
46 assert!(
47 offset_read
48 .checked_add(len)
49 .expect("operation will overflow read buffer")
50 <= data.len() * 8
51 );
52 let mut null_count = 0;
53 let mut acc = 0;
54 while len > acc {
55 let (n, len_set) = unsafe {
59 set_upto_64bits(
60 write_data,
61 data,
62 offset_write + acc,
63 offset_read + acc,
64 len - acc,
65 )
66 };
67 null_count += n;
68 acc += len_set;
69 }
70
71 null_count
72}
73
74#[inline]
80unsafe fn set_upto_64bits(
81 write_data: &mut [u8],
82 data: &[u8],
83 offset_write: usize,
84 offset_read: usize,
85 len: usize,
86) -> (usize, usize) {
87 let read_byte = offset_read / 8;
88 let read_shift = offset_read % 8;
89 let write_byte = offset_write / 8;
90 let write_shift = offset_write % 8;
91
92 if len >= 64 {
93 let chunk = unsafe { data.as_ptr().add(read_byte).cast::<u64>().read_unaligned() };
94 if read_shift == 0 {
95 if write_shift == 0 {
96 let len = 64;
98 let null_count = chunk.count_zeros() as usize;
99 unsafe { write_u64_bytes(write_data, write_byte, chunk) };
100 (null_count, len)
101 } else {
102 let len = 64 - write_shift;
104 let chunk = chunk << write_shift;
105 let null_count = len - chunk.count_ones() as usize;
106 unsafe { or_write_u64_bytes(write_data, write_byte, chunk) };
107 (null_count, len)
108 }
109 } else if write_shift == 0 {
110 let len = 64 - 8; let chunk = (chunk >> read_shift) & 0x00FFFFFFFFFFFFFF; let null_count = len - chunk.count_ones() as usize;
114 unsafe { write_u64_bytes(write_data, write_byte, chunk) };
115 (null_count, len)
116 } else {
117 let len = 64 - std::cmp::max(read_shift, write_shift);
118 let chunk = (chunk >> read_shift) << write_shift;
119 let null_count = len - chunk.count_ones() as usize;
120 unsafe { or_write_u64_bytes(write_data, write_byte, chunk) };
121 (null_count, len)
122 }
123 } else if len == 1 {
124 let byte_chunk = (unsafe { data.get_unchecked(read_byte) } >> read_shift) & 1;
125 unsafe { *write_data.get_unchecked_mut(write_byte) |= byte_chunk << write_shift };
126 ((byte_chunk ^ 1) as usize, 1)
127 } else {
128 let len = std::cmp::min(len, 64 - std::cmp::max(read_shift, write_shift));
129 let bytes = ceil(len + read_shift, 8);
130 let chunk = unsafe { read_bytes_to_u64(data, read_byte, bytes) };
132 let mask = u64::MAX >> (64 - len);
133 let chunk = (chunk >> read_shift) & mask; let chunk = chunk << write_shift; let null_count = len - chunk.count_ones() as usize;
136 let bytes = ceil(len + write_shift, 8);
137 for (i, c) in chunk.to_le_bytes().iter().enumerate().take(bytes) {
138 unsafe { *write_data.get_unchecked_mut(write_byte + i) |= c };
139 }
140 (null_count, len)
141 }
142}
143
144#[inline]
147unsafe fn read_bytes_to_u64(data: &[u8], offset: usize, count: usize) -> u64 {
148 debug_assert!(count <= 8);
149 let mut tmp: u64 = 0;
150 let src = unsafe { data.as_ptr().add(offset) };
151 unsafe { std::ptr::copy_nonoverlapping(src, std::ptr::from_mut(&mut tmp).cast::<u8>(), count) };
152 tmp
153}
154
155#[inline]
158unsafe fn write_u64_bytes(data: &mut [u8], offset: usize, chunk: u64) {
159 let ptr = unsafe { data.as_mut_ptr().add(offset) }.cast::<u64>();
160 unsafe { ptr.write_unaligned(chunk) };
161}
162
163#[inline]
169unsafe fn or_write_u64_bytes(data: &mut [u8], offset: usize, chunk: u64) {
170 let ptr = unsafe { data.as_mut_ptr().add(offset) };
171 let chunk = chunk | (unsafe { *ptr }) as u64;
172 unsafe { ptr.cast::<u64>().write_unaligned(chunk) };
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::bit_util::{get_bit, set_bit, unset_bit};
179 use rand::prelude::StdRng;
180 use rand::{RngExt, SeedableRng, TryRng};
181 use std::fmt::Display;
182
183 #[test]
184 fn test_set_bits_aligned() {
185 SetBitsTest {
186 write_data: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
187 data: vec![
188 0b11100111, 0b10100101, 0b10011001, 0b11011011, 0b11101011, 0b11000011, 0b11100111,
189 0b10100101,
190 ],
191 offset_write: 8,
192 offset_read: 0,
193 len: 64,
194 expected_data: vec![
195 0, 0b11100111, 0b10100101, 0b10011001, 0b11011011, 0b11101011, 0b11000011,
196 0b11100111, 0b10100101, 0,
197 ],
198 expected_null_count: 24,
199 }
200 .verify();
201 }
202
203 #[test]
204 fn test_set_bits_unaligned_destination_start() {
205 SetBitsTest {
206 write_data: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
207 data: vec![
208 0b11100111, 0b10100101, 0b10011001, 0b11011011, 0b11101011, 0b11000011, 0b11100111,
209 0b10100101,
210 ],
211 offset_write: 3,
212 offset_read: 0,
213 len: 64,
214 expected_data: vec![
215 0b00111000, 0b00101111, 0b11001101, 0b11011100, 0b01011110, 0b00011111, 0b00111110,
216 0b00101111, 0b00000101, 0b00000000,
217 ],
218 expected_null_count: 24,
219 }
220 .verify();
221 }
222
223 #[test]
224 fn test_set_bits_unaligned_destination_end() {
225 SetBitsTest {
226 write_data: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
227 data: vec![
228 0b11100111, 0b10100101, 0b10011001, 0b11011011, 0b11101011, 0b11000011, 0b11100111,
229 0b10100101,
230 ],
231 offset_write: 8,
232 offset_read: 0,
233 len: 62,
234 expected_data: vec![
235 0, 0b11100111, 0b10100101, 0b10011001, 0b11011011, 0b11101011, 0b11000011,
236 0b11100111, 0b00100101, 0,
237 ],
238 expected_null_count: 23,
239 }
240 .verify();
241 }
242
243 #[test]
244 fn test_set_bits_unaligned() {
245 SetBitsTest {
246 write_data: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
247 data: vec![
248 0b11100111, 0b10100101, 0b10011001, 0b11011011, 0b11101011, 0b11000011, 0b11100111,
249 0b10100101, 0b10011001, 0b11011011, 0b11101011, 0b11000011, 0b11100111, 0b10100101,
250 0b10011001, 0b11011011, 0b11101011, 0b11000011,
251 ],
252 offset_write: 3,
253 offset_read: 5,
254 len: 95,
255 expected_data: vec![
256 0b01111000, 0b01101001, 0b11100110, 0b11110110, 0b11111010, 0b11110000, 0b01111001,
257 0b01101001, 0b11100110, 0b11110110, 0b11111010, 0b11110000, 0b00000001,
258 ],
259 expected_null_count: 35,
260 }
261 .verify();
262 }
263
264 #[test]
265 fn set_bits_fuzz() {
266 let mut rng = StdRng::seed_from_u64(42);
267 let mut data = SetBitsTest::new();
268 for _ in 0..100 {
269 data.regen(&mut rng);
270 data.verify();
271 }
272 }
273
274 #[derive(Debug, Default)]
275 struct SetBitsTest {
276 write_data: Vec<u8>,
278 data: Vec<u8>,
280 offset_write: usize,
281 offset_read: usize,
282 len: usize,
283 expected_data: Vec<u8>,
285 expected_null_count: usize,
287 }
288
289 struct BinaryFormatter<'a>(&'a [u8]);
291 impl Display for BinaryFormatter<'_> {
292 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293 for byte in self.0 {
294 write!(f, "{byte:08b} ")?;
295 }
296 write!(f, " ")?;
297 Ok(())
298 }
299 }
300
301 impl Display for SetBitsTest {
302 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 writeln!(f, "SetBitsTest {{")?;
304 writeln!(f, " write_data: {}", BinaryFormatter(&self.write_data))?;
305 writeln!(f, " data: {}", BinaryFormatter(&self.data))?;
306 writeln!(
307 f,
308 " expected_data: {}",
309 BinaryFormatter(&self.expected_data)
310 )?;
311 writeln!(f, " offset_write: {}", self.offset_write)?;
312 writeln!(f, " offset_read: {}", self.offset_read)?;
313 writeln!(f, " len: {}", self.len)?;
314 writeln!(f, " expected_null_count: {}", self.expected_null_count)?;
315 writeln!(f, "}}")
316 }
317 }
318
319 impl SetBitsTest {
320 fn new() -> Self {
322 Self::default()
323 }
324
325 fn regen(&mut self, rng: &mut StdRng) {
327 let len = rng.random_range(0..=200);
339
340 let offset_write_bits = rng.random_range(0..=200);
342 let offset_write_bytes = if offset_write_bits % 8 == 0 {
343 offset_write_bits / 8
344 } else {
345 (offset_write_bits / 8) + 1
346 };
347 let extra_write_data_bytes = rng.random_range(0..=5); let extra_read_data_bytes = rng.random_range(0..=5); let offset_read_bits = rng.random_range(0..=200);
352 let offset_read_bytes = if offset_read_bits % 8 != 0 {
353 (offset_read_bits / 8) + 1
354 } else {
355 offset_read_bits / 8
356 };
357
358 self.write_data.clear();
360 self.write_data
361 .resize(offset_write_bytes + len + extra_write_data_bytes, 0);
362
363 self.offset_write = offset_write_bits;
367
368 self.data
370 .resize(offset_read_bytes + len + extra_read_data_bytes, 0);
371 rng.try_fill_bytes(self.data.as_mut_slice()).unwrap();
373 self.offset_read = offset_read_bits;
374
375 self.len = len;
376
377 self.expected_data.resize(self.write_data.len(), 0);
379 self.expected_data.copy_from_slice(&self.write_data);
380
381 self.expected_null_count = 0;
382 for i in 0..self.len {
383 let bit = get_bit(&self.data, self.offset_read + i);
384 if bit {
385 set_bit(&mut self.expected_data, self.offset_write + i);
386 } else {
387 unset_bit(&mut self.expected_data, self.offset_write + i);
388 self.expected_null_count += 1;
389 }
390 }
391 }
392
393 fn verify(&self) {
395 let mut actual = self.write_data.clone();
397 let null_count = set_bits(
398 &mut actual,
399 &self.data,
400 self.offset_write,
401 self.offset_read,
402 self.len,
403 );
404
405 assert_eq!(actual, self.expected_data, "self: {self}");
406 assert_eq!(null_count, self.expected_null_count, "self: {self}");
407 }
408 }
409
410 #[test]
411 fn test_set_upto_64bits() {
412 let write_data: &mut [u8] = &mut [0; 9];
414 let data: &[u8] = &[
415 0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001,
416 0b00000001, 0b00000001,
417 ];
418 let offset_write = 1;
419 let offset_read = 0;
420 let len = 65;
421 let (n, len_set) =
422 unsafe { set_upto_64bits(write_data, data, offset_write, offset_read, len) };
423 assert_eq!(n, 55);
424 assert_eq!(len_set, 63);
425 assert_eq!(
426 write_data,
427 &[
428 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000010, 0b00000010,
429 0b00000010, 0b00000000
430 ]
431 );
432
433 let write_data: &mut [u8] = &mut [0b00000000];
435 let data: &[u8] = &[0b00000001];
436 let offset_write = 1;
437 let offset_read = 0;
438 let len = 1;
439 let (n, len_set) =
440 unsafe { set_upto_64bits(write_data, data, offset_write, offset_read, len) };
441 assert_eq!(n, 0);
442 assert_eq!(len_set, 1);
443 assert_eq!(write_data, &[0b00000010]);
444 }
445
446 #[test]
447 #[should_panic(expected = "operation will overflow read buffer")]
448 fn test_overflow_read_buffer_bounds() {
449 let data = [0u8; 1];
451 let mut write_data = [0u8; 1];
452
453 let offset_write: usize = 0;
457 let offset_read: usize = usize::MAX - 7;
458 let len: usize = 8;
459
460 let _nulls = set_bits(&mut write_data, &data, offset_write, offset_read, len);
462 }
463
464 #[test]
465 #[should_panic(expected = "operation will overflow write buffer")]
466 fn test_overflow_write_buffer_bounds() {
467 let data = [0u8; 1];
469 let mut write_data = [0u8; 1];
470
471 let offset_write: usize = usize::MAX - 7;
475 let offset_read: usize = 0;
476 let len: usize = 8;
477
478 let _nulls = set_bits(&mut write_data, &data, offset_write, offset_read, len);
480 }
481}