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

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


The following commit(s) were added to refs/heads/main by this push:
     new 72e9a569 perf(compute): add ARM64 NEON compression for null-free 
32-bit fixed-width filters (#1286)
72e9a569 is described below

commit 72e9a5695337bab9ac01ec1e4d58177bc4949dc3
Author: Minh Vu <[email protected]>
AuthorDate: Fri Sep 4 18:46:17 2026 +0200

    perf(compute): add ARM64 NEON compression for null-free 32-bit fixed-width 
filters (#1286)
    
    ## Summary
    
    * **Add an ARM64 NEON path** for null-free 32-bit fixed-width filters.
    * **Compact two groups of four values** with table-driven `VTBL`.
    * **Use exact-size stores** for the selected values.
    * Keep the current fallbacks for nulls, short or unaligned inputs, dense
    masks, unsupported CPUs, and `noasm` builds.
    
    ## Benchmark
    
    Hardware: Apple M1 Pro, macOS arm64, Go 1.26.3.
    
    Command: `go test ./arrow/compute -run '^$' -bench
    '^BenchmarkFilter(Int32|Float32)MixedMasks$' -benchtime=100ms -count=3
    -benchmem`
    
    The baseline used the same command with `GODEBUG=cpu.all=off`, which
    forces the existing scalar path. Values are median ns/op from three
    runs. Pattern order is `alternating / random25 / random50 / random75 /
    clustered50 / all-selected / none-selected`.
    
    | Type | Rows | Baseline ns/op | NEON ns/op | Speedup |
    | --- | ---: | --- | --- | --- |
    | int32 | 1K | 9002 / 6043 / 7167 / 6126 / 4336 / 4603 / 3376 | 4398 /
    4345 / 4617 / 4679 / 4548 / 4812 / 3432 | 2.05x / 1.39x / 1.55x / 1.31x
    / 0.95x / 0.96x / 0.98x |
    | int32 | 64K | 274954 / 145437 / 226114 / 192618 / 36169 / 45217 / 6176
    | 37957 / 69222 / 90711 / 71447 / 35481 / 46478 / 6306 | 7.24x / 2.10x /
    2.49x / 2.70x / 1.02x / 0.97x / 0.98x |
    | int32 | 1M | 4016235 / 2118964 / 3441839 / 2839365 / 300915 / 232850 /
    48657 | 340022 / 1273778 / 1530240 / 1312927 / 291230 / 235818 / 48973 |
    11.81x / 1.66x / 2.25x / 2.16x / 1.03x / 0.99x / 0.99x |
    | float32 | 1K | 8875 / 5979 / 7188 / 6157 / 4455 / 4647 / 3373 | 4428 /
    4286 / 4579 / 4686 / 4441 / 4844 / 3418 | 2.00x / 1.40x / 1.57x / 1.31x
    / 1.00x / 0.96x / 0.99x |
    | float32 | 64K | 267098 / 145365 / 226897 / 193153 / 35817 / 44286 /
    6171 | 37340 / 71035 / 93770 / 73563 / 36372 / 44714 / 6239 | 7.15x /
    2.05x / 2.42x / 2.63x / 0.98x / 0.99x / 0.99x |
    | float32 | 1M | 4061853 / 2116060 / 3435942 / 2850531 / 304719 / 272701
    / 48689 | 344281 / 1268462 / 1516895 / 1300810 / 293596 / 233508 / 49292
    | 11.80x / 1.67x / 2.27x / 2.19x / 1.04x / 1.17x / 0.99x |
    
    Fallback controls stayed on the existing path:
    
    | Control | Baseline ns/op | NEON build ns/op |
    | --- | ---: | ---: |
    | unaligned filter offset 3 | 280053 | 271730 |
    | short input, 56 rows | 4436 | 4392 |
    | non-multiple length, 65537 rows | 272665 | 268016 |
    
    ## Tests
    
    * `go test ./arrow/compute/... -count=1`
    * `go test -race ./arrow/compute/internal/kernels ./arrow/compute
    -count=1`
    * `go test -tags noasm ./arrow/compute/internal/kernels ./arrow/compute
    -count=1`
    * `GOARCH=amd64 go test -c -o /dev/null
    ./arrow/compute/internal/kernels`
    * `GOARCH=amd64 go test -c -o /dev/null ./arrow/compute`
    
    ## Limitations
    
    * This is limited to ARM64 ASIMD, 32-bit fixed-width values, no value
    nulls, no filter nulls, aligned filter bitmap offsets, and lengths
    divisible by 8.
    * All other cases keep using the existing general or specialized paths.
---
 .../internal/kernels/filter_uint32_neon_arm64.go   |  90 +++++++++++++
 .../internal/kernels/filter_uint32_neon_arm64.s    | 149 +++++++++++++++++++++
 .../kernels/filter_uint32_neon_arm64_test.go       | 133 ++++++++++++++++++
 .../internal/kernels/filter_uint32_neon_noasm.go   |  23 ++++
 arrow/compute/internal/kernels/vector_selection.go |   3 +-
 arrow/compute/vector_selection_bench_test.go       |  80 ++++++++++-
 6 files changed, 474 insertions(+), 4 deletions(-)

diff --git a/arrow/compute/internal/kernels/filter_uint32_neon_arm64.go 
b/arrow/compute/internal/kernels/filter_uint32_neon_arm64.go
new file mode 100644
index 00000000..c5de5a1e
--- /dev/null
+++ b/arrow/compute/internal/kernels/filter_uint32_neon_arm64.go
@@ -0,0 +1,90 @@
+// 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.
+
+//go:build go1.18 && arm64 && !noasm && !appengine
+
+package kernels
+
+import (
+       "math/bits"
+       "unsafe"
+
+       "golang.org/x/sys/cpu"
+)
+
+var filterUint32NeonTables = makeFilterUint32NeonTables()
+
+func makeFilterUint32NeonTables() (tables [352]byte) {
+       for mask := 0; mask < 16; mask++ {
+               pos := 0
+               for lane := 0; lane < 4; lane++ {
+                       if mask&(1<<uint(lane)) == 0 {
+                               continue
+                       }
+                       for byteInLane := 0; byteInLane < 4; byteInLane++ {
+                               tables[mask*16+pos] = byte(lane*4 + byteInLane)
+                               pos++
+                       }
+               }
+               for ; pos < 16; pos++ {
+                       tables[mask*16+pos] = 0x80
+               }
+       }
+
+       for mask := 0; mask < 16; mask++ {
+               tables[336+mask] = byte(bits.OnesCount8(uint8(mask)))
+       }
+       return tables
+}
+
+//go:noescape
+func _filter_uint32_neon(values, filter, output, tables unsafe.Pointer, length 
int64)
+
+func filterUint32Neon(values []uint32, output []uint32, filterData []byte, 
filterOffset, length int64) bool {
+       if !cpu.ARM64.HasASIMD || length < 64 || length%8 != 0 || 
filterOffset%8 != 0 {
+               return false
+       }
+
+       numBytes := length / 8
+       filterByteOffset := filterOffset / 8
+       if filterByteOffset < 0 || filterByteOffset+numBytes > 
int64(len(filterData)) {
+               return false
+       }
+
+       mixedBytes := 0
+       const sampleBytes = 64
+       for i := int64(0); i < numBytes && i < sampleBytes; i++ {
+               mask := filterData[filterByteOffset+i]
+               if mask != 0 && mask != 0xff {
+                       mixedBytes++
+                       if mixedBytes == 4 {
+                               break
+                       }
+               }
+       }
+       if mixedBytes < 4 || len(output) == 0 {
+               return false
+       }
+
+       _filter_uint32_neon(
+               unsafe.Pointer(&values[0]),
+               unsafe.Pointer(&filterData[filterByteOffset]),
+               unsafe.Pointer(&output[0]),
+               unsafe.Pointer(&filterUint32NeonTables[0]),
+               length,
+       )
+       return true
+}
diff --git a/arrow/compute/internal/kernels/filter_uint32_neon_arm64.s 
b/arrow/compute/internal/kernels/filter_uint32_neon_arm64.s
new file mode 100644
index 00000000..032daea7
--- /dev/null
+++ b/arrow/compute/internal/kernels/filter_uint32_neon_arm64.s
@@ -0,0 +1,149 @@
+// 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.
+
+//go:build go1.18 && arm64 && !noasm && !appengine
+
+#include "textflag.h"
+
+// Each filter byte selects up to four uint32 values from each of two
+// four-value halves. The table-driven VTBL compacts one half in-place. The
+// count-specific stores write exactly the selected number of bytes, because
+// the output allocation is sized to the filter's population count.
+
+// func _filter_uint32_neon(values, filter, output, tables unsafe.Pointer, 
length int64)
+TEXT ยท_filter_uint32_neon(SB), NOSPLIT, $0-40
+       MOVD values+0(FP), R0
+       MOVD filter+8(FP), R1
+       MOVD output+16(FP), R2
+       MOVD tables+24(FP), R3
+       MOVD length+32(FP), R4
+
+       LSR $3, R4, R4
+
+filter_loop:
+       MOVBU (R1), R5
+       ADD $1, R1
+       CBZ R5, filter_next
+
+       CMPW $255, R5
+       BEQ filter_all
+
+       VLD1 (R0), [V0.B16]
+       ADD $16, R0, R8
+       VLD1 (R8), [V1.B16]
+
+       ANDW $15, R5, R6
+       ADD $336, R3, R8
+       MOVBU (R8)(R6<<0), R9
+       CBZ R9, filter_high
+
+       LSL $4, R6, R8
+       ADD R3, R8, R8
+       VLD1 (R8), [V2.B16]
+       VTBL V2.B16, [V0.B16], V0.B16
+
+       CMPW $1, R9
+       BEQ filter_low_store1
+       CMPW $2, R9
+       BEQ filter_low_store2
+       CMPW $3, R9
+       BEQ filter_low_store3
+       VST1 [V0.S4], (R2)
+       ADD $16, R2
+       B filter_high
+
+filter_low_store1:
+       VMOV V0.S[0], R8
+       MOVW R8, (R2)
+       ADD $4, R2
+       B filter_high
+
+filter_low_store2:
+       VMOV V0.S[0], R8
+       MOVW R8, (R2)
+       VMOV V0.S[1], R8
+       MOVW R8, 4(R2)
+       ADD $8, R2
+       B filter_high
+
+filter_low_store3:
+       VMOV V0.S[0], R8
+       MOVW R8, (R2)
+       VMOV V0.S[1], R8
+       MOVW R8, 4(R2)
+       VMOV V0.S[2], R8
+       MOVW R8, 8(R2)
+       ADD $12, R2
+
+filter_high:
+       LSR $4, R5, R6
+       ADD $336, R3, R8
+       MOVBU (R8)(R6<<0), R9
+       CBZ R9, filter_next
+
+       LSL $4, R6, R8
+       ADD R3, R8, R8
+       VLD1 (R8), [V2.B16]
+       VTBL V2.B16, [V1.B16], V1.B16
+
+       CMPW $1, R9
+       BEQ filter_high_store1
+       CMPW $2, R9
+       BEQ filter_high_store2
+       CMPW $3, R9
+       BEQ filter_high_store3
+       VST1 [V1.S4], (R2)
+       ADD $16, R2
+       B filter_next
+
+filter_high_store1:
+       VMOV V1.S[0], R8
+       MOVW R8, (R2)
+       ADD $4, R2
+       B filter_next
+
+filter_high_store2:
+       VMOV V1.S[0], R8
+       MOVW R8, (R2)
+       VMOV V1.S[1], R8
+       MOVW R8, 4(R2)
+       ADD $8, R2
+       B filter_next
+
+filter_high_store3:
+       VMOV V1.S[0], R8
+       MOVW R8, (R2)
+       VMOV V1.S[1], R8
+       MOVW R8, 4(R2)
+       VMOV V1.S[2], R8
+       MOVW R8, 8(R2)
+       ADD $12, R2
+       B filter_next
+
+filter_all:
+       VLD1 (R0), [V0.B16]
+       ADD $16, R0, R8
+       VLD1 (R8), [V1.B16]
+       VST1 [V0.B16], (R2)
+       ADD $16, R2
+       VST1 [V1.B16], (R2)
+       ADD $16, R2
+
+filter_next:
+       ADD $32, R0
+       SUBS $1, R4, R4
+       BNE filter_loop
+       RET
diff --git a/arrow/compute/internal/kernels/filter_uint32_neon_arm64_test.go 
b/arrow/compute/internal/kernels/filter_uint32_neon_arm64_test.go
new file mode 100644
index 00000000..d2d9d6ea
--- /dev/null
+++ b/arrow/compute/internal/kernels/filter_uint32_neon_arm64_test.go
@@ -0,0 +1,133 @@
+// 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.
+
+//go:build go1.18 && arm64 && !noasm && !appengine
+
+package kernels
+
+import (
+       "testing"
+
+       "golang.org/x/sys/cpu"
+)
+
+func TestFilterUint32NeonAllMasks(t *testing.T) {
+       if !cpu.ARM64.HasASIMD {
+               t.Skip("ARM64 SIMD is not available")
+       }
+
+       const (
+               bytes  = 256
+               length = bytes * 8
+       )
+       values := make([]uint32, length)
+       filter := make([]byte, bytes)
+       for i := range values {
+               values[i] = uint32(i*17 + 3)
+       }
+       for i := range filter {
+               filter[i] = byte(i)
+       }
+
+       expected := make([]uint32, 0, length)
+       for i, mask := range filter {
+               for lane := 0; lane < 8; lane++ {
+                       if mask&(1<<uint(lane)) != 0 {
+                               expected = append(expected, values[i*8+lane])
+                       }
+               }
+       }
+
+       backing := make([]uint32, len(expected)+1)
+       backing[len(expected)] = 0xdeadbeef
+       if !filterUint32Neon(values, backing[:len(expected)], filter, 0, 
length) {
+               t.Fatal("filterUint32Neon did not select the mixed-mask path")
+       }
+       for i, want := range expected {
+               if got := backing[i]; got != want {
+                       t.Fatalf("output[%d] = %d, want %d", i, got, want)
+               }
+       }
+       if got := backing[len(expected)]; got != 0xdeadbeef {
+               t.Fatalf("sentinel = %#x, want %#x", got, uint32(0xdeadbeef))
+       }
+}
+
+func TestFilterUint32NeonAlignedOffset(t *testing.T) {
+       if !cpu.ARM64.HasASIMD {
+               t.Skip("ARM64 SIMD is not available")
+       }
+
+       const (
+               offset = 8
+               length = 64
+       )
+       values := make([]uint32, length)
+       for i := range values {
+               values[i] = uint32(i)
+       }
+       filter := make([]byte, offset/8+length/8)
+       for i := range filter[offset/8:] {
+               filter[offset/8+i] = 0x55
+       }
+
+       output := make([]uint32, length/2)
+       if !filterUint32Neon(values, output, filter, offset, length) {
+               t.Fatal("filterUint32Neon did not select the aligned-offset 
path")
+       }
+       for i, got := range output {
+               want := uint32(2 * i)
+               if got != want {
+                       t.Fatalf("output[%d] = %d, want %d", i, got, want)
+               }
+       }
+}
+
+func TestFilterUint32NeonGuards(t *testing.T) {
+       if !cpu.ARM64.HasASIMD {
+               t.Skip("ARM64 SIMD is not available")
+       }
+
+       values := make([]uint32, 128)
+       mixed := make([]byte, 16)
+       for i := range mixed {
+               mixed[i] = 0x55
+       }
+       output := make([]uint32, 64)
+
+       tests := []struct {
+               name   string
+               filter []byte
+               offset int64
+               length int64
+               want   bool
+       }{
+               {name: "short", filter: mixed, length: 56},
+               {name: "non-multiple-of-eight", filter: mixed, length: 72 - 1},
+               {name: "unaligned-filter-offset", filter: mixed, offset: 3, 
length: 64},
+               {name: "all-false", filter: make([]byte, 8), length: 64},
+               {name: "all-true", filter: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff}, length: 64},
+               {name: "too-few-mixed-bytes", filter: []byte{0x55, 0x55, 0x55, 
0x00, 0x00, 0x00, 0x00, 0x00}, length: 64},
+               {name: "out-of-bounds-filter", filter: mixed[:4], length: 64},
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       if got := filterUint32Neon(values, output, tt.filter, 
tt.offset, tt.length); got != tt.want {
+                               t.Fatalf("filterUint32Neon() = %t, want %t", 
got, tt.want)
+                       }
+               })
+       }
+}
diff --git a/arrow/compute/internal/kernels/filter_uint32_neon_noasm.go 
b/arrow/compute/internal/kernels/filter_uint32_neon_noasm.go
new file mode 100644
index 00000000..66e28f3a
--- /dev/null
+++ b/arrow/compute/internal/kernels/filter_uint32_neon_noasm.go
@@ -0,0 +1,23 @@
+// 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.
+
+//go:build go1.18 && (noasm || !arm64 || appengine)
+
+package kernels
+
+func filterUint32Neon([]uint32, []uint32, []byte, int64, int64) bool {
+       return false
+}
diff --git a/arrow/compute/internal/kernels/vector_selection.go 
b/arrow/compute/internal/kernels/vector_selection.go
index 09454116..32a6f4b7 100644
--- a/arrow/compute/internal/kernels/vector_selection.go
+++ b/arrow/compute/internal/kernels/vector_selection.go
@@ -490,7 +490,8 @@ func PrimitiveFilter(ctx *exec.KernelCtx, batch 
*exec.ExecSpan, out *exec.ExecRe
        if bitWidth == 32 && values.Nulls == 0 && filter.Nulls == 0 {
                valuesData := exec.GetSpanValues[uint32](values, 1)
                outData := exec.GetSpanValues[uint32](out, 1)
-               if filterUint32Avx2(valuesData, outData, filter.Buffers[1].Buf, 
filter.Offset, values.Len) {
+               if filterUint32Avx2(valuesData, outData, filter.Buffers[1].Buf, 
filter.Offset, values.Len) ||
+                       filterUint32Neon(valuesData, outData, 
filter.Buffers[1].Buf, filter.Offset, values.Len) {
                        return nil
                }
        }
diff --git a/arrow/compute/vector_selection_bench_test.go 
b/arrow/compute/vector_selection_bench_test.go
index b5e8993e..4a14f6ad 100644
--- a/arrow/compute/vector_selection_bench_test.go
+++ b/arrow/compute/vector_selection_bench_test.go
@@ -32,6 +32,16 @@ import (
 var benchmarkFilterOutputLength int
 
 func BenchmarkFilterInt32MixedMasks(b *testing.B) {
+       benchmarkFilter32MixedMasks(b, makeFilterInt32BenchmarkInput)
+}
+
+func BenchmarkFilterFloat32MixedMasks(b *testing.B) {
+       benchmarkFilter32MixedMasks(b, makeFilterFloat32BenchmarkInput)
+}
+
+func benchmarkFilter32MixedMasks(b *testing.B,
+       makeInput func(*testing.B, int, func(int) bool) (arrow.Array, 
arrow.Array),
+) {
        patterns := []struct {
                name     string
                selected func(int) bool
@@ -50,7 +60,7 @@ func BenchmarkFilterInt32MixedMasks(b *testing.B) {
                for _, pattern := range patterns {
                        pattern := pattern
                        b.Run(fmt.Sprintf("size=%d/%s", size, pattern.name), 
func(b *testing.B) {
-                               values, filter := 
makeFilterInt32BenchmarkInput(b, size, pattern.selected)
+                               values, filter := makeInput(b, size, 
pattern.selected)
                                defer values.Release()
                                defer filter.Release()
 
@@ -70,16 +80,80 @@ func BenchmarkFilterInt32MixedMasks(b *testing.B) {
        }
 }
 
+func BenchmarkFilterInt32FallbackControls(b *testing.B) {
+       controls := []struct {
+               name   string
+               size   int
+               offset int64
+       }{
+               {name: "unaligned-filter-offset", size: 1 << 16, offset: 3},
+               {name: "short", size: 56},
+               {name: "non-multiple-of-eight", size: 1<<16 + 1},
+       }
+
+       for _, control := range controls {
+               control := control
+               b.Run(control.name, func(b *testing.B) {
+                       values, filter := 
makeFilterInt32BenchmarkInputWithOffset(b, control.size, control.offset,
+                               func(i int) bool { return i%2 == 0 })
+                       defer values.Release()
+                       defer filter.Release()
+
+                       b.ReportAllocs()
+                       b.SetBytes(int64(control.size * 4))
+                       b.ResetTimer()
+                       for i := 0; i < b.N; i++ {
+                               result, err := 
compute.FilterArray(context.Background(), values, filter, 
*compute.DefaultFilterOptions())
+                               if err != nil {
+                                       b.Fatal(err)
+                               }
+                               benchmarkFilterOutputLength = result.Len()
+                               result.Release()
+                       }
+               })
+       }
+}
+
 func makeFilterInt32BenchmarkInput(b *testing.B, size int, selected func(int) 
bool) (arrow.Array, arrow.Array) {
+       return makeFilterInt32BenchmarkInputWithOffset(b, size, 0, selected)
+}
+
+func makeFilterInt32BenchmarkInputWithOffset(b *testing.B, size int, offset 
int64, selected func(int) bool) (arrow.Array, arrow.Array) {
        b.Helper()
        mem := memory.DefaultAllocator
 
        valuesBuilder := array.NewInt32Builder(mem)
+       valuesBuilder.Reserve(size + int(offset))
+       for i := 0; i < size+int(offset); i++ {
+               valuesBuilder.Append(int32(i))
+       }
+       valuesBase := valuesBuilder.NewInt32Array()
+       valuesBuilder.Release()
+       values := array.NewSlice(valuesBase, offset, offset+int64(size))
+       valuesBase.Release()
+
+       filterBuilder := array.NewBooleanBuilder(mem)
+       filterBuilder.Reserve(size + int(offset))
+       for i := 0; i < size+int(offset); i++ {
+               filterBuilder.Append(selected(i))
+       }
+       filterBase := filterBuilder.NewBooleanArray()
+       filterBuilder.Release()
+       filter := array.NewSlice(filterBase, offset, offset+int64(size))
+       filterBase.Release()
+       return values, filter
+}
+
+func makeFilterFloat32BenchmarkInput(b *testing.B, size int, selected 
func(int) bool) (arrow.Array, arrow.Array) {
+       b.Helper()
+       mem := memory.DefaultAllocator
+
+       valuesBuilder := array.NewFloat32Builder(mem)
        valuesBuilder.Reserve(size)
        for i := 0; i < size; i++ {
-               valuesBuilder.Append(int32(i))
+               valuesBuilder.Append(float32(i))
        }
-       values := valuesBuilder.NewInt32Array()
+       values := valuesBuilder.NewFloat32Array()
        valuesBuilder.Release()
 
        filterBuilder := array.NewBooleanBuilder(mem)

Reply via email to