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