| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| #include "paimon/utils/row_range_index.h" | |
| #include <algorithm> | |
| #include <utility> | |
| namespace paimon { | |
| RowRangeIndex::RowRangeIndex(std::vector<Range> ranges) : ranges_(std::move(ranges)) { | |
| starts_.reserve(ranges_.size()); | |
| ends_.reserve(ranges_.size()); | |
| for (const auto& range : ranges_) { | |
| starts_.push_back(range.from); | |
| ends_.push_back(range.to); | |
| } | |
| } | |
| Result<RowRangeIndex> RowRangeIndex::Create(const std::vector<Range>& ranges, bool merge_adjacent) { | |
| return RowRangeIndex(Range::SortAndMergeOverlap(ranges, merge_adjacent)); | |
| } | |
| const std::vector<Range>& RowRangeIndex::Ranges() const { | |
| return ranges_; | |
| } | |
| bool RowRangeIndex::Intersects(int64_t start, int64_t end) const { | |
| int32_t candidate = LowerBound(start); | |
| return candidate < static_cast<int32_t>(starts_.size()) && starts_[candidate] <= end; | |
| } | |
| bool RowRangeIndex::Contains(const Range& range) const { | |
| int32_t candidate = LowerBound(range.from); | |
| return candidate < static_cast<int32_t>(ranges_.size()) && | |
| ranges_[candidate].from <= range.from && ranges_[candidate].to >= range.to; | |
| } | |
| bool RowRangeIndex::ContainsExactly(const Range& range) const { | |
| int32_t candidate = LowerBound(range.from); | |
| return candidate < static_cast<int32_t>(ranges_.size()) && ranges_[candidate] == range; | |
| } | |
| std::vector<Range> RowRangeIndex::IntersectedRanges(int64_t start, int64_t end) const { | |
| int32_t left = LowerBound(start); | |
| if (left >= static_cast<int32_t>(ranges_.size())) { | |
| return {}; | |
| } | |
| int32_t right = LowerBound(end); | |
| if (right >= static_cast<int32_t>(ranges_.size())) { | |
| right = static_cast<int32_t>(ranges_.size()) - 1; | |
| } | |
| if (starts_[left] > end) { | |
| return {}; | |
| } | |
| std::vector<Range> expected; | |
| // Add the first intersecting range, clipped to [start, end]. | |
| const Range& first_range = ranges_[left]; | |
| expected.emplace_back(std::max(start, first_range.from), std::min(end, first_range.to)); | |
| // Add all fully contained ranges between first and last. | |
| for (int32_t i = left + 1; i < right; ++i) { | |
| expected.push_back(ranges_[i]); | |
| } | |
| // Add the last intersecting range (if different from the first), clipped to [start, end]. | |
| if (right != left) { | |
| const Range& last_range = ranges_[right]; | |
| if (last_range.from <= end) { | |
| expected.emplace_back(std::max(start, last_range.from), std::min(end, last_range.to)); | |
| } | |
| } | |
| return expected; | |
| } | |
| int32_t RowRangeIndex::LowerBound(int64_t target) const { | |
| int32_t left = 0; | |
| auto right = static_cast<int32_t>(ends_.size()); | |
| while (left < right) { | |
| int32_t mid = left + (right - left) / 2; | |
| if (ends_[mid] < target) { | |
| left = mid + 1; | |
| } else { | |
| right = mid; | |
| } | |
| } | |
| return left; | |
| } | |
| } // namespace paimon |