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

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


The following commit(s) were added to refs/heads/main by this push:
     new 1acbca6  Add missing builders and concatenator support for "large" 
array types. (#302)
1acbca6 is described below

commit 1acbca65efb0fe949b665c34e82a08a27ef2d7ff
Author: Curt Hagenlocher <[email protected]>
AuthorDate: Mon Mar 30 17:48:21 2026 -0700

    Add missing builders and concatenator support for "large" array types. 
(#302)
    
    ## What's Changed
    
    When support for largebinary, largeutf8 and largelist were added,
    corresponding support for builders and concatenators were not added.
---
 src/Apache.Arrow/Arrays/ArrayDataConcatenator.cs   |  93 +++++++++++
 .../Arrays/ArrowArrayBuilderFactory.cs             |   6 +
 src/Apache.Arrow/Arrays/LargeBinaryArray.cs        | 170 +++++++++++++++++++++
 src/Apache.Arrow/Arrays/LargeListArray.cs          |  85 +++++++++++
 src/Apache.Arrow/Arrays/LargeStringArray.cs        |  31 ++++
 src/Apache.Arrow/Arrays/ListArray.cs               |   1 +
 src/Apache.Arrow/Arrays/ListViewArray.cs           |   2 +-
 src/Apache.Arrow/Arrays/MapArray.cs                |   1 +
 test/Apache.Arrow.Tests/ArrayBuilderTests.cs       |  57 +++++++
 .../ArrowArrayConcatenatorTests.cs                 |  33 ++++
 .../LargeBinaryArrayBuilderTests.cs                | 120 +++++++++++++++
 .../LargeListArrayBuilderTests.cs                  | 131 ++++++++++++++++
 .../LargeStringArrayBuilderTests.cs                |  84 ++++++++++
 13 files changed, 813 insertions(+), 1 deletion(-)

diff --git a/src/Apache.Arrow/Arrays/ArrayDataConcatenator.cs 
b/src/Apache.Arrow/Arrays/ArrayDataConcatenator.cs
index 609ebb9..a835435 100644
--- a/src/Apache.Arrow/Arrays/ArrayDataConcatenator.cs
+++ b/src/Apache.Arrow/Arrays/ArrayDataConcatenator.cs
@@ -55,6 +55,9 @@ namespace Apache.Arrow
             IArrowTypeVisitor<FixedSizeListType>,
             IArrowTypeVisitor<StructType>,
             IArrowTypeVisitor<UnionType>,
+            IArrowTypeVisitor<LargeBinaryType>,
+            IArrowTypeVisitor<LargeStringType>,
+            IArrowTypeVisitor<LargeListType>,
             IArrowTypeVisitor<MapType>
         {
             public ArrayData Result { get; private set; }
@@ -101,6 +104,12 @@ namespace Apache.Arrow
 
             public void Visit(StringViewType type) => 
ConcatenateBinaryViewArrayData(type);
 
+            public void Visit(LargeBinaryType type) => 
ConcatenateLargeVariableBinaryArrayData(type);
+
+            public void Visit(LargeStringType type) => 
ConcatenateLargeVariableBinaryArrayData(type);
+
+            public void Visit(LargeListType type) => 
ConcatenateLargeLists(type);
+
             public void Visit(ListType type) => ConcatenateLists(type);
 
             public void Visit(ListViewType type)
@@ -310,6 +319,90 @@ namespace Apache.Arrow
                 Result = new ArrayData(type, _totalLength, _totalNullCount, 0, 
new ArrowBuffer[] { validityBuffer, offsetBuffer }, new[] { combinedChild });
             }
 
+            private void ConcatenateLargeVariableBinaryArrayData(IArrowType 
type)
+            {
+                CheckData(type, 3);
+                ArrowBuffer validityBuffer = ConcatenateValidityBuffer();
+                ArrowBuffer offsetBuffer = ConcatenateLargeOffsetBuffer();
+                ArrowBuffer valueBuffer = 
ConcatenateLargeVariableBinaryValueBuffer();
+
+                Result = new ArrayData(type, _totalLength, _totalNullCount, 0, 
new ArrowBuffer[] { validityBuffer, offsetBuffer, valueBuffer });
+            }
+
+            private void ConcatenateLargeLists(LargeListType type)
+            {
+                CheckData(type, 2);
+                ArrowBuffer validityBuffer = ConcatenateValidityBuffer();
+                ArrowBuffer offsetBuffer = ConcatenateLargeOffsetBuffer();
+
+                var children = new List<ArrayData>(_arrayDataList.Count);
+                foreach (ArrayData arrayData in _arrayDataList)
+                {
+                    if (arrayData.Length == 0)
+                    {
+                        continue;
+                    }
+
+                    var child = arrayData.Children[0];
+                    ReadOnlySpan<long> offsets = 
arrayData.Buffers[1].Span.CastTo<long>().Slice(arrayData.Offset, 
arrayData.Length + 1);
+                    var firstOffset = offsets[0];
+                    var lastOffset = offsets[arrayData.Length];
+                    if (firstOffset != 0 || lastOffset != child.Length)
+                    {
+                        child = child.Slice(checked((int)firstOffset), 
checked((int)(lastOffset - firstOffset)));
+                    }
+
+                    children.Add(child);
+                }
+
+                ArrayData combinedChild = Concatenate(children, _allocator);
+
+                Result = new ArrayData(type, _totalLength, _totalNullCount, 0, 
new ArrowBuffer[] { validityBuffer, offsetBuffer }, new[] { combinedChild });
+            }
+
+            private ArrowBuffer ConcatenateLargeOffsetBuffer()
+            {
+                var builder = new ArrowBuffer.Builder<long>(_totalLength + 1);
+                long baseOffset = 0;
+
+                foreach (ArrayData arrayData in _arrayDataList)
+                {
+                    if (arrayData.Length == 0)
+                    {
+                        continue;
+                    }
+
+                    ReadOnlySpan<long> span = 
arrayData.Buffers[1].Span.CastTo<long>().Slice(arrayData.Offset, 
arrayData.Length + 1);
+                    var firstOffset = span[0];
+
+                    foreach (long offset in span.Slice(0, arrayData.Length))
+                    {
+                        builder.Append(baseOffset + offset - firstOffset);
+                    }
+
+                    baseOffset += span[arrayData.Length] - firstOffset;
+                }
+
+                builder.Append(baseOffset);
+
+                return builder.Build(_allocator);
+            }
+
+            private ArrowBuffer ConcatenateLargeVariableBinaryValueBuffer()
+            {
+                var builder = new ArrowBuffer.Builder<byte>();
+
+                foreach (ArrayData arrayData in _arrayDataList)
+                {
+                    var offsets = 
arrayData.Buffers[1].Span.CastTo<long>().Slice(arrayData.Offset, 
arrayData.Length + 1);
+                    var firstOffset = checked((int)offsets[0]);
+                    var lastOffset = checked((int)offsets[arrayData.Length]);
+                    
builder.Append(arrayData.Buffers[2].Span.Slice(firstOffset, lastOffset - 
firstOffset));
+                }
+
+                return builder.Build(_allocator);
+            }
+
             private ArrowBuffer ConcatenateValidityBuffer()
             {
                 if (_totalNullCount == 0)
diff --git a/src/Apache.Arrow/Arrays/ArrowArrayBuilderFactory.cs 
b/src/Apache.Arrow/Arrays/ArrowArrayBuilderFactory.cs
index f0afb93..f4f551c 100644
--- a/src/Apache.Arrow/Arrays/ArrowArrayBuilderFactory.cs
+++ b/src/Apache.Arrow/Arrays/ArrowArrayBuilderFactory.cs
@@ -95,6 +95,12 @@ namespace Apache.Arrow
                         IntervalUnit.MonthDayNanosecond => new 
MonthDayNanosecondIntervalArray.Builder(),
                         _ => throw new 
ArgumentOutOfRangeException($"unsupported interval unit <{intervalType.Unit}>")
                     };
+                case ArrowTypeId.LargeBinary:
+                    return new LargeBinaryArray.Builder();
+                case ArrowTypeId.LargeString:
+                    return new LargeStringArray.Builder();
+                case ArrowTypeId.LargeList:
+                    return new LargeListArray.Builder(dataType as 
LargeListType);
                 case ArrowTypeId.Map:
                     return new MapArray.Builder(dataType as MapType);
                 case ArrowTypeId.Struct:
diff --git a/src/Apache.Arrow/Arrays/LargeBinaryArray.cs 
b/src/Apache.Arrow/Arrays/LargeBinaryArray.cs
index 1219466..09e1ad8 100644
--- a/src/Apache.Arrow/Arrays/LargeBinaryArray.cs
+++ b/src/Apache.Arrow/Arrays/LargeBinaryArray.cs
@@ -17,12 +17,182 @@ using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
+using Apache.Arrow.Memory;
 using Apache.Arrow.Types;
 
 namespace Apache.Arrow;
 
 public class LargeBinaryArray : Array, IReadOnlyList<byte[]>, 
ICollection<byte[]>
 {
+    public class Builder : BuilderBase<LargeBinaryArray, Builder>
+    {
+        public Builder() : base(LargeBinaryType.Default) { }
+        public Builder(IArrowType dataType) : base(dataType) { }
+
+        protected override LargeBinaryArray Build(ArrayData data)
+        {
+            return new LargeBinaryArray(data);
+        }
+    }
+
+    public abstract class BuilderBase<TArray, TBuilder> : 
IArrowArrayBuilder<byte, TArray, TBuilder>
+        where TArray : IArrowArray
+        where TBuilder : class, IArrowArrayBuilder<byte, TArray, TBuilder>
+    {
+        protected IArrowType DataType { get; }
+        protected TBuilder Instance => this as TBuilder;
+        protected ArrowBuffer.Builder<long> ValueOffsets { get; }
+        protected ArrowBuffer.Builder<byte> ValueBuffer { get; }
+        protected ArrowBuffer.BitmapBuilder ValidityBuffer { get; }
+        protected long Offset { get; set; }
+        protected int NullCount => this.ValidityBuffer.UnsetBitCount;
+
+        protected BuilderBase(IArrowType dataType)
+        {
+            DataType = dataType;
+            ValueOffsets = new ArrowBuffer.Builder<long>();
+            ValueBuffer = new ArrowBuffer.Builder<byte>();
+            ValidityBuffer = new ArrowBuffer.BitmapBuilder();
+            ValueOffsets.Append(this.Offset);
+        }
+
+        protected abstract TArray Build(ArrayData data);
+
+        public int Length => ValueOffsets.Length - 1;
+
+        public TArray Build(MemoryAllocator allocator = default)
+        {
+            var bufs = new[]
+            {
+                NullCount > 0 ? ValidityBuffer.Build(allocator) : 
ArrowBuffer.Empty,
+                ValueOffsets.Build(allocator),
+                ValueBuffer.Build(allocator),
+            };
+            var data = new ArrayData(
+                DataType,
+                length: Length,
+                NullCount,
+                offset: 0,
+                bufs);
+
+            return Build(data);
+        }
+
+        public TBuilder AppendNull()
+        {
+            ValidityBuffer.Append(false);
+            ValueOffsets.Append(Offset);
+            return Instance;
+        }
+
+        public TBuilder Append(byte value)
+        {
+            ValueBuffer.Append(value);
+            ValidityBuffer.Append(true);
+            Offset++;
+            ValueOffsets.Append(Offset);
+            return Instance;
+        }
+
+        public TBuilder Append(ReadOnlySpan<byte> span)
+        {
+            ValueBuffer.Append(span);
+            ValidityBuffer.Append(true);
+            Offset += span.Length;
+            ValueOffsets.Append(Offset);
+            return Instance;
+        }
+
+        public TBuilder Append(IEnumerable<byte> value)
+        {
+            if (value == null)
+            {
+                return AppendNull();
+            }
+
+            long priorLength = ValueBuffer.Length;
+            ValueBuffer.AppendRange(value);
+            long valueLength = ValueBuffer.Length - priorLength;
+            Offset += valueLength;
+            ValidityBuffer.Append(true);
+            ValueOffsets.Append(Offset);
+            return Instance;
+        }
+
+        public TBuilder AppendRange(IEnumerable<byte> values)
+        {
+            if (values == null)
+            {
+                throw new ArgumentNullException(nameof(values));
+            }
+
+            foreach (byte b in values)
+            {
+                Append(b);
+            }
+
+            return Instance;
+        }
+
+        public TBuilder AppendRange(IEnumerable<byte[]> values)
+        {
+            if (values == null)
+            {
+                throw new ArgumentNullException(nameof(values));
+            }
+
+            foreach (byte[] arr in values)
+            {
+                if (arr == null)
+                {
+                    AppendNull();
+                }
+                else
+                {
+                    Append((ReadOnlySpan<byte>)arr);
+                }
+            }
+
+            return Instance;
+        }
+
+        public TBuilder Reserve(int capacity)
+        {
+            ValueOffsets.Reserve(capacity + 1);
+            ValueBuffer.Reserve(capacity);
+            ValidityBuffer.Reserve(capacity);
+            return Instance;
+        }
+
+        public TBuilder Resize(int length)
+        {
+            ValueOffsets.Resize(length + 1);
+            ValueBuffer.Resize(length);
+            ValidityBuffer.Resize(length);
+            return Instance;
+        }
+
+        public TBuilder Swap(int i, int j)
+        {
+            throw new NotImplementedException();
+        }
+
+        public TBuilder Set(int index, byte value)
+        {
+            throw new NotImplementedException();
+        }
+
+        public TBuilder Clear()
+        {
+            ValueOffsets.Clear();
+            ValueBuffer.Clear();
+            ValidityBuffer.Clear();
+            Offset = 0;
+            ValueOffsets.Append(Offset);
+            return Instance;
+        }
+    }
+
     public LargeBinaryArray(ArrayData data)
         : base(data)
     {
diff --git a/src/Apache.Arrow/Arrays/LargeListArray.cs 
b/src/Apache.Arrow/Arrays/LargeListArray.cs
index 6e37aa4..f4cef97 100644
--- a/src/Apache.Arrow/Arrays/LargeListArray.cs
+++ b/src/Apache.Arrow/Arrays/LargeListArray.cs
@@ -14,12 +14,97 @@
 // limitations under the License.
 
 using System;
+using Apache.Arrow.Memory;
 using Apache.Arrow.Types;
 
 namespace Apache.Arrow
 {
     public class LargeListArray : Array
     {
+        public class Builder : IArrowArrayBuilder<LargeListArray, Builder>
+        {
+            public IArrowArrayBuilder<IArrowArray, 
IArrowArrayBuilder<IArrowArray>> ValueBuilder { get; }
+
+            public int Length => ValueOffsetsBufferBuilder.Length;
+
+            private ArrowBuffer.Builder<long> ValueOffsetsBufferBuilder { get; 
}
+
+            private ArrowBuffer.BitmapBuilder ValidityBufferBuilder { get; }
+
+            public int NullCount { get; protected set; }
+
+            private IArrowType DataType { get; }
+
+            public Builder(IArrowType valueDataType) : this(new 
LargeListType(valueDataType))
+            {
+            }
+
+            public Builder(Field valueField) : this(new 
LargeListType(valueField))
+            {
+            }
+
+            internal Builder(LargeListType dataType)
+            {
+                ValueBuilder = 
ArrowArrayBuilderFactory.Build(dataType.ValueDataType);
+                ValueOffsetsBufferBuilder = new ArrowBuffer.Builder<long>();
+                ValidityBufferBuilder = new ArrowBuffer.BitmapBuilder();
+                DataType = dataType;
+            }
+
+            public Builder Append()
+            {
+                ValueOffsetsBufferBuilder.Append(ValueBuilder.Length);
+                ValidityBufferBuilder.Append(true);
+
+                return this;
+            }
+
+            public Builder AppendNull()
+            {
+                ValueOffsetsBufferBuilder.Append(ValueBuilder.Length);
+                ValidityBufferBuilder.Append(false);
+                NullCount++;
+
+                return this;
+            }
+
+            public LargeListArray Build(MemoryAllocator allocator = default)
+            {
+                ValueOffsetsBufferBuilder.Append(ValueBuilder.Length);
+
+                ArrowBuffer validityBuffer = NullCount > 0
+                                        ? 
ValidityBufferBuilder.Build(allocator)
+                                        : ArrowBuffer.Empty;
+
+                return new LargeListArray(DataType, Length - 1,
+                    ValueOffsetsBufferBuilder.Build(allocator), 
ValueBuilder.Build(allocator),
+                    validityBuffer, NullCount, 0);
+            }
+
+            public Builder Reserve(int capacity)
+            {
+                ValueOffsetsBufferBuilder.Reserve(capacity + 1);
+                ValidityBufferBuilder.Reserve(capacity);
+                return this;
+            }
+
+            public Builder Resize(int length)
+            {
+                ValueOffsetsBufferBuilder.Resize(length + 1);
+                ValidityBufferBuilder.Resize(length);
+                return this;
+            }
+
+            public Builder Clear()
+            {
+                ValueOffsetsBufferBuilder.Clear();
+                ValueBuilder.Clear();
+                ValidityBufferBuilder.Clear();
+                NullCount = 0;
+                return this;
+            }
+        }
+
         public IArrowArray Values { get; }
 
         public ArrowBuffer ValueOffsetsBuffer => Data.Buffers[1];
diff --git a/src/Apache.Arrow/Arrays/LargeStringArray.cs 
b/src/Apache.Arrow/Arrays/LargeStringArray.cs
index a12bae6..06752c2 100644
--- a/src/Apache.Arrow/Arrays/LargeStringArray.cs
+++ b/src/Apache.Arrow/Arrays/LargeStringArray.cs
@@ -26,6 +26,37 @@ public class LargeStringArray : LargeBinaryArray, 
IReadOnlyList<string>, ICollec
 {
     public static readonly Encoding DefaultEncoding = 
StringArray.DefaultEncoding;
 
+    public new class Builder : BuilderBase<LargeStringArray, Builder>
+    {
+        public Builder() : base(LargeStringType.Default) { }
+
+        protected override LargeStringArray Build(ArrayData data)
+        {
+            return new LargeStringArray(data);
+        }
+
+        public Builder Append(string value, Encoding encoding = null)
+        {
+            if (value == null)
+            {
+                return AppendNull();
+            }
+            encoding = encoding ?? DefaultEncoding;
+            byte[] span = encoding.GetBytes(value);
+            return Append(span.AsSpan());
+        }
+
+        public Builder AppendRange(IEnumerable<string> values, Encoding 
encoding = null)
+        {
+            foreach (string value in values)
+            {
+                Append(value, encoding);
+            }
+
+            return this;
+        }
+    }
+
     public LargeStringArray(ArrayData data)
         : base(ArrowTypeId.LargeString, data) { }
 
diff --git a/src/Apache.Arrow/Arrays/ListArray.cs 
b/src/Apache.Arrow/Arrays/ListArray.cs
index 4d2ff96..dd27e68 100644
--- a/src/Apache.Arrow/Arrays/ListArray.cs
+++ b/src/Apache.Arrow/Arrays/ListArray.cs
@@ -107,6 +107,7 @@ namespace Apache.Arrow
                 ValueOffsetsBufferBuilder.Clear();
                 ValueBuilder.Clear();
                 ValidityBufferBuilder.Clear();
+                NullCount = 0;
                 return this;
             }
 
diff --git a/src/Apache.Arrow/Arrays/ListViewArray.cs 
b/src/Apache.Arrow/Arrays/ListViewArray.cs
index 081385d..7bbb292 100644
--- a/src/Apache.Arrow/Arrays/ListViewArray.cs
+++ b/src/Apache.Arrow/Arrays/ListViewArray.cs
@@ -132,9 +132,9 @@ namespace Apache.Arrow
                 SizesBufferBuilder.Clear();
                 ValueBuilder.Clear();
                 ValidityBufferBuilder.Clear();
+                NullCount = 0;
                 return this;
             }
-
         }
 
         public IArrowArray Values { get; }
diff --git a/src/Apache.Arrow/Arrays/MapArray.cs 
b/src/Apache.Arrow/Arrays/MapArray.cs
index 341bb24..a488168 100644
--- a/src/Apache.Arrow/Arrays/MapArray.cs
+++ b/src/Apache.Arrow/Arrays/MapArray.cs
@@ -106,6 +106,7 @@ namespace Apache.Arrow
                 KeyBuilder.Clear();
                 ValueBuilder.Clear();
                 ValidityBufferBuilder.Clear();
+                NullCount = 0;
                 return this;
             }
 
diff --git a/test/Apache.Arrow.Tests/ArrayBuilderTests.cs 
b/test/Apache.Arrow.Tests/ArrayBuilderTests.cs
index 7588c34..2db71b2 100644
--- a/test/Apache.Arrow.Tests/ArrayBuilderTests.cs
+++ b/test/Apache.Arrow.Tests/ArrayBuilderTests.cs
@@ -138,6 +138,7 @@ namespace Apache.Arrow.Tests
             var emptyList = listBuilder.Build();
 
             Assert.Equal(0, emptyList.Length);
+            Assert.Equal(0, emptyList.NullCount);
 
             List<string> ConvertStringArrayToList(StringArray array)
             {
@@ -329,6 +330,62 @@ namespace Apache.Arrow.Tests
                 
((Int64Array)childList3.GetSlicedValues(2)).ToList(includeNulls: true));
         }
 
+        [Fact]
+        public void ListViewArrayBuilderClearResetsNullCount()
+        {
+            var builder = new ListViewArray.Builder(Int64Type.Default);
+            var valueBuilder = (Int64Array.Builder)builder.ValueBuilder;
+
+            builder.AppendNull();
+            builder.Append();
+            valueBuilder.Append(1);
+
+            var list = builder.Build();
+            Assert.Equal(2, list.Length);
+            Assert.Equal(1, list.NullCount);
+
+            builder.Clear();
+            builder.Append();
+            valueBuilder.Append(10);
+            var clearedList = builder.Build();
+
+            Assert.Equal(0, clearedList.NullCount);
+        }
+
+        [Fact]
+        public void MapArrayBuilderClearResetsNullCount()
+        {
+            var mapType = new MapType(
+                new 
Field.Builder().Name("key").DataType(StringType.Default).Nullable(false).Build(),
+                new 
Field.Builder().Name("value").DataType(Int32Type.Default).Nullable(true).Build(),
+                keySorted: false);
+
+            var builder = new MapArray.Builder(mapType);
+            var keyBuilder = (StringArray.Builder)builder.KeyBuilder;
+            var valueBuilder = (Int32Array.Builder)builder.ValueBuilder;
+
+            builder.Append();
+            keyBuilder.Append("a");
+            valueBuilder.Append(1);
+            builder.AppendNull();
+            builder.Append();
+            keyBuilder.Append("b");
+            valueBuilder.Append(2);
+
+            var map = builder.Build();
+            Assert.Equal(3, map.Length);
+            Assert.Equal(1, map.NullCount);
+
+            builder.Clear();
+            builder.Append();
+            keyBuilder.Append("x");
+            valueBuilder.Append(99);
+            var clearedMap = builder.Build();
+
+            Assert.Equal(1, clearedMap.Length);
+            Assert.Equal(0, clearedMap.NullCount);
+        }
+
         public class TimestampArrayBuilder
         {
             [Fact]
diff --git a/test/Apache.Arrow.Tests/ArrowArrayConcatenatorTests.cs 
b/test/Apache.Arrow.Tests/ArrowArrayConcatenatorTests.cs
index 758c426..f9589ef 100644
--- a/test/Apache.Arrow.Tests/ArrowArrayConcatenatorTests.cs
+++ b/test/Apache.Arrow.Tests/ArrowArrayConcatenatorTests.cs
@@ -84,6 +84,9 @@ namespace Apache.Arrow.Tests
                     new Decimal64Type(14, 4),
                     new Decimal128Type(14, 10),
                     new Decimal256Type(14, 10),
+                    LargeBinaryType.Default,
+                    LargeStringType.Default,
+                    new LargeListType(Int64Type.Default),
                     new ListType(Int64Type.Default),
                     new ListViewType(Int64Type.Default),
                     new StructType(new List<Field>{
@@ -154,6 +157,9 @@ namespace Apache.Arrow.Tests
             IArrowTypeVisitor<FixedSizeListType>,
             IArrowTypeVisitor<StructType>,
             IArrowTypeVisitor<UnionType>,
+            IArrowTypeVisitor<LargeBinaryType>,
+            IArrowTypeVisitor<LargeStringType>,
+            IArrowTypeVisitor<LargeListType>,
             IArrowTypeVisitor<MapType>
         {
             private readonly List<List<int?>> _baseData;
@@ -496,6 +502,33 @@ namespace Apache.Arrow.Tests
                         new[] { stringResultBuilder.Build().Data, 
intResultBuilder.Build().Data }));
             }
 
+            public void Visit(LargeBinaryType type) =>
+                GenerateTestData<LargeBinaryArray, 
LargeBinaryArray.Builder>(type, (builder, x) =>
+                {
+                    if (x % 2 == 0)
+                    {
+                        builder.Append((byte)x);
+                    }
+                    else
+                    {
+                        builder.Append(new byte[] { (byte)x, (byte)(x + 1) 
}.AsSpan());
+                    }
+                });
+
+            public void Visit(LargeStringType type) =>
+                GenerateTestData<LargeStringArray, 
LargeStringArray.Builder>(type, (builder, x) => builder.Append(x.ToString()));
+
+            public void Visit(LargeListType type) =>
+                GenerateTestData<LargeListArray, LargeListArray.Builder>(type, 
(builder, x) =>
+                {
+                    builder.Append();
+                    ((Int64Array.Builder)builder.ValueBuilder).Append(x);
+                }, initAction: (builder, length) =>
+                {
+                    builder.Reserve(length);
+                    builder.ValueBuilder.Reserve(length);
+                });
+
             public void Visit(MapType type) =>
                 GenerateTestData<MapArray, MapArray.Builder>(type, (builder, 
x) =>
                 {
diff --git a/test/Apache.Arrow.Tests/LargeBinaryArrayBuilderTests.cs 
b/test/Apache.Arrow.Tests/LargeBinaryArrayBuilderTests.cs
new file mode 100644
index 0000000..7172c93
--- /dev/null
+++ b/test/Apache.Arrow.Tests/LargeBinaryArrayBuilderTests.cs
@@ -0,0 +1,120 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Linq;
+using Xunit;
+
+namespace Apache.Arrow.Tests
+{
+    public class LargeBinaryArrayBuilderTests
+    {
+        [Fact]
+        public void AppendByteSpanBuildsCorrectArray()
+        {
+            var builder = new LargeBinaryArray.Builder();
+            builder.Append(new byte[] { 1, 2, 3 }.AsSpan());
+            builder.Append(new byte[] { 4, 5 }.AsSpan());
+            builder.AppendNull();
+            builder.Append(ReadOnlySpan<byte>.Empty);
+
+            var array = builder.Build();
+
+            Assert.Equal(4, array.Length);
+            Assert.Equal(new byte[] { 1, 2, 3 }, array.GetBytes(0).ToArray());
+            Assert.Equal(new byte[] { 4, 5 }, array.GetBytes(1).ToArray());
+            Assert.True(array.IsNull(2));
+            Assert.Empty(array.GetBytes(3).ToArray());
+        }
+
+        [Fact]
+        public void AppendSingleByteBuildsCorrectArray()
+        {
+            var builder = new LargeBinaryArray.Builder();
+            builder.Append((byte)10);
+            builder.Append((byte)20);
+
+            var array = builder.Build();
+
+            Assert.Equal(2, array.Length);
+            Assert.Equal(new byte[] { 10 }, array.GetBytes(0).ToArray());
+            Assert.Equal(new byte[] { 20 }, array.GetBytes(1).ToArray());
+        }
+
+        [Fact]
+        public void AppendRangeByteArraysBuildsCorrectArray()
+        {
+            var builder = new LargeBinaryArray.Builder();
+            builder.AppendRange(new byte[][]
+            {
+                new byte[] { 1, 2, 3 },
+                null,
+                new byte[] { 4, 5 },
+            });
+
+            var array = builder.Build();
+
+            Assert.Equal(3, array.Length);
+            Assert.Equal(new byte[] { 1, 2, 3 }, array.GetBytes(0).ToArray());
+            Assert.True(array.IsNull(1));
+            Assert.Equal(new byte[] { 4, 5 }, array.GetBytes(2).ToArray());
+        }
+
+        [Fact]
+        public void ClearResetsBuilder()
+        {
+            var builder = new LargeBinaryArray.Builder();
+            builder.Append(new byte[] { 1, 2, 3 }.AsSpan());
+            builder.Clear();
+            builder.Append(new byte[] { 4, 5 }.AsSpan());
+
+            var array = builder.Build();
+
+            Assert.Equal(1, array.Length);
+            Assert.Equal(new byte[] { 4, 5 }, array.GetBytes(0).ToArray());
+        }
+
+        [Fact]
+        public void LengthTracksAppendedItems()
+        {
+            var builder = new LargeBinaryArray.Builder();
+            Assert.Equal(0, builder.Length);
+
+            builder.Append(new byte[] { 1 }.AsSpan());
+            Assert.Equal(1, builder.Length);
+
+            builder.AppendNull();
+            Assert.Equal(2, builder.Length);
+
+            builder.Append((byte)5);
+            Assert.Equal(3, builder.Length);
+        }
+
+        [Fact]
+        public void NullCountIsCorrect()
+        {
+            var builder = new LargeBinaryArray.Builder();
+            builder.Append(new byte[] { 1 }.AsSpan());
+            builder.AppendNull();
+            builder.Append(new byte[] { 2 }.AsSpan());
+            builder.AppendNull();
+
+            var array = builder.Build();
+
+            Assert.Equal(4, array.Length);
+            Assert.Equal(2, array.NullCount);
+        }
+    }
+}
diff --git a/test/Apache.Arrow.Tests/LargeListArrayBuilderTests.cs 
b/test/Apache.Arrow.Tests/LargeListArrayBuilderTests.cs
new file mode 100644
index 0000000..3fd448a
--- /dev/null
+++ b/test/Apache.Arrow.Tests/LargeListArrayBuilderTests.cs
@@ -0,0 +1,131 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Apache.Arrow.Types;
+using Xunit;
+
+namespace Apache.Arrow.Tests
+{
+    public class LargeListArrayBuilderTests
+    {
+        [Fact]
+        public void AppendBuildsCorrectArray()
+        {
+            var builder = new LargeListArray.Builder(Int32Type.Default);
+            var valueBuilder = (Int32Array.Builder)builder.ValueBuilder;
+
+            builder.Append();
+            valueBuilder.Append(1);
+            valueBuilder.Append(2);
+
+            builder.Append();
+            valueBuilder.Append(3);
+
+            builder.AppendNull();
+
+            builder.Append();
+
+            var array = builder.Build();
+
+            Assert.Equal(4, array.Length);
+
+            var slice0 = (Int32Array)array.GetSlicedValues(0);
+            Assert.Equal(2, slice0.Length);
+            Assert.Equal(1, slice0.GetValue(0));
+            Assert.Equal(2, slice0.GetValue(1));
+
+            var slice1 = (Int32Array)array.GetSlicedValues(1);
+            Assert.Equal(1, slice1.Length);
+            Assert.Equal(3, slice1.GetValue(0));
+
+            Assert.Null(array.GetSlicedValues(2));
+
+            var slice3 = (Int32Array)array.GetSlicedValues(3);
+            Assert.Equal(0, slice3.Length);
+        }
+
+        [Fact]
+        public void NullCountIsCorrect()
+        {
+            var builder = new LargeListArray.Builder(Int32Type.Default);
+            var valueBuilder = (Int32Array.Builder)builder.ValueBuilder;
+
+            builder.Append();
+            valueBuilder.Append(1);
+
+            builder.AppendNull();
+            builder.AppendNull();
+
+            builder.Append();
+            valueBuilder.Append(2);
+
+            var array = builder.Build();
+
+            Assert.Equal(4, array.Length);
+            Assert.Equal(2, array.NullCount);
+        }
+
+        [Fact]
+        public void ClearResetsBuilder()
+        {
+            var builder = new LargeListArray.Builder(Int32Type.Default);
+            var valueBuilder = (Int32Array.Builder)builder.ValueBuilder;
+
+            builder.Append();
+            valueBuilder.Append(1);
+            builder.AppendNull();
+
+            builder.Clear();
+
+            builder.Append();
+            valueBuilder.Append(99);
+
+            var array = builder.Build();
+
+            Assert.Equal(1, array.Length);
+            Assert.Equal(0, array.NullCount);
+            var slice = (Int32Array)array.GetSlicedValues(0);
+            Assert.Equal(1, slice.Length);
+            Assert.Equal(99, slice.GetValue(0));
+        }
+
+        [Fact]
+        public void NestedStringListBuildsCorrectly()
+        {
+            var builder = new LargeListArray.Builder(StringType.Default);
+            var valueBuilder = (StringArray.Builder)builder.ValueBuilder;
+
+            builder.Append();
+            valueBuilder.Append("hello");
+            valueBuilder.Append("world");
+
+            builder.Append();
+            valueBuilder.Append("foo");
+
+            var array = builder.Build();
+
+            Assert.Equal(2, array.Length);
+
+            var slice0 = (StringArray)array.GetSlicedValues(0);
+            Assert.Equal(2, slice0.Length);
+            Assert.Equal("hello", slice0.GetString(0));
+            Assert.Equal("world", slice0.GetString(1));
+
+            var slice1 = (StringArray)array.GetSlicedValues(1);
+            Assert.Equal(1, slice1.Length);
+            Assert.Equal("foo", slice1.GetString(0));
+        }
+    }
+}
diff --git a/test/Apache.Arrow.Tests/LargeStringArrayBuilderTests.cs 
b/test/Apache.Arrow.Tests/LargeStringArrayBuilderTests.cs
new file mode 100644
index 0000000..e50a04b
--- /dev/null
+++ b/test/Apache.Arrow.Tests/LargeStringArrayBuilderTests.cs
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Xunit;
+
+namespace Apache.Arrow.Tests
+{
+    public class LargeStringArrayBuilderTests
+    {
+        [Fact]
+        public void AppendStringBuildsCorrectArray()
+        {
+            var builder = new LargeStringArray.Builder();
+            builder.Append("hello");
+            builder.Append("world");
+            builder.AppendNull();
+            builder.Append("");
+
+            var array = builder.Build();
+
+            Assert.Equal(4, array.Length);
+            Assert.Equal("hello", array.GetString(0));
+            Assert.Equal("world", array.GetString(1));
+            Assert.Null(array.GetString(2));
+            Assert.Equal("", array.GetString(3));
+        }
+
+        [Fact]
+        public void AppendRangeBuildsCorrectArray()
+        {
+            var builder = new LargeStringArray.Builder();
+            builder.AppendRange(new[] { "foo", null, "bar", "baz" });
+
+            var array = builder.Build();
+
+            Assert.Equal(4, array.Length);
+            Assert.Equal("foo", array.GetString(0));
+            Assert.Null(array.GetString(1));
+            Assert.Equal("bar", array.GetString(2));
+            Assert.Equal("baz", array.GetString(3));
+        }
+
+        [Fact]
+        public void ClearResetsBuilder()
+        {
+            var builder = new LargeStringArray.Builder();
+            builder.Append("hello");
+            builder.Clear();
+            builder.Append("world");
+
+            var array = builder.Build();
+
+            Assert.Equal(1, array.Length);
+            Assert.Equal("world", array.GetString(0));
+        }
+
+        [Fact]
+        public void NullCountIsCorrect()
+        {
+            var builder = new LargeStringArray.Builder();
+            builder.Append("a");
+            builder.AppendNull();
+            builder.Append("b");
+            builder.AppendNull();
+
+            var array = builder.Build();
+
+            Assert.Equal(4, array.Length);
+            Assert.Equal(2, array.NullCount);
+        }
+    }
+}


Reply via email to