Skip to main content

arrow_buffer/buffer/
boolean.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::bit_chunk_iterator::BitChunks;
19use crate::bit_iterator::{BitIndexIterator, BitIndexU32Iterator, BitIterator, BitSliceIterator};
20use crate::bit_util::read_u64;
21use crate::{
22    BooleanBufferBuilder, Buffer, MutableBuffer, bit_util, buffer_bin_and, buffer_bin_or,
23    buffer_bin_xor,
24};
25
26use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
27
28/// A slice-able [`Buffer`] containing bit-packed booleans
29///
30/// This structure represents a sequence of boolean values packed into a
31/// byte-aligned [`Buffer`]. Both the offset and length are represented in bits.
32///
33/// # Layout
34///
35/// The values are represented as little endian bit-packed values, where the
36/// least significant bit of each byte represents the first boolean value and
37/// then proceeding to the most significant bit.
38///
39/// For example, the 10 bit bitmask `0b0111001101` has length 10, and is
40/// represented using 2 bytes with offset 0 like this:
41///
42/// ```text
43///        ┌─────────────────────────────────┐    ┌─────────────────────────────────┐
44///        │┌───┬───┬───┬───┬───┬───┬───┬───┐│    │┌───┬───┬───┬───┬───┬───┬───┬───┐│
45///        ││ 1 │ 0 │ 1 │ 1 │ 0 │ 0 │ 1 │ 1 ││    ││ 1 │ 0 │ ? │ ? │ ? │ ? │ ? │ ? ││
46///        │└───┴───┴───┴───┴───┴───┴───┴───┘│    │└───┴───┴───┴───┴───┴───┴───┴───┘│
47/// bit    └─────────────────────────────────┘    └─────────────────────────────────┘
48/// offset  0             Byte 0             7    0              Byte 1            7
49///
50///         length = 10 bits, offset = 0
51/// ```
52///
53/// The same bitmask with length 10 and offset 3 would be represented using 2
54/// bytes like this:
55///
56/// ```text
57///       ┌─────────────────────────────────┐    ┌─────────────────────────────────┐
58///       │┌───┬───┬───┬───┬───┬───┬───┬───┐│    │┌───┬───┬───┬───┬───┬───┬───┬───┐│
59///       ││ ? │ ? │ ? │ 1 │ 0 │ 1 │ 1 │ 0 ││    ││ 0 │ 1 │ 1 │ 1 │ 0 │ ? │ ? │ ? ││
60///       │└───┴───┴───┴───┴───┴───┴───┴───┘│    │└───┴───┴───┴───┴───┴───┴───┴───┘│
61/// bit   └─────────────────────────────────┘    └─────────────────────────────────┘
62/// offset 0             Byte 0             7    0              Byte 1            7
63///
64///        length = 10 bits, offset = 3
65/// ```
66///
67/// Note that the bits marked `?` are not logically part of the mask and may
68/// contain either `0` or `1`
69///
70/// # Bitwise Operations
71///
72/// `BooleanBuffer` implements the standard bitwise traits for creating a new
73/// buffer ([`BitAnd`], [`BitOr`], [`BitXor`], [`Not`]) as well as the assign variants
74/// for updating an existing buffer in place when possible ([`BitAndAssign`],
75/// [`BitOrAssign`], [`BitXorAssign`]).
76///
77/// ```
78/// # use arrow_buffer::BooleanBuffer;
79/// let mut left = BooleanBuffer::from(&[true, false, true, true] as &[bool]);
80/// let right = BooleanBuffer::from(&[true, true, false, true] as &[bool]);
81///
82/// // Create a new buffer by applying bitwise AND
83/// let anded = &left & &right;
84/// assert_eq!(anded, BooleanBuffer::from(&[true, false, false, true] as &[bool]));
85///
86/// // Update `left` in place by applying bitwise AND in place
87/// left &= &right;
88/// assert_eq!(left, BooleanBuffer::from(&[true, false, false, true] as &[bool]));
89/// ```
90///
91/// # See Also
92/// * [`BooleanBufferBuilder`] for building [`BooleanBuffer`] instances
93/// * [`NullBuffer`] for representing null values in Arrow arrays
94///
95/// [`NullBuffer`]: crate::NullBuffer
96#[derive(Debug, Clone, Eq)]
97pub struct BooleanBuffer {
98    /// Underlying buffer (byte aligned)
99    buffer: Buffer,
100    /// Offset in bits (not bytes)
101    bit_offset: usize,
102    /// Length in bits (not bytes)
103    bit_len: usize,
104}
105
106impl PartialEq for BooleanBuffer {
107    fn eq(&self, other: &Self) -> bool {
108        if self.bit_len != other.bit_len {
109            return false;
110        }
111
112        let lhs = self.bit_chunks().iter_padded();
113        let rhs = other.bit_chunks().iter_padded();
114        lhs.zip(rhs).all(|(a, b)| a == b)
115    }
116}
117
118impl BooleanBuffer {
119    /// Create a new [`BooleanBuffer`] from a [`Buffer`], `bit_offset` offset and `bit_len` length
120    ///
121    /// # Panics
122    ///
123    /// This method will panic if `buffer` is not large enough
124    pub fn new(buffer: Buffer, bit_offset: usize, bit_len: usize) -> Self {
125        let total_len = bit_offset.saturating_add(bit_len);
126        let buffer_len = buffer.len();
127        let buffer_bit_len = buffer_len.saturating_mul(8);
128        assert!(
129            total_len <= buffer_bit_len,
130            "buffer not large enough (bit_offset: {bit_offset}, bit_len: {bit_len}, buffer_len: {buffer_len})"
131        );
132        Self {
133            buffer,
134            bit_offset,
135            bit_len,
136        }
137    }
138
139    /// Create a new [`BooleanBuffer`] of `length` bits (not bytes) where all values are `true`
140    pub fn new_set(length: usize) -> Self {
141        let mut builder = BooleanBufferBuilder::new(length);
142        builder.append_n(length, true);
143        builder.finish()
144    }
145
146    /// Create a new [`BooleanBuffer`] of `length` bits (not bytes) where all values are `false`
147    pub fn new_unset(length: usize) -> Self {
148        let buffer = MutableBuffer::new_null(length).into_buffer();
149        Self {
150            buffer,
151            bit_offset: 0,
152            bit_len: length,
153        }
154    }
155
156    /// Invokes `f` with indexes `0..len` collecting the boolean results into a new `BooleanBuffer`
157    pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, f: F) -> Self {
158        let buffer = MutableBuffer::collect_bool(len, f);
159        Self::new(buffer.into(), 0, len)
160    }
161
162    /// Create a new [`BooleanBuffer`] by copying the relevant bits from an
163    /// input buffer.
164    ///
165    /// # Notes:
166    /// * The new `BooleanBuffer` may have non zero offset
167    ///   and/or padding bits outside the logical range.
168    ///
169    /// # Example: Create a new [`BooleanBuffer`] copying a bit slice from in input slice
170    /// ```
171    /// # use arrow_buffer::BooleanBuffer;
172    /// let input = [0b11001100u8, 0b10111010u8];
173    /// // // Copy bits 4..16 from input
174    /// let result = BooleanBuffer::from_bits(&input, 4, 12);
175    /// // output is 12 bits long starting from bit offset 4
176    /// assert_eq!(result.len(), 12);
177    /// assert_eq!(result.offset(), 4);
178    /// // the expected 12 bits are 0b101110101100 (bits 4..16 of the input)
179    /// let expected_bits = [false, false, true, true, false, true, false, true, true, true, false, true];
180    /// for (i, v) in expected_bits.into_iter().enumerate() {
181    ///    assert_eq!(result.value(i), v);
182    /// }
183    /// // However, underlying buffer has (ignored) bits set outside the requested range
184    /// assert_eq!(result.values(), &[0b11001100u8, 0b10111010, 0, 0, 0, 0, 0, 0]);
185    pub fn from_bits(src: impl AsRef<[u8]>, offset_in_bits: usize, len_in_bits: usize) -> Self {
186        Self::from_bitwise_unary_op(src, offset_in_bits, len_in_bits, |a| a)
187    }
188
189    /// Create a new [`BooleanBuffer`] by applying the bitwise operation to `op`
190    /// to an input buffer.
191    ///
192    /// This function is faster than applying the operation bit by bit as
193    /// it processes input buffers in chunks of 64 bits (8 bytes) at a time
194    ///
195    /// # Notes:
196    /// * `op` takes a single `u64` inputs and produces one `u64` output.
197    /// * `op` must only apply bitwise operations
198    ///   on the relevant bits; the input `u64` may contain irrelevant bits
199    ///   and may be processed differently on different endian architectures.
200    /// * `op` may be called with input bits outside the requested range
201    /// * Returned `BooleanBuffer` may have non zero offset
202    /// * Returned `BooleanBuffer` may have bits set outside the requested range
203    ///
204    /// # See Also
205    /// - [`BooleanBuffer::from_bitwise_binary_op`] to create a new buffer from a binary operation
206    /// - [`apply_bitwise_unary_op`](bit_util::apply_bitwise_unary_op) for in-place unary bitwise operations
207    ///
208    /// # Example: Create new [`BooleanBuffer`] from bitwise `NOT`
209    /// ```
210    /// # use arrow_buffer::BooleanBuffer;
211    /// let input = [0b11001100u8, 0b10111010u8]; // 2 bytes = 16 bits
212    /// // NOT of bits 4..16
213    /// let result = BooleanBuffer::from_bitwise_unary_op(
214    ///  &input, 4, 12, |a| !a
215    /// );
216    /// // output is 12 bits long starting from bit offset 4
217    /// assert_eq!(result.len(), 12);
218    /// assert_eq!(result.offset(), 4);
219    /// // the expected 12 bits are 0b001100110101, (NOT of the requested bits)
220    /// let expected_bits = [true, true, false, false, true, false, true, false, false, false, true, false];
221    /// for (i, v) in expected_bits.into_iter().enumerate() {
222    ///     assert_eq!(result.value(i), v);
223    /// }
224    /// // However, underlying buffer has (ignored) bits set outside the requested range
225    /// let expected = [0b00110011u8, 0b01000101u8, 255, 255, 255, 255, 255, 255];
226    /// assert_eq!(result.values(), &expected);
227    /// ```
228    pub fn from_bitwise_unary_op<F>(
229        src: impl AsRef<[u8]>,
230        offset_in_bits: usize,
231        len_in_bits: usize,
232        mut op: F,
233    ) -> Self
234    where
235        F: FnMut(u64) -> u64,
236    {
237        let end = offset_in_bits + len_in_bits;
238        // Align start and end to 64 bit (8 byte) boundaries if possible to allow using the
239        // optimized code path as much as possible.
240        let aligned_offset = offset_in_bits & !63;
241        let aligned_end_bytes = bit_util::ceil(end, 64) * 8;
242        let src_len = src.as_ref().len();
243        let slice_end = aligned_end_bytes.min(src_len);
244
245        let aligned_start = &src.as_ref()[aligned_offset / 8..slice_end];
246
247        let (prefix, aligned_u64s, suffix) = unsafe { aligned_start.as_ref().align_to::<u64>() };
248        match (prefix, suffix) {
249            ([], []) => {
250                // the buffer is word (64 bit) aligned, so use optimized Vec code.
251                let result_u64s: Vec<u64> = aligned_u64s.iter().map(|l| op(*l)).collect();
252                return BooleanBuffer::new(result_u64s.into(), offset_in_bits % 64, len_in_bits);
253            }
254            ([], suffix) => {
255                let suffix = read_u64(suffix);
256                let result_u64s: Vec<u64> = aligned_u64s
257                    .iter()
258                    .cloned()
259                    .chain(std::iter::once(suffix))
260                    .map(&mut op)
261                    .collect();
262                return BooleanBuffer::new(result_u64s.into(), offset_in_bits % 64, len_in_bits);
263            }
264            _ => {}
265        }
266
267        // align to byte boundaries
268        // Use unaligned code path, handle remainder bytes
269        let chunks = aligned_start.chunks_exact(8);
270        let remainder = chunks.remainder();
271        let iter = chunks.map(|c| u64::from_le_bytes(c.try_into().unwrap()));
272        let vec_u64s: Vec<u64> = if remainder.is_empty() {
273            iter.map(&mut op).collect()
274        } else {
275            iter.chain(Some(read_u64(remainder))).map(&mut op).collect()
276        };
277
278        BooleanBuffer::new(vec_u64s.into(), offset_in_bits % 64, len_in_bits)
279    }
280
281    /// Create a new [`BooleanBuffer`] by applying the bitwise operation `op` to
282    /// the relevant bits from two input buffers.
283    ///
284    /// This function is faster than applying the operation bit by bit as
285    /// it processes input buffers in chunks of 64 bits (8 bytes) at a time
286    ///
287    /// # Notes:
288    /// * `op` takes two `u64` inputs and produces one `u64` output.
289    /// * `op` must only apply bitwise operations
290    ///   on the relevant bits; the input `u64` values may contain irrelevant bits
291    ///   and may be processed differently on different endian architectures.
292    /// * `op` may be called with input bits outside the requested range.
293    /// * Returned `BooleanBuffer` may have non zero offset
294    /// * Returned `BooleanBuffer` may have bits set outside the requested range
295    ///
296    /// # See Also
297    /// - [`BooleanBuffer::from_bitwise_unary_op`] for unary operations on a single input buffer.
298    /// - [`apply_bitwise_binary_op`](bit_util::apply_bitwise_binary_op) for in-place binary bitwise operations
299    ///
300    /// # Example: Create new [`BooleanBuffer`] from bitwise `AND` of two [`Buffer`]s
301    /// ```
302    /// # use arrow_buffer::{Buffer, BooleanBuffer};
303    /// let left = Buffer::from(vec![0b11001100u8, 0b10111010u8]); // 2 bytes = 16 bits
304    /// let right = Buffer::from(vec![0b10101010u8, 0b11011100u8, 0b11110000u8]); // 3 bytes = 24 bits
305    /// // AND of the first 12 bits
306    /// let result = BooleanBuffer::from_bitwise_binary_op(
307    ///   &left, 0, &right, 0, 12, |a, b| a & b
308    /// );
309    /// assert_eq!(result.len(), 12);
310    /// for i in 0..12 {
311    ///     assert_eq!(result.value(i), left.as_slice()[i / 8] >> (i % 8) & 1 == 1
312    ///         && right.as_slice()[i / 8] >> (i % 8) & 1 == 1);
313    /// }
314    /// ```
315    ///
316    /// # Example: Create new [`BooleanBuffer`] from bitwise `OR` of two byte slices
317    /// ```
318    /// # use arrow_buffer::{BooleanBuffer, bit_util};
319    /// let left = [0b11001100u8, 0b10111010u8];
320    /// let right = [0b10101010u8, 0b11011100u8];
321    /// // OR of bits 4..16 from left and bits 0..12 from right
322    /// let result = BooleanBuffer::from_bitwise_binary_op(
323    ///  &left, 4, &right, 0, 12, |a, b| a | b
324    /// );
325    /// assert_eq!(result.len(), 12);
326    /// for i in 0..12 {
327    ///     let l = bit_util::get_bit(&left, 4 + i);
328    ///     let r = bit_util::get_bit(&right, i);
329    ///     assert_eq!(result.value(i), l | r);
330    /// }
331    /// ```
332    pub fn from_bitwise_binary_op<F>(
333        left: impl AsRef<[u8]>,
334        left_offset_in_bits: usize,
335        right: impl AsRef<[u8]>,
336        right_offset_in_bits: usize,
337        len_in_bits: usize,
338        mut op: F,
339    ) -> Self
340    where
341        F: FnMut(u64, u64) -> u64,
342    {
343        let left = left.as_ref();
344        let right = right.as_ref();
345
346        // When both offsets share the same sub-64-bit alignment, we can
347        // align both to 64-bit boundaries and zip u64s directly,
348        // avoiding BitChunks bit-shifting entirely.
349        if left_offset_in_bits % 64 == right_offset_in_bits % 64 {
350            let bit_offset = left_offset_in_bits % 64;
351            let left_end = left_offset_in_bits + len_in_bits;
352            let right_end = right_offset_in_bits + len_in_bits;
353
354            let left_aligned = left_offset_in_bits & !63;
355            let right_aligned = right_offset_in_bits & !63;
356
357            let left_end_bytes = (bit_util::ceil(left_end, 64) * 8).min(left.len());
358            let right_end_bytes = (bit_util::ceil(right_end, 64) * 8).min(right.len());
359
360            let left_slice = &left[left_aligned / 8..left_end_bytes];
361            let right_slice = &right[right_aligned / 8..right_end_bytes];
362
363            let (lp, left_u64s, ls) = unsafe { left_slice.align_to::<u64>() };
364            let (rp, right_u64s, rs) = unsafe { right_slice.align_to::<u64>() };
365
366            match (lp, ls, rp, rs) {
367                ([], [], [], []) => {
368                    let result_u64s: Vec<u64> = left_u64s
369                        .iter()
370                        .zip(right_u64s.iter())
371                        .map(|(l, r)| op(*l, *r))
372                        .collect();
373                    return BooleanBuffer::new(result_u64s.into(), bit_offset, len_in_bits);
374                }
375                ([], left_suf, [], right_suf) => {
376                    let left_iter = left_u64s
377                        .iter()
378                        .cloned()
379                        .chain((!left_suf.is_empty()).then(|| read_u64(left_suf)));
380                    let right_iter = right_u64s
381                        .iter()
382                        .cloned()
383                        .chain((!right_suf.is_empty()).then(|| read_u64(right_suf)));
384                    let result_u64s: Vec<u64> =
385                        left_iter.zip(right_iter).map(|(l, r)| op(l, r)).collect();
386                    return BooleanBuffer::new(result_u64s.into(), bit_offset, len_in_bits);
387                }
388                _ => {}
389            }
390
391            // Memory not u64-aligned, use chunks_exact fallback
392            let left_chunks = left_slice.chunks_exact(8);
393            let left_rem = left_chunks.remainder();
394            let right_chunks = right_slice.chunks_exact(8);
395            let right_rem = right_chunks.remainder();
396
397            let left_iter = left_chunks.map(|c| u64::from_le_bytes(c.try_into().unwrap()));
398            let right_iter = right_chunks.map(|c| u64::from_le_bytes(c.try_into().unwrap()));
399
400            let result_u64s: Vec<u64> = if left_rem.is_empty() && right_rem.is_empty() {
401                left_iter.zip(right_iter).map(|(l, r)| op(l, r)).collect()
402            } else {
403                left_iter
404                    .chain(Some(read_u64(left_rem)))
405                    .zip(right_iter.chain(Some(read_u64(right_rem))))
406                    .map(|(l, r)| op(l, r))
407                    .collect()
408            };
409            return BooleanBuffer::new(result_u64s.into(), bit_offset, len_in_bits);
410        }
411
412        // Different sub-64-bit alignments: bit-shifting unavoidable
413        let left_chunks = BitChunks::new(left, left_offset_in_bits, len_in_bits);
414        let right_chunks = BitChunks::new(right, right_offset_in_bits, len_in_bits);
415
416        let chunks = left_chunks
417            .iter()
418            .zip(right_chunks.iter())
419            .map(|(left, right)| op(left, right));
420        // Soundness: `BitChunks` is a `BitChunks` trusted length iterator which
421        // correctly reports its upper bound
422        let mut buffer = unsafe { MutableBuffer::from_trusted_len_iter(chunks) };
423
424        let remainder_bytes = bit_util::ceil(left_chunks.remainder_len(), 8);
425        let rem = op(left_chunks.remainder_bits(), right_chunks.remainder_bits());
426        // we are counting its starting from the least significant bit, to to_le_bytes should be correct
427        let rem = &rem.to_le_bytes()[0..remainder_bytes];
428        buffer.extend_from_slice(rem);
429
430        BooleanBuffer {
431            buffer: Buffer::from(buffer),
432            bit_offset: 0,
433            bit_len: len_in_bits,
434        }
435    }
436
437    /// Returns the number of set bits in this buffer
438    pub fn count_set_bits(&self) -> usize {
439        self.buffer
440            .count_set_bits_offset(self.bit_offset, self.bit_len)
441    }
442
443    /// Finds the position of the n-th set bit (1-based) starting from `start` index.
444    /// If fewer than `n` set bits are found, returns the length of the buffer.
445    pub fn find_nth_set_bit_position(&self, start: usize, n: usize) -> usize {
446        if n == 0 {
447            return start;
448        }
449
450        self.slice(start, self.bit_len - start)
451            .set_indices()
452            .nth(n - 1)
453            .map(|idx| start + idx + 1)
454            .unwrap_or(self.bit_len)
455    }
456
457    /// Returns a [`BitChunks`] instance which can be used to iterate over
458    /// this buffer's bits in `u64` chunks
459    #[inline]
460    pub fn bit_chunks(&self) -> BitChunks<'_> {
461        BitChunks::new(self.values(), self.bit_offset, self.bit_len)
462    }
463
464    /// Returns the offset of this [`BooleanBuffer`] in bits (not bytes)
465    #[inline]
466    pub fn offset(&self) -> usize {
467        self.bit_offset
468    }
469
470    /// Returns the length of this [`BooleanBuffer`] in bits (not bytes)
471    #[inline]
472    pub fn len(&self) -> usize {
473        self.bit_len
474    }
475
476    /// Returns true if this [`BooleanBuffer`] is empty
477    #[inline]
478    pub fn is_empty(&self) -> bool {
479        self.bit_len == 0
480    }
481
482    /// Free up unused memory.
483    pub fn shrink_to_fit(&mut self) {
484        // TODO(emilk): we could shrink even more in the case where we are a small sub-slice of the full buffer
485        self.buffer.shrink_to_fit();
486    }
487
488    /// Returns the boolean value at index `i`.
489    ///
490    /// # Panics
491    ///
492    /// Panics if `i >= self.len()`
493    #[inline]
494    pub fn value(&self, idx: usize) -> bool {
495        assert!(idx < self.bit_len);
496        unsafe { self.value_unchecked(idx) }
497    }
498
499    /// Returns the boolean value at index `i`.
500    ///
501    /// # Safety
502    /// This doesn't check bounds, the caller must ensure that index < self.len()
503    #[inline]
504    pub unsafe fn value_unchecked(&self, i: usize) -> bool {
505        unsafe { bit_util::get_bit_raw(self.buffer.as_ptr(), i + self.bit_offset) }
506    }
507
508    /// Returns the packed values of this [`BooleanBuffer`] not including any offset
509    #[inline]
510    pub fn values(&self) -> &[u8] {
511        &self.buffer
512    }
513
514    /// Slices this [`BooleanBuffer`] by the provided `offset` and `length`
515    pub fn slice(&self, offset: usize, len: usize) -> Self {
516        assert!(
517            offset.saturating_add(len) <= self.bit_len,
518            "the length + offset of the sliced BooleanBuffer cannot exceed the existing length"
519        );
520        Self {
521            buffer: self.buffer.clone(),
522            bit_offset: self.bit_offset + offset,
523            bit_len: len,
524        }
525    }
526
527    /// Returns a new [`Buffer`] containing the sliced contents of this [`BooleanBuffer`]
528    ///
529    /// Equivalent to `self.buffer.bit_slice(self.offset, self.len)`
530    pub fn sliced(&self) -> Buffer {
531        self.buffer.bit_slice(self.bit_offset, self.bit_len)
532    }
533
534    /// Returns true if this [`BooleanBuffer`] is equal to `other`, using pointer comparisons
535    /// to determine buffer equality. This is cheaper than `PartialEq::eq` but may
536    /// return false when the arrays are logically equal
537    pub fn ptr_eq(&self, other: &Self) -> bool {
538        self.buffer.as_ptr() == other.buffer.as_ptr()
539            && self.bit_offset == other.bit_offset
540            && self.bit_len == other.bit_len
541    }
542
543    /// Returns the inner [`Buffer`]
544    ///
545    /// Note: this does not account for offset and length of this [`BooleanBuffer`]
546    #[inline]
547    pub fn inner(&self) -> &Buffer {
548        &self.buffer
549    }
550
551    /// Returns the inner [`Buffer`], consuming self
552    ///
553    /// Note: this does not account for offset and length of this [`BooleanBuffer`]
554    pub fn into_inner(self) -> Buffer {
555        self.buffer
556    }
557
558    /// Claim memory used by this buffer in the provided memory pool.
559    ///
560    /// See [`Buffer::claim`] for details.
561    #[cfg(feature = "pool")]
562    pub fn claim(&self, pool: &dyn crate::MemoryPool) {
563        self.buffer.claim(pool);
564    }
565
566    /// Apply a bitwise binary operation to `self`.
567    ///
568    /// If the underlying buffer is uniquely owned, reuses the allocation
569    /// and updates the bytes in place. If the underlying buffer is shared,
570    /// returns a newly allocated buffer.
571    ///
572    /// # API Notes
573    ///
574    /// If the buffer is reused, the result preserves the existing offset, which
575    /// may be non-zero.
576    fn bitwise_bin_op_assign<F>(&mut self, rhs: &BooleanBuffer, op: F)
577    where
578        F: FnMut(u64, u64) -> u64,
579    {
580        assert_eq!(self.bit_len, rhs.bit_len);
581        // Try to mutate in place if the buffer is uniquely owned
582        let buffer = std::mem::take(&mut self.buffer);
583        match buffer.into_mutable() {
584            Ok(mut buf) => {
585                bit_util::apply_bitwise_binary_op(
586                    &mut buf,
587                    self.bit_offset,
588                    &rhs.buffer,
589                    rhs.bit_offset,
590                    self.bit_len,
591                    op,
592                );
593                self.buffer = buf.into();
594            }
595            Err(buf) => {
596                self.buffer = buf;
597                *self = BooleanBuffer::from_bitwise_binary_op(
598                    self.values(),
599                    self.bit_offset,
600                    rhs.values(),
601                    rhs.bit_offset,
602                    self.bit_len,
603                    op,
604                );
605            }
606        }
607    }
608
609    /// Returns an iterator over the bits in this [`BooleanBuffer`]
610    pub fn iter(&self) -> BitIterator<'_> {
611        self.into_iter()
612    }
613
614    /// Returns an iterator over the set bit positions in this [`BooleanBuffer`]
615    pub fn set_indices(&self) -> BitIndexIterator<'_> {
616        BitIndexIterator::new(self.values(), self.bit_offset, self.bit_len)
617    }
618
619    /// Returns a `u32` iterator over set bit positions without any usize->u32 conversion
620    pub fn set_indices_u32(&self) -> BitIndexU32Iterator<'_> {
621        BitIndexU32Iterator::new(self.values(), self.bit_offset, self.bit_len)
622    }
623
624    /// Returns a [`BitSliceIterator`] yielding contiguous ranges of set bits
625    pub fn set_slices(&self) -> BitSliceIterator<'_> {
626        BitSliceIterator::new(self.values(), self.bit_offset, self.bit_len)
627    }
628}
629
630impl Not for &BooleanBuffer {
631    type Output = BooleanBuffer;
632
633    fn not(self) -> Self::Output {
634        BooleanBuffer::from_bitwise_unary_op(&self.buffer, self.bit_offset, self.bit_len, |a| !a)
635    }
636}
637
638impl BitAnd<&BooleanBuffer> for &BooleanBuffer {
639    type Output = BooleanBuffer;
640
641    fn bitand(self, rhs: &BooleanBuffer) -> Self::Output {
642        assert_eq!(self.bit_len, rhs.bit_len);
643        BooleanBuffer {
644            buffer: buffer_bin_and(
645                &self.buffer,
646                self.bit_offset,
647                &rhs.buffer,
648                rhs.bit_offset,
649                self.bit_len,
650            ),
651            bit_offset: 0,
652            bit_len: self.bit_len,
653        }
654    }
655}
656
657impl BitOr<&BooleanBuffer> for &BooleanBuffer {
658    type Output = BooleanBuffer;
659
660    fn bitor(self, rhs: &BooleanBuffer) -> Self::Output {
661        assert_eq!(self.bit_len, rhs.bit_len);
662        BooleanBuffer {
663            buffer: buffer_bin_or(
664                &self.buffer,
665                self.bit_offset,
666                &rhs.buffer,
667                rhs.bit_offset,
668                self.bit_len,
669            ),
670            bit_offset: 0,
671            bit_len: self.bit_len,
672        }
673    }
674}
675
676impl BitXor<&BooleanBuffer> for &BooleanBuffer {
677    type Output = BooleanBuffer;
678
679    fn bitxor(self, rhs: &BooleanBuffer) -> Self::Output {
680        assert_eq!(self.bit_len, rhs.bit_len);
681        BooleanBuffer {
682            buffer: buffer_bin_xor(
683                &self.buffer,
684                self.bit_offset,
685                &rhs.buffer,
686                rhs.bit_offset,
687                self.bit_len,
688            ),
689            bit_offset: 0,
690            bit_len: self.bit_len,
691        }
692    }
693}
694
695impl BitAndAssign<&BooleanBuffer> for BooleanBuffer {
696    fn bitand_assign(&mut self, rhs: &BooleanBuffer) {
697        self.bitwise_bin_op_assign(rhs, |a, b| a & b);
698    }
699}
700
701impl BitOrAssign<&BooleanBuffer> for BooleanBuffer {
702    fn bitor_assign(&mut self, rhs: &BooleanBuffer) {
703        self.bitwise_bin_op_assign(rhs, |a, b| a | b);
704    }
705}
706
707impl BitXorAssign<&BooleanBuffer> for BooleanBuffer {
708    fn bitxor_assign(&mut self, rhs: &BooleanBuffer) {
709        self.bitwise_bin_op_assign(rhs, |a, b| a ^ b);
710    }
711}
712
713impl<'a> IntoIterator for &'a BooleanBuffer {
714    type Item = bool;
715    type IntoIter = BitIterator<'a>;
716
717    fn into_iter(self) -> Self::IntoIter {
718        BitIterator::new(self.values(), self.bit_offset, self.bit_len)
719    }
720}
721
722impl From<&[bool]> for BooleanBuffer {
723    fn from(value: &[bool]) -> Self {
724        let mut builder = BooleanBufferBuilder::new(value.len());
725        builder.append_slice(value);
726        builder.finish()
727    }
728}
729
730impl From<Vec<bool>> for BooleanBuffer {
731    fn from(value: Vec<bool>) -> Self {
732        value.as_slice().into()
733    }
734}
735
736impl FromIterator<bool> for BooleanBuffer {
737    fn from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Self {
738        let iter = iter.into_iter();
739        let (hint, _) = iter.size_hint();
740        let mut builder = BooleanBufferBuilder::new(hint);
741        iter.for_each(|b| builder.append(b));
742        builder.finish()
743    }
744}
745
746#[cfg(test)]
747mod tests {
748    use super::*;
749
750    #[test]
751    fn test_boolean_new() {
752        let bytes = &[0, 1, 2, 3, 4];
753        let buf = Buffer::from(bytes);
754        let offset = 0;
755        let len = 24;
756
757        let boolean_buf = BooleanBuffer::new(buf.clone(), offset, len);
758        assert_eq!(bytes, boolean_buf.values());
759        assert_eq!(offset, boolean_buf.offset());
760        assert_eq!(len, boolean_buf.len());
761
762        assert_eq!(2, boolean_buf.count_set_bits());
763        assert_eq!(&buf, boolean_buf.inner());
764        assert_eq!(buf, boolean_buf.clone().into_inner());
765
766        assert!(!boolean_buf.is_empty())
767    }
768
769    #[test]
770    fn test_boolean_data_equality() {
771        let boolean_buf1 = BooleanBuffer::new(Buffer::from(&[0, 1, 4, 3, 5]), 0, 32);
772        let boolean_buf2 = BooleanBuffer::new(Buffer::from(&[0, 1, 4, 3, 5]), 0, 32);
773        assert_eq!(boolean_buf1, boolean_buf2);
774
775        // slice with same offset and same length should still preserve equality
776        let boolean_buf3 = boolean_buf1.slice(8, 16);
777        assert_ne!(boolean_buf1, boolean_buf3);
778        let boolean_buf4 = boolean_buf1.slice(0, 32);
779        assert_eq!(boolean_buf1, boolean_buf4);
780
781        // unequal because of different elements
782        let boolean_buf2 = BooleanBuffer::new(Buffer::from(&[0, 0, 2, 3, 4]), 0, 32);
783        assert_ne!(boolean_buf1, boolean_buf2);
784
785        // unequal because of different length
786        let boolean_buf2 = BooleanBuffer::new(Buffer::from(&[0, 1, 4, 3, 5]), 0, 24);
787        assert_ne!(boolean_buf1, boolean_buf2);
788
789        // ptr_eq
790        assert!(boolean_buf1.ptr_eq(&boolean_buf1));
791        assert!(boolean_buf2.ptr_eq(&boolean_buf2));
792        assert!(!boolean_buf1.ptr_eq(&boolean_buf2));
793    }
794
795    #[test]
796    fn test_boolean_slice() {
797        let bytes = &[0, 3, 2, 6, 2];
798        let boolean_buf1 = BooleanBuffer::new(Buffer::from(bytes), 0, 32);
799        let boolean_buf2 = BooleanBuffer::new(Buffer::from(bytes), 0, 32);
800
801        let boolean_slice1 = boolean_buf1.slice(16, 16);
802        let boolean_slice2 = boolean_buf2.slice(0, 16);
803        assert_eq!(boolean_slice1.values(), boolean_slice2.values());
804
805        assert_eq!(bytes, boolean_slice1.values());
806        assert_eq!(16, boolean_slice1.bit_offset);
807        assert_eq!(16, boolean_slice1.bit_len);
808
809        assert_eq!(bytes, boolean_slice2.values());
810        assert_eq!(0, boolean_slice2.bit_offset);
811        assert_eq!(16, boolean_slice2.bit_len);
812    }
813
814    #[test]
815    fn test_boolean_bitand() {
816        let offset = 0;
817        let len = 40;
818
819        let buf1 = Buffer::from(&[0, 1, 1, 0, 0]);
820        let boolean_buf1 = &BooleanBuffer::new(buf1, offset, len);
821
822        let buf2 = Buffer::from(&[0, 1, 1, 1, 0]);
823        let boolean_buf2 = &BooleanBuffer::new(buf2, offset, len);
824
825        let expected = BooleanBuffer::new(Buffer::from(&[0, 1, 1, 0, 0]), offset, len);
826        assert_eq!(boolean_buf1 & boolean_buf2, expected);
827    }
828
829    #[test]
830    fn test_boolean_bitor() {
831        let offset = 0;
832        let len = 40;
833
834        let buf1 = Buffer::from(&[0, 1, 1, 0, 0]);
835        let boolean_buf1 = &BooleanBuffer::new(buf1, offset, len);
836
837        let buf2 = Buffer::from(&[0, 1, 1, 1, 0]);
838        let boolean_buf2 = &BooleanBuffer::new(buf2, offset, len);
839
840        let expected = BooleanBuffer::new(Buffer::from(&[0, 1, 1, 1, 0]), offset, len);
841        assert_eq!(boolean_buf1 | boolean_buf2, expected);
842    }
843
844    #[test]
845    fn test_boolean_bitxor() {
846        let offset = 0;
847        let len = 40;
848
849        let buf1 = Buffer::from(&[0, 1, 1, 0, 0]);
850        let boolean_buf1 = &BooleanBuffer::new(buf1, offset, len);
851
852        let buf2 = Buffer::from(&[0, 1, 1, 1, 0]);
853        let boolean_buf2 = &BooleanBuffer::new(buf2, offset, len);
854
855        let expected = BooleanBuffer::new(Buffer::from(&[0, 0, 0, 1, 0]), offset, len);
856        assert_eq!(boolean_buf1 ^ boolean_buf2, expected);
857    }
858
859    #[test]
860    fn test_boolean_bitand_assign_shared_and_unshared() {
861        let rhs = BooleanBuffer::from(&[true, true, false, true, false, true][..]);
862        let original = BooleanBuffer::from(&[true, false, true, true, true, false][..]);
863
864        let mut unshared = BooleanBuffer::from(&[true, false, true, true, true, false][..]);
865        unshared &= &rhs;
866
867        let mut shared = original.clone();
868        let _shared_owner = shared.clone();
869        shared &= &rhs;
870
871        let expected = &original & &rhs;
872        assert_eq!(unshared, expected);
873        assert_eq!(shared, expected);
874    }
875
876    #[test]
877    fn test_boolean_bitor_assign() {
878        let rhs = BooleanBuffer::from(&[true, true, false, true, false, true][..]);
879        let original = BooleanBuffer::from(&[true, false, true, true, true, false][..]);
880
881        let mut actual = original.clone();
882        actual |= &rhs;
883
884        let expected = &original | &rhs;
885        assert_eq!(actual, expected);
886    }
887
888    #[test]
889    fn test_boolean_bitxor_assign() {
890        let rhs = BooleanBuffer::from(&[true, true, false, true, false, true][..]);
891        let original = BooleanBuffer::from(&[true, false, true, true, true, false][..]);
892
893        let mut actual = original.clone();
894        actual ^= &rhs;
895
896        let expected = &original ^ &rhs;
897        assert_eq!(actual, expected);
898    }
899
900    #[test]
901    fn test_boolean_not() {
902        let offset = 0;
903        let len = 40;
904
905        let buf = Buffer::from(&[0, 1, 1, 0, 0]);
906        let boolean_buf = &BooleanBuffer::new(buf, offset, len);
907
908        let expected = BooleanBuffer::new(Buffer::from(&[255, 254, 254, 255, 255]), offset, len);
909        assert_eq!(!boolean_buf, expected);
910
911        // Demonstrate that Non-zero offsets are preserved
912        let sliced = boolean_buf.slice(3, 20);
913        let result = !&sliced;
914        assert_eq!(result.offset(), 3);
915        assert_eq!(result.len(), sliced.len());
916        for i in 0..sliced.len() {
917            assert_eq!(result.value(i), !sliced.value(i));
918        }
919    }
920
921    #[test]
922    fn test_boolean_from_slice_bool() {
923        let v = [true, false, false];
924        let buf = BooleanBuffer::from(&v[..]);
925        assert_eq!(buf.offset(), 0);
926        assert_eq!(buf.len(), 3);
927        assert_eq!(buf.values().len(), 1);
928        assert!(buf.value(0));
929    }
930
931    #[test]
932    fn test_from_bitwise_unary_op() {
933        // Use 1024 boolean values so that at least some of the tests cover multiple u64 chunks and
934        // perfect alignment
935        let input_bools = (0..1024)
936            .map(|_| rand::random::<bool>())
937            .collect::<Vec<bool>>();
938        let input_buffer = BooleanBuffer::from(&input_bools[..]);
939
940        // Note ensure we test offsets over 100 to cover multiple u64 chunks
941        for offset in 0..1024 {
942            let result = BooleanBuffer::from_bitwise_unary_op(
943                input_buffer.values(),
944                offset,
945                input_buffer.len() - offset,
946                |a| !a,
947            );
948            let expected = input_bools[offset..]
949                .iter()
950                .map(|b| !*b)
951                .collect::<BooleanBuffer>();
952            assert_eq!(result, expected);
953        }
954
955        // Also test when the input doesn't cover the entire buffer
956        for offset in 0..512 {
957            let len = 512 - offset; // fixed length less than total
958            let result =
959                BooleanBuffer::from_bitwise_unary_op(input_buffer.values(), offset, len, |a| !a);
960            let expected = input_bools[offset..]
961                .iter()
962                .take(len)
963                .map(|b| !*b)
964                .collect::<BooleanBuffer>();
965            assert_eq!(result, expected);
966        }
967    }
968
969    #[test]
970    fn test_from_bitwise_unary_op_unaligned_fallback() {
971        // Deterministic affine sequence over u8: b[i] = 37*i + 11 (mod 256).
972        // This yields a non-trivial mix of bits (prefix: 11, 48, 85, 122, 159, 196, 233, 14, ...)
973        // so unary bit operations are exercised on varied input patterns.
974        let bytes = (0..80)
975            .map(|i| (i as u8).wrapping_mul(37).wrapping_add(11))
976            .collect::<Vec<_>>();
977        let base = bytes.as_ptr() as usize;
978        let shift = (0..8).find(|s| (base + s) % 8 != 0).unwrap();
979        let misaligned = &bytes[shift..];
980
981        // Case 1: fallback path with `remainder.is_empty() == true`
982        let src = &misaligned[..24];
983        let offset = 7;
984        let len = 96;
985        let result = BooleanBuffer::from_bitwise_unary_op(src, offset, len, |a| !a);
986        let expected = (0..len)
987            .map(|i| !bit_util::get_bit(src, offset + i))
988            .collect::<BooleanBuffer>();
989        assert_eq!(result, expected);
990        assert_eq!(result.offset(), offset % 64);
991
992        // Case 2: fallback path with `remainder.is_empty() == false`
993        let src = &misaligned[..13];
994        let offset = 3;
995        let len = 100;
996        let result = BooleanBuffer::from_bitwise_unary_op(src, offset, len, |a| !a);
997        let expected = (0..len)
998            .map(|i| !bit_util::get_bit(src, offset + i))
999            .collect::<BooleanBuffer>();
1000        assert_eq!(result, expected);
1001        assert_eq!(result.offset(), offset % 64);
1002    }
1003
1004    #[test]
1005    fn test_from_bitwise_binary_op() {
1006        // pick random boolean inputs
1007        let input_bools_left = (0..1024)
1008            .map(|_| rand::random::<bool>())
1009            .collect::<Vec<bool>>();
1010        let input_bools_right = (0..1024)
1011            .map(|_| rand::random::<bool>())
1012            .collect::<Vec<bool>>();
1013        let input_buffer_left = BooleanBuffer::from(&input_bools_left[..]);
1014        let input_buffer_right = BooleanBuffer::from(&input_bools_right[..]);
1015
1016        for left_offset in 0..200 {
1017            for right_offset in [0, 4, 5, 17, 33, 24, 45, 64, 65, 100, 200] {
1018                for len_offset in [0, 1, 44, 100, 256, 300, 512] {
1019                    let len = 1024 - len_offset - left_offset.max(right_offset); // ensure we don't go out of bounds
1020                    // compute with AND
1021                    let result = BooleanBuffer::from_bitwise_binary_op(
1022                        input_buffer_left.values(),
1023                        left_offset,
1024                        input_buffer_right.values(),
1025                        right_offset,
1026                        len,
1027                        |a, b| a & b,
1028                    );
1029                    // compute directly from bools
1030                    let expected = input_bools_left[left_offset..]
1031                        .iter()
1032                        .zip(&input_bools_right[right_offset..])
1033                        .take(len)
1034                        .map(|(a, b)| *a & *b)
1035                        .collect::<BooleanBuffer>();
1036                    assert_eq!(result, expected);
1037                }
1038            }
1039        }
1040    }
1041
1042    #[test]
1043    fn test_from_bitwise_binary_op_same_mod_64_unaligned_fallback() {
1044        // Exercise the shared-alignment fast path when both inputs are misaligned in memory,
1045        // forcing the chunks_exact fallback instead of align_to::<u64>().
1046        let left_bytes = [
1047            0,           // dropped so `&left_bytes[1..]` is not u64-aligned in memory
1048            0b1101_0010, // logical left bits start at bit 3 of this byte
1049            0b0110_1101,
1050            0b1010_0111,
1051            0b0001_1110,
1052            0b1110_0001,
1053            0b0101_1010,
1054            0b1001_0110,
1055            0b0011_1100,
1056            0b1011_0001,
1057            0b0100_1110,
1058            0b1100_0011,
1059            0b0111_1000,
1060        ];
1061        let right_bytes = [
1062            0,           // dropped so `&right_bytes[1..]` is not u64-aligned in memory
1063            0b1010_1100, // logical right bits start at bit 67 == bit 3 of the second 64-bit block
1064            0b0101_0011,
1065            0b1111_0000,
1066            0b0011_1010,
1067            0b1000_1111,
1068            0b0110_0101,
1069            0b1101_1000,
1070            0b0001_0111,
1071            0b1110_0100,
1072            0b0010_1101,
1073            0b1001_1010,
1074            0b0111_0001,
1075        ];
1076
1077        let left = &left_bytes[1..];
1078        let right = &right_bytes[1..];
1079
1080        let left_offset = 3;
1081        let right_offset = 67; // same mod 64 as left_offset, so this takes the shared-alignment path
1082        let len = 24; // leaves a partial trailing chunk, so this covers the non-empty remainder branch
1083
1084        let result = BooleanBuffer::from_bitwise_binary_op(
1085            left,
1086            left_offset,
1087            right,
1088            right_offset,
1089            len,
1090            |a, b| a & b,
1091        );
1092        let expected = (0..len)
1093            .map(|i| {
1094                bit_util::get_bit(left, left_offset + i)
1095                    & bit_util::get_bit(right, right_offset + i)
1096            })
1097            .collect::<BooleanBuffer>();
1098
1099        assert_eq!(result, expected);
1100        assert_eq!(result.offset(), left_offset % 64);
1101    }
1102
1103    #[test]
1104    fn test_from_bitwise_binary_op_same_mod_64_unaligned_fallback_no_remainder() {
1105        // Force the chunks_exact fallback with an exact 8-byte chunk so both remainders are empty.
1106        let left_bytes = [
1107            0,           // dropped so `&left_bytes[1..]` is not u64-aligned in memory
1108            0b1010_1100, // logical left bits start at bit 3 of this byte
1109            0b0110_1001,
1110            0b1101_0011,
1111            0b0001_1110,
1112            0b1110_0101,
1113            0b0101_1000,
1114            0b1001_0111,
1115            0b0011_1101,
1116        ];
1117        let right_bytes = [
1118            0,           // dropped so `&right_bytes[1..]` is not u64-aligned in memory
1119            0b0111_0010, // logical right bits start at bit 67 == bit 3 of the second 64-bit block
1120            0b1010_1001,
1121            0b0101_1110,
1122            0b1100_0011,
1123            0b0011_1011,
1124            0b1000_1110,
1125            0b1111_0001,
1126            0b0100_1101,
1127            0b1011_0110,
1128            0b0001_1011,
1129            0b1101_0100,
1130            0b0110_0011,
1131            0b1001_1110,
1132            0b0010_1001,
1133            0b1110_0110,
1134            0b0101_0001,
1135        ];
1136
1137        let left = &left_bytes[1..];
1138        let right = &right_bytes[1..];
1139
1140        let left_offset = 3;
1141        let right_offset = 67; // same mod 64 as left_offset, so this takes the shared-alignment path
1142        let len = 61; // 3 + 61 = 64, so the aligned slices are exactly one 8-byte chunk with empty remainders
1143
1144        let result = BooleanBuffer::from_bitwise_binary_op(
1145            left,
1146            left_offset,
1147            right,
1148            right_offset,
1149            len,
1150            |a, b| a | b,
1151        );
1152        let expected = (0..len)
1153            .map(|i| {
1154                bit_util::get_bit(left, left_offset + i)
1155                    | bit_util::get_bit(right, right_offset + i)
1156            })
1157            .collect::<BooleanBuffer>();
1158
1159        assert_eq!(result, expected);
1160        assert_eq!(result.offset(), left_offset % 64);
1161    }
1162
1163    #[test]
1164    fn test_extend_trusted_len_sets_byte_len() {
1165        // Ensures extend_trusted_len keeps the underlying byte length in sync with bit length.
1166        let mut builder = BooleanBufferBuilder::new(0);
1167        let bools: Vec<_> = (0..10).map(|i| i % 2 == 0).collect();
1168        unsafe { builder.extend_trusted_len(bools.into_iter()) };
1169        assert_eq!(builder.as_slice().len(), bit_util::ceil(builder.len(), 8));
1170    }
1171
1172    #[test]
1173    fn test_extend_trusted_len_then_append() {
1174        // Exercises append after extend_trusted_len to validate byte length and values.
1175        let mut builder = BooleanBufferBuilder::new(0);
1176        let bools: Vec<_> = (0..9).map(|i| i % 3 == 0).collect();
1177        unsafe { builder.extend_trusted_len(bools.clone().into_iter()) };
1178        builder.append(true);
1179        assert_eq!(builder.as_slice().len(), bit_util::ceil(builder.len(), 8));
1180        let finished = builder.finish();
1181        for (i, v) in bools.into_iter().chain(std::iter::once(true)).enumerate() {
1182            assert_eq!(finished.value(i), v, "at index {}", i);
1183        }
1184    }
1185
1186    #[test]
1187    fn test_find_nth_set_bit_position() {
1188        let bools = vec![true, false, true, true, false, true];
1189        let buffer = BooleanBuffer::from(bools);
1190
1191        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 1), 1);
1192        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 2), 3);
1193        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 3), 4);
1194        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 4), 6);
1195        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 5), 6);
1196
1197        assert_eq!(buffer.clone().find_nth_set_bit_position(1, 1), 3);
1198        assert_eq!(buffer.clone().find_nth_set_bit_position(3, 1), 4);
1199        assert_eq!(buffer.clone().find_nth_set_bit_position(3, 2), 6);
1200    }
1201
1202    #[test]
1203    fn test_find_nth_set_bit_position_large() {
1204        let mut bools = vec![false; 1000];
1205        bools[100] = true;
1206        bools[500] = true;
1207        bools[999] = true;
1208        let buffer = BooleanBuffer::from(bools);
1209
1210        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 1), 101);
1211        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 2), 501);
1212        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 3), 1000);
1213        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 4), 1000);
1214
1215        assert_eq!(buffer.clone().find_nth_set_bit_position(101, 1), 501);
1216    }
1217
1218    #[test]
1219    fn test_find_nth_set_bit_position_sliced() {
1220        let bools = vec![false, true, false, true, true, false, true]; // [F, T, F, T, T, F, T]
1221        let buffer = BooleanBuffer::from(bools);
1222        let slice = buffer.slice(1, 6); // [T, F, T, T, F, T]
1223
1224        assert_eq!(slice.len(), 6);
1225        // Logical indices: 0, 1, 2, 3, 4, 5
1226        // Logical values: T, F, T, T, F, T
1227
1228        assert_eq!(slice.clone().find_nth_set_bit_position(0, 1), 1);
1229        assert_eq!(slice.clone().find_nth_set_bit_position(0, 2), 3);
1230        assert_eq!(slice.clone().find_nth_set_bit_position(0, 3), 4);
1231        assert_eq!(slice.clone().find_nth_set_bit_position(0, 4), 6);
1232    }
1233
1234    #[test]
1235    fn test_find_nth_set_bit_position_all_set() {
1236        let buffer = BooleanBuffer::new_set(100);
1237        for i in 1..=100 {
1238            assert_eq!(buffer.clone().find_nth_set_bit_position(0, i), i);
1239        }
1240        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 101), 100);
1241    }
1242
1243    #[test]
1244    fn test_find_nth_set_bit_position_none_set() {
1245        let buffer = BooleanBuffer::new_unset(100);
1246        assert_eq!(buffer.clone().find_nth_set_bit_position(0, 1), 100);
1247    }
1248}