| 930 | namespace internal { |
| 931 | |
| 932 | std::vector<ArrayVector> RechunkArraysConsistently( |
| 933 | const std::vector<ArrayVector>& groups) { |
| 934 | if (groups.size() <= 1) { |
| 935 | return groups; |
| 936 | } |
| 937 | int64_t total_length = 0; |
| 938 | for (const auto& array : groups.front()) { |
| 939 | total_length += array->length(); |
| 940 | } |
| 941 | #ifndef NDEBUG |
| 942 | for (const auto& group : groups) { |
| 943 | int64_t group_length = 0; |
| 944 | for (const auto& array : group) { |
| 945 | group_length += array->length(); |
| 946 | } |
| 947 | DCHECK_EQ(group_length, total_length) |
| 948 | << "Array groups should have the same total number of elements"; |
| 949 | } |
| 950 | #endif |
| 951 | if (total_length == 0) { |
| 952 | return groups; |
| 953 | } |
| 954 | |
| 955 | // Set up result vectors |
| 956 | std::vector<ArrayVector> rechunked_groups(groups.size()); |
| 957 | |
| 958 | // Set up progress counters |
| 959 | std::vector<ArrayVector::const_iterator> current_arrays; |
| 960 | std::vector<int64_t> array_offsets; |
| 961 | for (const auto& group : groups) { |
| 962 | current_arrays.emplace_back(group.cbegin()); |
| 963 | array_offsets.emplace_back(0); |
| 964 | } |
| 965 | |
| 966 | // Scan all array vectors at once, rechunking along the way |
| 967 | int64_t start = 0; |
| 968 | while (start < total_length) { |
| 969 | // First compute max possible length for next chunk |
| 970 | int64_t chunk_length = std::numeric_limits<int64_t>::max(); |
| 971 | for (size_t i = 0; i < groups.size(); i++) { |
| 972 | auto& arr_it = current_arrays[i]; |
| 973 | auto& offset = array_offsets[i]; |
| 974 | // Skip any done arrays (including 0-length arrays) |
| 975 | while (offset == (*arr_it)->length()) { |
| 976 | ++arr_it; |
| 977 | offset = 0; |
| 978 | } |
| 979 | const auto& array = *arr_it; |
| 980 | DCHECK_GT(array->length(), offset); |
| 981 | chunk_length = std::min(chunk_length, array->length() - offset); |
| 982 | } |
| 983 | DCHECK_GT(chunk_length, 0); |
| 984 | |
| 985 | // Then slice all arrays along this chunk size |
| 986 | for (size_t i = 0; i < groups.size(); i++) { |
| 987 | const auto& array = *current_arrays[i]; |
| 988 | auto& offset = array_offsets[i]; |
| 989 | if (offset == 0 && array->length() == chunk_length) { |