| 2110 | // Implement 'coalesce' for any mix of scalar/array arguments for any fixed-width type |
| 2111 | template <typename Type> |
| 2112 | Status ExecArrayCoalesce(KernelContext* ctx, const ExecSpan& batch, ExecResult* out) { |
| 2113 | ArraySpan* output = out->array_span_mutable(); |
| 2114 | const int64_t out_offset = output->offset; |
| 2115 | // Use output validity buffer as mask to decide what values to copy |
| 2116 | uint8_t* out_valid = output->buffers[0].data; |
| 2117 | |
| 2118 | // Clear output validity buffer - no values are set initially |
| 2119 | bit_util::SetBitsTo(out_valid, out_offset, batch.length, false); |
| 2120 | uint8_t* out_values = output->buffers[1].data; |
| 2121 | |
| 2122 | for (const ExecValue& value : batch.values) { |
| 2123 | if (value.null_count() == 0) { |
| 2124 | // Valid scalar, or all-valid array |
| 2125 | CopyValuesAllValid<Type>(value, out_valid, out_values, out_offset, batch.length); |
| 2126 | break; |
| 2127 | } else if (value.is_array()) { |
| 2128 | // Array with nulls |
| 2129 | const ArraySpan& arr = value.array; |
| 2130 | const int64_t in_offset = arr.offset; |
| 2131 | const int64_t in_null_count = arr.GetNullCount(); |
| 2132 | DCHECK_GT(in_null_count, 0); |
| 2133 | const DataType& type = *arr.type; |
| 2134 | const uint8_t* in_valid = arr.buffers[0].data; |
| 2135 | const uint8_t* in_values = arr.buffers[1].data; |
| 2136 | |
| 2137 | if (in_null_count < 0.8 * batch.length) { |
| 2138 | // The input is not mostly null, we deem it more efficient to |
| 2139 | // copy values even underlying null slots instead of the more |
| 2140 | // expensive bitmasking using BinaryBitBlockCounter. |
| 2141 | BitRunReader bit_reader(out_valid, out_offset, batch.length); |
| 2142 | int64_t offset = 0; |
| 2143 | while (true) { |
| 2144 | const auto run = bit_reader.NextRun(); |
| 2145 | if (run.length == 0) { |
| 2146 | break; |
| 2147 | } |
| 2148 | if (!run.set) { |
| 2149 | // Copy from input |
| 2150 | CopyDataUtils<Type>::CopyData(type, in_values, in_offset + offset, out_values, |
| 2151 | out_offset + offset, run.length); |
| 2152 | } |
| 2153 | offset += run.length; |
| 2154 | } |
| 2155 | arrow::internal::BitmapOr(out_valid, out_offset, in_valid, in_offset, |
| 2156 | batch.length, out_offset, out_valid); |
| 2157 | } else { |
| 2158 | BinaryBitBlockCounter counter(in_valid, in_offset, out_valid, out_offset, |
| 2159 | batch.length); |
| 2160 | int64_t offset = 0; |
| 2161 | while (offset < batch.length) { |
| 2162 | const auto block = counter.NextAndNotWord(); |
| 2163 | if (block.AllSet()) { |
| 2164 | CopyValues<Type>(value, offset, block.length, out_valid, out_values, |
| 2165 | out_offset + offset); |
| 2166 | } else if (block.popcount) { |
| 2167 | for (int64_t j = 0; j < block.length; ++j) { |
| 2168 | if (!bit_util::GetBit(out_valid, out_offset + offset + j) && |
| 2169 | bit_util::GetBit(in_valid, in_offset + offset + j)) { |
nothing calls this directly
no test coverage detected