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