use crate::buffer::ScalarBuffer;
use crate::{ArrowNativeType, MutableBuffer, OffsetBufferBuilder};
use std::ops::Deref;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OffsetBuffer<O: ArrowNativeType>(ScalarBuffer<O>);
impl<O: ArrowNativeType> OffsetBuffer<O> {
pub fn new(buffer: ScalarBuffer<O>) -> Self {
assert!(!buffer.is_empty(), "offsets cannot be empty");
assert!(
buffer[0] >= O::usize_as(0),
"offsets must be greater than 0"
);
assert!(
buffer.windows(2).all(|w| w[0] <= w[1]),
"offsets must be monotonically increasing"
);
Self(buffer)
}
pub unsafe fn new_unchecked(buffer: ScalarBuffer<O>) -> Self {
Self(buffer)
}
pub fn new_empty() -> Self {
let buffer = MutableBuffer::from_len_zeroed(std::mem::size_of::<O>());
Self(buffer.into_buffer().into())
}
pub fn new_zeroed(len: usize) -> Self {
let len_bytes = len
.checked_add(1)
.and_then(|o| o.checked_mul(std::mem::size_of::<O>()))
.expect("overflow");
let buffer = MutableBuffer::from_len_zeroed(len_bytes);
Self(buffer.into_buffer().into())
}
pub fn from_lengths<I>(lengths: I) -> Self
where
I: IntoIterator<Item = usize>,
{
let iter = lengths.into_iter();
let mut out = Vec::with_capacity(iter.size_hint().0 + 1);
out.push(O::usize_as(0));
let mut acc = 0_usize;
for length in iter {
acc = acc.checked_add(length).expect("usize overflow");
out.push(O::usize_as(acc))
}
O::from_usize(acc).expect("offset overflow");
Self(out.into())
}
pub fn from_repeated_length(length: usize, n: usize) -> Self {
if n == 0 {
return Self::new_empty();
}
if length == 0 {
return Self::new_zeroed(n);
}
length.checked_mul(n).expect("usize overflow");
O::from_usize(length * n).expect("offset overflow");
let offsets = (0..=n)
.map(|index| O::usize_as(index * length))
.collect::<Vec<O>>();
Self(ScalarBuffer::from(offsets))
}
pub fn lengths(&self) -> impl ExactSizeIterator<Item = usize> + '_ {
self.0.windows(2).map(|x| x[1].as_usize() - x[0].as_usize())
}
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
pub fn inner(&self) -> &ScalarBuffer<O> {
&self.0
}
pub fn into_inner(self) -> ScalarBuffer<O> {
self.0
}
#[cfg(feature = "pool")]
pub fn claim(&self, pool: &dyn crate::MemoryPool) {
self.0.claim(pool);
}
pub fn slice(&self, offset: usize, len: usize) -> Self {
Self(self.0.slice(offset, len.saturating_add(1)))
}
#[inline]
pub fn ptr_eq(&self, other: &Self) -> bool {
self.0.ptr_eq(&other.0)
}
}
impl<T: ArrowNativeType> Deref for OffsetBuffer<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: ArrowNativeType> AsRef<[T]> for OffsetBuffer<T> {
#[inline]
fn as_ref(&self) -> &[T] {
self
}
}
impl<O: ArrowNativeType> From<OffsetBufferBuilder<O>> for OffsetBuffer<O> {
fn from(value: OffsetBufferBuilder<O>) -> Self {
value.finish()
}
}
impl<O: ArrowNativeType> Default for OffsetBuffer<O> {
fn default() -> Self {
Self::new_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic(expected = "offsets cannot be empty")]
fn empty_offsets() {
OffsetBuffer::new(Vec::<i32>::new().into());
}
#[test]
#[should_panic(expected = "offsets must be greater than 0")]
fn negative_offsets() {
OffsetBuffer::new(vec![-1, 0, 1].into());
}
#[test]
fn offsets() {
OffsetBuffer::new(vec![0, 1, 2, 3].into());
let offsets = OffsetBuffer::<i32>::new_zeroed(3);
assert_eq!(offsets.as_ref(), &[0; 4]);
let offsets = OffsetBuffer::<i32>::new_zeroed(0);
assert_eq!(offsets.as_ref(), &[0; 1]);
}
#[test]
#[should_panic(expected = "overflow")]
fn offsets_new_zeroed_overflow() {
OffsetBuffer::<i32>::new_zeroed(usize::MAX);
}
#[test]
#[should_panic(expected = "offsets must be monotonically increasing")]
fn non_monotonic_offsets() {
OffsetBuffer::new(vec![1, 2, 0].into());
}
#[test]
fn from_lengths() {
let buffer = OffsetBuffer::<i32>::from_lengths([2, 6, 3, 7, 2]);
assert_eq!(buffer.as_ref(), &[0, 2, 8, 11, 18, 20]);
let half_max = i32::MAX / 2;
let buffer = OffsetBuffer::<i32>::from_lengths([half_max as usize, half_max as usize]);
assert_eq!(buffer.as_ref(), &[0, half_max, half_max * 2]);
}
#[test]
#[should_panic(expected = "offset overflow")]
fn from_lengths_offset_overflow() {
OffsetBuffer::<i32>::from_lengths([i32::MAX as usize, 1]);
}
#[test]
#[should_panic(expected = "usize overflow")]
fn from_lengths_usize_overflow() {
OffsetBuffer::<i32>::from_lengths([usize::MAX, 1]);
}
#[test]
#[should_panic(expected = "offset overflow")]
fn from_repeated_lengths_offset_length_overflow() {
OffsetBuffer::<i32>::from_repeated_length(i32::MAX as usize / 4, 5);
}
#[test]
#[should_panic(expected = "offset overflow")]
fn from_repeated_lengths_offset_repeat_overflow() {
OffsetBuffer::<i32>::from_repeated_length(1, i32::MAX as usize + 1);
}
#[test]
#[should_panic(expected = "offset overflow")]
fn from_repeated_lengths_usize_length_overflow() {
OffsetBuffer::<i32>::from_repeated_length(usize::MAX, 1);
}
#[test]
#[should_panic(expected = "usize overflow")]
fn from_repeated_lengths_usize_length_usize_overflow() {
OffsetBuffer::<i32>::from_repeated_length(usize::MAX, 2);
}
#[test]
#[should_panic(expected = "offset overflow")]
fn from_repeated_lengths_usize_repeat_overflow() {
OffsetBuffer::<i32>::from_repeated_length(1, usize::MAX);
}
#[test]
fn get_lengths() {
let offsets = OffsetBuffer::<i32>::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]));
assert_eq!(offsets.lengths().collect::<Vec<usize>>(), vec![1, 3, 5]);
}
#[test]
fn get_lengths_should_be_with_fixed_size() {
let offsets = OffsetBuffer::<i32>::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]));
let iter = offsets.lengths();
assert_eq!(iter.size_hint(), (3, Some(3)));
assert_eq!(iter.len(), 3);
}
#[test]
fn get_lengths_from_empty_offset_buffer_should_be_empty_iterator() {
let offsets = OffsetBuffer::<i32>::new_empty();
assert_eq!(offsets.lengths().collect::<Vec<usize>>(), vec![]);
}
#[test]
fn impl_eq() {
fn are_equal<T: Eq>(a: &T, b: &T) -> bool {
a.eq(b)
}
assert!(
are_equal(
&OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9])),
&OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]))
),
"OffsetBuffer should implement Eq."
);
}
#[test]
fn impl_default() {
let default = OffsetBuffer::<i32>::default();
assert_eq!(default.as_ref(), &[0]);
}
#[test]
fn from_repeated_length_basic() {
let buffer = OffsetBuffer::<i32>::from_repeated_length(4, 3);
assert_eq!(buffer.as_ref(), &[0, 4, 8, 12]);
let lengths: Vec<usize> = buffer.lengths().collect();
assert_eq!(lengths, vec![4, 4, 4]);
}
#[test]
fn from_repeated_length_single_repeat() {
let buffer = OffsetBuffer::<i32>::from_repeated_length(5, 1);
assert_eq!(buffer.as_ref(), &[0, 5]);
let lengths: Vec<usize> = buffer.lengths().collect();
assert_eq!(lengths, vec![5]);
}
#[test]
fn from_repeated_length_zero_repeats() {
let buffer = OffsetBuffer::<i32>::from_repeated_length(10, 0);
assert_eq!(buffer, OffsetBuffer::<i32>::new_empty());
}
#[test]
fn from_repeated_length_zero_length() {
let buffer = OffsetBuffer::<i32>::from_repeated_length(0, 5);
assert_eq!(buffer.as_ref(), &[0, 0, 0, 0, 0, 0]);
let lengths: Vec<usize> = buffer.lengths().collect();
assert_eq!(lengths, vec![0, 0, 0, 0, 0]);
}
#[test]
fn from_repeated_length_large_values() {
let buffer = OffsetBuffer::<i32>::from_repeated_length(1000, 100);
assert_eq!(buffer[0], 0);
let lengths: Vec<usize> = buffer.lengths().collect();
assert_eq!(lengths.len(), 100);
assert!(lengths.iter().all(|&len| len == 1000));
}
#[test]
fn from_repeated_length_unit_length() {
let buffer = OffsetBuffer::<i32>::from_repeated_length(1, 10);
assert_eq!(buffer.as_ref(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let lengths: Vec<usize> = buffer.lengths().collect();
assert_eq!(lengths, vec![1; 10]);
}
#[test]
fn from_repeated_length_max_safe_values() {
let third_max = (i32::MAX / 3) as usize;
let buffer = OffsetBuffer::<i32>::from_repeated_length(third_max, 2);
assert_eq!(
buffer.as_ref(),
&[0, third_max as i32, (third_max * 2) as i32]
);
}
}