001/* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.collect; 016 017import static com.google.common.base.MoreObjects.firstNonNull; 018import static com.google.common.base.Preconditions.checkArgument; 019import static com.google.common.base.Preconditions.checkNotNull; 020import static com.google.common.collect.Iterators.emptyIterator; 021import static com.google.common.collect.Iterators.peekingIterator; 022import static com.google.common.collect.Maps.immutableEntry; 023import static com.google.common.collect.Maps.valueOrNull; 024import static com.google.common.collect.Sets.equalsImpl; 025import static com.google.common.collect.Sets.hashCodeImpl; 026 027import com.google.common.annotations.GwtIncompatible; 028import com.google.common.annotations.VisibleForTesting; 029import com.google.errorprone.annotations.concurrent.LazyInit; 030import java.io.Serializable; 031import java.util.Collection; 032import java.util.Comparator; 033import java.util.Iterator; 034import java.util.Map.Entry; 035import java.util.NavigableMap; 036import java.util.NoSuchElementException; 037import java.util.Set; 038import java.util.TreeMap; 039import org.jspecify.annotations.Nullable; 040 041/** 042 * An implementation of {@link RangeSet} backed by a {@link TreeMap}. 043 * 044 * @author Louis Wasserman 045 * @since 14.0 046 */ 047@GwtIncompatible // uses NavigableMap 048public class TreeRangeSet<C extends Comparable<?>> extends AbstractRangeSet<C> 049 implements Serializable { 050 051 @VisibleForTesting final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound; 052 053 /** Creates an empty {@code TreeRangeSet} instance. */ 054 public static <C extends Comparable<?>> TreeRangeSet<C> create() { 055 return new TreeRangeSet<>(new TreeMap<Cut<C>, Range<C>>()); 056 } 057 058 /** Returns a {@code TreeRangeSet} initialized with the ranges in the specified range set. */ 059 public static <C extends Comparable<?>> TreeRangeSet<C> create(RangeSet<C> rangeSet) { 060 TreeRangeSet<C> result = create(); 061 result.addAll(rangeSet); 062 return result; 063 } 064 065 /** 066 * Returns a {@code TreeRangeSet} representing the union of the specified ranges. 067 * 068 * <p>This is the smallest {@code RangeSet} which encloses each of the specified ranges. An 069 * element will be contained in this {@code RangeSet} if and only if it is contained in at least 070 * one {@code Range} in {@code ranges}. 071 * 072 * @since 21.0 073 */ 074 public static <C extends Comparable<?>> TreeRangeSet<C> create(Iterable<Range<C>> ranges) { 075 TreeRangeSet<C> result = create(); 076 result.addAll(ranges); 077 return result; 078 } 079 080 private TreeRangeSet(NavigableMap<Cut<C>, Range<C>> rangesByLowerCut) { 081 this.rangesByLowerBound = rangesByLowerCut; 082 } 083 084 @LazyInit private transient @Nullable Set<Range<C>> asRanges; 085 @LazyInit private transient @Nullable Set<Range<C>> asDescendingSetOfRanges; 086 087 @Override 088 public Set<Range<C>> asRanges() { 089 Set<Range<C>> result = asRanges; 090 if (result == null) { 091 result = asRanges = new AsRanges(rangesByLowerBound.values()); 092 } 093 return result; 094 } 095 096 @Override 097 public Set<Range<C>> asDescendingSetOfRanges() { 098 Set<Range<C>> result = asDescendingSetOfRanges; 099 if (result == null) { 100 result = asDescendingSetOfRanges = new AsRanges(rangesByLowerBound.descendingMap().values()); 101 } 102 return result; 103 } 104 105 final class AsRanges extends ForwardingCollection<Range<C>> implements Set<Range<C>> { 106 107 final Collection<Range<C>> delegate; 108 109 AsRanges(Collection<Range<C>> delegate) { 110 this.delegate = delegate; 111 } 112 113 @Override 114 protected Collection<Range<C>> delegate() { 115 return delegate; 116 } 117 118 @Override 119 public int hashCode() { 120 return hashCodeImpl(this); 121 } 122 123 @Override 124 public boolean equals(@Nullable Object o) { 125 return equalsImpl(this, o); 126 } 127 } 128 129 @Override 130 public @Nullable Range<C> rangeContaining(C value) { 131 checkNotNull(value); 132 Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(Cut.belowValue(value)); 133 if (floorEntry != null && floorEntry.getValue().contains(value)) { 134 return floorEntry.getValue(); 135 } else { 136 // TODO(kevinb): revisit this design choice 137 return null; 138 } 139 } 140 141 @Override 142 public boolean intersects(Range<C> range) { 143 checkNotNull(range); 144 Entry<Cut<C>, Range<C>> ceilingEntry = rangesByLowerBound.ceilingEntry(range.lowerBound); 145 if (ceilingEntry != null 146 && ceilingEntry.getValue().isConnected(range) 147 && !ceilingEntry.getValue().intersection(range).isEmpty()) { 148 return true; 149 } 150 Entry<Cut<C>, Range<C>> priorEntry = rangesByLowerBound.lowerEntry(range.lowerBound); 151 return priorEntry != null 152 && priorEntry.getValue().isConnected(range) 153 && !priorEntry.getValue().intersection(range).isEmpty(); 154 } 155 156 @Override 157 public boolean encloses(Range<C> range) { 158 checkNotNull(range); 159 Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound); 160 return floorEntry != null && floorEntry.getValue().encloses(range); 161 } 162 163 private @Nullable Range<C> rangeEnclosing(Range<C> range) { 164 checkNotNull(range); 165 Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound); 166 return (floorEntry != null && floorEntry.getValue().encloses(range)) 167 ? floorEntry.getValue() 168 : null; 169 } 170 171 @Override 172 public Range<C> span() { 173 Entry<Cut<C>, Range<C>> firstEntry = rangesByLowerBound.firstEntry(); 174 Entry<Cut<C>, Range<C>> lastEntry = rangesByLowerBound.lastEntry(); 175 if (firstEntry == null || lastEntry == null) { 176 /* 177 * Either both are null or neither is: Either the set is empty, or it's not. But we check both 178 * to make the nullness checker happy. 179 */ 180 throw new NoSuchElementException(); 181 } 182 return Range.create(firstEntry.getValue().lowerBound, lastEntry.getValue().upperBound); 183 } 184 185 @Override 186 public void add(Range<C> rangeToAdd) { 187 checkNotNull(rangeToAdd); 188 189 if (rangeToAdd.isEmpty()) { 190 return; 191 } 192 193 // We will use { } to illustrate ranges currently in the range set, and < > 194 // to illustrate rangeToAdd. 195 Cut<C> lbToAdd = rangeToAdd.lowerBound; 196 Cut<C> ubToAdd = rangeToAdd.upperBound; 197 198 Entry<Cut<C>, Range<C>> entryBelowLb = rangesByLowerBound.lowerEntry(lbToAdd); 199 if (entryBelowLb != null) { 200 // { < 201 Range<C> rangeBelowLb = entryBelowLb.getValue(); 202 if (rangeBelowLb.upperBound.compareTo(lbToAdd) >= 0) { 203 // { < }, and we will need to coalesce 204 if (rangeBelowLb.upperBound.compareTo(ubToAdd) >= 0) { 205 // { < > } 206 ubToAdd = rangeBelowLb.upperBound; 207 /* 208 * TODO(cpovirk): can we just "return;" here? Or, can we remove this if() entirely? If 209 * not, add tests to demonstrate the problem with each approach 210 */ 211 } 212 lbToAdd = rangeBelowLb.lowerBound; 213 } 214 } 215 216 Entry<Cut<C>, Range<C>> entryBelowUb = rangesByLowerBound.floorEntry(ubToAdd); 217 if (entryBelowUb != null) { 218 // { > 219 Range<C> rangeBelowUb = entryBelowUb.getValue(); 220 if (rangeBelowUb.upperBound.compareTo(ubToAdd) >= 0) { 221 // { > }, and we need to coalesce 222 ubToAdd = rangeBelowUb.upperBound; 223 } 224 } 225 226 // Remove ranges which are strictly enclosed. 227 rangesByLowerBound.subMap(lbToAdd, ubToAdd).clear(); 228 229 replaceRangeWithSameLowerBound(Range.create(lbToAdd, ubToAdd)); 230 } 231 232 @Override 233 public void remove(Range<C> rangeToRemove) { 234 checkNotNull(rangeToRemove); 235 236 if (rangeToRemove.isEmpty()) { 237 return; 238 } 239 240 // We will use { } to illustrate ranges currently in the range set, and < > 241 // to illustrate rangeToRemove. 242 243 Entry<Cut<C>, Range<C>> entryBelowLb = rangesByLowerBound.lowerEntry(rangeToRemove.lowerBound); 244 if (entryBelowLb != null) { 245 // { < 246 Range<C> rangeBelowLb = entryBelowLb.getValue(); 247 if (rangeBelowLb.upperBound.compareTo(rangeToRemove.lowerBound) >= 0) { 248 // { < }, and we will need to subdivide 249 if (rangeToRemove.hasUpperBound() 250 && rangeBelowLb.upperBound.compareTo(rangeToRemove.upperBound) >= 0) { 251 // { < > } 252 replaceRangeWithSameLowerBound( 253 Range.create(rangeToRemove.upperBound, rangeBelowLb.upperBound)); 254 } 255 replaceRangeWithSameLowerBound( 256 Range.create(rangeBelowLb.lowerBound, rangeToRemove.lowerBound)); 257 } 258 } 259 260 Entry<Cut<C>, Range<C>> entryBelowUb = rangesByLowerBound.floorEntry(rangeToRemove.upperBound); 261 if (entryBelowUb != null) { 262 // { > 263 Range<C> rangeBelowUb = entryBelowUb.getValue(); 264 if (rangeToRemove.hasUpperBound() 265 && rangeBelowUb.upperBound.compareTo(rangeToRemove.upperBound) >= 0) { 266 // { > } 267 replaceRangeWithSameLowerBound( 268 Range.create(rangeToRemove.upperBound, rangeBelowUb.upperBound)); 269 } 270 } 271 272 rangesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear(); 273 } 274 275 private void replaceRangeWithSameLowerBound(Range<C> range) { 276 if (range.isEmpty()) { 277 rangesByLowerBound.remove(range.lowerBound); 278 } else { 279 rangesByLowerBound.put(range.lowerBound, range); 280 } 281 } 282 283 @LazyInit private transient @Nullable RangeSet<C> complement; 284 285 @Override 286 public RangeSet<C> complement() { 287 RangeSet<C> result = complement; 288 if (result == null) { 289 result = complement = new Complement(); 290 } 291 return result; 292 } 293 294 @VisibleForTesting 295 static final class RangesByUpperBound<C extends Comparable<?>> 296 extends AbstractNavigableMap<Cut<C>, Range<C>> { 297 private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound; 298 299 /** 300 * upperBoundWindow represents the headMap/subMap/tailMap view of the entire "ranges by upper 301 * bound" map; it's a constraint on the *keys*, and does not affect the values. 302 */ 303 private final Range<Cut<C>> upperBoundWindow; 304 305 RangesByUpperBound(NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) { 306 this.rangesByLowerBound = rangesByLowerBound; 307 this.upperBoundWindow = Range.all(); 308 } 309 310 private RangesByUpperBound( 311 NavigableMap<Cut<C>, Range<C>> rangesByLowerBound, Range<Cut<C>> upperBoundWindow) { 312 this.rangesByLowerBound = rangesByLowerBound; 313 this.upperBoundWindow = upperBoundWindow; 314 } 315 316 private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) { 317 if (window.isConnected(upperBoundWindow)) { 318 return new RangesByUpperBound<>(rangesByLowerBound, window.intersection(upperBoundWindow)); 319 } else { 320 return ImmutableSortedMap.of(); 321 } 322 } 323 324 @Override 325 public NavigableMap<Cut<C>, Range<C>> subMap( 326 Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) { 327 return subMap( 328 Range.range( 329 fromKey, BoundType.forBoolean(fromInclusive), 330 toKey, BoundType.forBoolean(toInclusive))); 331 } 332 333 @Override 334 public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) { 335 return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive))); 336 } 337 338 @Override 339 public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) { 340 return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive))); 341 } 342 343 @Override 344 public Comparator<? super Cut<C>> comparator() { 345 return Ordering.natural(); 346 } 347 348 @Override 349 public boolean containsKey(@Nullable Object key) { 350 return get(key) != null; 351 } 352 353 @Override 354 public @Nullable Range<C> get(@Nullable Object key) { 355 if (key instanceof Cut) { 356 try { 357 @SuppressWarnings("unchecked") // we catch CCEs 358 Cut<C> cut = (Cut<C>) key; 359 if (!upperBoundWindow.contains(cut)) { 360 return null; 361 } 362 Entry<Cut<C>, Range<C>> candidate = rangesByLowerBound.lowerEntry(cut); 363 if (candidate != null && candidate.getValue().upperBound.equals(cut)) { 364 return candidate.getValue(); 365 } 366 } catch (ClassCastException e) { 367 return null; 368 } 369 } 370 return null; 371 } 372 373 @Override 374 Iterator<Entry<Cut<C>, Range<C>>> entryIterator() { 375 /* 376 * We want to start the iteration at the first range where the upper bound is in 377 * upperBoundWindow. 378 */ 379 Iterator<Range<C>> backingItr; 380 if (!upperBoundWindow.hasLowerBound()) { 381 backingItr = rangesByLowerBound.values().iterator(); 382 } else { 383 Entry<Cut<C>, Range<C>> lowerEntry = 384 rangesByLowerBound.lowerEntry(upperBoundWindow.lowerEndpoint()); 385 if (lowerEntry == null) { 386 backingItr = rangesByLowerBound.values().iterator(); 387 } else if (upperBoundWindow.lowerBound.isLessThan(lowerEntry.getValue().upperBound)) { 388 backingItr = rangesByLowerBound.tailMap(lowerEntry.getKey(), true).values().iterator(); 389 } else { 390 backingItr = 391 rangesByLowerBound 392 .tailMap(upperBoundWindow.lowerEndpoint(), true) 393 .values() 394 .iterator(); 395 } 396 } 397 return new AbstractIterator<Entry<Cut<C>, Range<C>>>() { 398 @Override 399 protected @Nullable Entry<Cut<C>, Range<C>> computeNext() { 400 if (!backingItr.hasNext()) { 401 return endOfData(); 402 } 403 Range<C> range = backingItr.next(); 404 if (upperBoundWindow.upperBound.isLessThan(range.upperBound)) { 405 return endOfData(); 406 } else { 407 return immutableEntry(range.upperBound, range); 408 } 409 } 410 }; 411 } 412 413 @Override 414 Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() { 415 Collection<Range<C>> candidates; 416 if (upperBoundWindow.hasUpperBound()) { 417 candidates = 418 rangesByLowerBound 419 .headMap(upperBoundWindow.upperEndpoint(), false) 420 .descendingMap() 421 .values(); 422 } else { 423 candidates = rangesByLowerBound.descendingMap().values(); 424 } 425 PeekingIterator<Range<C>> backingItr = peekingIterator(candidates.iterator()); 426 if (backingItr.hasNext() 427 && upperBoundWindow.upperBound.isLessThan(backingItr.peek().upperBound)) { 428 backingItr.next(); 429 } 430 return new AbstractIterator<Entry<Cut<C>, Range<C>>>() { 431 @Override 432 protected @Nullable Entry<Cut<C>, Range<C>> computeNext() { 433 if (!backingItr.hasNext()) { 434 return endOfData(); 435 } 436 Range<C> range = backingItr.next(); 437 return upperBoundWindow.lowerBound.isLessThan(range.upperBound) 438 ? immutableEntry(range.upperBound, range) 439 : endOfData(); 440 } 441 }; 442 } 443 444 @Override 445 public int size() { 446 if (upperBoundWindow.equals(Range.all())) { 447 return rangesByLowerBound.size(); 448 } 449 return Iterators.size(entryIterator()); 450 } 451 452 @Override 453 public boolean isEmpty() { 454 return upperBoundWindow.equals(Range.all()) 455 ? rangesByLowerBound.isEmpty() 456 : !entryIterator().hasNext(); 457 } 458 } 459 460 private static final class ComplementRangesByLowerBound<C extends Comparable<?>> 461 extends AbstractNavigableMap<Cut<C>, Range<C>> { 462 private final NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound; 463 private final NavigableMap<Cut<C>, Range<C>> positiveRangesByUpperBound; 464 465 /** 466 * complementLowerBoundWindow represents the headMap/subMap/tailMap view of the entire 467 * "complement ranges by lower bound" map; it's a constraint on the *keys*, and does not affect 468 * the values. 469 */ 470 private final Range<Cut<C>> complementLowerBoundWindow; 471 472 ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound) { 473 this(positiveRangesByLowerBound, Range.all()); 474 } 475 476 private ComplementRangesByLowerBound( 477 NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound, Range<Cut<C>> window) { 478 this.positiveRangesByLowerBound = positiveRangesByLowerBound; 479 this.positiveRangesByUpperBound = new RangesByUpperBound<>(positiveRangesByLowerBound); 480 this.complementLowerBoundWindow = window; 481 } 482 483 private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> subWindow) { 484 if (!complementLowerBoundWindow.isConnected(subWindow)) { 485 return ImmutableSortedMap.of(); 486 } else { 487 subWindow = subWindow.intersection(complementLowerBoundWindow); 488 return new ComplementRangesByLowerBound<>(positiveRangesByLowerBound, subWindow); 489 } 490 } 491 492 @Override 493 public NavigableMap<Cut<C>, Range<C>> subMap( 494 Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) { 495 return subMap( 496 Range.range( 497 fromKey, BoundType.forBoolean(fromInclusive), 498 toKey, BoundType.forBoolean(toInclusive))); 499 } 500 501 @Override 502 public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) { 503 return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive))); 504 } 505 506 @Override 507 public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) { 508 return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive))); 509 } 510 511 @Override 512 public Comparator<? super Cut<C>> comparator() { 513 return Ordering.natural(); 514 } 515 516 @Override 517 Iterator<Entry<Cut<C>, Range<C>>> entryIterator() { 518 /* 519 * firstComplementRangeLowerBound is the first complement range lower bound inside 520 * complementLowerBoundWindow. Complement range lower bounds are either positive range upper 521 * bounds, or Cut.belowAll(). 522 * 523 * positiveItr starts at the first positive range with lower bound greater than 524 * firstComplementRangeLowerBound. (Positive range lower bounds correspond to complement range 525 * upper bounds.) 526 */ 527 Collection<Range<C>> positiveRanges; 528 if (complementLowerBoundWindow.hasLowerBound()) { 529 positiveRanges = 530 positiveRangesByUpperBound 531 .tailMap( 532 complementLowerBoundWindow.lowerEndpoint(), 533 complementLowerBoundWindow.lowerBoundType() == BoundType.CLOSED) 534 .values(); 535 } else { 536 positiveRanges = positiveRangesByUpperBound.values(); 537 } 538 PeekingIterator<Range<C>> positiveItr = peekingIterator(positiveRanges.iterator()); 539 Cut<C> firstComplementRangeLowerBound; 540 if (complementLowerBoundWindow.contains(Cut.belowAll()) 541 && (!positiveItr.hasNext() || positiveItr.peek().lowerBound != Cut.<C>belowAll())) { 542 firstComplementRangeLowerBound = Cut.belowAll(); 543 } else if (positiveItr.hasNext()) { 544 firstComplementRangeLowerBound = positiveItr.next().upperBound; 545 } else { 546 return emptyIterator(); 547 } 548 return new AbstractIterator<Entry<Cut<C>, Range<C>>>() { 549 Cut<C> nextComplementRangeLowerBound = firstComplementRangeLowerBound; 550 551 @Override 552 protected @Nullable Entry<Cut<C>, Range<C>> computeNext() { 553 if (complementLowerBoundWindow.upperBound.isLessThan(nextComplementRangeLowerBound) 554 || nextComplementRangeLowerBound == Cut.<C>aboveAll()) { 555 return endOfData(); 556 } 557 Range<C> negativeRange; 558 if (positiveItr.hasNext()) { 559 Range<C> positiveRange = positiveItr.next(); 560 negativeRange = Range.create(nextComplementRangeLowerBound, positiveRange.lowerBound); 561 nextComplementRangeLowerBound = positiveRange.upperBound; 562 } else { 563 negativeRange = Range.create(nextComplementRangeLowerBound, Cut.aboveAll()); 564 nextComplementRangeLowerBound = Cut.aboveAll(); 565 } 566 return immutableEntry(negativeRange.lowerBound, negativeRange); 567 } 568 }; 569 } 570 571 @Override 572 Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() { 573 /* 574 * firstComplementRangeUpperBound is the upper bound of the last complement range with lower 575 * bound inside complementLowerBoundWindow. 576 * 577 * positiveItr starts at the first positive range with upper bound less than 578 * firstComplementRangeUpperBound. (Positive range upper bounds correspond to complement range 579 * lower bounds.) 580 */ 581 Cut<C> startingPoint = 582 complementLowerBoundWindow.hasUpperBound() 583 ? complementLowerBoundWindow.upperEndpoint() 584 : Cut.aboveAll(); 585 boolean inclusive = 586 complementLowerBoundWindow.hasUpperBound() 587 && complementLowerBoundWindow.upperBoundType() == BoundType.CLOSED; 588 PeekingIterator<Range<C>> positiveItr = 589 peekingIterator( 590 positiveRangesByUpperBound 591 .headMap(startingPoint, inclusive) 592 .descendingMap() 593 .values() 594 .iterator()); 595 Cut<C> cut; 596 if (positiveItr.hasNext()) { 597 cut = 598 (positiveItr.peek().upperBound == Cut.<C>aboveAll()) 599 ? positiveItr.next().lowerBound 600 : positiveRangesByLowerBound.higherKey(positiveItr.peek().upperBound); 601 } else if (!complementLowerBoundWindow.contains(Cut.belowAll()) 602 || positiveRangesByLowerBound.containsKey(Cut.belowAll())) { 603 return emptyIterator(); 604 } else { 605 cut = positiveRangesByLowerBound.higherKey(Cut.belowAll()); 606 } 607 Cut<C> firstComplementRangeUpperBound = firstNonNull(cut, Cut.aboveAll()); 608 return new AbstractIterator<Entry<Cut<C>, Range<C>>>() { 609 Cut<C> nextComplementRangeUpperBound = firstComplementRangeUpperBound; 610 611 @Override 612 protected @Nullable Entry<Cut<C>, Range<C>> computeNext() { 613 if (nextComplementRangeUpperBound == Cut.<C>belowAll()) { 614 return endOfData(); 615 } else if (positiveItr.hasNext()) { 616 Range<C> positiveRange = positiveItr.next(); 617 Range<C> negativeRange = 618 Range.create(positiveRange.upperBound, nextComplementRangeUpperBound); 619 nextComplementRangeUpperBound = positiveRange.lowerBound; 620 if (complementLowerBoundWindow.lowerBound.isLessThan(negativeRange.lowerBound)) { 621 return immutableEntry(negativeRange.lowerBound, negativeRange); 622 } 623 } else if (complementLowerBoundWindow.lowerBound.isLessThan(Cut.belowAll())) { 624 Range<C> negativeRange = Range.create(Cut.belowAll(), nextComplementRangeUpperBound); 625 nextComplementRangeUpperBound = Cut.belowAll(); 626 return immutableEntry(Cut.belowAll(), negativeRange); 627 } 628 return endOfData(); 629 } 630 }; 631 } 632 633 @Override 634 public int size() { 635 return Iterators.size(entryIterator()); 636 } 637 638 @Override 639 public @Nullable Range<C> get(@Nullable Object key) { 640 if (key instanceof Cut) { 641 try { 642 @SuppressWarnings("unchecked") 643 Cut<C> cut = (Cut<C>) key; 644 // tailMap respects the current window 645 Entry<Cut<C>, Range<C>> firstEntry = tailMap(cut, true).firstEntry(); 646 if (firstEntry != null && firstEntry.getKey().equals(cut)) { 647 return firstEntry.getValue(); 648 } 649 } catch (ClassCastException e) { 650 return null; 651 } 652 } 653 return null; 654 } 655 656 @Override 657 public boolean containsKey(@Nullable Object key) { 658 return get(key) != null; 659 } 660 } 661 662 private final class Complement extends TreeRangeSet<C> { 663 Complement() { 664 super(new ComplementRangesByLowerBound<C>(TreeRangeSet.this.rangesByLowerBound)); 665 } 666 667 @Override 668 public void add(Range<C> rangeToAdd) { 669 TreeRangeSet.this.remove(rangeToAdd); 670 } 671 672 @Override 673 public void remove(Range<C> rangeToRemove) { 674 TreeRangeSet.this.add(rangeToRemove); 675 } 676 677 @Override 678 public boolean contains(C value) { 679 return !TreeRangeSet.this.contains(value); 680 } 681 682 @Override 683 public RangeSet<C> complement() { 684 return TreeRangeSet.this; 685 } 686 } 687 688 private static final class SubRangeSetRangesByLowerBound<C extends Comparable<?>> 689 extends AbstractNavigableMap<Cut<C>, Range<C>> { 690 /** 691 * lowerBoundWindow is the headMap/subMap/tailMap view; it only restricts the keys, and does not 692 * affect the values. 693 */ 694 private final Range<Cut<C>> lowerBoundWindow; 695 696 /** 697 * restriction is the subRangeSet view; ranges are truncated to their intersection with 698 * restriction. 699 */ 700 private final Range<C> restriction; 701 702 private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound; 703 private final NavigableMap<Cut<C>, Range<C>> rangesByUpperBound; 704 705 private SubRangeSetRangesByLowerBound( 706 Range<Cut<C>> lowerBoundWindow, 707 Range<C> restriction, 708 NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) { 709 this.lowerBoundWindow = checkNotNull(lowerBoundWindow); 710 this.restriction = checkNotNull(restriction); 711 this.rangesByLowerBound = checkNotNull(rangesByLowerBound); 712 this.rangesByUpperBound = new RangesByUpperBound<>(rangesByLowerBound); 713 } 714 715 private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) { 716 if (!window.isConnected(lowerBoundWindow)) { 717 return ImmutableSortedMap.of(); 718 } else { 719 return new SubRangeSetRangesByLowerBound<>( 720 lowerBoundWindow.intersection(window), restriction, rangesByLowerBound); 721 } 722 } 723 724 @Override 725 public NavigableMap<Cut<C>, Range<C>> subMap( 726 Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) { 727 return subMap( 728 Range.range( 729 fromKey, 730 BoundType.forBoolean(fromInclusive), 731 toKey, 732 BoundType.forBoolean(toInclusive))); 733 } 734 735 @Override 736 public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) { 737 return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive))); 738 } 739 740 @Override 741 public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) { 742 return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive))); 743 } 744 745 @Override 746 public Comparator<? super Cut<C>> comparator() { 747 return Ordering.natural(); 748 } 749 750 @Override 751 public boolean containsKey(@Nullable Object key) { 752 return get(key) != null; 753 } 754 755 @Override 756 public @Nullable Range<C> get(@Nullable Object key) { 757 if (key instanceof Cut) { 758 try { 759 @SuppressWarnings("unchecked") // we catch CCE's 760 Cut<C> cut = (Cut<C>) key; 761 if (!lowerBoundWindow.contains(cut) 762 || cut.compareTo(restriction.lowerBound) < 0 763 || cut.compareTo(restriction.upperBound) >= 0) { 764 return null; 765 } else if (cut.equals(restriction.lowerBound)) { 766 // it might be present, truncated on the left 767 Range<C> candidate = valueOrNull(rangesByLowerBound.floorEntry(cut)); 768 if (candidate != null && candidate.upperBound.compareTo(restriction.lowerBound) > 0) { 769 return candidate.intersection(restriction); 770 } 771 } else { 772 Range<C> result = rangesByLowerBound.get(cut); 773 if (result != null) { 774 return result.intersection(restriction); 775 } 776 } 777 } catch (ClassCastException e) { 778 return null; 779 } 780 } 781 return null; 782 } 783 784 @Override 785 Iterator<Entry<Cut<C>, Range<C>>> entryIterator() { 786 if (restriction.isEmpty()) { 787 return emptyIterator(); 788 } 789 Iterator<Range<C>> completeRangeItr; 790 if (lowerBoundWindow.upperBound.isLessThan(restriction.lowerBound)) { 791 return emptyIterator(); 792 } else if (lowerBoundWindow.lowerBound.isLessThan(restriction.lowerBound)) { 793 // starts at the first range with upper bound strictly greater than restriction.lowerBound 794 completeRangeItr = 795 rangesByUpperBound.tailMap(restriction.lowerBound, false).values().iterator(); 796 } else { 797 // starts at the first range with lower bound above lowerBoundWindow.lowerBound 798 completeRangeItr = 799 rangesByLowerBound 800 .tailMap( 801 lowerBoundWindow.lowerBound.endpoint(), 802 lowerBoundWindow.lowerBoundType() == BoundType.CLOSED) 803 .values() 804 .iterator(); 805 } 806 Cut<Cut<C>> upperBoundOnLowerBounds = 807 Ordering.<Cut<Cut<C>>>natural() 808 .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound)); 809 return new AbstractIterator<Entry<Cut<C>, Range<C>>>() { 810 @Override 811 protected @Nullable Entry<Cut<C>, Range<C>> computeNext() { 812 if (!completeRangeItr.hasNext()) { 813 return endOfData(); 814 } 815 Range<C> nextRange = completeRangeItr.next(); 816 if (upperBoundOnLowerBounds.isLessThan(nextRange.lowerBound)) { 817 return endOfData(); 818 } else { 819 nextRange = nextRange.intersection(restriction); 820 return immutableEntry(nextRange.lowerBound, nextRange); 821 } 822 } 823 }; 824 } 825 826 @Override 827 Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() { 828 if (restriction.isEmpty()) { 829 return emptyIterator(); 830 } 831 Cut<Cut<C>> upperBoundOnLowerBounds = 832 Ordering.<Cut<Cut<C>>>natural() 833 .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound)); 834 Iterator<Range<C>> completeRangeItr = 835 rangesByLowerBound 836 .headMap( 837 upperBoundOnLowerBounds.endpoint(), 838 upperBoundOnLowerBounds.typeAsUpperBound() == BoundType.CLOSED) 839 .descendingMap() 840 .values() 841 .iterator(); 842 return new AbstractIterator<Entry<Cut<C>, Range<C>>>() { 843 @Override 844 protected @Nullable Entry<Cut<C>, Range<C>> computeNext() { 845 if (!completeRangeItr.hasNext()) { 846 return endOfData(); 847 } 848 Range<C> nextRange = completeRangeItr.next(); 849 if (restriction.lowerBound.compareTo(nextRange.upperBound) >= 0) { 850 return endOfData(); 851 } 852 nextRange = nextRange.intersection(restriction); 853 if (lowerBoundWindow.contains(nextRange.lowerBound)) { 854 return immutableEntry(nextRange.lowerBound, nextRange); 855 } else { 856 return endOfData(); 857 } 858 } 859 }; 860 } 861 862 @Override 863 public int size() { 864 return Iterators.size(entryIterator()); 865 } 866 } 867 868 @Override 869 public RangeSet<C> subRangeSet(Range<C> view) { 870 return view.equals(Range.all()) ? this : new SubRangeSet(view); 871 } 872 873 private final class SubRangeSet extends TreeRangeSet<C> { 874 private final Range<C> restriction; 875 876 SubRangeSet(Range<C> restriction) { 877 super( 878 new SubRangeSetRangesByLowerBound<C>( 879 Range.all(), restriction, TreeRangeSet.this.rangesByLowerBound)); 880 this.restriction = restriction; 881 } 882 883 @Override 884 public boolean encloses(Range<C> range) { 885 if (!restriction.isEmpty() && restriction.encloses(range)) { 886 Range<C> enclosing = TreeRangeSet.this.rangeEnclosing(range); 887 return enclosing != null && !enclosing.intersection(restriction).isEmpty(); 888 } 889 return false; 890 } 891 892 @Override 893 public @Nullable Range<C> rangeContaining(C value) { 894 if (!restriction.contains(value)) { 895 return null; 896 } 897 Range<C> result = TreeRangeSet.this.rangeContaining(value); 898 return (result == null) ? null : result.intersection(restriction); 899 } 900 901 @Override 902 public void add(Range<C> rangeToAdd) { 903 checkArgument( 904 restriction.encloses(rangeToAdd), 905 "Cannot add range %s to subRangeSet(%s)", 906 rangeToAdd, 907 restriction); 908 TreeRangeSet.this.add(rangeToAdd); 909 } 910 911 @Override 912 public void remove(Range<C> rangeToRemove) { 913 if (rangeToRemove.isConnected(restriction)) { 914 TreeRangeSet.this.remove(rangeToRemove.intersection(restriction)); 915 } 916 } 917 918 @Override 919 public boolean contains(C value) { 920 return restriction.contains(value) && TreeRangeSet.this.contains(value); 921 } 922 923 @Override 924 public void clear() { 925 TreeRangeSet.this.remove(restriction); 926 } 927 928 @Override 929 public RangeSet<C> subRangeSet(Range<C> view) { 930 if (view.encloses(restriction)) { 931 return this; 932 } else if (view.isConnected(restriction)) { 933 return new SubRangeSet(restriction.intersection(view)); 934 } else { 935 return ImmutableRangeSet.of(); 936 } 937 } 938 } 939}