| 271 | |
| 272 | template <typename offset_type> |
| 273 | Result<OffsetBufferOpOutcome> PutListViewOffsets(const ArrayData& input, |
| 274 | offset_type* sizes, const Buffer& src, |
| 275 | offset_type displacement, |
| 276 | offset_type* dst) { |
| 277 | if (src.size() == 0) { |
| 278 | return OffsetBufferOpOutcome::kOk; |
| 279 | } |
| 280 | const auto& validity_buffer = input.buffers[0]; |
| 281 | if (validity_buffer) { |
| 282 | // Ensure that it is safe to access all the bits in the validity bitmap of input. |
| 283 | RETURN_NOT_OK(internal::CheckSliceParams(/*size=*/8 * validity_buffer->size(), |
| 284 | input.offset, input.length, "buffer")); |
| 285 | } |
| 286 | |
| 287 | const auto offsets = src.data_as<offset_type>(); |
| 288 | DCHECK_EQ(static_cast<int64_t>(src.size() / sizeof(offset_type)), input.length); |
| 289 | |
| 290 | auto visit_not_null = [&](int64_t position) { |
| 291 | if (sizes[position] > 0) { |
| 292 | // NOTE: Concatenate can be called during IPC reads to append delta |
| 293 | // dictionaries. Avoid UB on non-validated input by doing the addition in the |
| 294 | // unsigned domain. (the result can later be validated using |
| 295 | // Array::ValidateFull) |
| 296 | const auto displaced_offset = SafeSignedAdd(offsets[position], displacement); |
| 297 | // displaced_offset>=0 is guaranteed by RangeOfValuesUsed returning the |
| 298 | // smallest offset of valid and non-empty list-views. |
| 299 | DCHECK_GE(displaced_offset, 0); |
| 300 | dst[position] = displaced_offset; |
| 301 | } else { |
| 302 | // Do nothing to leave the dst[position] as 0. |
| 303 | } |
| 304 | }; |
| 305 | |
| 306 | const auto* validity = validity_buffer ? validity_buffer->data_as<uint8_t>() : nullptr; |
| 307 | internal::OptionalBitBlockCounter bit_counter(validity, input.offset, input.length); |
| 308 | int64_t position = 0; |
| 309 | while (position < input.length) { |
| 310 | internal::BitBlockCount block = bit_counter.NextBlock(); |
| 311 | if (block.AllSet()) { |
| 312 | for (int64_t i = 0; i < block.length; ++i, ++position) { |
| 313 | visit_not_null(position); |
| 314 | } |
| 315 | } else if (block.NoneSet()) { |
| 316 | // NOTE: we don't have to do anything for the null entries regarding the |
| 317 | // offsets as the buffer is initialized to 0 when it is allocated. |
| 318 | |
| 319 | // Zero-out the sizes of the null entries to ensure these sizes are not |
| 320 | // greater than the new values length of the concatenated array. |
| 321 | memset(sizes + position, 0, block.length * sizeof(offset_type)); |
| 322 | position += block.length; |
| 323 | } else { |
| 324 | for (int64_t i = 0; i < block.length; ++i, ++position) { |
| 325 | if (bit_util::GetBit(validity, input.offset + position)) { |
| 326 | visit_not_null(position); |
| 327 | } else { |
| 328 | // Zero-out the size at position. |
| 329 | sizes[position] = 0; |
| 330 | } |
nothing calls this directly
no test coverage detected