mhilton commented on code in PR #8996:
URL: https://github.com/apache/arrow-rs/pull/8996#discussion_r2620328266
##########
arrow-buffer/src/buffer/boolean.rs:
##########
@@ -96,12 +96,128 @@ impl BooleanBuffer {
Self::new(buffer.into(), 0, len)
}
+ /// Create a new [`BooleanBuffer`] by copying the relevant bits from an
+ /// input buffer.
+ ///
+ /// # Notes:
+ /// * The new `BooleanBuffer` has zero offset, even if `offset_in_bits` is
non-zero
+ ///
+ /// # Example: Create a new [`BooleanBuffer`] copying a bit slice from in
input slice
+ /// ```
+ /// # use arrow_buffer::BooleanBuffer;
+ /// let input = [0b11001100u8, 0b10111010u8];
+ /// // // Copy bits 4..16 from input
+ /// let result = BooleanBuffer::from_bits(&input, 4, 12);
+ /// assert_eq!(result.values(), &[0b10101100u8, 0b00001011u8]);
+ pub fn from_bits(src: impl AsRef<[u8]>, offset_in_bits: usize,
len_in_bits: usize) -> Self {
+ Self::from_bitwise_unary_op(src, offset_in_bits, len_in_bits, |a| a)
+ }
+
+ /// Create a new [`BooleanBuffer`] by applying the bitwise operation to
`op`
+ /// to an input buffer.
+ ///
+ /// This function is faster than applying the operation bit by bit as
+ /// it processes input buffers in chunks of 64 bits (8 bytes) at a time
+ ///
+ /// # Notes:
+ /// * `op` takes a single `u64` inputs and produces one `u64` output.
+ /// * `op` must only apply bitwise operations
+ /// on the relevant bits; the input `u64` may contain irrelevant bits
+ /// and may be processed differently on different endian architectures.
+ /// * The output always has zero offset
+ ///
+ /// # See Also
+ /// - [`apply_bitwise_unary_op`](bit_util::apply_bitwise_unary_op) for
in-place unary bitwise operations
+ ///
+ /// # Example: Create new [`BooleanBuffer`] from bitwise `NOT` of an input
[`Buffer`]
+ /// ```
+ /// # use arrow_buffer::BooleanBuffer;
+ /// let input = [0b11001100u8, 0b10111010u8]; // 2 bytes = 16 bits
+ /// // NOT of the first 12 bits
+ /// let result = BooleanBuffer::from_bitwise_unary_op(
+ /// &input, 0, 12, |a| !a
+ /// );
+ /// assert_eq!(result.values(), &[0b00110011u8, 0b11110101u8]);
+ /// ```
+ pub fn from_bitwise_unary_op<F>(
+ src: impl AsRef<[u8]>,
+ offset_in_bits: usize,
+ len_in_bits: usize,
+ mut op: F,
+ ) -> Self
+ where
+ F: FnMut(u64) -> u64,
+ {
+ // try fast path for aligned input
+ if offset_in_bits & 0x7 == 0 {
+ // align to byte boundary
+ let aligned = &src.as_ref()[offset_in_bits / 8..];
+ if let Some(result) =
+ Self::try_from_aligned_bitwise_unary_op(aligned, len_in_bits,
&mut op)
+ {
+ return result;
+ }
+ }
+
+ let chunks = BitChunks::new(src.as_ref(), offset_in_bits, len_in_bits);
+ let mut result = MutableBuffer::with_capacity(chunks.num_u64s() * 8);
+ for chunk in chunks.iter() {
+ // SAFETY: reserved enough capacity above, (exactly num_u64s()
+ // items) and we assume `BitChunks` correctly reports upper bound
+ unsafe {
+ result.push_unchecked(op(chunk));
+ }
+ }
+ if chunks.remainder_len() > 0 {
+ debug_assert!(result.capacity() >= result.len() + 8); // should
not reallocate
+ // SAFETY: reserved enough capacity above, (exactly num_u64s()
+ // items) and we assume `BitChunks` correctly reports upper bound
+ unsafe {
+ result.push_unchecked(op(chunks.remainder_bits()));
+ }
+ // Just pushed one u64, which may have trailing zeros
+ result.truncate(chunks.num_bytes());
+ }
+
+ let buffer = Buffer::from(result);
+ BooleanBuffer {
+ buffer,
+ offset: 0,
+ len: len_in_bits,
+ }
+ }
+
+ /// Fast path for [`Self::from_bitwise_unary_op`] when input is aligned to
+ /// byte boundaries
Review Comment:
```suggestion
/// 8-byte (64-bit) boundaries
```
##########
arrow-buffer/src/buffer/boolean.rs:
##########
@@ -96,12 +96,128 @@ impl BooleanBuffer {
Self::new(buffer.into(), 0, len)
}
+ /// Create a new [`BooleanBuffer`] by copying the relevant bits from an
+ /// input buffer.
+ ///
+ /// # Notes:
+ /// * The new `BooleanBuffer` has zero offset, even if `offset_in_bits` is
non-zero
+ ///
+ /// # Example: Create a new [`BooleanBuffer`] copying a bit slice from in
input slice
+ /// ```
+ /// # use arrow_buffer::BooleanBuffer;
+ /// let input = [0b11001100u8, 0b10111010u8];
+ /// // // Copy bits 4..16 from input
+ /// let result = BooleanBuffer::from_bits(&input, 4, 12);
+ /// assert_eq!(result.values(), &[0b10101100u8, 0b00001011u8]);
+ pub fn from_bits(src: impl AsRef<[u8]>, offset_in_bits: usize,
len_in_bits: usize) -> Self {
+ Self::from_bitwise_unary_op(src, offset_in_bits, len_in_bits, |a| a)
+ }
+
+ /// Create a new [`BooleanBuffer`] by applying the bitwise operation to
`op`
+ /// to an input buffer.
+ ///
+ /// This function is faster than applying the operation bit by bit as
+ /// it processes input buffers in chunks of 64 bits (8 bytes) at a time
+ ///
+ /// # Notes:
+ /// * `op` takes a single `u64` inputs and produces one `u64` output.
+ /// * `op` must only apply bitwise operations
+ /// on the relevant bits; the input `u64` may contain irrelevant bits
+ /// and may be processed differently on different endian architectures.
+ /// * The output always has zero offset
+ ///
+ /// # See Also
+ /// - [`apply_bitwise_unary_op`](bit_util::apply_bitwise_unary_op) for
in-place unary bitwise operations
+ ///
+ /// # Example: Create new [`BooleanBuffer`] from bitwise `NOT` of an input
[`Buffer`]
+ /// ```
+ /// # use arrow_buffer::BooleanBuffer;
+ /// let input = [0b11001100u8, 0b10111010u8]; // 2 bytes = 16 bits
+ /// // NOT of the first 12 bits
+ /// let result = BooleanBuffer::from_bitwise_unary_op(
+ /// &input, 0, 12, |a| !a
+ /// );
+ /// assert_eq!(result.values(), &[0b00110011u8, 0b11110101u8]);
+ /// ```
+ pub fn from_bitwise_unary_op<F>(
+ src: impl AsRef<[u8]>,
+ offset_in_bits: usize,
+ len_in_bits: usize,
+ mut op: F,
+ ) -> Self
+ where
+ F: FnMut(u64) -> u64,
+ {
+ // try fast path for aligned input
+ if offset_in_bits & 0x7 == 0 {
Review Comment:
Seeing as `try_from_aligned_bitwise_unary_op` only actually does anything
when it is 64-bit aligned, maybe
```suggestion
if offset_in_bits & 0x3F == 0 {
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]