| 266 | |
| 267 | template <typename ListViewArrayT, bool HasNulls> |
| 268 | Result<std::shared_ptr<Array>> FlattenListViewArray(const ListViewArrayT& list_view_array, |
| 269 | MemoryPool* memory_pool) { |
| 270 | using offset_type = typename ListViewArrayT::offset_type; |
| 271 | const int64_t list_view_array_offset = list_view_array.offset(); |
| 272 | const int64_t list_view_array_length = list_view_array.length(); |
| 273 | std::shared_ptr<arrow::Array> value_array = list_view_array.values(); |
| 274 | |
| 275 | if (list_view_array_length == 0) { |
| 276 | return SliceArrayWithOffsets(*value_array, 0, 0); |
| 277 | } |
| 278 | |
| 279 | // If the list array is *all* nulls, then just return an empty array. |
| 280 | if constexpr (HasNulls) { |
| 281 | if (list_view_array.null_count() == list_view_array.length()) { |
| 282 | return MakeEmptyArray(value_array->type(), memory_pool); |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | const auto* validity = list_view_array.data()->template GetValues<uint8_t>(0, 0); |
| 287 | const auto* offsets = list_view_array.data()->template GetValues<offset_type>(1); |
| 288 | const auto* sizes = list_view_array.data()->template GetValues<offset_type>(2); |
| 289 | |
| 290 | auto is_null_or_empty = [&](int64_t i) { |
| 291 | if (HasNulls && !bit_util::GetBit(validity, list_view_array_offset + i)) { |
| 292 | return true; |
| 293 | } |
| 294 | return sizes[i] == 0; |
| 295 | }; |
| 296 | |
| 297 | // Index of the first valid, non-empty list-view. |
| 298 | int64_t first_i = 0; |
| 299 | for (; first_i < list_view_array_length; first_i++) { |
| 300 | if (!is_null_or_empty(first_i)) { |
| 301 | break; |
| 302 | } |
| 303 | } |
| 304 | // If all list-views are empty, return an empty array. |
| 305 | if (first_i == list_view_array_length) { |
| 306 | return MakeEmptyArray(value_array->type(), memory_pool); |
| 307 | } |
| 308 | |
| 309 | std::vector<std::shared_ptr<Array>> slices; |
| 310 | { |
| 311 | int64_t i = first_i; |
| 312 | auto begin_offset = offsets[i]; |
| 313 | auto end_offset = offsets[i] + sizes[i]; |
| 314 | i += 1; |
| 315 | // Inductive invariant: slices and the always non-empty values slice |
| 316 | // [begin_offset, end_offset) contains all the maximally contiguous slices of the |
| 317 | // values array that are covered by all the list-views before list-view i. |
| 318 | for (; i < list_view_array_length; i++) { |
| 319 | if (is_null_or_empty(i)) { |
| 320 | // The invariant is preserved by simply preserving the current set of slices. |
| 321 | } else { |
| 322 | if (offsets[i] == end_offset) { |
| 323 | end_offset += sizes[i]; |
| 324 | // The invariant is preserved because since the non-empty list-view i |
| 325 | // starts at end_offset, the current range can be extended to end at |
nothing calls this directly
no test coverage detected