github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/interval/range_group.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package interval 12 13 import ( 14 "bytes" 15 "container/list" 16 "fmt" 17 ) 18 19 // RangeGroup represents a set of possibly disjointed Ranges. The 20 // interface exposes methods to manipulate the group by adding and 21 // subtracting Ranges. All methods requiring a Range will panic 22 // if the provided range is inverted or empty. 23 // 24 // One use case of the interface is to add ranges to the group and 25 // observe whether the addition increases the size of the group or 26 // not, indicating whether the new range's interval is redundant, or 27 // if it is needed for the full composition of the group. Because 28 // the RangeGroup builds as more ranges are added, insertion order of 29 // the ranges is critical. For instance, if two identical ranges are 30 // added, only the first to be added with Add will return true, as it 31 // will be the only one to expand the group. 32 // 33 // Another use case of the interface is to add and subtract ranges as 34 // needed to the group, allowing the internals of the implementation 35 // to coalesce and split ranges when needed to factor the group to 36 // its minimum number of disjoint ranges. 37 type RangeGroup interface { 38 // Add will attempt to add the provided Range to the RangeGroup, 39 // returning whether the addition increased the range of the group 40 // or not. 41 Add(Range) bool 42 // Sub will attempt to remove the provided Range from the RangeGroup, 43 // returning whether the subtraction reduced the range of the group 44 // or not. 45 Sub(Range) bool 46 // Clear clears all ranges from the RangeGroup, resetting it to be 47 // used again. 48 Clear() 49 // Overlaps returns whether the provided Range is partially contained 50 // within the group of Ranges in the RangeGroup. 51 Overlaps(Range) bool 52 // Encloses returns whether the provided Range is fully contained 53 // within the group of Ranges in the RangeGroup. 54 Encloses(Range) bool 55 // ForEach calls the provided function with each Range stored in 56 // the group. An error is returned indicating whether the callback 57 // function saw an error, whereupon the Range iteration will halt 58 // (potentially prematurely) and the error will be returned from ForEach 59 // itself. If no error is returned from the callback, the method 60 // will visit all Ranges in the group before returning a nil error. 61 ForEach(func(Range) error) error 62 // Iterator returns an iterator to visit each Range stored in the 63 // group, in-order. It is not safe to mutate the RangeGroup while 64 // iteration is being performed. 65 Iterator() RangeGroupIterator 66 // Len returns the number of Ranges currently within the RangeGroup. 67 // This will always be equal to or less than the number of ranges added, 68 // as ranges that overlap will merge to produce a single larger range. 69 Len() int 70 fmt.Stringer 71 } 72 73 // RangeGroupIterator is an iterator that walks in-order over a RangeGroup. 74 type RangeGroupIterator interface { 75 // Next returns the next Range in the RangeGroup. It returns false 76 // if there are no more Ranges. 77 Next() (Range, bool) 78 } 79 80 const rangeListNodeBucketSize = 8 81 82 type rangeListNode struct { 83 slots [rangeListNodeBucketSize]Range // ordered, non-overlapping 84 len int 85 } 86 87 func newRangeListNodeWithRange(r Range) *rangeListNode { 88 var n rangeListNode 89 n.push(r) 90 return &n 91 } 92 93 func (n *rangeListNode) push(r Range) { 94 n.slots[n.len] = r 95 n.len++ 96 } 97 98 func (n *rangeListNode) full() bool { 99 return n.len == len(n.slots) 100 } 101 102 func (n *rangeListNode) min() Comparable { 103 return n.slots[0].Start 104 } 105 106 func (n *rangeListNode) max() Comparable { 107 return n.slots[n.len-1].End 108 } 109 110 // findIdx finds the upper-bound slot index that the provided range should fit 111 // in the rangeListNode. It also returns whether the slot is currently occupied 112 // by an overlapping range. 113 func (n *rangeListNode) findIdx(r Range, inclusive bool) (int, bool) { 114 overlapFn := overlapsExclusive 115 passedCmp := 0 116 if inclusive { 117 overlapFn = overlapsInclusive 118 passedCmp = -1 119 } 120 for i, nr := range n.slots[:n.len] { 121 switch { 122 case overlapFn(nr, r): 123 return i, true 124 case r.End.Compare(nr.Start) <= passedCmp: 125 // Past where overlapping ranges would be. 126 return i, false 127 } 128 } 129 return n.len, false 130 } 131 132 // rangeList is an implementation of a RangeGroup using a bucketted linked list 133 // to sequentially order non-overlapping ranges. 134 // 135 // rangeList is not safe for concurrent use by multiple goroutines. 136 type rangeList struct { 137 ll list.List 138 len int 139 } 140 141 // NewRangeList constructs a linked-list backed RangeGroup. 142 func NewRangeList() RangeGroup { 143 var rl rangeList 144 rl.ll.Init() 145 rl.ll.PushFront(&rangeListNode{}) 146 return &rl 147 } 148 149 // findNode returns the upper-bound node that the range would be bucketted in, 150 // along with that node's previous element. It also returns whether the range 151 // overlaps with the bounds of the node. 152 func (rl *rangeList) findNode(r Range, inclusive bool) (prev, cur *list.Element, inCur bool) { 153 if err := rangeError(r); err != nil { 154 panic(err) 155 } 156 reachedCmp := 1 157 passedCmp := 0 158 if inclusive { 159 reachedCmp = 0 160 passedCmp = -1 161 } 162 for e := rl.ll.Front(); e != nil; e = e.Next() { 163 n := e.Value.(*rangeListNode) 164 if n.len == 0 { 165 // The node is empty. This must be the last node in the list. 166 return prev, e, false 167 } 168 // Check if the range starts at a value less than (or equal to, for 169 // inclusive) the maximum value in this node. This is what we want. 170 if n.max().Compare(r.Start) >= reachedCmp { 171 // Determine whether the range overlap the node's bounds. 172 inCur := n.min().Compare(r.End) <= passedCmp 173 return prev, e, inCur 174 } 175 prev = e 176 } 177 return prev, nil, false 178 } 179 180 // insertAtIdx inserts the provided range at the specified index in the node. 181 // It performs any necessary slot movement to keep the ranges ordered. 182 // 183 // Note: e.Value is expected to be n, but we want to avoid repeated type 184 // assertions so both are taken as arguments. 185 func (rl *rangeList) insertAtIdx(e *list.Element, n *rangeListNode, r Range, i int) { 186 if n.full() { 187 // If the current node is full, we're going to need to shift off a range 188 // from one of the slots into a different node. If i is not pointing 189 // past the end of the range, we need to shift off the range currently 190 // in the last slot in this node. If i is pointing past the end of the 191 // range, we can just shift the new range to a different node without 192 // making any changes to this node. 193 toShift := n.slots[n.len-1] 194 noLocalChanges := false 195 if i == n.len { 196 toShift = r 197 198 // We're going to add range r to a different node, so there will be 199 // no local changes to this node. 200 noLocalChanges = true 201 } 202 203 // Check if the next node has room. Note that we only call insertAtIdx 204 // recursively on the next node if it is not full. We don't want to 205 // shift recursively all the way down the list. Instead, we'll just pay 206 // the constant cost below of inserting a fresh node in-between the 207 // current and next node. 208 next := e.Next() 209 insertedInNext := false 210 if next != nil { 211 nextN := next.Value.(*rangeListNode) 212 if !nextN.full() { 213 rl.insertAtIdx(next, nextN, toShift, 0) 214 insertedInNext = true 215 } 216 } 217 if !insertedInNext { 218 newN := newRangeListNodeWithRange(toShift) 219 rl.ll.InsertAfter(newN, e) 220 rl.len++ 221 } 222 223 if noLocalChanges { 224 return 225 } 226 } else { 227 n.len++ 228 rl.len++ 229 } 230 // Shift all others over and copy the new range in. Because of 231 // the n.full check, we know that we'll have at least one free 232 // slot open at the end. 233 copy(n.slots[i+1:n.len], n.slots[i:n.len-1]) 234 n.slots[i] = r 235 } 236 237 // Add implements RangeGroup. It iterates over the current ranges in the 238 // rangeList to find which overlap with the new range. If there is no 239 // overlap, the new range will be added and the function will return true. 240 // If there is some overlap, the function will return true if the new 241 // range increases the range of the rangeList, in which case it will be 242 // added to the list, and false if it does not increase the range, in which 243 // case it won't be added. If the range is added, the function will also attempt 244 // to merge any ranges within the list that now overlap. 245 func (rl *rangeList) Add(r Range) bool { 246 prev, cur, inCur := rl.findNode(r, true /* inclusive */) 247 248 var prevN *rangeListNode 249 if prev != nil { 250 prevN = prev.Value.(*rangeListNode) 251 } 252 if !inCur && prevN != nil && !prevN.full() { 253 // There is a previous node. Add the range to the end of that node. 254 prevN.push(r) 255 rl.len++ 256 return true 257 } 258 259 if cur != nil { 260 n := cur.Value.(*rangeListNode) 261 i, ok := n.findIdx(r, true /* inclusive */) 262 if !ok { 263 // The range can't be merged with any existing ranges, but should 264 // instead be inserted at slot i. This may force us to shift over 265 // other slots. 266 rl.insertAtIdx(cur, n, r, i) 267 return true 268 } 269 270 // If a current range fully contains the new range, no need to add it. 271 nr := n.slots[i] 272 if contains(nr, r) { 273 return false 274 } 275 276 // Merge as many ranges as possible and replace old range. All merges 277 // will be made into n.slots[i] because adding a range to the RangeGroup 278 // can result in only at most one group of ranges being merged. 279 // 280 // For example: 281 // existing ranges : ---- ----- ---- ---- ---- 282 // new range : -------------- 283 // resulting ranges: ---- ------------------- ---- 284 // 285 // In this example, n.slots[i] is the first existing range that overlaps 286 // with the new range. 287 newR := merge(nr, r) 288 n.slots[i] = newR 289 290 // Each iteration attempts to merge all of the ranges in a rangeListNode. 291 mergeElem := cur 292 origNode := true 293 for { 294 mergeN := mergeElem.Value.(*rangeListNode) 295 origLen := mergeN.len 296 297 // mergeState is the slot index to begin merging from 298 mergeStart := 0 299 if origNode { 300 mergeStart = i + 1 301 } 302 303 // Each iteration attempts to merge a single range into the current 304 // merge batch. 305 j := mergeStart 306 for ; j < origLen; j++ { 307 mergeR := mergeN.slots[j] 308 309 if overlapsInclusive(newR, mergeR) { 310 newR = merge(newR, mergeR) 311 n.slots[i] = newR 312 mergeN.len-- 313 rl.len-- 314 } else { 315 // If the ranges don't overlap, that means index j and up 316 // are still needed in the current node. Shift these over. 317 copy(mergeN.slots[mergeStart:mergeStart+origLen-j], mergeN.slots[j:origLen]) 318 return true 319 } 320 } 321 322 // If we didn't break, that means that all of the slots including 323 // and after mergeStart in the current node were merged. Continue 324 // onto the next node. 325 nextE := mergeElem.Next() 326 if !origNode { 327 // If this is not the current node, we can delete it 328 // completely. 329 rl.ll.Remove(mergeElem) 330 } 331 if nextE == nil { 332 return true 333 } 334 mergeElem = nextE 335 origNode = false 336 } 337 } 338 339 // The new range couldn't be added to the previous or the current node. 340 // We'll have to create a new node for the range. 341 n := newRangeListNodeWithRange(r) 342 if prevN != nil { 343 // There is a previous node and it is full. 344 rl.ll.InsertAfter(n, prev) 345 } else { 346 // There is no previous node. Add the range to a new node in the front 347 // of the list. 348 rl.ll.PushFront(n) 349 } 350 rl.len++ 351 return true 352 } 353 354 // Sub implements RangeGroup. It iterates over the current ranges in the 355 // rangeList to find which overlap with the range to subtract. For all 356 // ranges that overlap with the provided range, the overlapping segment of 357 // the range is removed. If the provided range fully contains a range in 358 // the rangeList, the range in the rangeList will be removed. The method 359 // returns whether the subtraction resulted in any decrease to the size 360 // of the RangeGroup. 361 func (rl *rangeList) Sub(r Range) bool { 362 _, cur, inCur := rl.findNode(r, false /* inclusive */) 363 if !inCur { 364 // The range does not overlap any nodes. Nothing to do. 365 return false 366 } 367 368 n := cur.Value.(*rangeListNode) 369 i, ok := n.findIdx(r, false /* inclusive */) 370 if !ok { 371 // The range does not overlap any ranges in the node. Nothing to do. 372 return false 373 } 374 375 for { 376 nr := n.slots[i] 377 if !overlapsExclusive(nr, r) { 378 // The range does not overlap nr so stop trying to subtract. The 379 // findIdx check above guarantees that this will never be the case 380 // for the first iteration of this loop. 381 return true 382 } 383 384 sCmp := nr.Start.Compare(r.Start) 385 eCmp := nr.End.Compare(r.End) 386 delStart := sCmp >= 0 387 delEnd := eCmp <= 0 388 389 switch { 390 case delStart && delEnd: 391 // Remove the entire range. 392 n.len-- 393 rl.len-- 394 if n.len == 0 { 395 // Move to the next node, removing the current node as long as 396 // it's not the only one in the list. 397 i = 0 398 next := cur.Next() 399 if rl.len > 0 { 400 rl.ll.Remove(cur) 401 } 402 if next == nil { 403 return true 404 } 405 cur = next 406 n = cur.Value.(*rangeListNode) 407 continue 408 } else { 409 // Replace the current Range. 410 copy(n.slots[i:n.len], n.slots[i+1:n.len+1]) 411 } 412 // Don't increment i. 413 case delStart: 414 // Remove the start of the range by truncating. Can return after. 415 n.slots[i].Start = r.End 416 return true 417 case delEnd: 418 // Remove the end of the range by truncating. 419 n.slots[i].End = r.Start 420 i++ 421 default: 422 // Remove the middle of the range by splitting and truncating. 423 oldEnd := nr.End 424 n.slots[i].End = r.Start 425 426 // Create right side of split. Can return after. 427 rSplit := Range{Start: r.End, End: oldEnd} 428 rl.insertAtIdx(cur, n, rSplit, i+1) 429 return true 430 } 431 432 // Move to the next node, if necessary. 433 if i >= n.len { 434 i = 0 435 cur = cur.Next() 436 if cur == nil { 437 return true 438 } 439 n = cur.Value.(*rangeListNode) 440 } 441 } 442 } 443 444 // Clear implements RangeGroup. It clears all ranges from the 445 // rangeList. 446 func (rl *rangeList) Clear() { 447 // Empty the first node, but keep it in the list. 448 f := rl.ll.Front().Value.(*rangeListNode) 449 *f = rangeListNode{} 450 451 // If the list has more than one node in it, remove all but the first. 452 if rl.ll.Len() > 1 { 453 rl.ll.Init() 454 rl.ll.PushBack(f) 455 } 456 rl.len = 0 457 } 458 459 // Overlaps implements RangeGroup. It returns whether the provided 460 // Range is partially contained within the group of Ranges in the rangeList. 461 func (rl *rangeList) Overlaps(r Range) bool { 462 if _, cur, inCur := rl.findNode(r, false /* inclusive */); inCur { 463 n := cur.Value.(*rangeListNode) 464 if _, ok := n.findIdx(r, false /* inclusive */); ok { 465 return true 466 } 467 } 468 return false 469 } 470 471 // Encloses implements RangeGroup. It returns whether the provided 472 // Range is fully contained within the group of Ranges in the rangeList. 473 func (rl *rangeList) Encloses(r Range) bool { 474 if _, cur, inCur := rl.findNode(r, false /* inclusive */); inCur { 475 n := cur.Value.(*rangeListNode) 476 if i, ok := n.findIdx(r, false /* inclusive */); ok { 477 return contains(n.slots[i], r) 478 } 479 } 480 return false 481 } 482 483 // ForEach implements RangeGroup. It calls the provided function f 484 // with each Range stored in the rangeList. 485 func (rl *rangeList) ForEach(f func(Range) error) error { 486 it := rangeListIterator{e: rl.ll.Front()} 487 for r, ok := it.Next(); ok; r, ok = it.Next() { 488 if err := f(r); err != nil { 489 return err 490 } 491 } 492 return nil 493 } 494 495 // rangeListIterator is an in-order iterator operating over a rangeList. 496 type rangeListIterator struct { 497 e *list.Element 498 idx int // next slot index 499 } 500 501 // Next implements RangeGroupIterator. It returns the next Range in the 502 // rangeList, or false. 503 func (rli *rangeListIterator) Next() (r Range, ok bool) { 504 if rli.e != nil { 505 n := rli.e.Value.(*rangeListNode) 506 507 // Get current index, return if invalid. 508 curIdx := rli.idx 509 if curIdx >= n.len { 510 return Range{}, false 511 } 512 513 // Move index and Element pointer forwards. 514 rli.idx = curIdx + 1 515 if rli.idx >= n.len { 516 rli.idx = 0 517 rli.e = rli.e.Next() 518 } 519 520 return n.slots[curIdx], true 521 } 522 return Range{}, false 523 } 524 525 // Iterator implements RangeGroup. It returns an iterator to iterate over 526 // the group of ranges. 527 func (rl *rangeList) Iterator() RangeGroupIterator { 528 return &rangeListIterator{e: rl.ll.Front()} 529 } 530 531 // Len implements RangeGroup. It returns the number of ranges in 532 // the rangeList. 533 func (rl *rangeList) Len() int { 534 return rl.len 535 } 536 537 func (rl *rangeList) String() string { 538 return rgString(rl) 539 } 540 541 // rangeTree is an implementation of a RangeGroup using an interval 542 // tree to efficiently store and search for non-overlapping ranges. 543 // 544 // rangeTree is not safe for concurrent use by multiple goroutines. 545 type rangeTree struct { 546 t Tree 547 idCount uintptr 548 } 549 550 // NewRangeTree constructs an interval tree backed RangeGroup. 551 func NewRangeTree() RangeGroup { 552 return &rangeTree{ 553 t: NewTree(InclusiveOverlapper), 554 } 555 } 556 557 // rangeKey implements Interface and can be inserted into a Tree. It 558 // provides uniqueness as well as a key interval. 559 type rangeKey struct { 560 r Range 561 id uintptr 562 } 563 564 var _ Interface = rangeKey{} 565 566 // makeKey creates a new rangeKey defined by the provided range. 567 func (rt *rangeTree) makeKey(r Range) rangeKey { 568 rt.idCount++ 569 return rangeKey{ 570 r: r, 571 id: rt.idCount, 572 } 573 } 574 575 // Range implements Interface. 576 func (rk rangeKey) Range() Range { 577 return rk.r 578 } 579 580 // ID implements Interface. 581 func (rk rangeKey) ID() uintptr { 582 return rk.id 583 } 584 585 func (rk rangeKey) String() string { 586 return fmt.Sprintf("%d: %q-%q", rk.id, rk.r.Start, rk.r.End) 587 } 588 589 // Add implements RangeGroup. It first uses the interval tree to lookup 590 // the current ranges which overlap with the new range. If there is no 591 // overlap, the new range will be added and the function will return true. 592 // If there is some overlap, the function will return true if the new 593 // range increases the range of the rangeTree, in which case it will be 594 // added to the tree, and false if it does not increase the range, in which 595 // case it won't be added. If the range is added, the function will also attempt 596 // to merge any ranges within the tree that now overlap. 597 func (rt *rangeTree) Add(r Range) bool { 598 if err := rangeError(r); err != nil { 599 panic(err) 600 } 601 overlaps := rt.t.Get(r) 602 if len(overlaps) == 0 { 603 key := rt.makeKey(r) 604 if err := rt.t.Insert(&key, false /* fast */); err != nil { 605 panic(err) 606 } 607 return true 608 } 609 first := overlaps[0].(*rangeKey) 610 611 // If a current range fully contains the new range, no 612 // need to add it. 613 if contains(first.r, r) { 614 return false 615 } 616 617 // Merge as many ranges as possible, and replace old range. 618 first.r = merge(first.r, r) 619 for _, o := range overlaps[1:] { 620 other := o.(*rangeKey) 621 first.r = merge(first.r, other.r) 622 if err := rt.t.Delete(o, true /* fast */); err != nil { 623 panic(err) 624 } 625 } 626 rt.t.AdjustRanges() 627 return true 628 } 629 630 // Sub implements RangeGroup. It first uses the interval tree to lookup 631 // the current ranges which overlap with the range to subtract. For all 632 // ranges that overlap with the provided range, the overlapping segment of 633 // the range is removed. If the provided range fully contains a range in 634 // the rangeTree, the range in the rangeTree will be removed. The method 635 // returns whether the subtraction resulted in any decrease to the size 636 // of the RangeGroup. 637 func (rt *rangeTree) Sub(r Range) bool { 638 if err := rangeError(r); err != nil { 639 panic(err) 640 } 641 overlaps := rt.t.GetWithOverlapper(r, ExclusiveOverlapper) 642 if len(overlaps) == 0 { 643 return false 644 } 645 646 for _, o := range overlaps { 647 rk := o.(*rangeKey) 648 sCmp := rk.r.Start.Compare(r.Start) 649 eCmp := rk.r.End.Compare(r.End) 650 651 delStart := sCmp >= 0 652 delEnd := eCmp <= 0 653 654 switch { 655 case delStart && delEnd: 656 // Remove the entire range. 657 if err := rt.t.Delete(o, true /* fast */); err != nil { 658 panic(err) 659 } 660 case delStart: 661 // Remove the start of the range by truncating. 662 rk.r.Start = r.End 663 case delEnd: 664 // Remove the end of the range by truncating. 665 rk.r.End = r.Start 666 default: 667 // Remove the middle of the range by splitting. 668 oldEnd := rk.r.End 669 rk.r.End = r.Start 670 671 rSplit := Range{Start: r.End, End: oldEnd} 672 rKey := rt.makeKey(rSplit) 673 if err := rt.t.Insert(&rKey, true /* fast */); err != nil { 674 panic(err) 675 } 676 } 677 } 678 rt.t.AdjustRanges() 679 return true 680 } 681 682 // Clear implements RangeGroup. It clears all rangeKeys from the rangeTree. 683 func (rt *rangeTree) Clear() { 684 rt.t.Clear() 685 } 686 687 // Overlaps implements RangeGroup. It returns whether the provided 688 // Range is partially contained within the group of Ranges in the rangeTree. 689 func (rt *rangeTree) Overlaps(r Range) bool { 690 if err := rangeError(r); err != nil { 691 panic(err) 692 } 693 overlaps := rt.t.GetWithOverlapper(r, ExclusiveOverlapper) 694 return len(overlaps) > 0 695 } 696 697 // Encloses implements RangeGroup. It returns whether the provided 698 // Range is fully contained within the group of Ranges in the rangeTree. 699 func (rt *rangeTree) Encloses(r Range) bool { 700 if err := rangeError(r); err != nil { 701 panic(err) 702 } 703 overlaps := rt.t.GetWithOverlapper(r, ExclusiveOverlapper) 704 if len(overlaps) != 1 { 705 return false 706 } 707 first := overlaps[0].(*rangeKey) 708 return contains(first.r, r) 709 } 710 711 // ForEach implements RangeGroup. It calls the provided function f 712 // with each Range stored in the rangeTree. 713 func (rt *rangeTree) ForEach(f func(Range) error) error { 714 var err error 715 rt.t.Do(func(i Interface) bool { 716 err = f(i.Range()) 717 return err != nil 718 }) 719 return err 720 } 721 722 // rangeListIterator is an in-order iterator operating over a rangeTree. 723 type rangeTreeIterator struct { 724 it TreeIterator 725 } 726 727 // Next implements RangeGroupIterator. It returns the next Range in the 728 // rangeTree, or false. 729 func (rti *rangeTreeIterator) Next() (r Range, ok bool) { 730 i, ok := rti.it.Next() 731 if !ok { 732 return Range{}, false 733 } 734 return i.Range(), true 735 } 736 737 // Iterator implements RangeGroup. It returns an iterator to iterate over 738 // the group of ranges. 739 func (rt *rangeTree) Iterator() RangeGroupIterator { 740 return &rangeTreeIterator{it: rt.t.Iterator()} 741 } 742 743 // Len implements RangeGroup. It returns the number of rangeKeys in 744 // the rangeTree. 745 func (rt *rangeTree) Len() int { 746 return rt.t.Len() 747 } 748 749 func (rt *rangeTree) String() string { 750 return rgString(rt) 751 } 752 753 // contains returns if the range in the out range fully contains the 754 // in range. 755 func contains(out, in Range) bool { 756 return in.Start.Compare(out.Start) >= 0 && out.End.Compare(in.End) >= 0 757 } 758 759 // merge merges the provided ranges together into their union range. The 760 // ranges must overlap or the function will not produce the correct output. 761 func merge(l, r Range) Range { 762 start := l.Start 763 if r.Start.Compare(start) < 0 { 764 start = r.Start 765 } 766 end := l.End 767 if r.End.Compare(end) > 0 { 768 end = r.End 769 } 770 return Range{Start: start, End: end} 771 } 772 773 // rgString returns a string representation of the ranges in a RangeGroup. 774 func rgString(rg RangeGroup) string { 775 var buffer bytes.Buffer 776 buffer.WriteRune('[') 777 space := false 778 if err := rg.ForEach(func(r Range) error { 779 if space { 780 buffer.WriteRune(' ') 781 } 782 buffer.WriteString(r.String()) 783 space = true 784 return nil 785 }); err != nil { 786 panic(err) 787 } 788 buffer.WriteRune(']') 789 return buffer.String() 790 } 791 792 // RangeGroupsOverlap determines if two RangeGroups contain any overlapping 793 // Ranges or if they are fully disjoint. It does so by iterating over the 794 // RangeGroups together and comparing subsequent ranges. 795 func RangeGroupsOverlap(rg1, rg2 RangeGroup) bool { 796 it1, it2 := rg1.Iterator(), rg2.Iterator() 797 r1, ok1 := it1.Next() 798 r2, ok2 := it2.Next() 799 if !ok1 || !ok2 { 800 return false 801 } 802 for { 803 // Check if the current pair of Ranges overlap. 804 if overlapsExclusive(r1, r2) { 805 return true 806 } 807 808 // If not, advance the Range further behind. 809 var ok bool 810 if r1.Start.Compare(r2.Start) < 0 { 811 r1, ok = it1.Next() 812 } else { 813 r2, ok = it2.Next() 814 } 815 if !ok { 816 return false 817 } 818 } 819 }