This is an automated email from the ASF dual-hosted git repository.

scovich pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new bee4595c13 Add `append_nulls` to `MapBuilder` (#9432)
bee4595c13 is described below

commit bee4595c13665b9dfbd2da3dd0232423a4f2b3c9
Author: Fokko Driesprong <[email protected]>
AuthorDate: Mon Mar 2 22:51:03 2026 +0100

    Add `append_nulls` to `MapBuilder` (#9432)
    
    # Which issue does this PR close?
    
    Closes #9431
    
    # Rationale for this change
    
    It would be nice to add `append_nulls` to MapBuilder, similar to
    `append_nulls` on `GenericListBuilder`. Appending the nulls at once,
    instead of using a loop has some nice performance implications:
    
    ```
    Benchmark results (1,000,000 nulls):
    
    ┌─────────────────────────┬─────────┐
    │         Method          │  Time   │
    ├─────────────────────────┼─────────┤
    │ append(false) in a loop │ 2.36 ms │
    ├─────────────────────────┼─────────┤
    │ append_nulls(N)         │ 50 µs   │
    └─────────────────────────┴─────────┘
    ```
    
    # What changes are included in this PR?
    
    A new public API.
    
    # Are these changes tested?
    
    With some fresh unit tests.
    
    # Are there any user-facing changes?
    
    A nice and convient new public API
---
 arrow-array/src/builder/map_builder.rs | 63 +++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 4 deletions(-)

diff --git a/arrow-array/src/builder/map_builder.rs 
b/arrow-array/src/builder/map_builder.rs
index b70d4b7388..5ff1625b49 100644
--- a/arrow-array/src/builder/map_builder.rs
+++ b/arrow-array/src/builder/map_builder.rs
@@ -154,11 +154,9 @@ impl<K: ArrayBuilder, V: ArrayBuilder> MapBuilder<K, V> {
         (&mut self.key_builder, &mut self.value_builder)
     }
 
-    /// Finish the current map array slot
-    ///
-    /// Returns an error if the key and values builders are in an inconsistent 
state.
+    /// Validates that key and value builders have equal lengths.
     #[inline]
-    pub fn append(&mut self, is_valid: bool) -> Result<(), ArrowError> {
+    fn validate_equal_lengths(&self) -> Result<(), ArrowError> {
         if self.key_builder.len() != self.value_builder.len() {
             return Err(ArrowError::InvalidArgumentError(format!(
                 "Cannot append to a map builder when its keys and values have 
unequal lengths of {} and {}",
@@ -166,11 +164,32 @@ impl<K: ArrayBuilder, V: ArrayBuilder> MapBuilder<K, V> {
                 self.value_builder.len()
             )));
         }
+        Ok(())
+    }
+
+    /// Finish the current map array slot
+    ///
+    /// Returns an error if the key and values builders are in an inconsistent 
state.
+    #[inline]
+    pub fn append(&mut self, is_valid: bool) -> Result<(), ArrowError> {
+        self.validate_equal_lengths()?;
         self.offsets_builder.push(self.key_builder.len() as i32);
         self.null_buffer_builder.append(is_valid);
         Ok(())
     }
 
+    /// Append `n` nulls to this [`MapBuilder`]
+    ///
+    /// Returns an error if the key and values builders are in an inconsistent 
state.
+    #[inline]
+    pub fn append_nulls(&mut self, n: usize) -> Result<(), ArrowError> {
+        self.validate_equal_lengths()?;
+        let offset = self.key_builder.len() as i32;
+        self.offsets_builder.extend(std::iter::repeat_n(offset, n));
+        self.null_buffer_builder.append_n_nulls(n);
+        Ok(())
+    }
+
     /// Builds the [`MapArray`]
     pub fn finish(&mut self) -> MapArray {
         let len = self.len();
@@ -436,6 +455,42 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_append_nulls() {
+        let mut builder = MapBuilder::new(None, Int32Builder::new(), 
Int32Builder::new());
+
+        builder.keys().append_value(1);
+        builder.values().append_value(100);
+        builder.append(true).unwrap();
+
+        builder.append_nulls(3).unwrap();
+
+        builder.keys().append_value(2);
+        builder.values().append_value(200);
+        builder.append(true).unwrap();
+
+        let map = builder.finish();
+        assert_eq!(map.len(), 5);
+        assert_eq!(map.null_count(), 3);
+        assert!(map.is_valid(0));
+        assert!(map.is_null(1));
+        assert!(map.is_null(2));
+        assert!(map.is_null(3));
+        assert!(map.is_valid(4));
+        assert_eq!(map.value_offsets(), &[0, 1, 1, 1, 1, 2]);
+    }
+
+    #[test]
+    fn test_append_nulls_inconsistent_state() {
+        let mut builder = MapBuilder::new(None, Int32Builder::new(), 
Int32Builder::new());
+        // Add a key without a matching value
+        builder.keys().append_value(1);
+
+        let result = builder.append_nulls(2);
+        assert!(result.is_err());
+        assert!(result.unwrap_err().to_string().contains("unequal lengths"));
+    }
+
     #[test]
     #[should_panic(expected = "Keys field must not be nullable")]
     fn test_with_nullable_keys_field() {

Reply via email to