| 84 | |
| 85 | template <typename RunEndType> |
| 86 | Result<std::shared_ptr<Array>> MakeLogicalRunEnds(const RunEndEncodedArray& self, |
| 87 | MemoryPool* pool) { |
| 88 | using RunEndCType = typename RunEndType::c_type; |
| 89 | if (self.offset() == 0) { |
| 90 | const auto& run_ends = *self.run_ends(); |
| 91 | if (self.length() == 0) { |
| 92 | return run_ends.Slice(0, 0); |
| 93 | } |
| 94 | |
| 95 | // If offset==0 and the non-zero logical length aligns perfectly with a |
| 96 | // physical run-end, we can return a slice of the run-ends array. |
| 97 | const int64_t physical_length = self.FindPhysicalLength(); |
| 98 | const auto* run_end_values = self.data()->child_data[0]->GetValues<RunEndCType>(1); |
| 99 | if (run_end_values[physical_length - 1] == self.length()) { |
| 100 | return run_ends.Slice(0, physical_length); |
| 101 | } |
| 102 | |
| 103 | // Otherwise we need to copy the run-ends array and adjust only the very |
| 104 | // last run-end. |
| 105 | auto new_run_ends_data = ArrayData::Make(run_ends.type(), physical_length, 0, 0); |
| 106 | { |
| 107 | ARROW_ASSIGN_OR_RAISE(auto buffer, |
| 108 | AllocateBuffer(physical_length * sizeof(RunEndCType), pool)); |
| 109 | new_run_ends_data->buffers = {NULLPTR, std::move(buffer)}; |
| 110 | } |
| 111 | auto* new_run_end_values = new_run_ends_data->GetMutableValues<RunEndCType>(1); |
| 112 | memcpy(new_run_end_values, run_end_values, |
| 113 | (physical_length - 1) * sizeof(RunEndCType)); |
| 114 | new_run_end_values[physical_length - 1] = static_cast<RunEndCType>(self.length()); |
| 115 | return MakeArray(std::move(new_run_ends_data)); |
| 116 | } |
| 117 | |
| 118 | // When the logical offset is non-zero, all run-end values need to be adjusted. |
| 119 | int64_t physical_offset = self.FindPhysicalOffset(); |
| 120 | int64_t physical_length = self.FindPhysicalLength(); |
| 121 | |
| 122 | const auto* run_end_values = self.data()->child_data[0]->GetValues<RunEndCType>(1); |
| 123 | NumericBuilder<RunEndType> builder(pool); |
| 124 | RETURN_NOT_OK(builder.Resize(physical_length)); |
| 125 | if (physical_length > 0) { |
| 126 | for (int64_t i = 0; i < physical_length - 1; i++) { |
| 127 | const auto run_end = run_end_values[physical_offset + i] - self.offset(); |
| 128 | DCHECK_LT(run_end, self.length()); |
| 129 | RETURN_NOT_OK(builder.Append(static_cast<RunEndCType>(run_end))); |
| 130 | } |
| 131 | DCHECK_GE(run_end_values[physical_offset + physical_length - 1] - self.offset(), |
| 132 | self.length()); |
| 133 | RETURN_NOT_OK(builder.Append(static_cast<RunEndCType>(self.length()))); |
| 134 | } |
| 135 | return builder.Finish(); |
| 136 | } |
| 137 | |
| 138 | } // namespace |
| 139 |
nothing calls this directly
no test coverage detected