From 65f9ad0186b9605609a922fab6d526537bec1d11 Mon Sep 17 00:00:00 2001 From: umtong Date: Tue, 27 Oct 2026 03:25:21 +0900 Subject: [PATCH 1/2] GH-55255: [C++][Compute] Support binary views in conditional kernels Add string_view and binary_view kernels for if_else, case_when, coalesce, and choose. Retain backing buffers and rebase selected view descriptors without copying out-of-line payloads. Cover scalar and sliced inputs, nulls, multiple buffers, nested condition offsets, invalid choose indices, and output lifetime after input release. --- .../arrow/compute/kernels/scalar_if_else.cc | 216 ++++++++++++++++++ .../compute/kernels/scalar_if_else_test.cc | 127 +++++++++- 2 files changed, 340 insertions(+), 3 deletions(-) diff --git a/cpp/src/arrow/compute/kernels/scalar_if_else.cc b/cpp/src/arrow/compute/kernels/scalar_if_else.cc index 1d8e6c1f62ef..72008eba0309 100644 --- a/cpp/src/arrow/compute/kernels/scalar_if_else.cc +++ b/cpp/src/arrow/compute/kernels/scalar_if_else.cc @@ -28,6 +28,7 @@ #include "arrow/compute/registry_internal.h" #include "arrow/result.h" #include "arrow/status.h" +#include "arrow/util/binary_view_util.h" #include "arrow/util/bit_block_counter.h" #include "arrow/util/bit_run_reader.h" #include "arrow/util/bitmap.h" @@ -2838,6 +2839,203 @@ void AddPrimitiveChooseKernels(const std::shared_ptr& scalar_fun } } + +template +Status ExecBinaryViewSelection(KernelContext* ctx, const ExecSpan& batch, + int first_value, Select&& select, ExecResult* out) { + using View = BinaryViewType::c_type; + std::vector> buffers(2); + std::vector buffer_offsets(batch.num_values()); + std::vector scalar_views(batch.num_values()); + constexpr size_t kMaxBuffers = std::numeric_limits::max(); + + // Retain the owners of referenced payloads and map each input's buffer indices + // into the output. Only view descriptors are copied below. + for (int arg = first_value; arg < batch.num_values(); ++arg) { + const auto& source = batch[arg]; + const size_t buffer_offset = buffers.size() - 2; + buffer_offsets[arg] = static_cast(buffer_offset); + if (source.is_array()) { + const auto input_buffers = source.array.GetVariadicBuffers(); + if (input_buffers.size() > kMaxBuffers - buffer_offset) { + return Status::CapacityError("Too many buffers in binary-view selection"); + } + buffers.insert(buffers.end(), input_buffers.begin(), input_buffers.end()); + } else if (source.scalar->is_valid) { + const auto& scalar = checked_cast(*source.scalar); + if (scalar.value->size() > std::numeric_limits::max()) { + return Status::CapacityError("Binary-view value exceeds 2GB"); + } + scalar_views[arg] = util::ToBinaryView( + scalar.value->data(), static_cast(scalar.value->size()), + buffer_offsets[arg], 0); + if (!scalar_views[arg].is_inline()) { + if (buffer_offset == kMaxBuffers) { + return Status::CapacityError("Too many buffers in binary-view selection"); + } + buffers.push_back(scalar.value); + } + } + } + + ARROW_ASSIGN_OR_RAISE(buffers[0], + AllocateEmptyBitmap(batch.length, ctx->memory_pool())); + ARROW_ASSIGN_OR_RAISE( + buffers[1], AllocateBuffer(batch.length * BinaryViewType::kSize, ctx->memory_pool())); + auto* validity = buffers[0]->mutable_data(); + auto* views = buffers[1]->mutable_data_as(); + int64_t null_count = 0; + for (int64_t row = 0; row < batch.length; ++row) { + ARROW_ASSIGN_OR_RAISE(int selected, select(row)); + if (selected < 0) { + views[row] = View{}; + ++null_count; + continue; + } + const auto& source = batch[selected]; + const bool valid = source.is_scalar() ? source.scalar->is_valid + : source.array.IsValid(row); + if (!valid) { + views[row] = View{}; + ++null_count; + continue; + } + bit_util::SetBit(validity, row); + if (source.is_scalar()) { + views[row] = scalar_views[selected]; + } else { + views[row] = source.array.GetValues(1)[row]; + if (!views[row].is_inline()) { + views[row].ref.buffer_index += buffer_offsets[selected]; + } + } + } + if (null_count == 0) { + buffers[0].reset(); + } + out->value = ArrayData::Make(out->type()->GetSharedPtr(), batch.length, + std::move(buffers), null_count); + return Status::OK(); +} + +Status IfElseBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, ExecResult* out) { + if (batch[0].is_scalar()) { + return IfElseGenericSXXCall(ctx, batch[0].scalar_as(), batch[1], + batch[2], out); + } + const auto& condition = batch[0].array; + return ExecBinaryViewSelection( + ctx, batch, 1, + [&](int64_t row) -> Result { + if (!condition.IsValid(row)) return -1; + return bit_util::GetBit(condition.buffers[1].data, condition.offset + row) ? 1 : 2; + }, + out); +} + +Status CaseWhenBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, + ExecResult* out) { + if (batch[0].null_count() > 0) { + return Status::Invalid("cond struct must not have outer nulls"); + } + if (batch[0].is_scalar()) { + return ExecVarWidthScalarCaseWhen(ctx, batch, out); + } + const auto& conditions = batch[0].array; + const bool has_else = conditions.type->num_fields() < batch.num_values() - 1; + return ExecBinaryViewSelection( + ctx, batch, 1, + [&](int64_t row) -> Result { + const int64_t index = conditions.offset + row; + for (int arg = 0; arg < conditions.type->num_fields(); ++arg) { + const auto& condition = conditions.child_data[arg]; + if (condition.IsValid(index) && + bit_util::GetBit(condition.buffers[1].data, condition.offset + index)) { + return arg + 1; + } + } + return has_else ? batch.num_values() - 1 : -1; + }, + out); +} + +Status CoalesceBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, + ExecResult* out) { + for (const auto& source : batch.values) { + if (source.is_scalar()) { + if (!source.scalar->is_valid) continue; + ARROW_ASSIGN_OR_RAISE( + auto result, MakeArrayFromScalar(*source.scalar, batch.length, ctx->memory_pool())); + out->value = result->data(); + return Status::OK(); + } + if (!source.array.MayHaveNulls()) { + out->value = source.array.ToArrayData(); + return Status::OK(); + } + break; + } + return ExecBinaryViewSelection( + ctx, batch, 0, + [&](int64_t row) -> Result { + for (int arg = 0; arg < batch.num_values(); ++arg) { + const auto& source = batch[arg]; + if (source.is_scalar() ? source.scalar->is_valid : source.array.IsValid(row)) { + return arg; + } + } + return -1; + }, + out); +} + +Status ChooseBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, ExecResult* out) { + auto select = [&](int64_t index) -> Result { + if (index < 0 || index >= batch.num_values() - 1) { + return Status::IndexError("choose: index ", index, " out of range"); + } + return static_cast(index) + 1; + }; + if (batch[0].is_scalar()) { + const auto& index = batch[0].scalar_as(); + if (!index.is_valid) { + ARROW_ASSIGN_OR_RAISE( + auto result, + MakeArrayOfNull(out->type()->GetSharedPtr(), batch.length, ctx->memory_pool())); + out->value = result->data(); + return Status::OK(); + } + ARROW_ASSIGN_OR_RAISE(int selected, select(index.value)); + const auto& source = batch[selected]; + if (source.is_array()) { + out->value = source.array.ToArrayData(); + } else { + ARROW_ASSIGN_OR_RAISE( + auto result, MakeArrayFromScalar(*source.scalar, batch.length, ctx->memory_pool())); + out->value = result->data(); + } + return Status::OK(); + } + const auto& indices = batch[0].array; + return ExecBinaryViewSelection( + ctx, batch, 1, + [&](int64_t row) -> Result { + if (!indices.IsValid(row)) return -1; + return select(indices.GetValues(1)[row]); + }, + out); +} + +void AddBinaryViewConditionalKernel(const std::shared_ptr& function, + std::shared_ptr signature, + ArrayKernelExec exec) { + ScalarKernel kernel(std::move(signature), exec); + kernel.null_handling = NullHandling::COMPUTED_NO_PREALLOCATE; + kernel.mem_allocation = MemAllocation::NO_PREALLOCATE; + kernel.can_write_into_slices = false; + DCHECK_OK(function->AddKernel(std::move(kernel))); +} + const FunctionDoc if_else_doc{"Choose values based on a condition", ("`cond` must be a Boolean scalar/ array. \n`left` or " "`right` must be of the same type scalar/ array.\n" @@ -2891,6 +3089,11 @@ void RegisterScalarIfElse(FunctionRegistry* registry) { AddPrimitiveIfElseKernels(func, {boolean(), float16()}); AddNullIfElseKernel(func); AddBinaryIfElseKernels(func, BaseBinaryTypes()); + for (const auto& type : {utf8_view(), binary_view()}) { + AddBinaryViewConditionalKernel( + func, KernelSignature::Make({boolean(), type, type}, type), + IfElseBinaryViewExec); + } AddFixedWidthIfElseKernel(func); AddFixedWidthIfElseKernel(func); AddFixedWidthIfElseKernel(func); @@ -2914,6 +3117,9 @@ void RegisterScalarIfElse(FunctionRegistry* registry) { AddCaseWhenKernel(func, Type::DECIMAL256, CaseWhenFunctor::Exec, all_value_types_match); AddBinaryCaseWhenKernels(func, BaseBinaryTypes(), all_value_types_match); + for (const auto& type : {utf8_view(), binary_view()}) { + AddCaseWhenKernel(func, type, CaseWhenBinaryViewExec, all_value_types_match); + } AddNestedCaseWhenKernels(func, all_value_types_match); DCHECK_OK(registry->AddFunction(std::move(func))); } @@ -2934,6 +3140,11 @@ void RegisterScalarIfElse(FunctionRegistry* registry) { for (const auto& ty : BaseBinaryTypes()) { AddCoalesceKernel(func, ty, GenerateTypeAgnosticVarBinaryBase(ty)); } + for (const auto& type : {utf8_view(), binary_view()}) { + AddBinaryViewConditionalKernel( + func, KernelSignature::Make({type}, FirstType, /*is_varargs=*/true), + CoalesceBinaryViewExec); + } AddNestedCoalesceKernels(func); DCHECK_OK(registry->AddFunction(std::move(func))); } @@ -2952,6 +3163,11 @@ void RegisterScalarIfElse(FunctionRegistry* registry) { for (const auto& ty : BaseBinaryTypes()) { AddChooseKernel(func, ty, GenerateTypeAgnosticVarBinaryBase(ty)); } + for (const auto& type : {utf8_view(), binary_view()}) { + AddBinaryViewConditionalKernel( + func, KernelSignature::Make({int64(), type}, LastType, /*is_varargs=*/true), + ChooseBinaryViewExec); + } DCHECK_OK(registry->AddFunction(std::move(func))); } } diff --git a/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc b/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc index e05a1f081beb..2042fb0d5ea6 100644 --- a/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc @@ -17,6 +17,7 @@ #include #include +#include #include @@ -77,6 +78,7 @@ using IfElseNumericBasedTypes = ::testing::Types; using BaseBinaryArrowTypes = ::testing::Types; +using ConditionalBinaryArrowTypes = ::testing::Types; using ListArrowTypes = ::testing::Types; using IntegralArrowTypes = ::testing::Types; #else @@ -85,6 +87,9 @@ using IfElseNumericBasedTypes = Int32Type, Int64Type, HalfFloatType, FloatType, DoubleType, Date32Type, Date64Type, Time32Type, Time64Type, TimestampType, MonthIntervalType, DurationType>; +using ConditionalBinaryArrowTypes = + ::testing::Types; #endif TYPED_TEST_SUITE(TestIfElsePrimitive, IfElseNumericBasedTypes); @@ -2085,7 +2090,7 @@ TEST(TestCaseWhen, FixedSizeBinaryRandom) { TestCaseWhenRandom(fixed_size_binary template class TestCaseWhenBinary : public ::testing::Test {}; -TYPED_TEST_SUITE(TestCaseWhenBinary, BaseBinaryArrowTypes); +TYPED_TEST_SUITE(TestCaseWhenBinary, ConditionalBinaryArrowTypes); TYPED_TEST(TestCaseWhenBinary, Basics) { auto type = default_type_instance(); @@ -2885,7 +2890,7 @@ template class TestCoalesceList : public ::testing::Test {}; TYPED_TEST_SUITE(TestCoalesceNumeric, IfElseNumericBasedTypes); -TYPED_TEST_SUITE(TestCoalesceBinary, BaseBinaryArrowTypes); +TYPED_TEST_SUITE(TestCoalesceBinary, ConditionalBinaryArrowTypes); TYPED_TEST_SUITE(TestCoalesceList, ListAndListViewArrowTypes); TYPED_TEST(TestCoalesceNumeric, Basics) { @@ -3749,7 +3754,7 @@ template class TestChooseBinary : public ::testing::Test {}; TYPED_TEST_SUITE(TestChooseNumeric, IfElseNumericBasedTypes); -TYPED_TEST_SUITE(TestChooseBinary, BaseBinaryArrowTypes); +TYPED_TEST_SUITE(TestChooseBinary, ConditionalBinaryArrowTypes); TYPED_TEST(TestChooseNumeric, FixedSize) { auto type = default_type_instance(); @@ -4001,5 +4006,121 @@ TEST(TestChooseKernel, Errors) { {ArrayFromJSON(int64(), "[-1]"), ArrayFromJSON(int32(), "[0]")})); } + +template +class TestConditionalBinaryView : public ::testing::Test {}; + +using ConditionalBinaryViewTypes = ::testing::Types; +TYPED_TEST_SUITE(TestConditionalBinaryView, ConditionalBinaryViewTypes); + +TYPED_TEST(TestConditionalBinaryView, IfElse) { + auto type = default_type_instance(); + CheckWithDifferentShapes( + ArrayFromJSON(boolean(), "[true, false, null, true, false]"), + ArrayFromJSON(type, + R"(["left value out of line", "", "short", null, "unused"])"), + ArrayFromJSON(type, + R"(["unused", "right value out of line", null, "short", null])"), + ArrayFromJSON(type, + R"(["left value out of line", "right value out of line", null, null, null])")); +} + +template +Result> MakeConditionalViewInput(bool left) { + typename TypeTraits::BuilderType builder; + builder.SetBlockSize(16); + RETURN_NOT_OK(builder.Append("prefix")); + RETURN_NOT_OK(builder.Append(left ? "first left value out of line" + : "first right value out of line")); + if (left) { + RETURN_NOT_OK(builder.AppendNull()); + } else { + RETURN_NOT_OK(builder.Append("second right value out of line")); + } + RETURN_NOT_OK(builder.Append(left ? "third left value out of line" + : "third right value out of line")); + ARROW_ASSIGN_OR_RAISE(auto array, builder.Finish()); + return array->Slice(1); +} + +TYPED_TEST(TestConditionalBinaryView, RetainSelectedBuffers) { + auto type = default_type_instance(); + for (const auto* function : {"if_else", "case_when", "coalesce", "choose"}) { + for (bool scalar_right : {false, true}) { + SCOPED_TRACE(function); + SCOPED_TRACE(scalar_right); + ASSERT_OK_AND_ASSIGN(auto left, MakeConditionalViewInput(true)); + Datum right; + std::weak_ptr right_buffer; + if (scalar_right) { + right = ScalarFromJSON(type, R"("second right value out of line")"); + right_buffer = right.scalar_as().value; + } else { + ASSERT_OK_AND_ASSIGN(auto array, MakeConditionalViewInput(false)); + const auto* views = ArraySpan(*array->data()).GetValues(1); + right_buffer = array->data()->buffers[2 + views[1].ref.buffer_index]; + right = std::move(array); + } + const auto* left_views = + ArraySpan(*left->data()).GetValues(1); + std::weak_ptr left_buffer = + left->data()->buffers[2 + left_views[2].ref.buffer_index]; + auto condition = ArrayFromJSON(boolean(), "[true, false, true]"); + DatumVector inputs; + if (std::string_view(function) == "if_else") { + inputs = {condition, left, right}; + } else if (std::string_view(function) == "case_when") { + inputs = {MakeStruct({condition}), left, right}; + } else if (std::string_view(function) == "choose") { + inputs = {ArrayFromJSON(int64(), "[0, 1, 0]"), left, right}; + } else { + inputs = {left, right}; + } + auto expected = ArrayFromJSON( + type, + R"(["first left value out of line", "second right value out of line", "third left value out of line"])"); + CheckScalar(function, inputs, expected); + ASSERT_OK_AND_ASSIGN(auto result, CallFunction(function, inputs)); + inputs.clear(); + left.reset(); + right = Datum(); + ASSERT_FALSE(left_buffer.expired()); + ASSERT_FALSE(right_buffer.expired()); + ASSERT_OK(result.make_array()->ValidateFull()); + AssertArraysEqual(*expected, *result.make_array()); + } + } +} + +TYPED_TEST(TestConditionalBinaryView, CaseWhenNestedOffsets) { + auto type = default_type_instance(); + auto child = ArrayFromJSON(boolean(), "[false, false, true, false, null, true]") + ->Slice(1); + auto conditions = MakeStruct({child}).make_array()->Slice(1, 3); + auto left = ArrayFromJSON(type, R"(["left out of line", "unused", "unused"])"); + auto right = ArrayFromJSON(type, R"(["unused", "right out of line", "fallback"])"); + CheckScalar("case_when", {conditions, left, right}, + ArrayFromJSON(type, R"(["left out of line", "right out of line", "fallback"])")); + CheckScalar("case_when", {conditions, left}, + ArrayFromJSON(type, R"(["left out of line", null, null])")); + EXPECT_RAISES_WITH_MESSAGE_THAT( + Invalid, ::testing::HasSubstr("cond struct"), + CallFunction("case_when", {MakeNullScalar(conditions->type()), left})); +} + +TYPED_TEST(TestConditionalBinaryView, ChooseInvalidIndices) { + auto type = default_type_instance(); + auto value = ScalarFromJSON(type, R"("value out of line")"); + for (int64_t index : {int64_t{-1}, int64_t{1}, std::numeric_limits::max()}) { + EXPECT_RAISES_WITH_MESSAGE_THAT( + IndexError, ::testing::HasSubstr("out of range"), + CallFunction("choose", {Datum(index), value})); + ASSERT_OK_AND_ASSIGN(auto indices, MakeArrayFromScalar(Int64Scalar(index), 1)); + EXPECT_RAISES_WITH_MESSAGE_THAT( + IndexError, ::testing::HasSubstr("out of range"), + CallFunction("choose", {indices, value})); + } +} + } // namespace compute } // namespace arrow From 15c3b34c614f048e7daf393a7a30558b1456f26e Mon Sep 17 00:00:00 2001 From: umtong Date: Tue, 27 Oct 2026 03:40:52 +0900 Subject: [PATCH 2/2] Apply clang-format 18.1.8 to conditional view kernels --- .../arrow/compute/kernels/scalar_if_else.cc | 44 +++++++++---------- .../compute/kernels/scalar_if_else_test.cc | 35 +++++++-------- 2 files changed, 39 insertions(+), 40 deletions(-) diff --git a/cpp/src/arrow/compute/kernels/scalar_if_else.cc b/cpp/src/arrow/compute/kernels/scalar_if_else.cc index 72008eba0309..ff585cac3a31 100644 --- a/cpp/src/arrow/compute/kernels/scalar_if_else.cc +++ b/cpp/src/arrow/compute/kernels/scalar_if_else.cc @@ -2839,10 +2839,9 @@ void AddPrimitiveChooseKernels(const std::shared_ptr& scalar_fun } } - template -Status ExecBinaryViewSelection(KernelContext* ctx, const ExecSpan& batch, - int first_value, Select&& select, ExecResult* out) { +Status ExecBinaryViewSelection(KernelContext* ctx, const ExecSpan& batch, int first_value, + Select&& select, ExecResult* out) { using View = BinaryViewType::c_type; std::vector> buffers(2); std::vector buffer_offsets(batch.num_values()); @@ -2866,9 +2865,9 @@ Status ExecBinaryViewSelection(KernelContext* ctx, const ExecSpan& batch, if (scalar.value->size() > std::numeric_limits::max()) { return Status::CapacityError("Binary-view value exceeds 2GB"); } - scalar_views[arg] = util::ToBinaryView( - scalar.value->data(), static_cast(scalar.value->size()), - buffer_offsets[arg], 0); + scalar_views[arg] = util::ToBinaryView(scalar.value->data(), + static_cast(scalar.value->size()), + buffer_offsets[arg], 0); if (!scalar_views[arg].is_inline()) { if (buffer_offset == kMaxBuffers) { return Status::CapacityError("Too many buffers in binary-view selection"); @@ -2879,9 +2878,9 @@ Status ExecBinaryViewSelection(KernelContext* ctx, const ExecSpan& batch, } ARROW_ASSIGN_OR_RAISE(buffers[0], - AllocateEmptyBitmap(batch.length, ctx->memory_pool())); - ARROW_ASSIGN_OR_RAISE( - buffers[1], AllocateBuffer(batch.length * BinaryViewType::kSize, ctx->memory_pool())); + AllocateEmptyBitmap(batch.length, ctx->memory_pool())); + ARROW_ASSIGN_OR_RAISE(buffers[1], AllocateBuffer(batch.length * BinaryViewType::kSize, + ctx->memory_pool())); auto* validity = buffers[0]->mutable_data(); auto* views = buffers[1]->mutable_data_as(); int64_t null_count = 0; @@ -2893,8 +2892,8 @@ Status ExecBinaryViewSelection(KernelContext* ctx, const ExecSpan& batch, continue; } const auto& source = batch[selected]; - const bool valid = source.is_scalar() ? source.scalar->is_valid - : source.array.IsValid(row); + const bool valid = + source.is_scalar() ? source.scalar->is_valid : source.array.IsValid(row); if (!valid) { views[row] = View{}; ++null_count; @@ -2921,14 +2920,15 @@ Status ExecBinaryViewSelection(KernelContext* ctx, const ExecSpan& batch, Status IfElseBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, ExecResult* out) { if (batch[0].is_scalar()) { return IfElseGenericSXXCall(ctx, batch[0].scalar_as(), batch[1], - batch[2], out); + batch[2], out); } const auto& condition = batch[0].array; return ExecBinaryViewSelection( ctx, batch, 1, [&](int64_t row) -> Result { if (!condition.IsValid(row)) return -1; - return bit_util::GetBit(condition.buffers[1].data, condition.offset + row) ? 1 : 2; + return bit_util::GetBit(condition.buffers[1].data, condition.offset + row) ? 1 + : 2; }, out); } @@ -2964,8 +2964,8 @@ Status CoalesceBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, for (const auto& source : batch.values) { if (source.is_scalar()) { if (!source.scalar->is_valid) continue; - ARROW_ASSIGN_OR_RAISE( - auto result, MakeArrayFromScalar(*source.scalar, batch.length, ctx->memory_pool())); + ARROW_ASSIGN_OR_RAISE(auto result, MakeArrayFromScalar(*source.scalar, batch.length, + ctx->memory_pool())); out->value = result->data(); return Status::OK(); } @@ -3010,8 +3010,8 @@ Status ChooseBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, ExecResul if (source.is_array()) { out->value = source.array.ToArrayData(); } else { - ARROW_ASSIGN_OR_RAISE( - auto result, MakeArrayFromScalar(*source.scalar, batch.length, ctx->memory_pool())); + ARROW_ASSIGN_OR_RAISE(auto result, MakeArrayFromScalar(*source.scalar, batch.length, + ctx->memory_pool())); out->value = result->data(); } return Status::OK(); @@ -3027,8 +3027,8 @@ Status ChooseBinaryViewExec(KernelContext* ctx, const ExecSpan& batch, ExecResul } void AddBinaryViewConditionalKernel(const std::shared_ptr& function, - std::shared_ptr signature, - ArrayKernelExec exec) { + std::shared_ptr signature, + ArrayKernelExec exec) { ScalarKernel kernel(std::move(signature), exec); kernel.null_handling = NullHandling::COMPUTED_NO_PREALLOCATE; kernel.mem_allocation = MemAllocation::NO_PREALLOCATE; @@ -3090,9 +3090,9 @@ void RegisterScalarIfElse(FunctionRegistry* registry) { AddNullIfElseKernel(func); AddBinaryIfElseKernels(func, BaseBinaryTypes()); for (const auto& type : {utf8_view(), binary_view()}) { - AddBinaryViewConditionalKernel( - func, KernelSignature::Make({boolean(), type, type}, type), - IfElseBinaryViewExec); + AddBinaryViewConditionalKernel(func, + KernelSignature::Make({boolean(), type, type}, type), + IfElseBinaryViewExec); } AddFixedWidthIfElseKernel(func); AddFixedWidthIfElseKernel(func); diff --git a/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc b/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc index 2042fb0d5ea6..c59f7c2eb904 100644 --- a/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_if_else_test.cc @@ -4006,7 +4006,6 @@ TEST(TestChooseKernel, Errors) { {ArrayFromJSON(int64(), "[-1]"), ArrayFromJSON(int32(), "[0]")})); } - template class TestConditionalBinaryView : public ::testing::Test {}; @@ -4017,12 +4016,12 @@ TYPED_TEST(TestConditionalBinaryView, IfElse) { auto type = default_type_instance(); CheckWithDifferentShapes( ArrayFromJSON(boolean(), "[true, false, null, true, false]"), - ArrayFromJSON(type, - R"(["left value out of line", "", "short", null, "unused"])"), + ArrayFromJSON(type, R"(["left value out of line", "", "short", null, "unused"])"), ArrayFromJSON(type, R"(["unused", "right value out of line", null, "short", null])"), - ArrayFromJSON(type, - R"(["left value out of line", "right value out of line", null, null, null])")); + ArrayFromJSON( + type, + R"(["left value out of line", "right value out of line", null, null, null])")); } template @@ -4031,14 +4030,14 @@ Result> MakeConditionalViewInput(bool left) { builder.SetBlockSize(16); RETURN_NOT_OK(builder.Append("prefix")); RETURN_NOT_OK(builder.Append(left ? "first left value out of line" - : "first right value out of line")); + : "first right value out of line")); if (left) { RETURN_NOT_OK(builder.AppendNull()); } else { RETURN_NOT_OK(builder.Append("second right value out of line")); } RETURN_NOT_OK(builder.Append(left ? "third left value out of line" - : "third right value out of line")); + : "third right value out of line")); ARROW_ASSIGN_OR_RAISE(auto array, builder.Finish()); return array->Slice(1); } @@ -4057,7 +4056,8 @@ TYPED_TEST(TestConditionalBinaryView, RetainSelectedBuffers) { right_buffer = right.scalar_as().value; } else { ASSERT_OK_AND_ASSIGN(auto array, MakeConditionalViewInput(false)); - const auto* views = ArraySpan(*array->data()).GetValues(1); + const auto* views = + ArraySpan(*array->data()).GetValues(1); right_buffer = array->data()->buffers[2 + views[1].ref.buffer_index]; right = std::move(array); } @@ -4094,13 +4094,14 @@ TYPED_TEST(TestConditionalBinaryView, RetainSelectedBuffers) { TYPED_TEST(TestConditionalBinaryView, CaseWhenNestedOffsets) { auto type = default_type_instance(); - auto child = ArrayFromJSON(boolean(), "[false, false, true, false, null, true]") - ->Slice(1); + auto child = + ArrayFromJSON(boolean(), "[false, false, true, false, null, true]")->Slice(1); auto conditions = MakeStruct({child}).make_array()->Slice(1, 3); auto left = ArrayFromJSON(type, R"(["left out of line", "unused", "unused"])"); auto right = ArrayFromJSON(type, R"(["unused", "right out of line", "fallback"])"); - CheckScalar("case_when", {conditions, left, right}, - ArrayFromJSON(type, R"(["left out of line", "right out of line", "fallback"])")); + CheckScalar( + "case_when", {conditions, left, right}, + ArrayFromJSON(type, R"(["left out of line", "right out of line", "fallback"])")); CheckScalar("case_when", {conditions, left}, ArrayFromJSON(type, R"(["left out of line", null, null])")); EXPECT_RAISES_WITH_MESSAGE_THAT( @@ -4112,13 +4113,11 @@ TYPED_TEST(TestConditionalBinaryView, ChooseInvalidIndices) { auto type = default_type_instance(); auto value = ScalarFromJSON(type, R"("value out of line")"); for (int64_t index : {int64_t{-1}, int64_t{1}, std::numeric_limits::max()}) { - EXPECT_RAISES_WITH_MESSAGE_THAT( - IndexError, ::testing::HasSubstr("out of range"), - CallFunction("choose", {Datum(index), value})); + EXPECT_RAISES_WITH_MESSAGE_THAT(IndexError, ::testing::HasSubstr("out of range"), + CallFunction("choose", {Datum(index), value})); ASSERT_OK_AND_ASSIGN(auto indices, MakeArrayFromScalar(Int64Scalar(index), 1)); - EXPECT_RAISES_WITH_MESSAGE_THAT( - IndexError, ::testing::HasSubstr("out of range"), - CallFunction("choose", {indices, value})); + EXPECT_RAISES_WITH_MESSAGE_THAT(IndexError, ::testing::HasSubstr("out of range"), + CallFunction("choose", {indices, value})); } }