Returns a "compacted" version of this array The original array will *not* be modified # Garbage Collection Before GC: ```text ┌──────┐ │......│ │......│ ┌────────────────────┐ ┌ ─ ─ ─ ▶ │Data1 │ Large buffer │ View 1 │─ ─ ─ ─ │......│ with data that ├────────────────────┤ │......│ is not referred │ View 2 │─ ─ ─ ─ ─ ─ ─ ─▶ │Data2 │ to by
(&self)
| 513 | /// Note: this function does not attempt to canonicalize / deduplicate values. For this |
| 514 | /// feature see [`GenericByteViewBuilder::with_deduplicate_strings`]. |
| 515 | pub fn gc(&self) -> Self { |
| 516 | // 1) Read basic properties once |
| 517 | let len = self.len(); // number of elements |
| 518 | let nulls = self.nulls().cloned(); // reuse & clone existing null bitmap |
| 519 | |
| 520 | // 1.5) Fast path: if there are no buffers, just reuse original views and no data blocks |
| 521 | if self.data_buffers().is_empty() { |
| 522 | return unsafe { |
| 523 | GenericByteViewArray::new_unchecked( |
| 524 | self.views().clone(), |
| 525 | vec![], // empty data blocks |
| 526 | nulls, |
| 527 | ) |
| 528 | }; |
| 529 | } |
| 530 | |
| 531 | // 2) Calculate total size of all non-inline data and detect if any exists |
| 532 | let total_large = self.total_buffer_bytes_used(); |
| 533 | |
| 534 | // 2.5) Fast path: if there is no non-inline data, avoid buffer allocation & processing |
| 535 | if total_large == 0 { |
| 536 | // Views are inline-only or all null; just reuse original views and no data blocks |
| 537 | return unsafe { |
| 538 | GenericByteViewArray::new_unchecked( |
| 539 | self.views().clone(), |
| 540 | vec![], // empty data blocks |
| 541 | nulls, |
| 542 | ) |
| 543 | }; |
| 544 | } |
| 545 | |
| 546 | let (views_buf, data_blocks) = if total_large < i32::MAX as usize { |
| 547 | // fast path, the entire data fits in a single buffer |
| 548 | // 3) Allocate exactly capacity for all non-inline data |
| 549 | let mut data_buf = Vec::with_capacity(total_large); |
| 550 | |
| 551 | // 4) Iterate over views and process each inline/non-inline view |
| 552 | let views_buf: Vec<u128> = (0..len) |
| 553 | .map(|i| unsafe { self.copy_view_to_buffer(i, 0, &mut data_buf) }) |
| 554 | .collect(); |
| 555 | let data_block = Buffer::from_vec(data_buf); |
| 556 | let data_blocks = vec![data_block]; |
| 557 | (views_buf, data_blocks) |
| 558 | } else { |
| 559 | // slow path, need to split into multiple buffers |
| 560 | |
| 561 | struct GcCopyGroup { |
| 562 | total_buffer_bytes: usize, |
| 563 | total_len: usize, |
| 564 | } |
| 565 | |
| 566 | impl GcCopyGroup { |
| 567 | fn new(total_buffer_bytes: u32, total_len: usize) -> Self { |
| 568 | Self { |
| 569 | total_buffer_bytes: total_buffer_bytes as usize, |
| 570 | total_len, |
| 571 | } |
| 572 | } |