| 384 | |
| 385 | private: |
| 386 | IterationResult FillForLast(ElementRange* range, ElementRange* child_range, |
| 387 | PathWriteContext* context) { |
| 388 | // First fill int the remainder of the list. |
| 389 | RETURN_IF_ERROR(FillRepLevels(child_range->Size(), rep_level_, context)); |
| 390 | |
| 391 | // Once we've reached this point the following preconditions should hold: |
| 392 | // 1. There are no more repeated path nodes to deal with. |
| 393 | // 2. Null values would have shortened the range to ensure all remaining |
| 394 | // list elements are present (though they may be empty lists). |
| 395 | // 3. No element of range spans a parent list (intermediate |
| 396 | // list nodes only handle one list entry at a time). |
| 397 | // |
| 398 | // Given these preconditions it is safe to fill runs on contiguous non-empty |
| 399 | // lists here and expand the range in the child node accordingly. |
| 400 | while (!range->Empty()) { |
| 401 | ElementRange next_child_range = selector_.GetRange(range->start); |
| 402 | if (next_child_range.Empty()) { |
| 403 | // The empty range will need to be handled after we pass down the accumulated |
| 404 | // range because it affects def_level placement and we need to get the children |
| 405 | // def_levels entered first. |
| 406 | break; |
| 407 | } |
| 408 | // FillForLast extends child_range by updating only its end. Non-contiguous |
| 409 | // selectors must split at gaps. |
| 410 | if constexpr (RangeSelector::kContiguous) { |
| 411 | DCHECK_EQ(next_child_range.start, child_range->end) |
| 412 | << next_child_range.start << " != " << child_range->end; |
| 413 | } else { |
| 414 | if (next_child_range.start != child_range->end) { |
| 415 | break; |
| 416 | } |
| 417 | } |
| 418 | // This is the start of a new list. We can be sure it only applies |
| 419 | // to the previous list (and doesn't jump to the start of any list |
| 420 | // further up in nesting due to the constraints mentioned at the start |
| 421 | // of the function). |
| 422 | RETURN_IF_ERROR(context->AppendRepLevel(prev_rep_level_)); |
| 423 | RETURN_IF_ERROR(context->AppendRepLevels(next_child_range.Size() - 1, rep_level_)); |
| 424 | child_range->end = next_child_range.end; |
| 425 | ++range->start; |
| 426 | } |
| 427 | |
| 428 | // Do book-keeping to track the elements of the arrays that are actually visited |
| 429 | // beyond this point. This is necessary to identify "gaps" in values that should |
| 430 | // not be processed (written out to parquet). |
| 431 | context->RecordPostListVisit(*child_range); |
| 432 | return kNext; |
| 433 | } |
| 434 | |
| 435 | RangeSelector selector_; |
| 436 | int16_t prev_rep_level_; |
nothing calls this directly
no test coverage detected