arrow_buffer/buffer/
mutable.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 std::alloc::{Layout, handle_alloc_error};
19use std::mem;
20use std::ptr::NonNull;
21
22use crate::alloc::{ALIGNMENT, Deallocation};
23use crate::{
24    bytes::Bytes,
25    native::{ArrowNativeType, ToByteSlice},
26    util::bit_util,
27};
28
29#[cfg(feature = "pool")]
30use crate::pool::{MemoryPool, MemoryReservation};
31#[cfg(feature = "pool")]
32use std::sync::Mutex;
33
34use super::Buffer;
35
36/// A [`MutableBuffer`] is Arrow's interface to build a [`Buffer`] out of items or slices of items.
37///
38/// [`Buffer`]s created from [`MutableBuffer`] (via `into`) are guaranteed to be aligned
39/// along cache lines and in multiple of 64 bytes.
40///
41/// Use [MutableBuffer::push] to insert an item, [MutableBuffer::extend_from_slice]
42/// to insert many items, and `into` to convert it to [`Buffer`].
43///
44/// # See Also
45/// * For a safe, strongly typed API consider using [`Vec`] and [`ScalarBuffer`](crate::ScalarBuffer)
46/// * To apply bitwise operations, see [`apply_bitwise_binary_op`] and [`apply_bitwise_unary_op`]
47///
48/// [`apply_bitwise_binary_op`]: crate::bit_util::apply_bitwise_binary_op
49/// [`apply_bitwise_unary_op`]: crate::bit_util::apply_bitwise_unary_op
50///
51/// # Example
52///
53/// ```
54/// # use arrow_buffer::buffer::{Buffer, MutableBuffer};
55/// let mut buffer = MutableBuffer::new(0);
56/// buffer.push(256u32);
57/// buffer.extend_from_slice(&[1u32]);
58/// let buffer: Buffer = buffer.into();
59/// assert_eq!(buffer.as_slice(), &[0u8, 1, 0, 0, 1, 0, 0, 0])
60/// ```
61#[derive(Debug)]
62pub struct MutableBuffer {
63    // dangling iff capacity = 0
64    data: NonNull<u8>,
65    // invariant: len <= capacity
66    len: usize,
67    layout: Layout,
68
69    /// Memory reservation for tracking memory usage
70    #[cfg(feature = "pool")]
71    reservation: Mutex<Option<Box<dyn MemoryReservation>>>,
72}
73
74impl MutableBuffer {
75    /// Allocate a new [MutableBuffer] with initial capacity to be at least `capacity`.
76    ///
77    /// See [`MutableBuffer::with_capacity`].
78    #[inline]
79    pub fn new(capacity: usize) -> Self {
80        Self::with_capacity(capacity)
81    }
82
83    /// Allocate a new [MutableBuffer] with initial capacity to be at least `capacity`.
84    ///
85    /// # Panics
86    ///
87    /// If `capacity`, when rounded up to the nearest multiple of [`ALIGNMENT`], is greater
88    /// then `isize::MAX`, then this function will panic.
89    #[inline]
90    pub fn with_capacity(capacity: usize) -> Self {
91        let capacity = bit_util::round_upto_multiple_of_64(capacity);
92        let layout = Layout::from_size_align(capacity, ALIGNMENT)
93            .expect("failed to create layout for MutableBuffer");
94        let data = match layout.size() {
95            0 => dangling_ptr(),
96            _ => {
97                // Safety: Verified size != 0
98                let raw_ptr = unsafe { std::alloc::alloc(layout) };
99                NonNull::new(raw_ptr).unwrap_or_else(|| handle_alloc_error(layout))
100            }
101        };
102        Self {
103            data,
104            len: 0,
105            layout,
106            #[cfg(feature = "pool")]
107            reservation: std::sync::Mutex::new(None),
108        }
109    }
110
111    /// Allocates a new [MutableBuffer] with `len` and capacity to be at least `len` where
112    /// all bytes are guaranteed to be `0u8`.
113    /// # Example
114    /// ```
115    /// # use arrow_buffer::buffer::{Buffer, MutableBuffer};
116    /// let mut buffer = MutableBuffer::from_len_zeroed(127);
117    /// assert_eq!(buffer.len(), 127);
118    /// assert!(buffer.capacity() >= 127);
119    /// let data = buffer.as_slice_mut();
120    /// assert_eq!(data[126], 0u8);
121    /// ```
122    pub fn from_len_zeroed(len: usize) -> Self {
123        let layout = Layout::from_size_align(len, ALIGNMENT).unwrap();
124        let data = match layout.size() {
125            0 => dangling_ptr(),
126            _ => {
127                // Safety: Verified size != 0
128                let raw_ptr = unsafe { std::alloc::alloc_zeroed(layout) };
129                NonNull::new(raw_ptr).unwrap_or_else(|| handle_alloc_error(layout))
130            }
131        };
132        Self {
133            data,
134            len,
135            layout,
136            #[cfg(feature = "pool")]
137            reservation: std::sync::Mutex::new(None),
138        }
139    }
140
141    /// Allocates a new [MutableBuffer] from given `Bytes`.
142    pub(crate) fn from_bytes(bytes: Bytes) -> Result<Self, Bytes> {
143        let layout = match bytes.deallocation() {
144            Deallocation::Standard(layout) => *layout,
145            _ => return Err(bytes),
146        };
147
148        let len = bytes.len();
149        let data = bytes.ptr();
150        #[cfg(feature = "pool")]
151        let reservation = bytes.reservation.lock().unwrap().take();
152        mem::forget(bytes);
153
154        Ok(Self {
155            data,
156            len,
157            layout,
158            #[cfg(feature = "pool")]
159            reservation: Mutex::new(reservation),
160        })
161    }
162
163    /// creates a new [MutableBuffer] with capacity and length capable of holding `len` bits.
164    /// This is useful to create a buffer for packed bitmaps.
165    pub fn new_null(len: usize) -> Self {
166        let num_bytes = bit_util::ceil(len, 8);
167        MutableBuffer::from_len_zeroed(num_bytes)
168    }
169
170    /// Set the bits in the range of `[0, end)` to 0 (if `val` is false), or 1 (if `val`
171    /// is true). Also extend the length of this buffer to be `end`.
172    ///
173    /// This is useful when one wants to clear (or set) the bits and then manipulate
174    /// the buffer directly (e.g., modifying the buffer by holding a mutable reference
175    /// from `data_mut()`).
176    pub fn with_bitset(mut self, end: usize, val: bool) -> Self {
177        assert!(end <= self.layout.size());
178        let v = if val { 255 } else { 0 };
179        unsafe {
180            std::ptr::write_bytes(self.data.as_ptr(), v, end);
181            self.len = end;
182        }
183        self
184    }
185
186    /// Ensure that `count` bytes from `start` contain zero bits
187    ///
188    /// This is used to initialize the bits in a buffer, however, it has no impact on the
189    /// `len` of the buffer and so can be used to initialize the memory region from
190    /// `len` to `capacity`.
191    pub fn set_null_bits(&mut self, start: usize, count: usize) {
192        assert!(
193            start.saturating_add(count) <= self.layout.size(),
194            "range start index {start} and count {count} out of bounds for \
195            buffer of length {}",
196            self.layout.size(),
197        );
198
199        // Safety: `self.data[start..][..count]` is in-bounds and well-aligned for `u8`
200        unsafe {
201            std::ptr::write_bytes(self.data.as_ptr().add(start), 0, count);
202        }
203    }
204
205    /// Ensures that this buffer has at least `self.len + additional` bytes. This re-allocates iff
206    /// `self.len + additional > capacity`.
207    /// # Example
208    /// ```
209    /// # use arrow_buffer::buffer::{Buffer, MutableBuffer};
210    /// let mut buffer = MutableBuffer::new(0);
211    /// buffer.reserve(253); // allocates for the first time
212    /// (0..253u8).for_each(|i| buffer.push(i)); // no reallocation
213    /// let buffer: Buffer = buffer.into();
214    /// assert_eq!(buffer.len(), 253);
215    /// ```
216    // For performance reasons, this must be inlined so that the `if` is executed inside the caller, and not as an extra call that just
217    // exits.
218    #[inline(always)]
219    pub fn reserve(&mut self, additional: usize) {
220        let required_cap = self.len + additional;
221        if required_cap > self.layout.size() {
222            let new_capacity = bit_util::round_upto_multiple_of_64(required_cap);
223            let new_capacity = std::cmp::max(new_capacity, self.layout.size() * 2);
224            self.reallocate(new_capacity)
225        }
226    }
227
228    /// Adding to this mutable buffer `slice_to_repeat` repeated `repeat_count` times.
229    ///
230    /// # Example
231    ///
232    /// ## Repeat the same string bytes multiple times
233    /// ```
234    /// # use arrow_buffer::buffer::MutableBuffer;
235    /// let mut buffer = MutableBuffer::new(0);
236    /// let bytes_to_repeat = b"ab";
237    /// buffer.repeat_slice_n_times(bytes_to_repeat, 3);
238    /// assert_eq!(buffer.as_slice(), b"ababab");
239    /// ```
240    pub fn repeat_slice_n_times<T: ArrowNativeType>(
241        &mut self,
242        slice_to_repeat: &[T],
243        repeat_count: usize,
244    ) {
245        if repeat_count == 0 || slice_to_repeat.is_empty() {
246            return;
247        }
248
249        let bytes_to_repeat = size_of_val(slice_to_repeat);
250
251        // Ensure capacity
252        self.reserve(repeat_count * bytes_to_repeat);
253
254        // Save the length before we do all the copies to know where to start from
255        let length_before = self.len;
256
257        // Copy the initial slice once so we can use doubling strategy on it
258        self.extend_from_slice(slice_to_repeat);
259
260        // This tracks how much bytes we have added by repeating so far
261        let added_repeats_length = bytes_to_repeat;
262        assert_eq!(
263            self.len - length_before,
264            added_repeats_length,
265            "should copy exactly the same number of bytes"
266        );
267
268        // Number of times the slice was repeated
269        let mut already_repeated_times = 1;
270
271        // We will use doubling strategy to fill the buffer in log(repeat_count) steps
272        while already_repeated_times < repeat_count {
273            // How many slices can we copy in this iteration
274            // (either double what we have, or just the remaining ones)
275            let number_of_slices_to_copy =
276                already_repeated_times.min(repeat_count - already_repeated_times);
277            let number_of_bytes_to_copy = number_of_slices_to_copy * bytes_to_repeat;
278
279            unsafe {
280                // Get to the start of the data before we started copying anything
281                let src = self.data.as_ptr().add(length_before) as *const u8;
282
283                // Go to the current location to copy to (end of current data)
284                let dst = self.data.as_ptr().add(self.len);
285
286                // SAFETY: the pointers are not overlapping as there is `number_of_bytes_to_copy` or less between them
287                std::ptr::copy_nonoverlapping(src, dst, number_of_bytes_to_copy)
288            }
289
290            // Advance the length by the amount of data we just copied (doubled)
291            self.len += number_of_bytes_to_copy;
292
293            already_repeated_times += number_of_slices_to_copy;
294        }
295    }
296
297    #[cold]
298    fn reallocate(&mut self, capacity: usize) {
299        let new_layout = Layout::from_size_align(capacity, self.layout.align()).unwrap();
300        if new_layout.size() == 0 {
301            if self.layout.size() != 0 {
302                // Safety: data was allocated with layout
303                unsafe { std::alloc::dealloc(self.as_mut_ptr(), self.layout) };
304                self.layout = new_layout
305            }
306            return;
307        }
308
309        let data = match self.layout.size() {
310            // Safety: new_layout is not empty
311            0 => unsafe { std::alloc::alloc(new_layout) },
312            // Safety: verified new layout is valid and not empty
313            _ => unsafe { std::alloc::realloc(self.as_mut_ptr(), self.layout, capacity) },
314        };
315        self.data = NonNull::new(data).unwrap_or_else(|| handle_alloc_error(new_layout));
316        self.layout = new_layout;
317        #[cfg(feature = "pool")]
318        {
319            if let Some(reservation) = self.reservation.lock().unwrap().as_mut() {
320                reservation.resize(self.layout.size());
321            }
322        }
323    }
324
325    /// Truncates this buffer to `len` bytes
326    ///
327    /// If `len` is greater than the buffer's current length, this has no effect
328    #[inline(always)]
329    pub fn truncate(&mut self, len: usize) {
330        if len > self.len {
331            return;
332        }
333        self.len = len;
334        #[cfg(feature = "pool")]
335        {
336            if let Some(reservation) = self.reservation.lock().unwrap().as_mut() {
337                reservation.resize(self.len);
338            }
339        }
340    }
341
342    /// Resizes the buffer, either truncating its contents (with no change in capacity), or
343    /// growing it (potentially reallocating it) and writing `value` in the newly available bytes.
344    /// # Example
345    /// ```
346    /// # use arrow_buffer::buffer::{Buffer, MutableBuffer};
347    /// let mut buffer = MutableBuffer::new(0);
348    /// buffer.resize(253, 2); // allocates for the first time
349    /// assert_eq!(buffer.as_slice()[252], 2u8);
350    /// ```
351    // For performance reasons, this must be inlined so that the `if` is executed inside the caller, and not as an extra call that just
352    // exits.
353    #[inline(always)]
354    pub fn resize(&mut self, new_len: usize, value: u8) {
355        if new_len > self.len {
356            let diff = new_len - self.len;
357            self.reserve(diff);
358            // write the value
359            unsafe { self.data.as_ptr().add(self.len).write_bytes(value, diff) };
360        }
361        // this truncates the buffer when new_len < self.len
362        self.len = new_len;
363        #[cfg(feature = "pool")]
364        {
365            if let Some(reservation) = self.reservation.lock().unwrap().as_mut() {
366                reservation.resize(self.len);
367            }
368        }
369    }
370
371    /// Shrinks the capacity of the buffer as much as possible.
372    /// The new capacity will aligned to the nearest 64 bit alignment.
373    ///
374    /// # Example
375    /// ```
376    /// # use arrow_buffer::buffer::{Buffer, MutableBuffer};
377    /// // 2 cache lines
378    /// let mut buffer = MutableBuffer::new(128);
379    /// assert_eq!(buffer.capacity(), 128);
380    /// buffer.push(1);
381    /// buffer.push(2);
382    ///
383    /// buffer.shrink_to_fit();
384    /// assert!(buffer.capacity() >= 64 && buffer.capacity() < 128);
385    /// ```
386    pub fn shrink_to_fit(&mut self) {
387        let new_capacity = bit_util::round_upto_multiple_of_64(self.len);
388        if new_capacity < self.layout.size() {
389            self.reallocate(new_capacity)
390        }
391    }
392
393    /// Returns whether this buffer is empty or not.
394    #[inline]
395    pub const fn is_empty(&self) -> bool {
396        self.len == 0
397    }
398
399    /// Returns the length (the number of bytes written) in this buffer.
400    /// The invariant `buffer.len() <= buffer.capacity()` is always upheld.
401    #[inline]
402    pub const fn len(&self) -> usize {
403        self.len
404    }
405
406    /// Returns the total capacity in this buffer, in bytes.
407    ///
408    /// The invariant `buffer.len() <= buffer.capacity()` is always upheld.
409    #[inline]
410    pub const fn capacity(&self) -> usize {
411        self.layout.size()
412    }
413
414    /// Clear all existing data from this buffer.
415    pub fn clear(&mut self) {
416        self.len = 0
417    }
418
419    /// Returns the data stored in this buffer as a slice.
420    pub fn as_slice(&self) -> &[u8] {
421        self
422    }
423
424    /// Returns the data stored in this buffer as a mutable slice.
425    pub fn as_slice_mut(&mut self) -> &mut [u8] {
426        self
427    }
428
429    /// Returns a raw pointer to this buffer's internal memory
430    /// This pointer is guaranteed to be aligned along cache-lines.
431    #[inline]
432    pub const fn as_ptr(&self) -> *const u8 {
433        self.data.as_ptr()
434    }
435
436    /// Returns a mutable raw pointer to this buffer's internal memory
437    /// This pointer is guaranteed to be aligned along cache-lines.
438    #[inline]
439    pub fn as_mut_ptr(&mut self) -> *mut u8 {
440        self.data.as_ptr()
441    }
442
443    #[inline]
444    pub(super) fn into_buffer(self) -> Buffer {
445        let bytes = unsafe { Bytes::new(self.data, self.len, Deallocation::Standard(self.layout)) };
446        #[cfg(feature = "pool")]
447        {
448            let reservation = self.reservation.lock().unwrap().take();
449            *bytes.reservation.lock().unwrap() = reservation;
450        }
451        std::mem::forget(self);
452        Buffer::from(bytes)
453    }
454
455    /// View this buffer as a mutable slice of a specific type.
456    ///
457    /// # Panics
458    ///
459    /// This function panics if the underlying buffer is not aligned
460    /// correctly for type `T`.
461    pub fn typed_data_mut<T: ArrowNativeType>(&mut self) -> &mut [T] {
462        // SAFETY
463        // ArrowNativeType is trivially transmutable, is sealed to prevent potentially incorrect
464        // implementation outside this crate, and this method checks alignment
465        let (prefix, offsets, suffix) = unsafe { self.as_slice_mut().align_to_mut::<T>() };
466        assert!(prefix.is_empty() && suffix.is_empty());
467        offsets
468    }
469
470    /// View buffer as a immutable slice of a specific type.
471    ///
472    /// # Panics
473    ///
474    /// This function panics if the underlying buffer is not aligned
475    /// correctly for type `T`.
476    pub fn typed_data<T: ArrowNativeType>(&self) -> &[T] {
477        // SAFETY
478        // ArrowNativeType is trivially transmutable, is sealed to prevent potentially incorrect
479        // implementation outside this crate, and this method checks alignment
480        let (prefix, offsets, suffix) = unsafe { self.as_slice().align_to::<T>() };
481        assert!(prefix.is_empty() && suffix.is_empty());
482        offsets
483    }
484
485    /// Extends this buffer from a slice of items that can be represented in bytes, increasing its capacity if needed.
486    /// # Example
487    /// ```
488    /// # use arrow_buffer::buffer::MutableBuffer;
489    /// let mut buffer = MutableBuffer::new(0);
490    /// buffer.extend_from_slice(&[2u32, 0]);
491    /// assert_eq!(buffer.len(), 8) // u32 has 4 bytes
492    /// ```
493    #[inline]
494    pub fn extend_from_slice<T: ArrowNativeType>(&mut self, items: &[T]) {
495        let additional = mem::size_of_val(items);
496        self.reserve(additional);
497        unsafe {
498            // this assumes that `[ToByteSlice]` can be copied directly
499            // without calling `to_byte_slice` for each element,
500            // which is correct for all ArrowNativeType implementations.
501            let src = items.as_ptr() as *const u8;
502            let dst = self.data.as_ptr().add(self.len);
503            std::ptr::copy_nonoverlapping(src, dst, additional)
504        }
505        self.len += additional;
506    }
507
508    /// Extends the buffer with a new item, increasing its capacity if needed.
509    /// # Example
510    /// ```
511    /// # use arrow_buffer::buffer::MutableBuffer;
512    /// let mut buffer = MutableBuffer::new(0);
513    /// buffer.push(256u32);
514    /// assert_eq!(buffer.len(), 4) // u32 has 4 bytes
515    /// ```
516    #[inline]
517    pub fn push<T: ToByteSlice>(&mut self, item: T) {
518        let additional = std::mem::size_of::<T>();
519        self.reserve(additional);
520        unsafe {
521            let src = item.to_byte_slice().as_ptr();
522            let dst = self.data.as_ptr().add(self.len);
523            std::ptr::copy_nonoverlapping(src, dst, additional);
524        }
525        self.len += additional;
526    }
527
528    /// Extends the buffer with a new item, without checking for sufficient capacity
529    /// # Safety
530    /// Caller must ensure that the capacity()-len()>=`size_of<T>`()
531    #[inline]
532    pub unsafe fn push_unchecked<T: ToByteSlice>(&mut self, item: T) {
533        let additional = std::mem::size_of::<T>();
534        let src = item.to_byte_slice().as_ptr();
535        let dst = unsafe { self.data.as_ptr().add(self.len) };
536        unsafe { std::ptr::copy_nonoverlapping(src, dst, additional) };
537        self.len += additional;
538    }
539
540    /// Extends the buffer by `additional` bytes equal to `0u8`, incrementing its capacity if needed.
541    #[inline]
542    pub fn extend_zeros(&mut self, additional: usize) {
543        self.resize(self.len + additional, 0);
544    }
545
546    /// # Safety
547    /// The caller must ensure that the buffer was properly initialized up to `len`.
548    #[inline]
549    pub unsafe fn set_len(&mut self, len: usize) {
550        assert!(len <= self.capacity());
551        self.len = len;
552    }
553
554    /// Invokes `f` with values `0..len` collecting the boolean results into a new `MutableBuffer`
555    ///
556    /// This is similar to `from_trusted_len_iter_bool`, however, can be significantly faster
557    /// as it eliminates the conditional `Iterator::next`
558    #[inline]
559    pub fn collect_bool<F: FnMut(usize) -> bool>(len: usize, mut f: F) -> Self {
560        let mut buffer: Vec<u64> = Vec::with_capacity(bit_util::ceil(len, 64));
561
562        let chunks = len / 64;
563        let remainder = len % 64;
564        buffer.extend((0..chunks).map(|chunk| {
565            let mut packed = 0;
566            for bit_idx in 0..64 {
567                let i = bit_idx + chunk * 64;
568                packed |= (f(i) as u64) << bit_idx;
569            }
570
571            packed
572        }));
573
574        if remainder != 0 {
575            let mut packed = 0;
576            for bit_idx in 0..remainder {
577                let i = bit_idx + chunks * 64;
578                packed |= (f(i) as u64) << bit_idx;
579            }
580
581            buffer.push(packed)
582        }
583
584        let mut buffer: MutableBuffer = buffer.into();
585        buffer.truncate(bit_util::ceil(len, 8));
586        buffer
587    }
588
589    /// Register this [`MutableBuffer`] with the provided [`MemoryPool`]
590    ///
591    /// This claims the memory used by this buffer in the pool, allowing for
592    /// accurate accounting of memory usage. Any prior reservation will be
593    /// released so this works well when the buffer is being shared among
594    /// multiple arrays.
595    #[cfg(feature = "pool")]
596    pub fn claim(&self, pool: &dyn MemoryPool) {
597        *self.reservation.lock().unwrap() = Some(pool.reserve(self.capacity()));
598    }
599}
600
601/// Creates a non-null pointer with alignment of [`ALIGNMENT`]
602///
603/// This is similar to [`NonNull::dangling`]
604#[inline]
605pub(crate) fn dangling_ptr() -> NonNull<u8> {
606    // SAFETY: ALIGNMENT is a non-zero usize which is then cast
607    // to a *mut u8. Therefore, `ptr` is not null and the conditions for
608    // calling new_unchecked() are respected.
609    #[cfg(miri)]
610    {
611        // Since miri implies a nightly rust version we can use the unstable strict_provenance feature
612        unsafe { NonNull::new_unchecked(std::ptr::without_provenance_mut(ALIGNMENT)) }
613    }
614    #[cfg(not(miri))]
615    {
616        unsafe { NonNull::new_unchecked(ALIGNMENT as *mut u8) }
617    }
618}
619
620impl<A: ArrowNativeType> Extend<A> for MutableBuffer {
621    #[inline]
622    fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
623        let iterator = iter.into_iter();
624        self.extend_from_iter(iterator)
625    }
626}
627
628impl<T: ArrowNativeType> From<Vec<T>> for MutableBuffer {
629    fn from(value: Vec<T>) -> Self {
630        // Safety
631        // Vec::as_ptr guaranteed to not be null and ArrowNativeType are trivially transmutable
632        let data = unsafe { NonNull::new_unchecked(value.as_ptr() as _) };
633        let len = value.len() * mem::size_of::<T>();
634        // Safety
635        // Vec guaranteed to have a valid layout matching that of `Layout::array`
636        // This is based on `RawVec::current_memory`
637        let layout = unsafe { Layout::array::<T>(value.capacity()).unwrap_unchecked() };
638        mem::forget(value);
639        Self {
640            data,
641            len,
642            layout,
643            #[cfg(feature = "pool")]
644            reservation: std::sync::Mutex::new(None),
645        }
646    }
647}
648
649impl MutableBuffer {
650    #[inline]
651    pub(super) fn extend_from_iter<T: ArrowNativeType, I: Iterator<Item = T>>(
652        &mut self,
653        mut iterator: I,
654    ) {
655        let item_size = std::mem::size_of::<T>();
656        let (lower, _) = iterator.size_hint();
657        let additional = lower * item_size;
658        self.reserve(additional);
659
660        // this is necessary because of https://github.com/rust-lang/rust/issues/32155
661        let mut len = SetLenOnDrop::new(&mut self.len);
662        let mut dst = unsafe { self.data.as_ptr().add(len.local_len) };
663        let capacity = self.layout.size();
664
665        while len.local_len + item_size <= capacity {
666            if let Some(item) = iterator.next() {
667                unsafe {
668                    let src = item.to_byte_slice().as_ptr();
669                    std::ptr::copy_nonoverlapping(src, dst, item_size);
670                    dst = dst.add(item_size);
671                }
672                len.local_len += item_size;
673            } else {
674                break;
675            }
676        }
677        drop(len);
678
679        iterator.for_each(|item| self.push(item));
680    }
681
682    /// Creates a [`MutableBuffer`] from an [`Iterator`] with a trusted (upper) length.
683    /// Prefer this to `collect` whenever possible, as it is faster ~60% faster.
684    /// # Example
685    /// ```
686    /// # use arrow_buffer::buffer::MutableBuffer;
687    /// let v = vec![1u32];
688    /// let iter = v.iter().map(|x| x * 2);
689    /// let buffer = unsafe { MutableBuffer::from_trusted_len_iter(iter) };
690    /// assert_eq!(buffer.len(), 4) // u32 has 4 bytes
691    /// ```
692    /// # Safety
693    /// This method assumes that the iterator's size is correct and is undefined behavior
694    /// to use it on an iterator that reports an incorrect length.
695    // This implementation is required for two reasons:
696    // 1. there is no trait `TrustedLen` in stable rust and therefore
697    //    we can't specialize `extend` for `TrustedLen` like `Vec` does.
698    // 2. `from_trusted_len_iter` is faster.
699    #[inline]
700    pub unsafe fn from_trusted_len_iter<T: ArrowNativeType, I: Iterator<Item = T>>(
701        iterator: I,
702    ) -> Self {
703        let item_size = std::mem::size_of::<T>();
704        let (_, upper) = iterator.size_hint();
705        let upper = upper.expect("from_trusted_len_iter requires an upper limit");
706        let len = upper * item_size;
707
708        let mut buffer = MutableBuffer::new(len);
709
710        let mut dst = buffer.data.as_ptr();
711        for item in iterator {
712            // note how there is no reserve here (compared with `extend_from_iter`)
713            let src = item.to_byte_slice().as_ptr();
714            unsafe { std::ptr::copy_nonoverlapping(src, dst, item_size) };
715            dst = unsafe { dst.add(item_size) };
716        }
717        assert_eq!(
718            unsafe { dst.offset_from(buffer.data.as_ptr()) } as usize,
719            len,
720            "Trusted iterator length was not accurately reported"
721        );
722        buffer.len = len;
723        buffer
724    }
725
726    /// Creates a [`MutableBuffer`] from a boolean [`Iterator`] with a trusted (upper) length.
727    /// # use arrow_buffer::buffer::MutableBuffer;
728    /// # Example
729    /// ```
730    /// # use arrow_buffer::buffer::MutableBuffer;
731    /// let v = vec![false, true, false];
732    /// let iter = v.iter().map(|x| *x || true);
733    /// let buffer = unsafe { MutableBuffer::from_trusted_len_iter_bool(iter) };
734    /// assert_eq!(buffer.len(), 1) // 3 booleans have 1 byte
735    /// ```
736    /// # Safety
737    /// This method assumes that the iterator's size is correct and is undefined behavior
738    /// to use it on an iterator that reports an incorrect length.
739    // This implementation is required for two reasons:
740    // 1. there is no trait `TrustedLen` in stable rust and therefore
741    //    we can't specialize `extend` for `TrustedLen` like `Vec` does.
742    // 2. `from_trusted_len_iter_bool` is faster.
743    #[inline]
744    pub unsafe fn from_trusted_len_iter_bool<I: Iterator<Item = bool>>(mut iterator: I) -> Self {
745        let (_, upper) = iterator.size_hint();
746        let len = upper.expect("from_trusted_len_iter requires an upper limit");
747
748        Self::collect_bool(len, |_| iterator.next().unwrap())
749    }
750
751    /// Creates a [`MutableBuffer`] from an [`Iterator`] with a trusted (upper) length or errors
752    /// if any of the items of the iterator is an error.
753    /// Prefer this to `collect` whenever possible, as it is faster ~60% faster.
754    /// # Safety
755    /// This method assumes that the iterator's size is correct and is undefined behavior
756    /// to use it on an iterator that reports an incorrect length.
757    #[inline]
758    pub unsafe fn try_from_trusted_len_iter<
759        E,
760        T: ArrowNativeType,
761        I: Iterator<Item = Result<T, E>>,
762    >(
763        iterator: I,
764    ) -> Result<Self, E> {
765        let item_size = std::mem::size_of::<T>();
766        let (_, upper) = iterator.size_hint();
767        let upper = upper.expect("try_from_trusted_len_iter requires an upper limit");
768        let len = upper * item_size;
769
770        let mut buffer = MutableBuffer::new(len);
771
772        let mut dst = buffer.data.as_ptr();
773        for item in iterator {
774            let item = item?;
775            // note how there is no reserve here (compared with `extend_from_iter`)
776            let src = item.to_byte_slice().as_ptr();
777            unsafe { std::ptr::copy_nonoverlapping(src, dst, item_size) };
778            dst = unsafe { dst.add(item_size) };
779        }
780        // try_from_trusted_len_iter is instantiated a lot, so we extract part of it into a less
781        // generic method to reduce compile time
782        unsafe fn finalize_buffer(dst: *mut u8, buffer: &mut MutableBuffer, len: usize) {
783            unsafe {
784                assert_eq!(
785                    dst.offset_from(buffer.data.as_ptr()) as usize,
786                    len,
787                    "Trusted iterator length was not accurately reported"
788                );
789                buffer.len = len;
790            }
791        }
792        unsafe { finalize_buffer(dst, &mut buffer, len) };
793        Ok(buffer)
794    }
795}
796
797impl Default for MutableBuffer {
798    fn default() -> Self {
799        Self::with_capacity(0)
800    }
801}
802
803impl std::ops::Deref for MutableBuffer {
804    type Target = [u8];
805
806    fn deref(&self) -> &[u8] {
807        unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len) }
808    }
809}
810
811impl std::ops::DerefMut for MutableBuffer {
812    fn deref_mut(&mut self) -> &mut [u8] {
813        unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
814    }
815}
816
817impl AsRef<[u8]> for &MutableBuffer {
818    fn as_ref(&self) -> &[u8] {
819        self.as_slice()
820    }
821}
822
823impl Drop for MutableBuffer {
824    fn drop(&mut self) {
825        if self.layout.size() != 0 {
826            // Safety: data was allocated with standard allocator with given layout
827            unsafe { std::alloc::dealloc(self.data.as_ptr() as _, self.layout) };
828        }
829    }
830}
831
832impl PartialEq for MutableBuffer {
833    fn eq(&self, other: &MutableBuffer) -> bool {
834        if self.len != other.len {
835            return false;
836        }
837        if self.layout != other.layout {
838            return false;
839        }
840        self.as_slice() == other.as_slice()
841    }
842}
843
844unsafe impl Sync for MutableBuffer {}
845unsafe impl Send for MutableBuffer {}
846
847struct SetLenOnDrop<'a> {
848    len: &'a mut usize,
849    local_len: usize,
850}
851
852impl<'a> SetLenOnDrop<'a> {
853    #[inline]
854    fn new(len: &'a mut usize) -> Self {
855        SetLenOnDrop {
856            local_len: *len,
857            len,
858        }
859    }
860}
861
862impl Drop for SetLenOnDrop<'_> {
863    #[inline]
864    fn drop(&mut self) {
865        *self.len = self.local_len;
866    }
867}
868
869/// Creating a `MutableBuffer` instance by setting bits according to the boolean values
870impl std::iter::FromIterator<bool> for MutableBuffer {
871    fn from_iter<I>(iter: I) -> Self
872    where
873        I: IntoIterator<Item = bool>,
874    {
875        let mut iterator = iter.into_iter();
876        let mut result = {
877            let byte_capacity: usize = iterator.size_hint().0.saturating_add(7) / 8;
878            MutableBuffer::new(byte_capacity)
879        };
880
881        loop {
882            let mut exhausted = false;
883            let mut byte_accum: u8 = 0;
884            let mut mask: u8 = 1;
885
886            //collect (up to) 8 bits into a byte
887            while mask != 0 {
888                if let Some(value) = iterator.next() {
889                    byte_accum |= match value {
890                        true => mask,
891                        false => 0,
892                    };
893                    mask <<= 1;
894                } else {
895                    exhausted = true;
896                    break;
897                }
898            }
899
900            // break if the iterator was exhausted before it provided a bool for this byte
901            if exhausted && mask == 1 {
902                break;
903            }
904
905            //ensure we have capacity to write the byte
906            if result.len() == result.capacity() {
907                //no capacity for new byte, allocate 1 byte more (plus however many more the iterator advertises)
908                let additional_byte_capacity = 1usize.saturating_add(
909                    iterator.size_hint().0.saturating_add(7) / 8, //convert bit count to byte count, rounding up
910                );
911                result.reserve(additional_byte_capacity)
912            }
913
914            // Soundness: capacity was allocated above
915            unsafe { result.push_unchecked(byte_accum) };
916            if exhausted {
917                break;
918            }
919        }
920        result
921    }
922}
923
924impl<T: ArrowNativeType> std::iter::FromIterator<T> for MutableBuffer {
925    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
926        let mut buffer = Self::default();
927        buffer.extend_from_iter(iter.into_iter());
928        buffer
929    }
930}
931
932#[cfg(test)]
933mod tests {
934    use super::*;
935
936    #[test]
937    fn test_mutable_new() {
938        let buf = MutableBuffer::new(63);
939        assert_eq!(64, buf.capacity());
940        assert_eq!(0, buf.len());
941        assert!(buf.is_empty());
942    }
943
944    #[test]
945    fn test_mutable_default() {
946        let buf = MutableBuffer::default();
947        assert_eq!(0, buf.capacity());
948        assert_eq!(0, buf.len());
949        assert!(buf.is_empty());
950
951        let mut buf = MutableBuffer::default();
952        buf.extend_from_slice(b"hello");
953        assert_eq!(5, buf.len());
954        assert_eq!(b"hello", buf.as_slice());
955    }
956
957    #[test]
958    fn test_mutable_extend_from_slice() {
959        let mut buf = MutableBuffer::new(100);
960        buf.extend_from_slice(b"hello");
961        assert_eq!(5, buf.len());
962        assert_eq!(b"hello", buf.as_slice());
963
964        buf.extend_from_slice(b" world");
965        assert_eq!(11, buf.len());
966        assert_eq!(b"hello world", buf.as_slice());
967
968        buf.clear();
969        assert_eq!(0, buf.len());
970        buf.extend_from_slice(b"hello arrow");
971        assert_eq!(11, buf.len());
972        assert_eq!(b"hello arrow", buf.as_slice());
973    }
974
975    #[test]
976    fn mutable_extend_from_iter() {
977        let mut buf = MutableBuffer::new(0);
978        buf.extend(vec![1u32, 2]);
979        assert_eq!(8, buf.len());
980        assert_eq!(&[1u8, 0, 0, 0, 2, 0, 0, 0], buf.as_slice());
981
982        buf.extend(vec![3u32, 4]);
983        assert_eq!(16, buf.len());
984        assert_eq!(
985            &[1u8, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
986            buf.as_slice()
987        );
988    }
989
990    #[test]
991    fn mutable_extend_from_iter_unaligned_u64() {
992        let mut buf = MutableBuffer::new(16);
993        buf.push(1_u8);
994        buf.extend([1_u64]);
995        assert_eq!(9, buf.len());
996        assert_eq!(&[1u8, 1u8, 0, 0, 0, 0, 0, 0, 0], buf.as_slice());
997    }
998
999    #[test]
1000    fn mutable_extend_from_slice_unaligned_u64() {
1001        let mut buf = MutableBuffer::new(16);
1002        buf.extend_from_slice(&[1_u8]);
1003        buf.extend_from_slice(&[1_u64]);
1004        assert_eq!(9, buf.len());
1005        assert_eq!(&[1u8, 1u8, 0, 0, 0, 0, 0, 0, 0], buf.as_slice());
1006    }
1007
1008    #[test]
1009    fn mutable_push_unaligned_u64() {
1010        let mut buf = MutableBuffer::new(16);
1011        buf.push(1_u8);
1012        buf.push(1_u64);
1013        assert_eq!(9, buf.len());
1014        assert_eq!(&[1u8, 1u8, 0, 0, 0, 0, 0, 0, 0], buf.as_slice());
1015    }
1016
1017    #[test]
1018    fn mutable_push_unchecked_unaligned_u64() {
1019        let mut buf = MutableBuffer::new(16);
1020        unsafe {
1021            buf.push_unchecked(1_u8);
1022            buf.push_unchecked(1_u64);
1023        }
1024        assert_eq!(9, buf.len());
1025        assert_eq!(&[1u8, 1u8, 0, 0, 0, 0, 0, 0, 0], buf.as_slice());
1026    }
1027
1028    #[test]
1029    fn test_from_trusted_len_iter() {
1030        let iter = vec![1u32, 2].into_iter();
1031        let buf = unsafe { MutableBuffer::from_trusted_len_iter(iter) };
1032        assert_eq!(8, buf.len());
1033        assert_eq!(&[1u8, 0, 0, 0, 2, 0, 0, 0], buf.as_slice());
1034    }
1035
1036    #[test]
1037    fn test_mutable_reserve() {
1038        let mut buf = MutableBuffer::new(1);
1039        assert_eq!(64, buf.capacity());
1040
1041        // Reserving a smaller capacity should have no effect.
1042        buf.reserve(10);
1043        assert_eq!(64, buf.capacity());
1044
1045        buf.reserve(80);
1046        assert_eq!(128, buf.capacity());
1047
1048        buf.reserve(129);
1049        assert_eq!(256, buf.capacity());
1050    }
1051
1052    #[test]
1053    fn test_mutable_resize() {
1054        let mut buf = MutableBuffer::new(1);
1055        assert_eq!(64, buf.capacity());
1056        assert_eq!(0, buf.len());
1057
1058        buf.resize(20, 0);
1059        assert_eq!(64, buf.capacity());
1060        assert_eq!(20, buf.len());
1061
1062        buf.resize(10, 0);
1063        assert_eq!(64, buf.capacity());
1064        assert_eq!(10, buf.len());
1065
1066        buf.resize(100, 0);
1067        assert_eq!(128, buf.capacity());
1068        assert_eq!(100, buf.len());
1069
1070        buf.resize(30, 0);
1071        assert_eq!(128, buf.capacity());
1072        assert_eq!(30, buf.len());
1073
1074        buf.resize(0, 0);
1075        assert_eq!(128, buf.capacity());
1076        assert_eq!(0, buf.len());
1077    }
1078
1079    #[test]
1080    fn test_mutable_into() {
1081        let mut buf = MutableBuffer::new(1);
1082        buf.extend_from_slice(b"aaaa bbbb cccc dddd");
1083        assert_eq!(19, buf.len());
1084        assert_eq!(64, buf.capacity());
1085        assert_eq!(b"aaaa bbbb cccc dddd", buf.as_slice());
1086
1087        let immutable_buf: Buffer = buf.into();
1088        assert_eq!(19, immutable_buf.len());
1089        assert_eq!(64, immutable_buf.capacity());
1090        assert_eq!(b"aaaa bbbb cccc dddd", immutable_buf.as_slice());
1091    }
1092
1093    #[test]
1094    fn test_mutable_equal() {
1095        let mut buf = MutableBuffer::new(1);
1096        let mut buf2 = MutableBuffer::new(1);
1097
1098        buf.extend_from_slice(&[0xaa]);
1099        buf2.extend_from_slice(&[0xaa, 0xbb]);
1100        assert!(buf != buf2);
1101
1102        buf.extend_from_slice(&[0xbb]);
1103        assert_eq!(buf, buf2);
1104
1105        buf2.reserve(65);
1106        assert!(buf != buf2);
1107    }
1108
1109    #[test]
1110    fn test_mutable_shrink_to_fit() {
1111        let mut buffer = MutableBuffer::new(128);
1112        assert_eq!(buffer.capacity(), 128);
1113        buffer.push(1);
1114        buffer.push(2);
1115
1116        buffer.shrink_to_fit();
1117        assert!(buffer.capacity() >= 64 && buffer.capacity() < 128);
1118    }
1119
1120    #[test]
1121    fn test_mutable_set_null_bits() {
1122        let mut buffer = MutableBuffer::new(8).with_bitset(8, true);
1123
1124        for i in 0..=buffer.capacity() {
1125            buffer.set_null_bits(i, 0);
1126            assert_eq!(buffer[..8], [255; 8][..]);
1127        }
1128
1129        buffer.set_null_bits(1, 4);
1130        assert_eq!(buffer[..8], [255, 0, 0, 0, 0, 255, 255, 255][..]);
1131    }
1132
1133    #[test]
1134    #[should_panic = "out of bounds for buffer of length"]
1135    fn test_mutable_set_null_bits_oob() {
1136        let mut buffer = MutableBuffer::new(64);
1137        buffer.set_null_bits(1, buffer.capacity());
1138    }
1139
1140    #[test]
1141    #[should_panic = "out of bounds for buffer of length"]
1142    fn test_mutable_set_null_bits_oob_by_overflow() {
1143        let mut buffer = MutableBuffer::new(0);
1144        buffer.set_null_bits(1, usize::MAX);
1145    }
1146
1147    #[test]
1148    fn from_iter() {
1149        let buffer = [1u16, 2, 3, 4].into_iter().collect::<MutableBuffer>();
1150        assert_eq!(buffer.len(), 4 * mem::size_of::<u16>());
1151        assert_eq!(buffer.as_slice(), &[1, 0, 2, 0, 3, 0, 4, 0]);
1152    }
1153
1154    #[test]
1155    #[should_panic(expected = "failed to create layout for MutableBuffer: LayoutError")]
1156    fn test_with_capacity_panics_above_max_capacity() {
1157        let max_capacity = isize::MAX as usize - (isize::MAX as usize % ALIGNMENT);
1158        let _ = MutableBuffer::with_capacity(max_capacity + 1);
1159    }
1160
1161    #[cfg(feature = "pool")]
1162    mod pool_tests {
1163        use super::*;
1164        use crate::pool::{MemoryPool, TrackingMemoryPool};
1165
1166        #[test]
1167        fn test_reallocate_with_pool() {
1168            let pool = TrackingMemoryPool::default();
1169            let mut buffer = MutableBuffer::with_capacity(100);
1170            buffer.claim(&pool);
1171
1172            // Initial capacity should be 128 (multiple of 64)
1173            assert_eq!(buffer.capacity(), 128);
1174            assert_eq!(pool.used(), 128);
1175
1176            // Reallocate to a larger size
1177            buffer.reallocate(200);
1178
1179            // The capacity is exactly the requested size, not rounded up
1180            assert_eq!(buffer.capacity(), 200);
1181            assert_eq!(pool.used(), 200);
1182
1183            // Reallocate to a smaller size
1184            buffer.reallocate(50);
1185
1186            // The capacity is exactly the requested size, not rounded up
1187            assert_eq!(buffer.capacity(), 50);
1188            assert_eq!(pool.used(), 50);
1189        }
1190
1191        #[test]
1192        fn test_truncate_with_pool() {
1193            let pool = TrackingMemoryPool::default();
1194            let mut buffer = MutableBuffer::with_capacity(100);
1195
1196            // Fill buffer with some data
1197            buffer.resize(80, 1);
1198            assert_eq!(buffer.len(), 80);
1199
1200            buffer.claim(&pool);
1201            assert_eq!(pool.used(), 128);
1202
1203            // Truncate buffer
1204            buffer.truncate(40);
1205            assert_eq!(buffer.len(), 40);
1206            assert_eq!(pool.used(), 40);
1207
1208            // Truncate to zero
1209            buffer.truncate(0);
1210            assert_eq!(buffer.len(), 0);
1211            assert_eq!(pool.used(), 0);
1212        }
1213
1214        #[test]
1215        fn test_resize_with_pool() {
1216            let pool = TrackingMemoryPool::default();
1217            let mut buffer = MutableBuffer::with_capacity(100);
1218            buffer.claim(&pool);
1219
1220            // Initial state
1221            assert_eq!(buffer.len(), 0);
1222            assert_eq!(pool.used(), 128);
1223
1224            // Resize to increase length
1225            buffer.resize(50, 1);
1226            assert_eq!(buffer.len(), 50);
1227            assert_eq!(pool.used(), 50);
1228
1229            // Resize to increase length beyond capacity
1230            buffer.resize(150, 1);
1231            assert_eq!(buffer.len(), 150);
1232            assert_eq!(buffer.capacity(), 256);
1233            assert_eq!(pool.used(), 150);
1234
1235            // Resize to decrease length
1236            buffer.resize(30, 1);
1237            assert_eq!(buffer.len(), 30);
1238            assert_eq!(pool.used(), 30);
1239        }
1240
1241        #[test]
1242        fn test_buffer_lifecycle_with_pool() {
1243            let pool = TrackingMemoryPool::default();
1244
1245            // Create a buffer with memory reservation
1246            let mut mutable = MutableBuffer::with_capacity(100);
1247            mutable.resize(80, 1);
1248            mutable.claim(&pool);
1249
1250            // Memory reservation is based on capacity when using claim()
1251            assert_eq!(pool.used(), 128);
1252
1253            // Convert to immutable Buffer
1254            let buffer = mutable.into_buffer();
1255
1256            // Memory reservation should be preserved
1257            assert_eq!(pool.used(), 128);
1258
1259            // Drop the buffer and the reservation should be released
1260            drop(buffer);
1261            assert_eq!(pool.used(), 0);
1262        }
1263    }
1264
1265    fn create_expected_repeated_slice<T: ArrowNativeType>(
1266        slice_to_repeat: &[T],
1267        repeat_count: usize,
1268    ) -> Buffer {
1269        let mut expected = MutableBuffer::new(size_of_val(slice_to_repeat) * repeat_count);
1270        for _ in 0..repeat_count {
1271            // Not using push_slice_repeated as this is the function under test
1272            expected.extend_from_slice(slice_to_repeat);
1273        }
1274        expected.into()
1275    }
1276
1277    // Helper to test a specific repeat count with various slice sizes
1278    fn test_repeat_count<T: ArrowNativeType + PartialEq + std::fmt::Debug>(
1279        repeat_count: usize,
1280        test_data: &[T],
1281    ) {
1282        let mut buffer = MutableBuffer::new(0);
1283        buffer.repeat_slice_n_times(test_data, repeat_count);
1284
1285        let expected = create_expected_repeated_slice(test_data, repeat_count);
1286        let result: Buffer = buffer.into();
1287
1288        assert_eq!(
1289            result,
1290            expected,
1291            "Failed for repeat_count={}, slice_len={}",
1292            repeat_count,
1293            test_data.len()
1294        );
1295    }
1296
1297    #[test]
1298    fn test_repeat_slice_count_edge_cases() {
1299        // Empty slice
1300        test_repeat_count(100, &[] as &[i32]);
1301
1302        // Zero repeats
1303        test_repeat_count(0, &[1i32, 2, 3]);
1304    }
1305
1306    #[test]
1307    fn test_small_repeats_counts() {
1308        // test any special implementation for small repeat counts
1309        let data = &[1u8, 2, 3, 4, 5];
1310
1311        for _ in 1..=10 {
1312            test_repeat_count(2, data);
1313        }
1314    }
1315
1316    #[test]
1317    fn test_different_size_of_i32_repeat_slice() {
1318        let data: &[i32] = &[1, 2, 3];
1319        let data_with_single_item: &[i32] = &[42];
1320
1321        for data in &[data, data_with_single_item] {
1322            for item in 1..=9 {
1323                let base_repeat_count = 2_usize.pow(item);
1324                test_repeat_count(base_repeat_count - 1, data);
1325                test_repeat_count(base_repeat_count, data);
1326                test_repeat_count(base_repeat_count + 1, data);
1327            }
1328        }
1329    }
1330
1331    #[test]
1332    fn test_different_size_of_u8_repeat_slice() {
1333        let data: &[u8] = &[1, 2, 3];
1334        let data_with_single_item: &[u8] = &[10];
1335
1336        for data in &[data, data_with_single_item] {
1337            for item in 1..=9 {
1338                let base_repeat_count = 2_usize.pow(item);
1339                test_repeat_count(base_repeat_count - 1, data);
1340                test_repeat_count(base_repeat_count, data);
1341                test_repeat_count(base_repeat_count + 1, data);
1342            }
1343        }
1344    }
1345
1346    #[test]
1347    fn test_different_size_of_u16_repeat_slice() {
1348        let data: &[u16] = &[1, 2, 3];
1349        let data_with_single_item: &[u16] = &[10];
1350
1351        for data in &[data, data_with_single_item] {
1352            for item in 1..=9 {
1353                let base_repeat_count = 2_usize.pow(item);
1354                test_repeat_count(base_repeat_count - 1, data);
1355                test_repeat_count(base_repeat_count, data);
1356                test_repeat_count(base_repeat_count + 1, data);
1357            }
1358        }
1359    }
1360
1361    #[test]
1362    fn test_various_slice_lengths() {
1363        // Test different slice lengths with same repeat pattern
1364        let repeat_count = 37; // Arbitrary non-power-of-2
1365
1366        // Single element
1367        test_repeat_count(repeat_count, &[42i32]);
1368
1369        // Small slices
1370        test_repeat_count(repeat_count, &[1i32, 2]);
1371        test_repeat_count(repeat_count, &[1i32, 2, 3]);
1372        test_repeat_count(repeat_count, &[1i32, 2, 3, 4]);
1373        test_repeat_count(repeat_count, &[1i32, 2, 3, 4, 5]);
1374
1375        // Larger slices
1376        let data_10: Vec<i32> = (0..10).collect();
1377        test_repeat_count(repeat_count, &data_10);
1378
1379        let data_100: Vec<i32> = (0..100).collect();
1380        test_repeat_count(repeat_count, &data_100);
1381
1382        let data_1000: Vec<i32> = (0..1000).collect();
1383        test_repeat_count(repeat_count, &data_1000);
1384    }
1385}