use super::{Buffer, MutableBuffer};
use crate::BooleanBuffer;
use crate::util::bit_util::ceil;
pub fn bitwise_quaternary_op_helper<F>(
buffers: [&Buffer; 4],
offsets: [usize; 4],
len_in_bits: usize,
op: F,
) -> Buffer
where
F: Fn(u64, u64, u64, u64) -> u64,
{
let first_chunks = buffers[0].bit_chunks(offsets[0], len_in_bits);
let second_chunks = buffers[1].bit_chunks(offsets[1], len_in_bits);
let third_chunks = buffers[2].bit_chunks(offsets[2], len_in_bits);
let fourth_chunks = buffers[3].bit_chunks(offsets[3], len_in_bits);
let chunks = first_chunks
.iter()
.zip(second_chunks.iter())
.zip(third_chunks.iter())
.zip(fourth_chunks.iter())
.map(|(((first, second), third), fourth)| op(first, second, third, fourth));
let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
let remainder_bytes = ceil(first_chunks.remainder_len(), 8);
let rem = op(
first_chunks.remainder_bits(),
second_chunks.remainder_bits(),
third_chunks.remainder_bits(),
fourth_chunks.remainder_bits(),
);
let rem = &rem.to_le_bytes()[0..remainder_bytes];
buffer.extend_from_slice(rem);
buffer.into()
}
pub fn bitwise_bin_op_helper<F>(
left: &Buffer,
left_offset_in_bits: usize,
right: &Buffer,
right_offset_in_bits: usize,
len_in_bits: usize,
mut op: F,
) -> Buffer
where
F: FnMut(u64, u64) -> u64,
{
let left_chunks = left.bit_chunks(left_offset_in_bits, len_in_bits);
let right_chunks = right.bit_chunks(right_offset_in_bits, len_in_bits);
let chunks = left_chunks
.iter()
.zip(right_chunks.iter())
.map(|(left, right)| op(left, right));
let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
let rem = op(left_chunks.remainder_bits(), right_chunks.remainder_bits());
let rem = &rem.to_le_bytes()[0..remainder_bytes];
buffer.extend_from_slice(rem);
buffer.into()
}
pub fn bitwise_unary_op_helper<F>(
left: &Buffer,
offset_in_bits: usize,
len_in_bits: usize,
mut op: F,
) -> Buffer
where
F: FnMut(u64) -> u64,
{
let mut result =
MutableBuffer::new(ceil(len_in_bits, 8)).with_bitset(len_in_bits / 64 * 8, false);
let left_chunks = left.bit_chunks(offset_in_bits, len_in_bits);
let result_chunks = result.typed_data_mut::<u64>().iter_mut();
result_chunks
.zip(left_chunks.iter())
.for_each(|(res, left)| {
*res = op(left);
});
let remainder_bytes = ceil(left_chunks.remainder_len(), 8);
let rem = op(left_chunks.remainder_bits());
let rem = &rem.to_le_bytes()[0..remainder_bytes];
result.extend_from_slice(rem);
result.into()
}
pub fn buffer_bin_and(
left: &Buffer,
left_offset_in_bits: usize,
right: &Buffer,
right_offset_in_bits: usize,
len_in_bits: usize,
) -> Buffer {
let result = BooleanBuffer::from_bitwise_binary_op(
left,
left_offset_in_bits,
right,
right_offset_in_bits,
len_in_bits,
|a, b| a & b,
);
if result.offset() == 0 {
result.into_inner()
} else {
result.sliced()
}
}
pub fn buffer_bin_or(
left: &Buffer,
left_offset_in_bits: usize,
right: &Buffer,
right_offset_in_bits: usize,
len_in_bits: usize,
) -> Buffer {
let result = BooleanBuffer::from_bitwise_binary_op(
left,
left_offset_in_bits,
right,
right_offset_in_bits,
len_in_bits,
|a, b| a | b,
);
if result.offset() == 0 {
result.into_inner()
} else {
result.sliced()
}
}
pub fn buffer_bin_xor(
left: &Buffer,
left_offset_in_bits: usize,
right: &Buffer,
right_offset_in_bits: usize,
len_in_bits: usize,
) -> Buffer {
let result = BooleanBuffer::from_bitwise_binary_op(
left,
left_offset_in_bits,
right,
right_offset_in_bits,
len_in_bits,
|a, b| a ^ b,
);
if result.offset() == 0 {
result.into_inner()
} else {
result.sliced()
}
}
pub fn buffer_bin_and_not(
left: &Buffer,
left_offset_in_bits: usize,
right: &Buffer,
right_offset_in_bits: usize,
len_in_bits: usize,
) -> Buffer {
let result = BooleanBuffer::from_bitwise_binary_op(
left,
left_offset_in_bits,
right,
right_offset_in_bits,
len_in_bits,
|a, b| a & !b,
);
if result.offset() == 0 {
result.into_inner()
} else {
result.sliced()
}
}
pub fn buffer_unary_not(left: &Buffer, offset_in_bits: usize, len_in_bits: usize) -> Buffer {
BooleanBuffer::from_bitwise_unary_op(left, offset_in_bits, len_in_bits, |a| !a).into_inner()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buffer_bin_ops_return_zero_offset_buffers() {
let left = Buffer::from(vec![0b1010_1100, 0b0110_1001]);
let right = Buffer::from(vec![0, 0, 0, 0, 0, 0, 0, 0, 0b1110_0101, 0b0101_1000]);
let left_offset = 1;
let right_offset = 65; let len = 7;
for (op, wrapper) in [
(
(|a, b| a & b) as fn(u64, u64) -> u64,
buffer_bin_and as fn(&Buffer, usize, &Buffer, usize, usize) -> Buffer,
),
(((|a, b| a | b) as fn(u64, u64) -> u64), buffer_bin_or),
(((|a, b| a ^ b) as fn(u64, u64) -> u64), buffer_bin_xor),
(((|a, b| a & !b) as fn(u64, u64) -> u64), buffer_bin_and_not),
] {
let unsliced = BooleanBuffer::from_bitwise_binary_op(
&left,
left_offset,
&right,
right_offset,
len,
op,
);
assert_eq!(unsliced.offset(), 1);
let result = wrapper(&left, left_offset, &right, right_offset, len);
assert_eq!(result, unsliced.sliced());
assert_eq!(result.len(), 1);
}
}
}