## Coverage Report

#### Created: 2025-11-17 14:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/arrow-rs/arrow-array/src/builder/boolean_builder.rs

    Line
    Count
    Source
    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
    use crate::builder::{ArrayBuilder, BooleanBufferBuilder};
    19
    use crate::{Array, ArrayRef, BooleanArray};
    20
    use arrow_buffer::Buffer;
    21
    use arrow_buffer::NullBufferBuilder;
    22
    use arrow_data::ArrayData;
    23
    use arrow_schema::{ArrowError, DataType};
    24
    use std::any::Any;
    25
    use std::sync::Arc;
    26
    27
    /// Builder for [`BooleanArray`]
    28
    ///
    29
    /// # Example
    30
    ///
    31
    /// Create a `BooleanArray` from a `BooleanBuilder`
    32
    ///
    33
    /// ```
    34
    ///
    35
    /// # use arrow_array::{Array, BooleanArray, builder::BooleanBuilder};
    36
    ///
    37
    /// let mut b = BooleanBuilder::new();
    38
    /// b.append_value(true);
    39
    /// b.append_null();
    40
    /// b.append_value(false);
    41
    /// b.append_value(true);
    42
    /// let arr = b.finish();
    43
    ///
    44
    /// assert_eq!(4, arr.len());
    45
    /// assert_eq!(1, arr.null_count());
    46
    /// assert_eq!(true, arr.value(0));
    47
    /// assert!(arr.is_valid(0));
    48
    /// assert!(!arr.is_null(0));
    49
    /// assert!(!arr.is_valid(1));
    50
    /// assert!(arr.is_null(1));
    51
    /// assert_eq!(false, arr.value(2));
    52
    /// assert!(arr.is_valid(2));
    53
    /// assert!(!arr.is_null(2));
    54
    /// assert_eq!(true, arr.value(3));
    55
    /// assert!(arr.is_valid(3));
    56
    /// assert!(!arr.is_null(3));
    57
    /// ```
    58
    #[derive(Debug)]
    59
    pub struct BooleanBuilder {
    60
        values_builder: BooleanBufferBuilder,
    61
        null_buffer_builder: NullBufferBuilder,
    62
    }
    63
    64
    impl Default for BooleanBuilder {
    65
    0
        fn default() -> Self {
    66
    0
            Self::new()
    67
    0
        }
    68
    }
    69
    70
    impl BooleanBuilder {
    71
        /// Creates a new boolean builder
    72
    0
        pub fn new() -> Self {
    73
    0
            Self::with_capacity(1024)
    74
    0
        }
    75
    76
        /// Creates a new boolean builder with space for `capacity` elements without re-allocating
    77
    947
        pub fn with_capacity(capacity: usize) -> Self {
    78
    947
            Self {
    79
    947
                values_builder: BooleanBufferBuilder::new(capacity),
    80
    947
                null_buffer_builder: NullBufferBuilder::new(capacity),
    81
    947
            }
    82
    947
        }
    83
    84
        /// Returns the capacity of this builder measured in slots of type `T`
    85
    0
        pub fn capacity(&self) -> usize {
    86
    0
            self.values_builder.capacity()
    87
    0
        }
    88
    89
        /// Appends a value of type `T` into the builder
    90
        #[inline]
    91
    28
        pub fn append_value(&mut self, v: bool) {
    92
    28
            self.values_builder.append(v);
    93
    28
            self.null_buffer_builder.append_non_null();
    94
    28
        }
    95
    96
        /// Appends a null slot into the builder
    97
        #[inline]
    98
    11
        pub fn append_null(&mut self) {
    99
    11
            self.null_buffer_builder.append_null();
    100
    11
            self.values_builder.advance(1);
    101
    11
        }
    102
    103
        /// Appends `n` `null`s into the builder.
    104
        #[inline]
    105
        pub fn append_nulls(&mut self, n: usize) {
    106
            self.null_buffer_builder.append_n_nulls(n);
    107
            self.values_builder.advance(n);
    108
        }
    109
    110
        /// Appends an `Option<T>` into the builder
    111
        #[inline]
    112
    39
        pub fn append_option(&mut self, v: Option<bool>) {
    113
    39
            match v {
    114
    11
                None => self.append_null(),
    115
    28
                Some(v) => self.append_value(v),
    116
            };
    117
    39
        }
    118
    119
        /// Appends a slice of type `T` into the builder
    120
        #[inline]
    121
        pub fn append_slice(&mut self, v: &[bool]) {
    122
            self.values_builder.append_slice(v);
    123
            self.null_buffer_builder.append_n_non_nulls(v.len());
    124
        }
    125
    126
        /// Appends n `additional` bits of value `v` into the buffer
    127
        #[inline]
    128
        pub fn append_n(&mut self, additional: usize, v: bool) {
    129
            self.values_builder.append_n(additional, v);
    130
            self.null_buffer_builder.append_n_non_nulls(additional);
    131
        }
    132
    133
        /// Appends values from a slice of type `T` and a validity boolean slice.
    134
        ///
    135
        /// Returns an error if the slices are of different lengths
    136
        #[inline]
    137
        pub fn append_values(&mut self, values: &[bool], is_valid: &[bool]) -> Result<(), ArrowError> {
    138
            if values.len() != is_valid.len() {
    139
                Err(ArrowError::InvalidArgumentError(
    140
                    "Value and validity lengths must be equal".to_string(),
    141
                ))
    142
            } else {
    143
                self.null_buffer_builder.append_slice(is_valid);
    144
                self.values_builder.append_slice(values);
    145
                Ok(())
    146
            }
    147
        }
    148
    149
        /// Appends array values and null to this builder as is
    150
        /// (this means that underlying null values are copied as is).
    151
        #[inline]
    152
    941
        pub fn append_array(&mut self, array: &BooleanArray) {
    153
    941
            self.values_builder.append_buffer(array.values());
    154
    941
            if let Some(null_buffer784) = array.nulls() {
    155
    784
                self.null_buffer_builder.append_buffer(null_buffer);
    156
    784
            } else {
    157
    157
                self.null_buffer_builder.append_n_non_nulls(array.len());
    158
    157
            }
    159
    941
        }
    160
    161
        /// Builds the [BooleanArray] and reset this builder.
    162
    947
        pub fn finish(&mut self) -> BooleanArray {
    163
    947
            let len = self.len();
    164
    947
            let null_bit_buffer = self.null_buffer_builder.finish();
    165
    947
            let builder = ArrayData::builder(DataType::Boolean)
    166
    947
                .len(len)
    167
    947
                .add_buffer(self.values_builder.finish().into_inner())
    168
    947
                .nulls(null_bit_buffer);
    169
    170
    947
            let array_data = unsafe { builder.build_unchecked() };
    171
    947
            BooleanArray::from(array_data)
    172
    947
        }
    173
    174
        /// Builds the [BooleanArray] without resetting the builder.
    175
    0
        pub fn finish_cloned(&self) -> BooleanArray {
    176
    0
            let len = self.len();
    177
    0
            let nulls = self.null_buffer_builder.finish_cloned();
    178
    0
            let value_buffer = Buffer::from_slice_ref(self.values_builder.as_slice());
    179
    0
            let builder = ArrayData::builder(DataType::Boolean)
    180
    0
                .len(len)
    181
    0
                .add_buffer(value_buffer)
    182
    0
                .nulls(nulls);
    183
    184
    0
            let array_data = unsafe { builder.build_unchecked() };
    185
    0
            BooleanArray::from(array_data)
    186
    0
        }
    187
    188
        /// Returns the current values buffer as a slice
    189
        ///
    190
        /// Boolean values are bit-packed into bytes. To extract the i-th boolean
    191
        /// from the bytes, you can use `arrow_buffer::bit_util::get_bit()`.
    192
    0
        pub fn values_slice(&self) -> &[u8] {
    193
    0
            self.values_builder.as_slice()
    194
    0
        }
    195
    196
        /// Returns the current null buffer as a slice
    197
    0
        pub fn validity_slice(&self) -> Option<&[u8]> {
    198
    0
            self.null_buffer_builder.as_slice()
    199
    0
        }
    200
    }
    201
    202
    impl ArrayBuilder for BooleanBuilder {
    203
        /// Returns the builder as a non-mutable `Any` reference.
    204
    0
        fn as_any(&self) -> &dyn Any {
    205
    0
            self
    206
    0
        }
    207
    208
        /// Returns the builder as a mutable `Any` reference.
    209
    39
        fn as_any_mut(&mut self) -> &mut dyn Any {
    210
    39
            self
    211
    39
        }
    212
    213
        /// Returns the boxed builder as a box of `Any`.
    214
    0
        fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
    215
    0
            self
    216
    0
        }
    217
    218
        /// Returns the number of array slots in the builder
    219
    954
        fn len(&self) -> usize {
    220
    954
            self.values_builder.len()
    221
    954
        }
    222
    223
        /// Builds the array and reset this builder.
    224
    7
        fn finish(&mut self) -> ArrayRef {
    225
    7
            Arc::new(self.finish())
    226
    7
        }
    227
    228
        /// Builds the array without resetting the builder.
    229
    0
        fn finish_cloned(&self) -> ArrayRef {
    230
    0
            Arc::new(self.finish_cloned())
    231
    0
        }
    232
    }
    233
    234
    impl Extend<Option<bool>> for BooleanBuilder {
    235
        #[inline]
    236
    939
        fn extend<T: IntoIterator<Item = Option<bool>>>(&mut self, iter: T) {
    237
    939
            let buffered = iter.into_iter().collect::<Vec<_>>();
    238
    939
            let array = unsafe {
    239
                // SAFETY: std::vec::IntoIter implements TrustedLen
    240
    939
                BooleanArray::from_trusted_len_iter(buffered.into_iter())
    241
            };
    242
    939
            self.append_array(&array)
    243
    939
        }
    244
    }
    245
    246
    #[cfg(test)]
    247
    mod tests {
    248
        use super::*;
    249
        use crate::Array;
    250
        use arrow_buffer::{BooleanBuffer, NullBuffer};
    251
    252
        #[test]
    253
        fn test_boolean_array_builder() {
    254
            // 00000010 01001000
    255
            let buf = Buffer::from([72_u8, 2_u8]);
    256
            let mut builder = BooleanArray::builder(10);
    257
            for i in 0..10 {
    258
                if i == 3 || i == 6 || i == 9 {
    259
                    builder.append_value(true);
    260
                } else {
    261
                    builder.append_value(false);
    262
                }
    263
            }
    264
    265
            let arr = builder.finish();
    266
            assert_eq!(&buf, arr.values().inner());
    267
            assert_eq!(10, arr.len());
    268
            assert_eq!(0, arr.offset());
    269
            assert_eq!(0, arr.null_count());
    270
            for i in 0..10 {
    271
                assert!(!arr.is_null(i));
    272
                assert!(arr.is_valid(i));
    273
                assert_eq!(i == 3 || i == 6 || i == 9, arr.value(i), "failed at {i}")
    274
            }
    275
        }
    276
    277
        #[test]
    278
        fn test_boolean_array_builder_append_slice() {
    279
            let arr1 = BooleanArray::from(vec![Some(true), Some(false), None, None, Some(false)]);
    280
    281
            let mut builder = BooleanArray::builder(0);
    282
            builder.append_slice(&[true, false]);
    283
            builder.append_null();
    284
            builder.append_null();
    285
            builder.append_value(false);
    286
            let arr2 = builder.finish();
    287
    288
            assert_eq!(arr1, arr2);
    289
        }
    290
    291
        #[test]
    292
        fn test_boolean_array_builder_append_slice_large() {
    293
            let arr1 = BooleanArray::from(vec![true; 513]);
    294
    295
            let mut builder = BooleanArray::builder(512);
    296
            builder.append_slice(&[true; 513]);
    297
            let arr2 = builder.finish();
    298
    299
            assert_eq!(arr1, arr2);
    300
        }
    301
    302
        #[test]
    303
        fn test_boolean_array_builder_no_null() {
    304
            let mut builder = BooleanArray::builder(0);
    305
            builder.append_option(Some(true));
    306
            builder.append_value(false);
    307
            builder.append_slice(&[true, false, true]);
    308
            builder
    309
                .append_values(&[false, false, true], &[true, true, true])
    310
                .unwrap();
    311
    312
            let array = builder.finish();
    313
            assert_eq!(0, array.null_count());
    314
            assert!(array.nulls().is_none());
    315
        }
    316
    317
        #[test]
    318
        fn test_boolean_array_builder_finish_cloned() {
    319
            let mut builder = BooleanArray::builder(16);
    320
            builder.append_option(Some(true));
    321
            builder.append_value(false);
    322
            builder.append_slice(&[true, false, true]);
    323
            let mut array = builder.finish_cloned();
    324
            assert_eq!(3, array.true_count());
    325
            assert_eq!(2, array.false_count());
    326
    327
            builder
    328
                .append_values(&[false, false, true], &[true, true, true])
    329
                .unwrap();
    330
    331
            array = builder.finish();
    332
            assert_eq!(4, array.true_count());
    333
            assert_eq!(4, array.false_count());
    334
    335
            assert_eq!(0, array.null_count());
    336
            assert!(array.nulls().is_none());
    337
        }
    338
    339
        #[test]
    340
        fn test_extend() {
    341
            let mut builder = BooleanBuilder::new();
    342
            builder.extend([false, false, true, false, false].into_iter().map(Some));
    343
            builder.extend([true, true, false].into_iter().map(Some));
    344
            let array = builder.finish();
    345
            let values = array.iter().map(|x| x.unwrap()).collect::<Vec<_>>();
    346
            assert_eq!(
    347
                &values,
    348
                &[false, false, true, false, false, true, true, false]
    349
            )
    350
        }
    351
    352
        #[test]
    353
        fn test_boolean_array_builder_append_n() {
    354
            let mut builder = BooleanBuilder::new();
    355
            builder.append_n(3, true);
    356
            builder.append_n(2, false);
    357
            let array = builder.finish();
    358
            assert_eq!(3, array.true_count());
    359
            assert_eq!(2, array.false_count());
    360
            assert_eq!(0, array.null_count());
    361
    362
            let values = array.iter().map(|x| x.unwrap()).collect::<Vec<_>>();
    363
            assert_eq!(&values, &[true, true, true, false, false])
    364
        }
    365
    366
        #[test]
    367
        fn test_append_array() {
    368
            let input = vec![
    369
                Some(true),
    370
                None,
    371
                Some(true),
    372
                None,
    373
                Some(false),
    374
                None,
    375
                None,
    376
                None,
    377
                Some(false),
    378
                Some(false),
    379
                Some(false),
    380
                Some(true),
    381
                Some(false),
    382
            ];
    383
            let arr1 = BooleanArray::from(input[..5].to_vec());
    384
            let arr2 = BooleanArray::from(input[5..8].to_vec());
    385
            let arr3 = BooleanArray::from(input[8..].to_vec());
    386
    387
            let mut builder = BooleanBuilder::new();
    388
            builder.append_array(&arr1);
    389
            builder.append_array(&arr2);
    390
            builder.append_array(&arr3);
    391
            let actual = builder.finish();
    392
            let expected = BooleanArray::from(input);
    393
    394
            assert_eq!(actual, expected);
    395
        }
    396
    397
        #[test]
    398
        fn test_append_array_add_underlying_null_values() {
    399
            let array = BooleanArray::new(
    400
                BooleanBuffer::from(vec![true, false, true, false]),
    401
                Some(NullBuffer::from(&[true, true, false, false])),
    402
            );
    403
    404
            let mut builder = BooleanBuilder::new();
    405
            builder.append_array(&array);
    406
            let actual = builder.finish();
    407
    408
            assert_eq!(actual, array);
    409
            assert_eq!(actual.values(), array.values())
    410
        }
    411
    }