Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/enums/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2759,6 +2759,28 @@ impl Array {
}
}

/// Appends rows `[offset..offset+len)` from another array into self.
/// Extends data and null masks directly from the source range.
pub fn concat_array_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
match (self, other) {
(Array::NumericArray(lhs), Array::NumericArray(rhs)) => lhs.append_range(rhs, offset, len),
(Array::BooleanArray(a), Array::BooleanArray(b)) => Arc::make_mut(a).append_range(b, offset, len),
(Array::TextArray(lhs), Array::TextArray(rhs)) => lhs.append_range(rhs, offset, len),
#[cfg(feature = "datetime")]
(Array::TemporalArray(lhs), Array::TemporalArray(rhs)) => lhs.append_range(rhs, offset, len),
(Array::Null, Array::Null) => Ok(()),
(lhs, rhs) => Err(MinarrowError::TypeError {
from: "Array",
to: "Array",
message: Some(format!(
"Cannot append_range {:?} into {:?}",
rhs.arrow_type(),
lhs.arrow_type()
)),
}),
}
}

/// Inserts all values (and null mask if present) from `other` into `self` at the specified index.
///
/// This is an **O(n)** operation.
Expand Down
25 changes: 25 additions & 0 deletions src/enums/collections/numeric_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,31 @@ impl NumericArray {
}
}

pub fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
match (self, other) {
#[cfg(feature = "extended_numeric_types")]
(NumericArray::Int8(a), NumericArray::Int8(b)) => Arc::make_mut(a).append_range(b, offset, len),
#[cfg(feature = "extended_numeric_types")]
(NumericArray::Int16(a), NumericArray::Int16(b)) => Arc::make_mut(a).append_range(b, offset, len),
(NumericArray::Int32(a), NumericArray::Int32(b)) => Arc::make_mut(a).append_range(b, offset, len),
(NumericArray::Int64(a), NumericArray::Int64(b)) => Arc::make_mut(a).append_range(b, offset, len),
#[cfg(feature = "extended_numeric_types")]
(NumericArray::UInt8(a), NumericArray::UInt8(b)) => Arc::make_mut(a).append_range(b, offset, len),
#[cfg(feature = "extended_numeric_types")]
(NumericArray::UInt16(a), NumericArray::UInt16(b)) => Arc::make_mut(a).append_range(b, offset, len),
(NumericArray::UInt32(a), NumericArray::UInt32(b)) => Arc::make_mut(a).append_range(b, offset, len),
(NumericArray::UInt64(a), NumericArray::UInt64(b)) => Arc::make_mut(a).append_range(b, offset, len),
(NumericArray::Float32(a), NumericArray::Float32(b)) => Arc::make_mut(a).append_range(b, offset, len),
(NumericArray::Float64(a), NumericArray::Float64(b)) => Arc::make_mut(a).append_range(b, offset, len),
(NumericArray::Null, NumericArray::Null) => Ok(()),
(lhs, rhs) => Err(MinarrowError::TypeError {
from: "NumericArray",
to: "NumericArray",
message: Some(format!("Cannot append_range {:?} into {:?}", rhs, lhs)),
}),
}
}

/// Inserts all values (and null mask if present) from `other` into `self` at the specified index.
///
/// This is an **O(n)** operation.
Expand Down
13 changes: 13 additions & 0 deletions src/enums/collections/temporal_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,19 @@ impl TemporalArray {
}
}

pub fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
match (self, other) {
(TemporalArray::Datetime32(a), TemporalArray::Datetime32(b)) => Arc::make_mut(a).append_range(b, offset, len),
(TemporalArray::Datetime64(a), TemporalArray::Datetime64(b)) => Arc::make_mut(a).append_range(b, offset, len),
(TemporalArray::Null, TemporalArray::Null) => Ok(()),
(lhs, rhs) => Err(MinarrowError::TypeError {
from: "TemporalArray",
to: "TemporalArray",
message: Some(format!("Cannot append_range {:?} into {:?}", rhs, lhs)),
}),
}
}

/// Inserts all values (and null mask if present) from `other` into `self` at the specified index.
///
/// This is an **O(n)** operation.
Expand Down
21 changes: 21 additions & 0 deletions src/enums/collections/text_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,27 @@ impl TextArray {
}
}

pub fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
match (self, other) {
(TextArray::String32(a), TextArray::String32(b)) => Arc::make_mut(a).append_range(b, offset, len),
#[cfg(feature = "large_string")]
(TextArray::String64(a), TextArray::String64(b)) => Arc::make_mut(a).append_range(b, offset, len),
#[cfg(feature = "extended_categorical")]
(TextArray::Categorical8(a), TextArray::Categorical8(b)) => Arc::make_mut(a).append_range(b, offset, len),
#[cfg(feature = "extended_categorical")]
(TextArray::Categorical16(a), TextArray::Categorical16(b)) => Arc::make_mut(a).append_range(b, offset, len),
(TextArray::Categorical32(a), TextArray::Categorical32(b)) => Arc::make_mut(a).append_range(b, offset, len),
#[cfg(feature = "extended_categorical")]
(TextArray::Categorical64(a), TextArray::Categorical64(b)) => Arc::make_mut(a).append_range(b, offset, len),
(TextArray::Null, TextArray::Null) => Ok(()),
(lhs, rhs) => Err(MinarrowError::TypeError {
from: "TextArray",
to: "TextArray",
message: Some(format!("Cannot append_range {:?} into {:?}", rhs, lhs)),
}),
}
}

/// Inserts all values (and null mask if present) from `other` into `self` at the specified index.
///
/// This is an **O(n)** operation.
Expand Down
34 changes: 34 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,34 @@ macro_rules! impl_masked_array {
}
}

fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), $crate::enums::error::MinarrowError> {
if len == 0 { return Ok(()); }
if offset + len > other.len() {
return Err($crate::enums::error::MinarrowError::IndexError(
format!("append_range: offset {} + len {} exceeds source length {}", offset, len, other.len())
));
}
let orig_len = self.len();

self.data_mut().extend_from_slice(&other.data()[offset..offset + len]);

match (self.null_mask_mut(), other.null_mask()) {
(Some(self_mask), Some(other_mask)) => {
self_mask.extend_from_bitmask_range(other_mask, offset, len);
}
(Some(self_mask), None) => {
self_mask.resize(orig_len + len, true);
}
(None, Some(other_mask)) => {
let mut mask = Bitmask::new_set_all(orig_len, true);
mask.extend_from_bitmask_range(other_mask, offset, len);
self.set_null_mask(Some(mask));
}
(None, None) => {}
}
Ok(())
}

/// Inserts all values (and null mask if present) from `other` into `self` at the specified index.
///
/// This is an **O(n)** operation.
Expand Down Expand Up @@ -933,6 +961,9 @@ macro_rules! impl_arc_masked_array {
fn append_array(&mut self, other: &Self) {
::std::sync::Arc::make_mut(self).append_array(&**other)
}
fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), $crate::enums::error::MinarrowError> {
::std::sync::Arc::make_mut(self).append_range(&**other, offset, len)
}
fn insert_rows(
&mut self,
index: usize,
Expand Down Expand Up @@ -1054,6 +1085,9 @@ macro_rules! impl_arc_masked_array {
fn append_array(&mut self, other: &Self) {
::std::sync::Arc::make_mut(self).append_array(&**other)
}
fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), $crate::enums::error::MinarrowError> {
::std::sync::Arc::make_mut(self).append_range(&**other, offset, len)
}
fn insert_rows(
&mut self,
index: usize,
Expand Down
29 changes: 29 additions & 0 deletions src/structs/bitmask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,35 @@ impl Bitmask {
}
}

/// Appends bits `[offset..offset+len)` from another bitmask into self.
/// Byte-aligned sources copy whole bytes directly. Unaligned sources
/// shift bytes to align before copying.
pub fn extend_from_bitmask_range(&mut self, other: &Bitmask, offset: usize, len: usize) {
if len == 0 { return; }
let src_bytes = other.bits.as_slice();
if offset & 7 == 0 {
// Source is byte-aligned - pass the bytes starting at the offset
self.extend_from_slice(&src_bytes[offset >> 3..], len);
} else {
// Unaligned source - shift bytes to produce an aligned slice
let src_byte_start = offset >> 3;
let bit_shift = (offset & 7) as u32;
let n_src_bytes = ((len + 7) >> 3) + 1; // +1 for the shifted tail
let end = (src_byte_start + n_src_bytes).min(src_bytes.len());
let mut shifted = Vec::with_capacity(n_src_bytes);
for i in src_byte_start..end {
let lo = src_bytes[i] >> bit_shift;
let hi = if i + 1 < src_bytes.len() {
src_bytes[i + 1] << (8 - bit_shift)
} else {
0
};
shifted.push(lo | hi);
}
self.extend_from_slice(&shifted, len);
}
}

/// Extends the bitmask by appending `len` bits from a bit-packed `[u8]` slice.
///
/// - `src`: The source byte slice (bit-packed; LSB = first bit).
Expand Down
8 changes: 8 additions & 0 deletions src/structs/field_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,14 @@ impl FieldArray {
self.refresh_null_count();
}

/// Appends rows `[offset..offset+len)` from another FieldArray into self.
/// Extends data directly from the source's backing buffer.
pub fn concat_range(&mut self, other: &FieldArray, offset: usize, len: usize) -> Result<(), MinarrowError> {
self.array.concat_array_range(&other.array, offset, len)?;
self.refresh_null_count();
Ok(())
}

/// Provides mutable access to the underlying array with automatic null_count refresh.
/// Uses copy-on-write semantics - clones array data if Arc reference count > 1.
/// Use this for operations that may change the null count.
Expand Down
29 changes: 29 additions & 0 deletions src/structs/variants/boolean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,35 @@ impl MaskedArray for BooleanArray<()> {
}
}

fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
if len == 0 { return Ok(()); }
if offset + len > other.len() {
return Err(MinarrowError::IndexError(
format!("append_range: offset {} + len {} exceeds source length {}", offset, len, other.len())
));
}
let orig_len = self.len();

self.data.extend_from_bitmask_range(&other.data, offset, len);
self.len += len;

match (self.null_mask_mut(), other.null_mask()) {
(Some(self_mask), Some(other_mask)) => {
self_mask.extend_from_bitmask_range(other_mask, offset, len);
}
(Some(self_mask), None) => {
self_mask.resize(orig_len + len, true);
}
(None, Some(other_mask)) => {
let mut mask = Bitmask::new_set_all(orig_len, true);
mask.extend_from_bitmask_range(other_mask, offset, len);
self.set_null_mask(Some(mask));
}
(None, None) => {}
}
Ok(())
}

/// Inserts all values from `other` into `self` at the specified index.
///
/// This is an O(n) operation for BooleanArray due to bit-packed data.
Expand Down
45 changes: 31 additions & 14 deletions src/structs/variants/categorical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -798,35 +798,52 @@ impl<T: Integer> MaskedArray for CategoricalArray<T> {
fn append_array(&mut self, other: &Self) {
let orig_len = self.len();
let other_len = other.len();
if other_len == 0 { return; }

if other_len == 0 {
return;
}

// Append data
self.data_mut().extend_from_slice(other.data());

// Handle null masks
match (self.null_mask_mut(), other.null_mask()) {
(Some(self_mask), Some(other_mask)) => {
self_mask.extend_from_bitmask(other_mask);
}
(Some(self_mask), None) => {
// Mark all appended as valid.
self_mask.resize(orig_len + other_len, true);
}
(None, Some(other_mask)) => {
// Materialise new null mask for self, all existing valid.
let mut mask = Bitmask::new_set_all(orig_len + other_len, true);
for i in 0..other_len {
mask.set(orig_len + i, other_mask.get(i));
}
let mut mask = Bitmask::new_set_all(orig_len, true);
mask.extend_from_bitmask(other_mask);
self.set_null_mask(Some(mask));
}
(None, None) => {
// No mask in either: nothing to do.
(None, None) => {}
}
}

fn append_range(&mut self, other: &Self, offset: usize, len: usize) -> Result<(), MinarrowError> {
if len == 0 { return Ok(()); }
if offset + len > other.len() {
return Err(MinarrowError::IndexError(
format!("append_range: offset {} + len {} exceeds source length {}", offset, len, other.len())
));
}
let orig_len = self.len();

self.data_mut().extend_from_slice(&other.data()[offset..offset + len]);

match (self.null_mask_mut(), other.null_mask()) {
(Some(self_mask), Some(other_mask)) => {
self_mask.extend_from_bitmask_range(other_mask, offset, len);
}
(Some(self_mask), None) => {
self_mask.resize(orig_len + len, true);
}
(None, Some(other_mask)) => {
let mut mask = Bitmask::new_set_all(orig_len, true);
mask.extend_from_bitmask_range(other_mask, offset, len);
self.set_null_mask(Some(mask));
}
(None, None) => {}
}
Ok(())
}

/// Inserts all values from `other` into `self` at the specified index.
Expand Down
Loading
Loading