Subtract `right_` from `left_`, and return the result as Value::Ranges.
| 251 | |
| 252 | // Subtract `right_` from `left_`, and return the result as Value::Ranges. |
| 253 | Value::Ranges subtract(const Value::Ranges& left_, const Value::Ranges& right_) |
| 254 | { |
| 255 | if (left_.range_size() == 0 || right_.range_size() == 0) { |
| 256 | return left_; |
| 257 | } |
| 258 | |
| 259 | // Convert the input `Ranges` to `vector<internal::Range>` and |
| 260 | // sort the vector based on the start of a range. |
| 261 | auto sortRanges = [](const Value::Ranges& ranges) { |
| 262 | vector<internal::Range> result; |
| 263 | result.reserve(ranges.range_size()); |
| 264 | |
| 265 | foreach (const Value::Range& range, ranges.range()) { |
| 266 | result.push_back({range.begin(), range.end()}); |
| 267 | } |
| 268 | |
| 269 | std::sort( |
| 270 | result.begin(), |
| 271 | result.end(), |
| 272 | [](const internal::Range& left, const internal::Range& right) { |
| 273 | return left.start < right.start; |
| 274 | }); |
| 275 | |
| 276 | return result; |
| 277 | }; |
| 278 | |
| 279 | Value::Ranges result; |
| 280 | |
| 281 | vector<internal::Range> left = sortRanges(left_); |
| 282 | vector<internal::Range> right = sortRanges(right_); |
| 283 | |
| 284 | vector<internal::Range>::iterator itLeft = left.begin(); |
| 285 | for (vector<internal::Range>::const_iterator itRight = right.cbegin(); |
| 286 | itLeft != left.end() && itRight != right.cend();) { |
| 287 | // Non-overlap: |
| 288 | // L: |___| |
| 289 | // R: |___| |
| 290 | if (itLeft->end < itRight->start) { |
| 291 | Value::Range* newRange = result.add_range(); |
| 292 | newRange->set_begin(itLeft->start); |
| 293 | newRange->set_end(itLeft->end); |
| 294 | |
| 295 | itLeft++; |
| 296 | continue; |
| 297 | } |
| 298 | |
| 299 | // Non-overlap: |
| 300 | // L: |___| |
| 301 | // R: |___| |
| 302 | if (itLeft->start > itRight->end) { |
| 303 | itRight++; |
| 304 | continue; |
| 305 | } |
| 306 | |
| 307 | if (itLeft->start < itRight->start) { |
| 308 | Value::Range* newRange = result.add_range(); |
| 309 | newRange->set_begin(itLeft->start); |
| 310 | newRange->set_end(itRight->start - 1); |