| 1569 | // given helper functions to copy data from a source array to a target array |
| 1570 | template <typename Type> |
| 1571 | Status ExecArrayCaseWhen(KernelContext* ctx, const ExecSpan& batch, ExecResult* out) { |
| 1572 | const ArraySpan& conds_array = batch[0].array; |
| 1573 | if (conds_array.GetNullCount() > 0) { |
| 1574 | return Status::Invalid( |
| 1575 | "cond struct must not be a null scalar or " |
| 1576 | "have top-level nulls"); |
| 1577 | } |
| 1578 | ArraySpan* output = out->array_span_mutable(); |
| 1579 | const int64_t out_offset = output->offset; |
| 1580 | const auto num_value_args = batch.values.size() - 1; |
| 1581 | const bool have_else_arg = |
| 1582 | static_cast<size_t>(conds_array.type->num_fields()) < num_value_args; |
| 1583 | uint8_t* out_valid = output->buffers[0].data; |
| 1584 | uint8_t* out_values = output->buffers[1].data; |
| 1585 | |
| 1586 | if (have_else_arg) { |
| 1587 | // Copy 'else' value into output |
| 1588 | CopyValues<Type>(batch.values.back(), /*in_offset=*/0, batch.length, out_valid, |
| 1589 | out_values, out_offset); |
| 1590 | } else { |
| 1591 | // There's no 'else' argument, so we should have an all-null validity bitmap |
| 1592 | bit_util::SetBitsTo(out_valid, out_offset, batch.length, false); |
| 1593 | } |
| 1594 | |
| 1595 | // Allocate a temporary bitmap to determine which elements still need setting. |
| 1596 | ARROW_ASSIGN_OR_RAISE(auto mask_buffer, ctx->AllocateBitmap(batch.length)); |
| 1597 | uint8_t* mask = mask_buffer->mutable_data(); |
| 1598 | std::memset(mask, 0xFF, mask_buffer->size()); |
| 1599 | |
| 1600 | // Then iterate through each argument in turn and set elements. |
| 1601 | for (int i = 0; i < batch.num_values() - (have_else_arg ? 2 : 1); i++) { |
| 1602 | const ArraySpan& cond_array = conds_array.child_data[i]; |
| 1603 | const int64_t cond_offset = conds_array.offset + cond_array.offset; |
| 1604 | const uint8_t* cond_values = cond_array.buffers[1].data; |
| 1605 | const ExecValue& value = batch[i + 1]; |
| 1606 | int64_t offset = 0; |
| 1607 | |
| 1608 | if (cond_array.GetNullCount() == 0) { |
| 1609 | // If no valid buffer, visit mask & cond bitmap simultaneously |
| 1610 | BinaryBitBlockCounter counter(mask, /*start_offset=*/0, cond_values, cond_offset, |
| 1611 | batch.length); |
| 1612 | while (offset < batch.length) { |
| 1613 | const auto block = counter.NextAndWord(); |
| 1614 | if (block.AllSet()) { |
| 1615 | CopyValues<Type>(value, offset, block.length, out_valid, out_values, |
| 1616 | out_offset + offset); |
| 1617 | bit_util::SetBitsTo(mask, offset, block.length, false); |
| 1618 | } else if (block.popcount) { |
| 1619 | for (int64_t j = 0; j < block.length; ++j) { |
| 1620 | if (bit_util::GetBit(mask, offset + j) && |
| 1621 | bit_util::GetBit(cond_values, cond_offset + offset + j)) { |
| 1622 | CopyValues<Type>(value, offset + j, /*length=*/1, out_valid, out_values, |
| 1623 | out_offset + offset + j); |
| 1624 | bit_util::SetBitTo(mask, offset + j, false); |
| 1625 | } |
| 1626 | } |
| 1627 | } |
| 1628 | offset += block.length; |
nothing calls this directly
no test coverage detected