Skip to content

Commit 49c27d6

Browse files
authored
Add special implementation for zip for Utf8View/BinaryView scalars (#8963)
# Which issue does this PR close? - Closes #8724 # Rationale for this change It's explained in the issue. # What changes are included in this PR? This adds a special implementation for Utf8View/BinaryView scalars for zip based on the design from #8653. It also includes tests. Benchmarks are available here: - #8988 # Are these changes tested? Yes. # Are there any user-facing changes? There is a new struct `ByteViewScalarImpl`. <details close> <summary>Benchmarks</summary> System: Apple M1 Max with 10 cores on macOS 26.1 ``` group branch main ----- ------ ---- zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/10pct_true 1.00 3.5±0.04µs ? ?/sec 37.06 128.9±1.36µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/1pct_true 1.00 3.5±0.07µs ? ?/sec 35.76 125.1±1.76µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/50pct_nulls 1.00 3.7±0.12µs ? ?/sec 36.91 136.8±2.17µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/50pct_true 1.00 3.5±0.06µs ? ?/sec 40.30 139.9±2.11µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/90pct_true 1.00 3.6±0.10µs ? ?/sec 30.57 108.5±2.62µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/99pct_true 1.00 3.5±0.05µs ? ?/sec 28.40 99.8±2.12µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/all_false 1.00 3.5±0.02µs ? ?/sec 36.04 127.4±3.14µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_null_scalar_vs_null_scalar/all_true 1.00 3.5±0.08µs ? ?/sec 27.39 97.1±1.11µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/10pct_true 1.00 28.2±0.37µs ? ?/sec 2.70 75.9±0.61µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/1pct_true 1.00 7.2±0.24µs ? ?/sec 9.89 71.4±12.56µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/50pct_nulls 1.00 51.0±2.97µs ? ?/sec 1.75 89.4±2.50µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/50pct_true 1.00 62.1±1.00µs ? ?/sec 1.61 99.7±4.68µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/90pct_true 1.00 28.8±0.64µs ? ?/sec 2.63 75.7±1.22µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/99pct_true 1.00 7.7±0.11µs ? ?/sec 8.98 69.0±0.74µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/all_false 1.00 3.7±0.13µs ? ?/sec 19.06 69.8±1.55µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/non_nulls_scalars/all_true 1.00 3.6±0.10µs ? ?/sec 18.90 68.0±1.12µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/10pct_true 1.00 3.8±0.07µs ? ?/sec 28.85 108.4±3.09µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/1pct_true 1.00 3.8±0.09µs ? ?/sec 25.83 98.7±2.71µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/50pct_nulls 1.00 3.9±0.06µs ? ?/sec 32.25 127.3±7.41µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/50pct_true 1.00 3.7±0.06µs ? ?/sec 37.66 139.5±3.00µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/90pct_true 1.00 3.8±0.16µs ? ?/sec 34.52 129.5±1.53µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/99pct_true 1.00 3.7±0.05µs ? ?/sec 33.83 124.8±1.28µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/all_false 1.00 3.8±0.09µs ? ?/sec 26.08 98.8±2.02µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 10/null_vs_non_null_scalar/all_true 1.00 3.8±0.08µs ? ?/sec 32.56 123.9±1.48µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/10pct_true 1.00 3.6±0.06µs ? ?/sec 36.09 129.8±6.06µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/1pct_true 1.00 3.6±0.35µs ? ?/sec 34.05 122.9±5.06µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/50pct_nulls 1.00 3.7±0.12µs ? ?/sec 36.77 137.9±5.49µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/50pct_true 1.00 3.6±0.09µs ? ?/sec 38.23 137.4±3.35µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/90pct_true 1.00 3.6±0.06µs ? ?/sec 29.20 104.8±1.64µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/99pct_true 1.00 3.6±0.15µs ? ?/sec 26.94 96.9±2.73µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/all_false 1.00 3.6±0.05µs ? ?/sec 34.97 127.5±5.81µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_null_scalar_vs_null_scalar/all_true 1.00 3.8±1.05µs ? ?/sec 24.98 95.0±2.14µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/10pct_true 1.00 28.9±0.46µs ? ?/sec 2.69 77.7±1.57µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/1pct_true 1.00 7.3±0.09µs ? ?/sec 9.81 71.6±1.96µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/50pct_nulls 1.00 50.3±1.16µs ? ?/sec 1.74 87.7±1.14µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/50pct_true 1.00 63.5±1.44µs ? ?/sec 1.59 100.7±1.97µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/90pct_true 1.00 29.8±0.48µs ? ?/sec 2.64 78.6±2.85µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/99pct_true 1.00 8.2±0.12µs ? ?/sec 8.54 69.7±0.91µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/all_false 1.00 3.8±0.07µs ? ?/sec 18.77 71.6±1.51µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/non_nulls_scalars/all_true 1.00 3.8±0.11µs ? ?/sec 18.31 68.8±1.10µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/10pct_true 1.00 3.8±0.07µs ? ?/sec 27.36 104.3±1.35µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/1pct_true 1.00 3.8±0.07µs ? ?/sec 24.86 94.8±1.12µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/50pct_nulls 1.00 4.0±0.04µs ? ?/sec 29.84 117.9±1.34µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/50pct_true 1.00 3.9±0.21µs ? ?/sec 35.19 137.1±3.87µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/90pct_true 1.00 3.8±0.06µs ? ?/sec 32.78 125.8±1.73µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/99pct_true 1.00 3.8±0.11µs ? ?/sec 31.87 121.5±1.47µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/all_false 1.00 3.8±0.07µs ? ?/sec 25.36 95.5±1.89µs ? ?/sec zip_8192_from_string_views size 10 and string_views size 100/null_vs_non_null_scalar/all_true 1.00 3.9±0.20µs ? ?/sec 30.83 121.7±3.36µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/10pct_true 1.00 3.7±0.73µs ? ?/sec 35.72 132.2±6.77µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/1pct_true 1.00 3.6±0.04µs ? ?/sec 35.35 125.8±2.79µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/50pct_nulls 1.00 3.8±0.11µs ? ?/sec 36.05 136.0±2.59µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/50pct_true 1.00 3.6±0.13µs ? ?/sec 39.36 142.5±6.32µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/90pct_true 1.00 3.6±0.11µs ? ?/sec 29.63 107.5±2.03µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/99pct_true 1.00 3.6±0.08µs ? ?/sec 28.40 102.2±6.74µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/all_false 1.00 3.6±0.05µs ? ?/sec 34.83 126.0±2.12µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_null_scalar_vs_null_scalar/all_true 1.00 3.6±0.05µs ? ?/sec 27.38 98.6±1.62µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/10pct_true 1.00 29.9±2.79µs ? ?/sec 2.51 75.1±0.98µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/1pct_true 1.00 7.2±0.16µs ? ?/sec 9.48 68.3±1.01µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/50pct_nulls 1.00 50.5±1.90µs ? ?/sec 1.68 84.6±1.27µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/50pct_true 1.00 64.4±0.60µs ? ?/sec 1.53 98.6±1.71µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/90pct_true 1.00 29.7±0.61µs ? ?/sec 2.57 76.1±1.15µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/99pct_true 1.00 7.9±0.09µs ? ?/sec 8.89 70.5±2.13µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/all_false 1.00 3.7±0.06µs ? ?/sec 18.31 67.8±0.86µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/non_nulls_scalars/all_true 1.00 3.7±0.06µs ? ?/sec 18.35 67.9±1.16µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/10pct_true 1.00 3.8±0.12µs ? ?/sec 28.20 107.5±2.55µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/1pct_true 1.00 3.9±0.16µs ? ?/sec 25.73 99.5±2.19µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/50pct_nulls 1.00 4.1±0.14µs ? ?/sec 29.98 122.2±2.27µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/50pct_true 1.00 3.8±0.08µs ? ?/sec 37.05 140.1±2.01µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/90pct_true 1.00 3.9±0.20µs ? ?/sec 33.52 131.8±3.10µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/99pct_true 1.00 3.8±0.09µs ? ?/sec 33.55 127.6±3.56µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/all_false 1.00 3.8±0.08µs ? ?/sec 26.47 100.8±5.55µs ? ?/sec zip_8192_from_string_views size 100 and string_views size 100/null_vs_non_null_scalar/all_true 1.00 3.9±0.06µs ? ?/sec 32.05 124.6±2.16µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/10pct_true 1.00 3.6±0.40µs ? ?/sec 35.16 126.4±1.92µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/1pct_true 1.00 3.5±0.07µs ? ?/sec 35.43 123.6±4.98µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/50pct_nulls 1.00 3.7±0.06µs ? ?/sec 36.06 132.4±1.80µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/50pct_true 1.00 3.6±0.06µs ? ?/sec 38.44 136.9±2.82µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/90pct_true 1.00 3.5±0.04µs ? ?/sec 29.82 105.2±2.25µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/99pct_true 1.00 3.5±0.08µs ? ?/sec 27.48 96.9±1.69µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/all_false 1.00 3.6±0.12µs ? ?/sec 33.80 123.0±2.52µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_null_scalar_vs_null_scalar/all_true 1.00 3.6±0.14µs ? ?/sec 26.74 95.0±1.74µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/10pct_true 1.00 27.9±0.32µs ? ?/sec 2.65 73.9±1.31µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/1pct_true 1.00 6.9±0.09µs ? ?/sec 9.64 67.0±0.92µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/50pct_nulls 1.00 49.0±0.60µs ? ?/sec 1.73 84.7±2.45µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/50pct_true 1.00 62.4±2.22µs ? ?/sec 1.56 97.1±2.37µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/90pct_true 1.00 28.7±0.37µs ? ?/sec 2.59 74.1±1.17µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/99pct_true 1.00 7.8±0.20µs ? ?/sec 8.69 67.7±1.34µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/all_false 1.00 3.6±0.09µs ? ?/sec 18.78 68.2±2.16µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/non_nulls_scalars/all_true 1.00 3.6±0.05µs ? ?/sec 19.10 68.4±11.77µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/10pct_true 1.00 3.8±0.21µs ? ?/sec 27.30 104.1±1.34µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/1pct_true 1.00 3.7±0.04µs ? ?/sec 25.76 95.8±2.00µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/50pct_nulls 1.00 4.2±0.96µs ? ?/sec 28.05 118.0±1.17µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/50pct_true 1.00 3.9±0.13µs ? ?/sec 35.42 136.6±3.78µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/90pct_true 1.00 3.8±0.10µs ? ?/sec 33.31 125.5±1.89µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/99pct_true 1.00 3.8±0.04µs ? ?/sec 32.36 121.6±1.80µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/all_false 1.00 3.7±0.04µs ? ?/sec 25.64 95.1±0.98µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 10/null_vs_non_null_scalar/all_true 1.00 3.9±0.07µs ? ?/sec 31.19 121.2±2.69µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/10pct_true 1.00 3.5±0.04µs ? ?/sec 35.69 126.5±2.89µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/1pct_true 1.00 3.6±0.05µs ? ?/sec 33.84 120.9±1.68µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/50pct_nulls 1.00 3.7±0.10µs ? ?/sec 35.72 133.2±3.49µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/50pct_true 1.00 3.6±0.12µs ? ?/sec 38.28 136.0±2.11µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/90pct_true 1.00 3.5±0.06µs ? ?/sec 29.81 104.4±1.56µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/99pct_true 1.00 3.5±0.08µs ? ?/sec 27.69 98.1±2.86µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/all_false 1.00 3.6±0.10µs ? ?/sec 33.58 122.3±1.77µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_null_scalar_vs_null_scalar/all_true 1.00 3.5±0.08µs ? ?/sec 26.79 94.7±1.02µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/10pct_true 1.00 29.0±0.51µs ? ?/sec 2.59 75.1±1.08µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/1pct_true 1.00 7.4±0.10µs ? ?/sec 9.41 69.2±1.76µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/50pct_nulls 1.00 50.2±0.54µs ? ?/sec 1.70 85.2±1.17µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/50pct_true 1.00 64.1±1.59µs ? ?/sec 1.51 96.9±1.22µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/90pct_true 1.00 29.8±0.36µs ? ?/sec 2.55 75.9±2.47µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/99pct_true 1.00 8.2±0.17µs ? ?/sec 8.24 67.8±1.11µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/all_false 1.00 3.8±0.07µs ? ?/sec 17.96 68.8±1.15µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/non_nulls_scalars/all_true 1.00 3.8±0.12µs ? ?/sec 17.37 66.1±0.97µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/10pct_true 1.00 3.8±0.27µs ? ?/sec 27.57 105.2±3.06µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/1pct_true 1.00 3.7±0.08µs ? ?/sec 25.44 94.8±0.94µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/50pct_nulls 1.00 3.9±0.07µs ? ?/sec 30.10 118.6±2.83µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/50pct_true 1.00 3.9±0.30µs ? ?/sec 35.20 135.6±1.67µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/90pct_true 1.00 3.9±0.55µs ? ?/sec 32.58 125.9±2.14µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/99pct_true 1.00 3.8±0.36µs ? ?/sec 32.47 122.9±4.15µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/all_false 1.00 3.8±0.10µs ? ?/sec 25.24 94.9±0.97µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 100/null_vs_non_null_scalar/all_true 1.00 3.8±0.09µs ? ?/sec 31.58 120.3±1.65µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/10pct_true 1.00 3.5±0.04µs ? ?/sec 37.39 131.4±4.74µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/1pct_true 1.00 3.5±0.09µs ? ?/sec 35.84 126.8±3.56µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/50pct_nulls 1.00 3.7±0.06µs ? ?/sec 37.15 137.8±3.16µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/50pct_true 1.00 3.5±0.06µs ? ?/sec 39.19 138.9±4.82µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/90pct_true 1.00 3.6±0.04µs ? ?/sec 30.30 107.9±5.71µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/99pct_true 1.00 3.6±0.05µs ? ?/sec 27.33 97.7±2.10µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/all_false 1.00 3.6±0.06µs ? ?/sec 34.64 124.7±2.24µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_null_scalar_vs_null_scalar/all_true 1.00 3.7±0.19µs ? ?/sec 26.17 96.9±1.75µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/10pct_true 1.00 28.7±0.55µs ? ?/sec 2.66 76.2±1.45µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/1pct_true 1.00 7.2±0.12µs ? ?/sec 9.58 69.0±0.80µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/50pct_nulls 1.00 49.5±1.15µs ? ?/sec 1.75 86.8±2.09µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/50pct_true 1.00 62.6±0.88µs ? ?/sec 1.65 103.4±16.82µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/90pct_true 1.00 29.1±0.49µs ? ?/sec 2.69 78.3±2.51µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/99pct_true 1.00 7.8±0.09µs ? ?/sec 9.01 70.2±1.72µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/all_false 1.00 3.7±0.06µs ? ?/sec 18.77 68.7±0.73µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/non_nulls_scalars/all_true 1.00 3.6±0.10µs ? ?/sec 18.73 68.2±1.44µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/10pct_true 1.00 3.9±0.11µs ? ?/sec 27.68 106.9±2.29µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/1pct_true 1.00 3.9±0.19µs ? ?/sec 26.12 101.9±8.79µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/50pct_nulls 1.00 4.1±0.07µs ? ?/sec 29.91 122.7±3.28µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/50pct_true 1.00 3.8±0.14µs ? ?/sec 36.82 141.4±3.69µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/90pct_true 1.00 3.8±0.10µs ? ?/sec 34.15 131.4±2.99µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/99pct_true 1.00 3.8±0.06µs ? ?/sec 32.89 125.2±3.21µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/all_false 1.00 3.8±0.06µs ? ?/sec 26.05 99.2±2.30µs ? ?/sec zip_8192_from_string_views size 3 and string_views size 3/null_vs_non_null_scalar/all_true 1.00 4.0±0.33µs ? ?/sec 32.00 126.7±25.05µs ? ?/sec ``` </details>
1 parent 44d4c90 commit 49c27d6

File tree

1 file changed

+337
-4
lines changed

1 file changed

+337
-4
lines changed

arrow-select/src/zip.rs

Lines changed: 337 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@
1919
2020
use crate::filter::{SlicesIterator, prep_null_mask_filter};
2121
use arrow_array::cast::AsArray;
22-
use arrow_array::types::{BinaryType, ByteArrayType, LargeBinaryType, LargeUtf8Type, Utf8Type};
22+
use arrow_array::types::{
23+
BinaryType, BinaryViewType, ByteArrayType, ByteViewType, LargeBinaryType, LargeUtf8Type,
24+
StringViewType, Utf8Type,
25+
};
2326
use arrow_array::*;
2427
use arrow_buffer::{
2528
BooleanBuffer, Buffer, MutableBuffer, NullBuffer, OffsetBuffer, OffsetBufferBuilder,
26-
ScalarBuffer,
29+
ScalarBuffer, ToByteSlice,
2730
};
28-
use arrow_data::ArrayData;
2931
use arrow_data::transform::MutableArrayData;
32+
use arrow_data::{ArrayData, ByteView};
3033
use arrow_schema::{ArrowError, DataType};
3134
use std::fmt::{Debug, Formatter};
3235
use std::hash::Hash;
@@ -284,7 +287,12 @@ impl ScalarZipper {
284287
DataType::LargeBinary => {
285288
Arc::new(BytesScalarImpl::<LargeBinaryType>::new(truthy, falsy)) as Arc<dyn ZipImpl>
286289
},
287-
// TODO: Handle Utf8View https://github.com/apache/arrow-rs/issues/8724
290+
DataType::Utf8View => {
291+
Arc::new(ByteViewScalarImpl::<StringViewType>::new(truthy, falsy)) as Arc<dyn ZipImpl>
292+
},
293+
DataType::BinaryView => {
294+
Arc::new(ByteViewScalarImpl::<BinaryViewType>::new(truthy, falsy)) as Arc<dyn ZipImpl>
295+
},
288296
_ => {
289297
Arc::new(FallbackImpl::new(truthy, falsy)) as Arc<dyn ZipImpl>
290298
},
@@ -657,6 +665,177 @@ fn maybe_prep_null_mask_filter(predicate: &BooleanArray) -> BooleanBuffer {
657665
}
658666
}
659667

668+
struct ByteViewScalarImpl<T: ByteViewType> {
669+
truthy_view: Option<u128>,
670+
truthy_buffers: Vec<Buffer>,
671+
falsy_view: Option<u128>,
672+
falsy_buffers: Vec<Buffer>,
673+
phantom: PhantomData<T>,
674+
}
675+
676+
impl<T: ByteViewType> ByteViewScalarImpl<T> {
677+
fn new(truthy: &dyn Array, falsy: &dyn Array) -> Self {
678+
let (truthy_view, truthy_buffers) = Self::get_value_from_scalar(truthy);
679+
let (falsy_view, falsy_buffers) = Self::get_value_from_scalar(falsy);
680+
Self {
681+
truthy_view,
682+
truthy_buffers,
683+
falsy_view,
684+
falsy_buffers,
685+
phantom: PhantomData,
686+
}
687+
}
688+
689+
fn get_value_from_scalar(scalar: &dyn Array) -> (Option<u128>, Vec<Buffer>) {
690+
if scalar.is_null(0) {
691+
(None, vec![])
692+
} else {
693+
let (views, buffers, _) = scalar.as_byte_view::<T>().clone().into_parts();
694+
(views.first().copied(), buffers)
695+
}
696+
}
697+
698+
fn get_views_for_single_non_nullable(
699+
predicate: BooleanBuffer,
700+
value: u128,
701+
buffers: Vec<Buffer>,
702+
) -> (ScalarBuffer<u128>, Vec<Buffer>, Option<NullBuffer>) {
703+
let number_of_true = predicate.count_set_bits();
704+
let number_of_values = predicate.len();
705+
706+
// Fast path for all nulls
707+
if number_of_true == 0 {
708+
// All values are null
709+
return (
710+
vec![0; number_of_values].into(),
711+
vec![],
712+
Some(NullBuffer::new_null(number_of_values)),
713+
);
714+
}
715+
let bytes = vec![value; number_of_values];
716+
717+
// If value is true and we want to handle the TRUTHY case, the null buffer will have 1 (meaning not null)
718+
// If value is false and we want to handle the FALSY case, the null buffer will have 0 (meaning null)
719+
let nulls = NullBuffer::new(predicate);
720+
(bytes.into(), buffers, Some(nulls))
721+
}
722+
723+
fn get_views_for_non_nullable(
724+
predicate: BooleanBuffer,
725+
result_len: usize,
726+
truthy_view: u128,
727+
truthy_buffers: Vec<Buffer>,
728+
falsy_view: u128,
729+
falsy_buffers: Vec<Buffer>,
730+
) -> (ScalarBuffer<u128>, Vec<Buffer>, Option<NullBuffer>) {
731+
let true_count = predicate.count_set_bits();
732+
match true_count {
733+
0 => {
734+
// all values are falsy
735+
(vec![falsy_view; result_len].into(), falsy_buffers, None)
736+
}
737+
n if n == predicate.len() => {
738+
// all values are truthy
739+
(vec![truthy_view; result_len].into(), truthy_buffers, None)
740+
}
741+
_ => {
742+
let true_count = predicate.count_set_bits();
743+
let mut buffers: Vec<Buffer> = truthy_buffers.to_vec();
744+
745+
// If the falsy buffers are empty, we can use the falsy view as it is, because the value
746+
// is completely inlined. Otherwise, we have non-inlined values in the buffer, and we need
747+
// to recalculate the falsy view
748+
let view_falsy = if falsy_buffers.is_empty() {
749+
falsy_view
750+
} else {
751+
let byte_view_falsy = ByteView::from(falsy_view);
752+
let new_index_falsy_buffers =
753+
buffers.len() as u32 + byte_view_falsy.buffer_index;
754+
buffers.extend(falsy_buffers);
755+
let byte_view_falsy =
756+
byte_view_falsy.with_buffer_index(new_index_falsy_buffers);
757+
byte_view_falsy.as_u128()
758+
};
759+
760+
let total_number_of_bytes = true_count * 16 + (predicate.len() - true_count) * 16;
761+
let mut mutable = MutableBuffer::new(total_number_of_bytes);
762+
let mut filled = 0;
763+
764+
SlicesIterator::from(&predicate).for_each(|(start, end)| {
765+
if start > filled {
766+
let false_repeat_count = start - filled;
767+
mutable
768+
.repeat_slice_n_times(view_falsy.to_byte_slice(), false_repeat_count);
769+
}
770+
let true_repeat_count = end - start;
771+
mutable.repeat_slice_n_times(truthy_view.to_byte_slice(), true_repeat_count);
772+
filled = end;
773+
});
774+
775+
if filled < predicate.len() {
776+
let false_repeat_count = predicate.len() - filled;
777+
mutable.repeat_slice_n_times(view_falsy.to_byte_slice(), false_repeat_count);
778+
}
779+
780+
let bytes = Buffer::from(mutable);
781+
(bytes.into(), buffers, None)
782+
}
783+
}
784+
}
785+
}
786+
787+
impl<T: ByteViewType> Debug for ByteViewScalarImpl<T> {
788+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
789+
f.debug_struct("ByteViewScalarImpl")
790+
.field("truthy", &self.truthy_view)
791+
.field("falsy", &self.falsy_view)
792+
.finish()
793+
}
794+
}
795+
796+
impl<T: ByteViewType> ZipImpl for ByteViewScalarImpl<T> {
797+
fn create_output(&self, predicate: &BooleanArray) -> Result<ArrayRef, ArrowError> {
798+
let result_len = predicate.len();
799+
// Nulls are treated as false
800+
let predicate = maybe_prep_null_mask_filter(predicate);
801+
802+
let (views, buffers, nulls) = match (self.truthy_view, self.falsy_view) {
803+
(Some(truthy), Some(falsy)) => Self::get_views_for_non_nullable(
804+
predicate,
805+
result_len,
806+
truthy,
807+
self.truthy_buffers.clone(),
808+
falsy,
809+
self.falsy_buffers.clone(),
810+
),
811+
(Some(truthy), None) => Self::get_views_for_single_non_nullable(
812+
predicate,
813+
truthy,
814+
self.truthy_buffers.clone(),
815+
),
816+
(None, Some(falsy)) => {
817+
let predicate = predicate.not();
818+
Self::get_views_for_single_non_nullable(
819+
predicate,
820+
falsy,
821+
self.falsy_buffers.clone(),
822+
)
823+
}
824+
(None, None) => {
825+
// All values are null
826+
(
827+
vec![0; result_len].into(),
828+
vec![],
829+
Some(NullBuffer::new_null(result_len)),
830+
)
831+
}
832+
};
833+
834+
let result = unsafe { GenericByteViewArray::<T>::new_unchecked(views, buffers, nulls) };
835+
Ok(Arc::new(result))
836+
}
837+
}
838+
660839
#[cfg(test)]
661840
mod test {
662841
use super::*;
@@ -1222,4 +1401,158 @@ mod test {
12221401
]);
12231402
assert_eq!(actual, &expected);
12241403
}
1404+
1405+
#[test]
1406+
fn test_zip_kernel_scalar_strings_array_view() {
1407+
let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1408+
let scalar_falsy = Scalar::new(StringViewArray::from(vec!["world"]));
1409+
1410+
let mask = BooleanArray::from(vec![true, false, true, false]);
1411+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1412+
let actual = out.as_string_view();
1413+
let expected = StringViewArray::from(vec![
1414+
Some("hello"),
1415+
Some("world"),
1416+
Some("hello"),
1417+
Some("world"),
1418+
]);
1419+
assert_eq!(actual, &expected);
1420+
}
1421+
1422+
#[test]
1423+
fn test_zip_kernel_scalar_binary_array_view() {
1424+
let scalar_truthy = Scalar::new(BinaryViewArray::from_iter_values(vec![b"hello"]));
1425+
let scalar_falsy = Scalar::new(BinaryViewArray::from_iter_values(vec![b"world"]));
1426+
1427+
let mask = BooleanArray::from(vec![true, false]);
1428+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1429+
let actual = out.as_byte_view();
1430+
let expected = BinaryViewArray::from_iter_values(vec![b"hello", b"world"]);
1431+
assert_eq!(actual, &expected);
1432+
}
1433+
1434+
#[test]
1435+
fn test_zip_kernel_scalar_strings_array_view_with_nulls() {
1436+
let scalar_truthy = Scalar::new(StringViewArray::from_iter_values(["hello"]));
1437+
let scalar_falsy = Scalar::new(StringViewArray::new_null(1));
1438+
1439+
let mask = BooleanArray::from(vec![true, true, false, false, true]);
1440+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1441+
let actual = out.as_any().downcast_ref::<StringViewArray>().unwrap();
1442+
let expected = StringViewArray::from_iter(vec![
1443+
Some("hello"),
1444+
Some("hello"),
1445+
None,
1446+
None,
1447+
Some("hello"),
1448+
]);
1449+
assert_eq!(actual, &expected);
1450+
}
1451+
1452+
#[test]
1453+
fn test_zip_kernel_scalar_strings_array_view_all_true_null() {
1454+
let scalar_truthy = Scalar::new(StringViewArray::new_null(1));
1455+
let scalar_falsy = Scalar::new(StringViewArray::new_null(1));
1456+
let mask = BooleanArray::from(vec![true, true]);
1457+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1458+
let actual = out.as_any().downcast_ref::<StringViewArray>().unwrap();
1459+
let expected = StringViewArray::from_iter(vec![None::<String>, None]);
1460+
assert_eq!(actual, &expected);
1461+
}
1462+
1463+
#[test]
1464+
fn test_zip_kernel_scalar_strings_array_view_all_false_null() {
1465+
let scalar_truthy = Scalar::new(StringViewArray::new_null(1));
1466+
let scalar_falsy = Scalar::new(StringViewArray::new_null(1));
1467+
let mask = BooleanArray::from(vec![false, false]);
1468+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1469+
let actual = out.as_any().downcast_ref::<StringViewArray>().unwrap();
1470+
let expected = StringViewArray::from_iter(vec![None::<String>, None]);
1471+
assert_eq!(actual, &expected);
1472+
}
1473+
1474+
#[test]
1475+
fn test_zip_kernel_scalar_string_array_view_all_true() {
1476+
let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1477+
let scalar_falsy = Scalar::new(StringViewArray::from(vec!["world"]));
1478+
1479+
let mask = BooleanArray::from(vec![true, true]);
1480+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1481+
let actual = out.as_string_view();
1482+
let expected = StringViewArray::from(vec![Some("hello"), Some("hello")]);
1483+
assert_eq!(actual, &expected);
1484+
}
1485+
1486+
#[test]
1487+
fn test_zip_kernel_scalar_string_array_view_all_false() {
1488+
let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1489+
let scalar_falsy = Scalar::new(StringViewArray::from(vec!["world"]));
1490+
1491+
let mask = BooleanArray::from(vec![false, false]);
1492+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1493+
let actual = out.as_string_view();
1494+
let expected = StringViewArray::from(vec![Some("world"), Some("world")]);
1495+
assert_eq!(actual, &expected);
1496+
}
1497+
1498+
#[test]
1499+
fn test_zip_kernel_scalar_strings_large_strings() {
1500+
let scalar_truthy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1501+
let scalar_falsy = Scalar::new(StringViewArray::from(vec!["another longer than 12 bytes"]));
1502+
1503+
let mask = BooleanArray::from(vec![true, false]);
1504+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1505+
let actual = out.as_string_view();
1506+
let expected = StringViewArray::from(vec![
1507+
Some("longer than 12 bytes"),
1508+
Some("another longer than 12 bytes"),
1509+
]);
1510+
assert_eq!(actual, &expected);
1511+
}
1512+
1513+
#[test]
1514+
fn test_zip_kernel_scalar_strings_array_view_large_short_strings() {
1515+
let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1516+
let scalar_falsy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1517+
1518+
let mask = BooleanArray::from(vec![true, false, true, false]);
1519+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1520+
let actual = out.as_string_view();
1521+
let expected = StringViewArray::from(vec![
1522+
Some("hello"),
1523+
Some("longer than 12 bytes"),
1524+
Some("hello"),
1525+
Some("longer than 12 bytes"),
1526+
]);
1527+
assert_eq!(actual, &expected);
1528+
}
1529+
#[test]
1530+
fn test_zip_kernel_scalar_strings_array_view_large_all_true() {
1531+
let scalar_truthy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1532+
let scalar_falsy = Scalar::new(StringViewArray::from(vec!["another longer than 12 bytes"]));
1533+
1534+
let mask = BooleanArray::from(vec![true, true]);
1535+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1536+
let actual = out.as_string_view();
1537+
let expected = StringViewArray::from(vec![
1538+
Some("longer than 12 bytes"),
1539+
Some("longer than 12 bytes"),
1540+
]);
1541+
assert_eq!(actual, &expected);
1542+
}
1543+
1544+
#[test]
1545+
fn test_zip_kernel_scalar_strings_array_view_large_all_false() {
1546+
let scalar_truthy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1547+
let scalar_falsy = Scalar::new(StringViewArray::from(vec!["another longer than 12 bytes"]));
1548+
1549+
let mask = BooleanArray::from(vec![false, false]);
1550+
let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1551+
let actual = out.as_string_view();
1552+
let expected = StringViewArray::from(vec![
1553+
Some("another longer than 12 bytes"),
1554+
Some("another longer than 12 bytes"),
1555+
]);
1556+
assert_eq!(actual, &expected);
1557+
}
12251558
}

0 commit comments

Comments
 (0)