static void coalesce(Value::Ranges* ranges, const Value::Range& range) { // Note that we assume that ranges has already been coalesced. Value::Ranges result; Value::Range temp = range; for (int i = 0; i < ranges->range_size(); i++) { const Value::Range& current = ranges->range(i); // Check if current and range overlap. Note, we only need to // compare with range and not with temp to check for overlap // because we expect ranges to be coalesced to begin with! if (current.begin() <= range.end() && current.end() >= range.begin() ) { // Update temp with new boundaries. temp.set_begin(std::min(range.begin(), current.begin())); temp.set_end(std::max(range.end(), current.end())); } else { // No overlap. result.add_range()->MergeFrom(current); } } result.add_range()->MergeFrom(temp); *ranges = result; }
// Subtract `right_` from `left_`, and return the result as Value::Ranges. Value::Ranges subtract(const Value::Ranges& left_, const Value::Ranges& right_) { if (left_.range_size() == 0 || right_.range_size() == 0) { return left_; } // Convert the input `Ranges` to `vector<internal::Range>` and // sort the vector based on the start of a range. auto sortRanges = [](const Value::Ranges& ranges) { vector<internal::Range> result; result.reserve(ranges.range_size()); foreach (const Value::Range& range, ranges.range()) { result.push_back({range.begin(), range.end()}); } std::sort( result.begin(), result.end(), [](const internal::Range& left, const internal::Range& right) { return left.start < right.start; }); return result; }; Value::Ranges result; vector<internal::Range> left = sortRanges(left_); vector<internal::Range> right = sortRanges(right_); vector<internal::Range>::iterator itLeft = left.begin(); for (vector<internal::Range>::const_iterator itRight = right.cbegin(); itLeft != left.end() && itRight != right.cend();) { // Non-overlap: // L: |___| // R: |___| if (itLeft->end < itRight->start) { Value::Range* newRange = result.add_range(); newRange->set_begin(itLeft->start); newRange->set_end(itLeft->end); itLeft++; continue; } // Non-overlap: // L: |___| // R: |___| if (itLeft->start > itRight->end) { itRight++; continue; } if (itLeft->start < itRight->start) { Value::Range* newRange = result.add_range(); newRange->set_begin(itLeft->start); newRange->set_end(itRight->start - 1); if (itLeft->end <= itRight->end) { // L: |_____| // R: |____| itLeft++; } else { // L: |________| // R: |___| itLeft->start = itRight->end + 1; itRight++; } } else { // itLeft->start >= itRight->start if (itLeft->end <= itRight->end) { // L: |____| // R: |________| itLeft++; } else { // L: |_____| // R: |____| itLeft->start = itRight->end + 1; itRight++; } } } // Traverse what's left in the `left`, if any. while (itLeft != left.end()) { // TODO(mzhu): Consider reserving the exact size. Value::Range* newRange = result.add_range(); newRange->set_begin(itLeft->start); newRange->set_end(itLeft->end); itLeft++; } return result; }