Skip to main content

arrow_data/transform/
mod.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
18//! Low-level array data abstractions.
19//!
20//! Provides utilities for creating, manipulating, and converting Arrow arrays
21//! made of primitive types, strings, and nested types.
22
23use super::{ArrayData, ArrayDataBuilder, ByteView, data::new_buffers};
24use crate::bit_mask::set_bits;
25use arrow_buffer::buffer::{BooleanBuffer, NullBuffer};
26use arrow_buffer::{ArrowNativeType, Buffer, IntervalMonthDayNano, MutableBuffer, bit_util, i256};
27use arrow_schema::{ArrowError, DataType, IntervalUnit, UnionMode};
28use half::f16;
29use num_integer::Integer;
30use std::mem;
31
32mod boolean;
33mod fixed_binary;
34mod fixed_size_list;
35mod list;
36mod list_view;
37mod null;
38mod primitive;
39mod run;
40mod structure;
41mod union;
42mod utils;
43mod variable_size;
44
45type ExtendNullBits<'a> = Box<dyn Fn(&mut _MutableArrayData, usize, usize) + 'a>;
46// function that extends `[start..start+len]` to the mutable array.
47// this is dynamic because different data_types influence how buffers and children are extended.
48type Extend<'a> =
49    Box<dyn Fn(&mut _MutableArrayData, usize, usize, usize) -> Result<(), ArrowError> + 'a>;
50
51type ExtendNulls = Box<dyn Fn(&mut _MutableArrayData, usize) -> Result<(), ArrowError>>;
52
53/// A mutable [ArrayData] that knows how to freeze itself into an [ArrayData].
54/// This is just a data container.
55#[derive(Debug)]
56struct _MutableArrayData<'a> {
57    pub data_type: DataType,
58    pub null_count: usize,
59
60    pub len: usize,
61    pub null_buffer: Option<MutableBuffer>,
62
63    // arrow specification only allows up to 3 buffers (2 ignoring the nulls above).
64    // Thus, we place them in the stack to avoid bound checks and greater data locality.
65    pub buffer1: MutableBuffer,
66    pub buffer2: MutableBuffer,
67    pub child_data: Vec<MutableArrayData<'a>>,
68}
69
70impl _MutableArrayData<'_> {
71    fn null_buffer(&mut self) -> &mut MutableBuffer {
72        self.null_buffer
73            .as_mut()
74            .expect("MutableArrayData not nullable")
75    }
76}
77
78fn build_extend_null_bits(array: &ArrayData, use_nulls: bool) -> ExtendNullBits<'_> {
79    if let Some(nulls) = array.nulls() {
80        let bytes = nulls.validity();
81        Box::new(move |mutable, start, len| {
82            let mutable_len = mutable.len;
83            let out = mutable.null_buffer();
84            utils::resize_for_bits(out, mutable_len + len);
85            mutable.null_count += set_bits(
86                out.as_slice_mut(),
87                bytes,
88                mutable_len,
89                nulls.offset() + start,
90                len,
91            );
92        })
93    } else if use_nulls {
94        Box::new(|mutable, _, len| {
95            let mutable_len = mutable.len;
96            let out = mutable.null_buffer();
97            utils::resize_for_bits(out, mutable_len + len);
98            let write_data = out.as_slice_mut();
99            (0..len).for_each(|i| {
100                bit_util::set_bit(write_data, mutable_len + i);
101            });
102        })
103    } else {
104        Box::new(|_, _, _| {})
105    }
106}
107
108/// Efficiently create an [ArrayData] from one or more existing [ArrayData]s by
109/// copying chunks.
110///
111/// The main use case of this struct is to perform unary operations to arrays of
112/// arbitrary types, such as `filter` and `take`.
113///
114/// # Example
115/// ```
116/// use arrow_buffer::Buffer;
117/// use arrow_data::ArrayData;
118/// use arrow_data::transform::MutableArrayData;
119/// use arrow_schema::DataType;
120/// fn i32_array(values: &[i32]) -> ArrayData {
121///   ArrayData::try_new(DataType::Int32, values.len(), None, 0, vec![Buffer::from_slice_ref(values)], vec![]).unwrap()
122/// }
123/// let arr1  = i32_array(&[1, 2, 3, 4, 5]);
124/// let arr2  = i32_array(&[6, 7, 8, 9, 10]);
125/// // Create a mutable array for copying values from arr1 and arr2, with a capacity for 6 elements
126/// let capacity = 3 * std::mem::size_of::<i32>();
127/// let mut mutable = MutableArrayData::new(vec![&arr1, &arr2], false, 10);
128/// // Copy the first 3 elements from arr1
129/// mutable.extend(0, 0, 3);
130/// // Copy the last 3 elements from arr2
131/// mutable.extend(1, 2, 5);
132/// // Complete the MutableArrayData into a new ArrayData
133/// let frozen = mutable.freeze();
134/// assert_eq!(frozen, i32_array(&[1, 2, 3, 8, 9, 10]));
135/// ```
136pub struct MutableArrayData<'a> {
137    /// Input arrays: the data being read FROM.
138    ///
139    /// Note all actual reads of the arrays go through the closures for extending
140    /// values and nulls; these references are only kept for bounds checking.
141    arrays: Vec<&'a ArrayData>,
142
143    /// In progress output array: The data being written TO
144    ///
145    /// Note these fields are in a separate struct, [_MutableArrayData], as they
146    /// cannot be in [MutableArrayData] itself due to mutability invariants (interior
147    /// mutability): [MutableArrayData] contains a function that can only mutate
148    /// [_MutableArrayData], not [MutableArrayData] itself
149    data: _MutableArrayData<'a>,
150
151    /// The child data of the `Array` in Dictionary arrays.
152    ///
153    /// This is not stored in `_MutableArrayData` because these values are
154    /// constant and only needed at the end, when freezing [_MutableArrayData].
155    dictionary: Option<ArrayData>,
156
157    /// Variadic data buffers referenced by views.
158    ///
159    /// Note this this is not stored in `_MutableArrayData` because these values
160    /// are constant and only needed at the end, when freezing
161    /// [_MutableArrayData]
162    variadic_data_buffers: Vec<Buffer>,
163
164    /// function used to extend output array with values from input arrays.
165    ///
166    /// This function's lifetime is bound to the input arrays because it reads
167    /// values from them.
168    extend_values: Vec<Extend<'a>>,
169
170    /// function used to extend the output array with nulls from input arrays.
171    ///
172    /// This function's lifetime is bound to the input arrays because it reads
173    /// nulls from it.
174    extend_null_bits: Vec<ExtendNullBits<'a>>,
175
176    /// function used to extend the output array with null elements.
177    ///
178    /// This function is independent of the arrays and therefore has no lifetime.
179    extend_nulls: ExtendNulls,
180}
181
182impl std::fmt::Debug for MutableArrayData<'_> {
183    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
184        // ignores the closures.
185        f.debug_struct("MutableArrayData")
186            .field("data", &self.data)
187            .finish()
188    }
189}
190
191/// Builds an extend that adds `offset` to the source primitive
192/// Additionally validates that `max` fits into the
193/// the underlying primitive returning None if not
194fn build_extend_dictionary(array: &ArrayData, offset: usize, max: usize) -> Option<Extend<'_>> {
195    macro_rules! validate_and_build {
196        ($dt: ty) => {{
197            // `max` is the merged dictionary length; the largest key index is
198            // `max - 1`, so the key type only needs to hold `max - 1` (e.g. 256
199            // values use keys 0..=255, which fit in u8).
200            let _: $dt = max.saturating_sub(1).try_into().ok()?;
201            let offset: $dt = offset.try_into().ok()?;
202            Some(primitive::build_extend_with_offset(array, offset))
203        }};
204    }
205    match array.data_type() {
206        DataType::Dictionary(child_data_type, _) => match child_data_type.as_ref() {
207            DataType::UInt8 => validate_and_build!(u8),
208            DataType::UInt16 => validate_and_build!(u16),
209            DataType::UInt32 => validate_and_build!(u32),
210            DataType::UInt64 => validate_and_build!(u64),
211            DataType::Int8 => validate_and_build!(i8),
212            DataType::Int16 => validate_and_build!(i16),
213            DataType::Int32 => validate_and_build!(i32),
214            DataType::Int64 => validate_and_build!(i64),
215            _ => unreachable!(),
216        },
217        _ => None,
218    }
219}
220
221/// Builds an extend that adds `buffer_offset` to any buffer indices encountered
222fn build_extend_view(array: &ArrayData, buffer_offset: u32) -> Extend<'_> {
223    let views = array.buffer::<u128>(0);
224    Box::new(
225        move |mutable: &mut _MutableArrayData, _, start: usize, len: usize| {
226            mutable
227                .buffer1
228                .extend(views[start..start + len].iter().map(|v| {
229                    let len = *v as u32;
230                    if len <= 12 {
231                        return *v; // Stored inline
232                    }
233                    let mut view = ByteView::from(*v);
234                    view.buffer_index += buffer_offset;
235                    view.into()
236                }));
237            Ok(())
238        },
239    )
240}
241
242fn build_extend(array: &ArrayData) -> Extend<'_> {
243    match array.data_type() {
244        DataType::Null => null::build_extend(array),
245        DataType::Boolean => boolean::build_extend(array),
246        DataType::UInt8 => primitive::build_extend::<u8>(array),
247        DataType::UInt16 => primitive::build_extend::<u16>(array),
248        DataType::UInt32 => primitive::build_extend::<u32>(array),
249        DataType::UInt64 => primitive::build_extend::<u64>(array),
250        DataType::Int8 => primitive::build_extend::<i8>(array),
251        DataType::Int16 => primitive::build_extend::<i16>(array),
252        DataType::Int32 => primitive::build_extend::<i32>(array),
253        DataType::Int64 => primitive::build_extend::<i64>(array),
254        DataType::Float32 => primitive::build_extend::<f32>(array),
255        DataType::Float64 => primitive::build_extend::<f64>(array),
256        DataType::Date32 | DataType::Time32(_) | DataType::Interval(IntervalUnit::YearMonth) => {
257            primitive::build_extend::<i32>(array)
258        }
259        DataType::Date64
260        | DataType::Time64(_)
261        | DataType::Timestamp(_, _)
262        | DataType::Duration(_)
263        | DataType::Interval(IntervalUnit::DayTime) => primitive::build_extend::<i64>(array),
264        DataType::Interval(IntervalUnit::MonthDayNano) => {
265            primitive::build_extend::<IntervalMonthDayNano>(array)
266        }
267        DataType::Decimal32(_, _) => primitive::build_extend::<i32>(array),
268        DataType::Decimal64(_, _) => primitive::build_extend::<i64>(array),
269        DataType::Decimal128(_, _) => primitive::build_extend::<i128>(array),
270        DataType::Decimal256(_, _) => primitive::build_extend::<i256>(array),
271        DataType::Utf8 | DataType::Binary => variable_size::build_extend::<i32>(array),
272        DataType::LargeUtf8 | DataType::LargeBinary => variable_size::build_extend::<i64>(array),
273        DataType::BinaryView | DataType::Utf8View => unreachable!("should use build_extend_view"),
274        DataType::Map(_, _) | DataType::List(_) => list::build_extend::<i32>(array),
275        DataType::LargeList(_) => list::build_extend::<i64>(array),
276        DataType::ListView(_) => list_view::build_extend::<i32>(array),
277        DataType::LargeListView(_) => list_view::build_extend::<i64>(array),
278        DataType::Dictionary(_, _) => unreachable!("should use build_extend_dictionary"),
279        DataType::Struct(_) => structure::build_extend(array),
280        DataType::FixedSizeBinary(_) => fixed_binary::build_extend(array),
281        DataType::Float16 => primitive::build_extend::<f16>(array),
282        DataType::FixedSizeList(_, _) => fixed_size_list::build_extend(array),
283        DataType::Union(_, mode) => match mode {
284            UnionMode::Sparse => union::build_extend_sparse(array),
285            UnionMode::Dense => union::build_extend_dense(array),
286        },
287        DataType::RunEndEncoded(_, _) => run::build_extend(array),
288    }
289}
290
291fn build_extend_nulls(data_type: &DataType) -> ExtendNulls {
292    Box::new(match data_type {
293        DataType::Null => null::extend_nulls,
294        DataType::Boolean => boolean::extend_nulls,
295        DataType::UInt8 => primitive::extend_nulls::<u8>,
296        DataType::UInt16 => primitive::extend_nulls::<u16>,
297        DataType::UInt32 => primitive::extend_nulls::<u32>,
298        DataType::UInt64 => primitive::extend_nulls::<u64>,
299        DataType::Int8 => primitive::extend_nulls::<i8>,
300        DataType::Int16 => primitive::extend_nulls::<i16>,
301        DataType::Int32 => primitive::extend_nulls::<i32>,
302        DataType::Int64 => primitive::extend_nulls::<i64>,
303        DataType::Float32 => primitive::extend_nulls::<f32>,
304        DataType::Float64 => primitive::extend_nulls::<f64>,
305        DataType::Date32 | DataType::Time32(_) | DataType::Interval(IntervalUnit::YearMonth) => {
306            primitive::extend_nulls::<i32>
307        }
308        DataType::Date64
309        | DataType::Time64(_)
310        | DataType::Timestamp(_, _)
311        | DataType::Duration(_)
312        | DataType::Interval(IntervalUnit::DayTime) => primitive::extend_nulls::<i64>,
313        DataType::Interval(IntervalUnit::MonthDayNano) => {
314            primitive::extend_nulls::<IntervalMonthDayNano>
315        }
316        DataType::Decimal32(_, _) => primitive::extend_nulls::<i32>,
317        DataType::Decimal64(_, _) => primitive::extend_nulls::<i64>,
318        DataType::Decimal128(_, _) => primitive::extend_nulls::<i128>,
319        DataType::Decimal256(_, _) => primitive::extend_nulls::<i256>,
320        DataType::Utf8 | DataType::Binary => variable_size::extend_nulls::<i32>,
321        DataType::LargeUtf8 | DataType::LargeBinary => variable_size::extend_nulls::<i64>,
322        DataType::BinaryView | DataType::Utf8View => primitive::extend_nulls::<u128>,
323        DataType::Map(_, _) | DataType::List(_) => list::extend_nulls::<i32>,
324        DataType::LargeList(_) => list::extend_nulls::<i64>,
325        DataType::ListView(_) => list_view::extend_nulls::<i32>,
326        DataType::LargeListView(_) => list_view::extend_nulls::<i64>,
327        DataType::Dictionary(child_data_type, _) => match child_data_type.as_ref() {
328            DataType::UInt8 => primitive::extend_nulls::<u8>,
329            DataType::UInt16 => primitive::extend_nulls::<u16>,
330            DataType::UInt32 => primitive::extend_nulls::<u32>,
331            DataType::UInt64 => primitive::extend_nulls::<u64>,
332            DataType::Int8 => primitive::extend_nulls::<i8>,
333            DataType::Int16 => primitive::extend_nulls::<i16>,
334            DataType::Int32 => primitive::extend_nulls::<i32>,
335            DataType::Int64 => primitive::extend_nulls::<i64>,
336            _ => unreachable!(),
337        },
338        DataType::Struct(_) => structure::extend_nulls,
339        DataType::FixedSizeBinary(_) => fixed_binary::extend_nulls,
340        DataType::Float16 => primitive::extend_nulls::<f16>,
341        DataType::FixedSizeList(_, _) => fixed_size_list::extend_nulls,
342        DataType::Union(_, mode) => match mode {
343            UnionMode::Sparse => union::extend_nulls_sparse,
344            UnionMode::Dense => union::extend_nulls_dense,
345        },
346        DataType::RunEndEncoded(_, _) => run::extend_nulls,
347    })
348}
349
350fn preallocate_offset_and_binary_buffer<Offset: ArrowNativeType + Integer>(
351    capacity: usize,
352    binary_size: usize,
353) -> [MutableBuffer; 2] {
354    // offsets
355    let mut buffer = MutableBuffer::new((1 + capacity) * mem::size_of::<Offset>());
356    // safety: `unsafe` code assumes that this buffer is initialized with one element
357    buffer.push(Offset::zero());
358
359    [
360        buffer,
361        MutableBuffer::new(binary_size * mem::size_of::<u8>()),
362    ]
363}
364
365/// Define capacities to pre-allocate for child data or data buffers.
366#[derive(Debug, Clone)]
367pub enum Capacities {
368    /// Binary, Utf8 and LargeUtf8 data types
369    ///
370    /// Defines
371    /// * the capacity of the array offsets
372    /// * the capacity of the binary/ str buffer
373    Binary(usize, Option<usize>),
374    /// List, LargeList and Map data types
375    ///
376    /// Defines
377    /// * the capacity of the array offsets
378    /// * the capacity of the child data
379    ///
380    /// For Map the child data is the entries [`DataType::Struct`], so the child
381    /// capacity is a [`Capacities::Struct`] holding the key and value capacities.
382    List(usize, Option<Box<Capacities>>),
383    /// Struct type
384    ///
385    /// Defines
386    /// * the capacity of the array
387    /// * the capacities of the fields
388    Struct(usize, Option<Vec<Capacities>>),
389    /// Dictionary type
390    ///
391    /// Defines
392    /// * the capacity of the array/keys
393    /// * the capacity of the values
394    Dictionary(usize, Option<Box<Capacities>>),
395    /// Don't preallocate inner buffers and rely on array growth strategy
396    Array(usize),
397}
398
399impl<'a> MutableArrayData<'a> {
400    /// Returns a new [MutableArrayData] with capacity to `capacity` slots and
401    /// specialized to create an [ArrayData] from multiple `arrays`.
402    ///
403    /// # Arguments
404    /// * `arrays` - the source arrays to copy from
405    /// * `use_nulls` - a flag indicating whether the caller intends to call `extend_nulls`.
406    ///   Note: null-handling is enabled automatically if any source array contains nulls.
407    /// * `capacity` - the preallocated capacity of the output array, in slots (number of elements)
408    ///
409    /// if `use_nulls` is `false` and no source arrays contains nulls, calling
410    /// [MutableArrayData::extend_nulls] or [MutableArrayData::try_extend_nulls] will panic.
411    pub fn new(arrays: Vec<&'a ArrayData>, use_nulls: bool, capacity: usize) -> Self {
412        Self::with_capacities(arrays, use_nulls, Capacities::Array(capacity))
413    }
414
415    /// Fallible variant of [MutableArrayData::new].
416    ///
417    /// Unlike [MutableArrayData::new], this does not panic when merging dictionary
418    /// arrays whose combined values would overflow the dictionary key type. Instead,
419    /// it returns an error, letting callers (e.g. [`interleave`](crate) / `concat`)
420    /// surface it as a normal error.
421    pub fn try_new(
422        arrays: Vec<&'a ArrayData>,
423        use_nulls: bool,
424        capacity: usize,
425    ) -> Result<Self, ArrowError> {
426        Self::try_with_capacities(arrays, use_nulls, Capacities::Array(capacity))
427    }
428
429    /// Similar to [MutableArrayData::new], but lets users define the
430    /// preallocated capacities of the array with more granularity.
431    ///
432    /// See [MutableArrayData::new] for more information on the arguments.
433    ///
434    /// # Panics
435    ///
436    /// * if the given `capacities` don't match the data type of `arrays`
437    /// * if a [Capacities] variant is not yet supported
438    /// * when merging dictionary arrays whose combined values overflow the
439    ///   dictionary key type — see [MutableArrayData::try_with_capacities] for a
440    ///   fallible variant
441    pub fn with_capacities(
442        arrays: Vec<&'a ArrayData>,
443        use_nulls: bool,
444        capacities: Capacities,
445    ) -> Self {
446        Self::try_with_capacities(arrays, use_nulls, capacities)
447            .expect("MutableArrayData::new is infallible")
448    }
449
450    /// Fallible variant of [MutableArrayData::with_capacities].
451    ///
452    /// Returns an error instead of panicking when merging dictionary arrays whose
453    /// combined values would overflow the dictionary key type. Still panics for
454    /// other unsupported combinations (inconsistent input types, unsupported
455    /// `Capacities` variants) as documented on [MutableArrayData::with_capacities].
456    pub fn try_with_capacities(
457        arrays: Vec<&'a ArrayData>,
458        use_nulls: bool,
459        capacities: Capacities,
460    ) -> Result<Self, ArrowError> {
461        let data_type = arrays[0].data_type();
462
463        for a in arrays.iter().skip(1) {
464            assert_eq!(
465                data_type,
466                a.data_type(),
467                "Arrays with inconsistent types passed to MutableArrayData"
468            )
469        }
470
471        // if any of the arrays has nulls, insertions from any array requires setting bits
472        // as there is at least one array with nulls.
473        let use_nulls = use_nulls | arrays.iter().any(|array| array.null_count() > 0);
474
475        let mut array_capacity;
476
477        let [buffer1, buffer2] = match (data_type, &capacities) {
478            (
479                DataType::LargeUtf8 | DataType::LargeBinary,
480                Capacities::Binary(capacity, Some(value_cap)),
481            ) => {
482                array_capacity = *capacity;
483                preallocate_offset_and_binary_buffer::<i64>(*capacity, *value_cap)
484            }
485            (DataType::Utf8 | DataType::Binary, Capacities::Binary(capacity, Some(value_cap))) => {
486                array_capacity = *capacity;
487                preallocate_offset_and_binary_buffer::<i32>(*capacity, *value_cap)
488            }
489            (_, Capacities::Array(capacity)) => {
490                array_capacity = *capacity;
491                new_buffers(data_type, *capacity)
492            }
493            (
494                DataType::List(_)
495                | DataType::LargeList(_)
496                | DataType::ListView(_)
497                | DataType::LargeListView(_)
498                | DataType::FixedSizeList(_, _)
499                | DataType::Map(_, _),
500                Capacities::List(capacity, _),
501            ) => {
502                array_capacity = *capacity;
503                new_buffers(data_type, *capacity)
504            }
505            (DataType::Struct(_), Capacities::Struct(capacity, _)) => {
506                array_capacity = *capacity;
507                new_buffers(data_type, *capacity)
508            }
509            _ => panic!("Capacities: {capacities:?} not yet supported"),
510        };
511
512        let child_data = match &data_type {
513            DataType::Decimal32(_, _)
514            | DataType::Decimal64(_, _)
515            | DataType::Decimal128(_, _)
516            | DataType::Decimal256(_, _)
517            | DataType::Null
518            | DataType::Boolean
519            | DataType::UInt8
520            | DataType::UInt16
521            | DataType::UInt32
522            | DataType::UInt64
523            | DataType::Int8
524            | DataType::Int16
525            | DataType::Int32
526            | DataType::Int64
527            | DataType::Float16
528            | DataType::Float32
529            | DataType::Float64
530            | DataType::Date32
531            | DataType::Date64
532            | DataType::Time32(_)
533            | DataType::Time64(_)
534            | DataType::Duration(_)
535            | DataType::Timestamp(_, _)
536            | DataType::Utf8
537            | DataType::Binary
538            | DataType::LargeUtf8
539            | DataType::LargeBinary
540            | DataType::BinaryView
541            | DataType::Utf8View
542            | DataType::Interval(_)
543            | DataType::FixedSizeBinary(_) => vec![],
544            DataType::Map(_, _)
545            | DataType::List(_)
546            | DataType::LargeList(_)
547            | DataType::ListView(_)
548            | DataType::LargeListView(_) => {
549                let children = arrays
550                    .iter()
551                    .map(|array| &array.child_data()[0])
552                    .collect::<Vec<_>>();
553
554                let capacities =
555                    if let Capacities::List(capacity, ref child_capacities) = capacities {
556                        child_capacities
557                            .clone()
558                            .map(|c| *c)
559                            .unwrap_or(Capacities::Array(capacity))
560                    } else {
561                        Capacities::Array(array_capacity)
562                    };
563
564                vec![MutableArrayData::try_with_capacities(
565                    children, use_nulls, capacities,
566                )?]
567            }
568            // the dictionary type just appends keys and clones the values.
569            DataType::Dictionary(_, _) => vec![],
570            DataType::Struct(fields) => match capacities {
571                Capacities::Struct(capacity, Some(ref child_capacities)) => {
572                    array_capacity = capacity;
573                    (0..fields.len())
574                        .zip(child_capacities)
575                        .map(|(i, child_cap)| {
576                            let child_arrays = arrays
577                                .iter()
578                                .map(|array| &array.child_data()[i])
579                                .collect::<Vec<_>>();
580                            MutableArrayData::try_with_capacities(
581                                child_arrays,
582                                use_nulls,
583                                child_cap.clone(),
584                            )
585                        })
586                        .collect::<Result<Vec<_>, _>>()?
587                }
588                Capacities::Struct(capacity, None) => {
589                    array_capacity = capacity;
590                    (0..fields.len())
591                        .map(|i| {
592                            let child_arrays = arrays
593                                .iter()
594                                .map(|array| &array.child_data()[i])
595                                .collect::<Vec<_>>();
596                            MutableArrayData::try_new(child_arrays, use_nulls, capacity)
597                        })
598                        .collect::<Result<Vec<_>, _>>()?
599                }
600                _ => (0..fields.len())
601                    .map(|i| {
602                        let child_arrays = arrays
603                            .iter()
604                            .map(|array| &array.child_data()[i])
605                            .collect::<Vec<_>>();
606                        MutableArrayData::try_new(child_arrays, use_nulls, array_capacity)
607                    })
608                    .collect::<Result<Vec<_>, _>>()?,
609            },
610            DataType::RunEndEncoded(_, _) => {
611                let run_ends_child = arrays
612                    .iter()
613                    .map(|array| &array.child_data()[0])
614                    .collect::<Vec<_>>();
615                let value_child = arrays
616                    .iter()
617                    .map(|array| &array.child_data()[1])
618                    .collect::<Vec<_>>();
619                vec![
620                    MutableArrayData::try_new(run_ends_child, false, array_capacity)?,
621                    MutableArrayData::try_new(value_child, use_nulls, array_capacity)?,
622                ]
623            }
624            DataType::FixedSizeList(_, size) => {
625                let children = arrays
626                    .iter()
627                    .map(|array| &array.child_data()[0])
628                    .collect::<Vec<_>>();
629                let capacities =
630                    if let Capacities::List(capacity, ref child_capacities) = capacities {
631                        child_capacities
632                            .clone()
633                            .map(|c| *c)
634                            .unwrap_or(Capacities::Array(capacity * *size as usize))
635                    } else {
636                        Capacities::Array(array_capacity * *size as usize)
637                    };
638                vec![MutableArrayData::try_with_capacities(
639                    children, use_nulls, capacities,
640                )?]
641            }
642            DataType::Union(fields, _) => (0..fields.len())
643                .map(|i| {
644                    let child_arrays = arrays
645                        .iter()
646                        .map(|array| &array.child_data()[i])
647                        .collect::<Vec<_>>();
648                    MutableArrayData::try_new(child_arrays, use_nulls, array_capacity)
649                })
650                .collect::<Result<Vec<_>, _>>()?,
651        };
652
653        // Get the dictionary if any, and if it is a concatenation of multiple
654        let (dictionary, dict_concat) = match &data_type {
655            DataType::Dictionary(_, _) => {
656                // If more than one dictionary, concatenate dictionaries together
657                let dict_concat = !arrays
658                    .windows(2)
659                    .all(|a| a[0].child_data()[0].ptr_eq(&a[1].child_data()[0]));
660
661                match dict_concat {
662                    false => (Some(arrays[0].child_data()[0].clone()), false),
663                    true => {
664                        if let Capacities::Dictionary(_, _) = capacities {
665                            panic!("dictionary capacity not yet supported")
666                        }
667                        let dictionaries: Vec<_> =
668                            arrays.iter().map(|array| &array.child_data()[0]).collect();
669                        let lengths: Vec<_> = dictionaries
670                            .iter()
671                            .map(|dictionary| dictionary.len())
672                            .collect();
673                        let capacity = lengths.iter().sum();
674
675                        let mut mutable = MutableArrayData::new(dictionaries, false, capacity);
676
677                        for (i, len) in lengths.iter().enumerate() {
678                            mutable.try_extend(i, 0, *len).expect(
679                                "extend failed while building dictionary; \
680                                 this is a bug in MutableArrayData",
681                            )
682                        }
683
684                        (Some(mutable.freeze()), true)
685                    }
686                }
687            }
688            _ => (None, false),
689        };
690
691        let variadic_data_buffers = match &data_type {
692            DataType::BinaryView | DataType::Utf8View => arrays
693                .iter()
694                .flat_map(|x| x.buffers().iter().skip(1))
695                .map(Buffer::clone)
696                .collect(),
697            _ => vec![],
698        };
699
700        let extend_nulls = build_extend_nulls(data_type);
701
702        let extend_null_bits = arrays
703            .iter()
704            .map(|array| build_extend_null_bits(array, use_nulls))
705            .collect();
706
707        let null_buffer = use_nulls.then(|| {
708            let null_bytes = bit_util::ceil(array_capacity, 8);
709            MutableBuffer::from_len_zeroed(null_bytes)
710        });
711
712        let extend_values = match &data_type {
713            DataType::Dictionary(_, _) => {
714                let mut next_offset = 0;
715                let extend_values: Result<Vec<_>, _> = arrays
716                    .iter()
717                    .map(|array| {
718                        let offset = next_offset;
719                        let dict_len = array.child_data()[0].len();
720
721                        if dict_concat {
722                            next_offset += dict_len;
723                        }
724
725                        build_extend_dictionary(array, offset, offset + dict_len)
726                            .ok_or(ArrowError::DictionaryKeyOverflowError)
727                    })
728                    .collect();
729
730                extend_values?
731            }
732            DataType::BinaryView | DataType::Utf8View => {
733                let mut next_offset = 0u32;
734                arrays
735                    .iter()
736                    .map(|arr| {
737                        let num_data_buffers = (arr.buffers().len() - 1) as u32;
738                        let offset = next_offset;
739                        next_offset = next_offset
740                            .checked_add(num_data_buffers)
741                            .expect("view buffer index overflow");
742                        build_extend_view(arr, offset)
743                    })
744                    .collect()
745            }
746            _ => arrays.iter().map(|array| build_extend(array)).collect(),
747        };
748
749        let data = _MutableArrayData {
750            data_type: data_type.clone(),
751            len: 0,
752            null_count: 0,
753            null_buffer,
754            buffer1,
755            buffer2,
756            child_data,
757        };
758        Ok(Self {
759            arrays,
760            data,
761            dictionary,
762            variadic_data_buffers,
763            extend_values,
764            extend_null_bits,
765            extend_nulls,
766        })
767    }
768
769    /// Extends the in progress array with a region of the input arrays, returning an error on
770    /// overflow.
771    ///
772    /// # Arguments
773    /// * `index` - the index of array that you want to copy values from
774    /// * `start` - the start index of the chunk (inclusive)
775    /// * `end` - the end index of the chunk (exclusive)
776    ///
777    /// # Errors
778    /// Returns an error if
779    /// * `index` >= the number of source arrays,
780    /// * `start..end` is not a valid range within the `index`th array, or
781    /// * offset arithmetic overflows the underlying integer type.
782    pub fn try_extend(&mut self, index: usize, start: usize, end: usize) -> Result<(), ArrowError> {
783        let Some(array_len) = self.arrays.get(index).map(|array| array.len()) else {
784            return Err(ArrowError::InvalidArgumentError(format!(
785                "Source array index {index} is out of bounds: there are {} source arrays",
786                self.arrays.len()
787            )));
788        };
789        if end < start || array_len < end {
790            return Err(ArrowError::InvalidArgumentError(format!(
791                "Invalid range {start}..{end} for source array {index} of length {array_len}"
792            )));
793        }
794
795        let len = end - start;
796        (self.extend_null_bits[index])(&mut self.data, start, len);
797        // Snapshot buffer lengths before attempting the extend so we can roll
798        // back to a consistent state if it fails.
799        let buf1_len = self.data.buffer1.len();
800        let buf2_len = self.data.buffer2.len();
801        if let Err(e) = (self.extend_values[index])(&mut self.data, index, start, len) {
802            // Restore buffers to their pre-call lengths so the array remains
803            // in a valid state for the caller to inspect or retry.
804            self.data.buffer1.truncate(buf1_len);
805            self.data.buffer2.truncate(buf2_len);
806            return Err(e);
807        }
808        self.data.len += len;
809        Ok(())
810    }
811
812    /// Extends the in progress array with a region of the input arrays.
813    ///
814    /// # Panics
815    /// This function panics if
816    /// * `index` >= the number of source arrays,
817    /// * `start..end` is not a valid range within the `index`th array, or
818    /// * the offset type overflows (e.g. more than 2 GiB in a `StringArray`).
819    #[deprecated(
820        since = "59.0.0",
821        note = "Use `try_extend` which returns an error on overflow instead of panicking"
822    )]
823    pub fn extend(&mut self, index: usize, start: usize, end: usize) {
824        self.try_extend(index, start, end).expect("extend failed")
825    }
826
827    /// Extends the in progress array with null elements, ignoring the input arrays, returning an
828    /// error on overflow.
829    ///
830    /// Prefer this over [`extend_nulls`](Self::extend_nulls) to handle cases where the run-end
831    /// counter overflows (relevant for `RunEndEncoded` arrays).
832    ///
833    /// # Errors
834    ///
835    /// Returns an error if this [`MutableArrayData`] was not created with `use_nulls` and none
836    /// of the source arrays are nullable, or if the run-end counter overflows.
837    pub fn try_extend_nulls(&mut self, len: usize) -> Result<(), ArrowError> {
838        if self.data.null_buffer.is_none() {
839            return Err(ArrowError::InvalidArgumentError(
840                "MutableArrayData cannot be extended with nulls: it was created with `use_nulls` \
841                 set to false and no source array is nullable"
842                    .to_owned(),
843            ));
844        }
845
846        self.data.len += len;
847        let bit_len = bit_util::ceil(self.data.len, 8);
848        let nulls = self.data.null_buffer();
849        nulls
850            .try_resize(bit_len, 0)
851            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
852        self.data.null_count += len;
853        (self.extend_nulls)(&mut self.data, len)?;
854        Ok(())
855    }
856
857    /// Extends the in progress array with null elements, ignoring the input arrays.
858    ///
859    /// # Panics
860    ///
861    /// Panics if this [`MutableArrayData`] was not created with `use_nulls` and none of the
862    /// source arrays are nullable, or if the run-end counter overflows.
863    #[deprecated(
864        since = "59.0.0",
865        note = "Use `try_extend_nulls` which returns an error on overflow instead of panicking"
866    )]
867    pub fn extend_nulls(&mut self, len: usize) {
868        self.try_extend_nulls(len).expect("extend_nulls failed")
869    }
870
871    /// Returns the current length
872    #[inline]
873    pub fn len(&self) -> usize {
874        self.data.len
875    }
876
877    /// Returns true if len is 0
878    #[inline]
879    pub fn is_empty(&self) -> bool {
880        self.data.len == 0
881    }
882
883    /// Returns the current null count
884    #[inline]
885    pub fn null_count(&self) -> usize {
886        self.data.null_count
887    }
888
889    /// Creates a [ArrayData] from the in progress array, consuming `self`.
890    pub fn freeze(self) -> ArrayData {
891        unsafe { self.into_builder().build_unchecked() }
892    }
893
894    /// Consume self and returns the in progress array as [`ArrayDataBuilder`].
895    ///
896    /// This is useful for extending the default behavior of MutableArrayData.
897    pub fn into_builder(self) -> ArrayDataBuilder {
898        let data = self.data;
899
900        let buffers = match data.data_type {
901            DataType::Null
902            | DataType::Struct(_)
903            | DataType::FixedSizeList(_, _)
904            | DataType::RunEndEncoded(_, _) => {
905                vec![]
906            }
907            DataType::BinaryView | DataType::Utf8View => {
908                let mut b = self.variadic_data_buffers;
909                b.insert(0, data.buffer1.into());
910                b
911            }
912            DataType::Utf8
913            | DataType::Binary
914            | DataType::LargeUtf8
915            | DataType::LargeBinary
916            | DataType::ListView(_)
917            | DataType::LargeListView(_) => {
918                vec![data.buffer1.into(), data.buffer2.into()]
919            }
920            DataType::Union(_, mode) => {
921                match mode {
922                    // Based on Union's DataTypeLayout
923                    UnionMode::Sparse => vec![data.buffer1.into()],
924                    UnionMode::Dense => vec![data.buffer1.into(), data.buffer2.into()],
925                }
926            }
927            _ => vec![data.buffer1.into()],
928        };
929
930        let child_data = match data.data_type {
931            DataType::Dictionary(_, _) => vec![self.dictionary.unwrap()],
932            _ => data.child_data.into_iter().map(|x| x.freeze()).collect(),
933        };
934
935        let nulls = match data.data_type {
936            // RunEndEncoded, Null, and Union arrays cannot have top-level null bitmasks
937            DataType::RunEndEncoded(_, _) | DataType::Null | DataType::Union(_, _) => None,
938            _ => data
939                .null_buffer
940                .map(|nulls| {
941                    let bools = BooleanBuffer::new(nulls.into(), 0, data.len);
942                    unsafe { NullBuffer::new_unchecked(bools, data.null_count) }
943                })
944                .filter(|n| n.null_count() > 0),
945        };
946
947        ArrayDataBuilder::new(data.data_type)
948            .offset(0)
949            .len(data.len)
950            .nulls(nulls)
951            .buffers(buffers)
952            .child_data(child_data)
953    }
954}
955
956// See arrow/tests/array_transform.rs for tests of transform functionality
957
958#[cfg(test)]
959mod test {
960    use super::*;
961    use arrow_schema::Field;
962    use std::sync::Arc;
963
964    fn int64_array_data(values: Vec<i64>) -> ArrayData {
965        let len = values.len();
966        ArrayData::try_new(
967            DataType::Int64,
968            len,
969            None,
970            0,
971            vec![arrow_buffer::Buffer::from_slice_ref(&values)],
972            vec![],
973        )
974        .unwrap()
975    }
976
977    #[test]
978    fn test_try_extend_invalid_index_and_range() {
979        let array = int64_array_data(vec![1, 2, 3]);
980        let mut mutable = MutableArrayData::new(vec![&array], false, 3);
981
982        let err = mutable.try_extend(1, 0, 1).unwrap_err();
983        assert_eq!(
984            err.to_string(),
985            "Invalid argument error: Source array index 1 is out of bounds: there are 1 source arrays"
986        );
987
988        let err = mutable.try_extend(0, 0, 4).unwrap_err();
989        assert_eq!(
990            err.to_string(),
991            "Invalid argument error: Invalid range 0..4 for source array 0 of length 3"
992        );
993
994        // `end < start` used to underflow:
995        let err = mutable.try_extend(0, 2, 1).unwrap_err();
996        assert_eq!(
997            err.to_string(),
998            "Invalid argument error: Invalid range 2..1 for source array 0 of length 3"
999        );
1000
1001        // The bounds are inclusive of the full array:
1002        mutable.try_extend(0, 3, 3).unwrap();
1003        mutable.try_extend(0, 0, 3).unwrap();
1004        assert_eq!(mutable.len(), 3);
1005    }
1006
1007    #[test]
1008    fn test_try_extend_nulls_without_null_buffer() {
1009        let array = int64_array_data(vec![1, 2, 3]);
1010        let mut mutable = MutableArrayData::new(vec![&array], false, 3);
1011        let err = mutable.try_extend_nulls(1).unwrap_err();
1012        assert!(
1013            err.to_string().contains("cannot be extended with nulls"),
1014            "unexpected error: {err}"
1015        );
1016
1017        let mut mutable = MutableArrayData::new(vec![&array], true, 3);
1018        mutable.try_extend_nulls(1).unwrap();
1019        assert_eq!(mutable.len(), 1);
1020    }
1021
1022    #[test]
1023    fn test_list_append_with_capacities() {
1024        let array = ArrayData::new_empty(&DataType::List(Arc::new(Field::new(
1025            "element",
1026            DataType::Int64,
1027            false,
1028        ))));
1029
1030        let mutable = MutableArrayData::with_capacities(
1031            vec![&array],
1032            false,
1033            Capacities::List(6, Some(Box::new(Capacities::Array(17)))),
1034        );
1035
1036        // capacities are rounded up to multiples of 64 by MutableBuffer
1037        assert_eq!(mutable.data.buffer1.capacity(), 64);
1038        assert_eq!(mutable.data.child_data[0].data.buffer1.capacity(), 192);
1039    }
1040
1041    #[test]
1042    fn test_map_append_with_capacities() {
1043        let entries = Arc::new(Field::new(
1044            "entries",
1045            DataType::Struct(
1046                vec![
1047                    Field::new("keys", DataType::Int64, false),
1048                    Field::new("values", DataType::Int64, true),
1049                ]
1050                .into(),
1051            ),
1052            false,
1053        ));
1054        let array = ArrayData::new_empty(&DataType::Map(entries, false));
1055
1056        let mutable = MutableArrayData::with_capacities(
1057            vec![&array],
1058            false,
1059            Capacities::List(
1060                6,
1061                Some(Box::new(Capacities::Struct(
1062                    17,
1063                    Some(vec![Capacities::Array(17), Capacities::Array(17)]),
1064                ))),
1065            ),
1066        );
1067
1068        // capacities are rounded up to multiples of 64 by MutableBuffer
1069        // the map offsets buffer holds `1 + 6` i32s
1070        assert_eq!(mutable.data.buffer1.capacity(), 64);
1071
1072        // the entries struct itself has no buffers of its own
1073        let entries = &mutable.data.child_data[0];
1074        assert_eq!(entries.data.buffer1.capacity(), 0);
1075
1076        // both key and value buffers hold 17 i64s
1077        assert_eq!(entries.data.child_data[0].data.buffer1.capacity(), 192);
1078        assert_eq!(entries.data.child_data[1].data.buffer1.capacity(), 192);
1079    }
1080}