001/* 002 * Copyright (C) 2012 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021import static com.google.common.base.Predicates.compose; 022import static com.google.common.base.Predicates.in; 023import static com.google.common.base.Predicates.not; 024import static com.google.common.collect.Iterators.emptyIterator; 025import static com.google.common.collect.Maps.immutableEntry; 026import static java.util.Collections.emptyMap; 027import static java.util.Objects.requireNonNull; 028 029import com.google.common.annotations.GwtIncompatible; 030import com.google.common.base.MoreObjects; 031import com.google.common.base.Predicate; 032import com.google.common.collect.Maps.IteratorBasedAbstractMap; 033import java.util.AbstractMap; 034import java.util.Collection; 035import java.util.Iterator; 036import java.util.List; 037import java.util.Map; 038import java.util.Map.Entry; 039import java.util.NavigableMap; 040import java.util.NoSuchElementException; 041import java.util.Set; 042import java.util.function.BiFunction; 043import javax.annotation.CheckForNull; 044import org.checkerframework.checker.nullness.qual.Nullable; 045 046/** 047 * An implementation of {@code RangeMap} based on a {@code TreeMap}, supporting all optional 048 * operations. 049 * 050 * <p>Like all {@code RangeMap} implementations, this supports neither null keys nor null values. 051 * 052 * @author Louis Wasserman 053 * @since 14.0 054 */ 055@SuppressWarnings("rawtypes") // https://github.com/google/guava/issues/989 056@GwtIncompatible // NavigableMap 057public final class TreeRangeMap<K extends Comparable, V> implements RangeMap<K, V> { 058 059 private final NavigableMap<Cut<K>, RangeMapEntry<K, V>> entriesByLowerBound; 060 061 /** Returns a new, empty {@link TreeRangeMap}. */ 062 public static <K extends Comparable, V> TreeRangeMap<K, V> create() { 063 return new TreeRangeMap<>(); 064 } 065 066 /** 067 * Returns a new {@link TreeRangeMap} containing the same ranges as the given {@code RangeMap}. 068 * 069 * @since 33.4.0 070 */ 071 @SuppressWarnings("unchecked") 072 public static <K extends Comparable<?>, V> TreeRangeMap<K, V> copyOf( 073 RangeMap<K, ? extends V> rangeMap) { 074 if (rangeMap instanceof TreeRangeMap) { 075 NavigableMap<Cut<K>, RangeMapEntry<K, V>> entriesByLowerBound = Maps.newTreeMap(); 076 entriesByLowerBound.putAll(((TreeRangeMap<K, V>) rangeMap).entriesByLowerBound); 077 return new TreeRangeMap<>(entriesByLowerBound); 078 } else { 079 NavigableMap<Cut<K>, RangeMapEntry<K, V>> entriesByLowerBound = Maps.newTreeMap(); 080 for (Entry<Range<K>, ? extends V> entry : rangeMap.asMapOfRanges().entrySet()) { 081 entriesByLowerBound.put( 082 entry.getKey().lowerBound(), new RangeMapEntry<K, V>(entry.getKey(), entry.getValue())); 083 } 084 return new TreeRangeMap<>(entriesByLowerBound); 085 } 086 } 087 088 private TreeRangeMap() { 089 this.entriesByLowerBound = Maps.newTreeMap(); 090 } 091 092 private TreeRangeMap(NavigableMap<Cut<K>, RangeMapEntry<K, V>> entriesByLowerBound) { 093 this.entriesByLowerBound = entriesByLowerBound; 094 } 095 096 private static final class RangeMapEntry<K extends Comparable, V> 097 extends AbstractMapEntry<Range<K>, V> { 098 private final Range<K> range; 099 private final V value; 100 101 RangeMapEntry(Cut<K> lowerBound, Cut<K> upperBound, V value) { 102 this(Range.create(lowerBound, upperBound), value); 103 } 104 105 RangeMapEntry(Range<K> range, V value) { 106 this.range = range; 107 this.value = value; 108 } 109 110 @Override 111 public Range<K> getKey() { 112 return range; 113 } 114 115 @Override 116 public V getValue() { 117 return value; 118 } 119 120 public boolean contains(K value) { 121 return range.contains(value); 122 } 123 124 Cut<K> getLowerBound() { 125 return range.lowerBound; 126 } 127 128 Cut<K> getUpperBound() { 129 return range.upperBound; 130 } 131 } 132 133 @Override 134 @CheckForNull 135 public V get(K key) { 136 Entry<Range<K>, V> entry = getEntry(key); 137 return (entry == null) ? null : entry.getValue(); 138 } 139 140 @Override 141 @CheckForNull 142 public Entry<Range<K>, V> getEntry(K key) { 143 Entry<Cut<K>, RangeMapEntry<K, V>> mapEntry = 144 entriesByLowerBound.floorEntry(Cut.belowValue(key)); 145 if (mapEntry != null && mapEntry.getValue().contains(key)) { 146 return mapEntry.getValue(); 147 } else { 148 return null; 149 } 150 } 151 152 @Override 153 public void put(Range<K> range, V value) { 154 if (!range.isEmpty()) { 155 checkNotNull(value); 156 remove(range); 157 entriesByLowerBound.put(range.lowerBound, new RangeMapEntry<K, V>(range, value)); 158 } 159 } 160 161 @Override 162 public void putCoalescing(Range<K> range, V value) { 163 // don't short-circuit if the range is empty - it may be between two ranges we can coalesce. 164 if (entriesByLowerBound.isEmpty()) { 165 put(range, value); 166 return; 167 } 168 169 Range<K> coalescedRange = coalescedRange(range, checkNotNull(value)); 170 put(coalescedRange, value); 171 } 172 173 /** Computes the coalesced range for the given range+value - does not mutate the map. */ 174 private Range<K> coalescedRange(Range<K> range, V value) { 175 Range<K> coalescedRange = range; 176 Entry<Cut<K>, RangeMapEntry<K, V>> lowerEntry = 177 entriesByLowerBound.lowerEntry(range.lowerBound); 178 coalescedRange = coalesce(coalescedRange, value, lowerEntry); 179 180 Entry<Cut<K>, RangeMapEntry<K, V>> higherEntry = 181 entriesByLowerBound.floorEntry(range.upperBound); 182 coalescedRange = coalesce(coalescedRange, value, higherEntry); 183 184 return coalescedRange; 185 } 186 187 /** Returns the range that spans the given range and entry, if the entry can be coalesced. */ 188 private static <K extends Comparable, V> Range<K> coalesce( 189 Range<K> range, V value, @CheckForNull Entry<Cut<K>, RangeMapEntry<K, V>> entry) { 190 if (entry != null 191 && entry.getValue().getKey().isConnected(range) 192 && entry.getValue().getValue().equals(value)) { 193 return range.span(entry.getValue().getKey()); 194 } 195 return range; 196 } 197 198 @Override 199 public void putAll(RangeMap<K, ? extends V> rangeMap) { 200 for (Entry<Range<K>, ? extends V> entry : rangeMap.asMapOfRanges().entrySet()) { 201 put(entry.getKey(), entry.getValue()); 202 } 203 } 204 205 @Override 206 public void clear() { 207 entriesByLowerBound.clear(); 208 } 209 210 @Override 211 public Range<K> span() { 212 Entry<Cut<K>, RangeMapEntry<K, V>> firstEntry = entriesByLowerBound.firstEntry(); 213 Entry<Cut<K>, RangeMapEntry<K, V>> lastEntry = entriesByLowerBound.lastEntry(); 214 // Either both are null or neither is, but we check both to satisfy the nullness checker. 215 if (firstEntry == null || lastEntry == null) { 216 throw new NoSuchElementException(); 217 } 218 return Range.create( 219 firstEntry.getValue().getKey().lowerBound, lastEntry.getValue().getKey().upperBound); 220 } 221 222 private void putRangeMapEntry(Cut<K> lowerBound, Cut<K> upperBound, V value) { 223 entriesByLowerBound.put(lowerBound, new RangeMapEntry<K, V>(lowerBound, upperBound, value)); 224 } 225 226 @Override 227 public void remove(Range<K> rangeToRemove) { 228 if (rangeToRemove.isEmpty()) { 229 return; 230 } 231 232 /* 233 * The comments for this method will use [ ] to indicate the bounds of rangeToRemove and ( ) to 234 * indicate the bounds of ranges in the range map. 235 */ 236 Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryBelowToTruncate = 237 entriesByLowerBound.lowerEntry(rangeToRemove.lowerBound); 238 if (mapEntryBelowToTruncate != null) { 239 // we know ( [ 240 RangeMapEntry<K, V> rangeMapEntry = mapEntryBelowToTruncate.getValue(); 241 if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.lowerBound) > 0) { 242 // we know ( [ ) 243 if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) { 244 // we know ( [ ] ), so insert the range ] ) back into the map -- 245 // it's being split apart 246 putRangeMapEntry( 247 rangeToRemove.upperBound, 248 rangeMapEntry.getUpperBound(), 249 mapEntryBelowToTruncate.getValue().getValue()); 250 } 251 // overwrite mapEntryToTruncateBelow with a truncated range 252 putRangeMapEntry( 253 rangeMapEntry.getLowerBound(), 254 rangeToRemove.lowerBound, 255 mapEntryBelowToTruncate.getValue().getValue()); 256 } 257 } 258 259 Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryAboveToTruncate = 260 entriesByLowerBound.lowerEntry(rangeToRemove.upperBound); 261 if (mapEntryAboveToTruncate != null) { 262 // we know ( ] 263 RangeMapEntry<K, V> rangeMapEntry = mapEntryAboveToTruncate.getValue(); 264 if (rangeMapEntry.getUpperBound().compareTo(rangeToRemove.upperBound) > 0) { 265 // we know ( ] ), and since we dealt with truncating below already, 266 // we know [ ( ] ) 267 putRangeMapEntry( 268 rangeToRemove.upperBound, 269 rangeMapEntry.getUpperBound(), 270 mapEntryAboveToTruncate.getValue().getValue()); 271 } 272 } 273 entriesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear(); 274 } 275 276 private void split(Cut<K> cut) { 277 /* 278 * The comments for this method will use | to indicate the cut point and ( ) to indicate the 279 * bounds of ranges in the range map. 280 */ 281 Entry<Cut<K>, RangeMapEntry<K, V>> mapEntryToSplit = entriesByLowerBound.lowerEntry(cut); 282 if (mapEntryToSplit == null) { 283 return; 284 } 285 // we know ( | 286 RangeMapEntry<K, V> rangeMapEntry = mapEntryToSplit.getValue(); 287 if (rangeMapEntry.getUpperBound().compareTo(cut) <= 0) { 288 return; 289 } 290 // we know ( | ) 291 putRangeMapEntry(rangeMapEntry.getLowerBound(), cut, rangeMapEntry.getValue()); 292 putRangeMapEntry(cut, rangeMapEntry.getUpperBound(), rangeMapEntry.getValue()); 293 } 294 295 /** 296 * @since 28.1 297 */ 298 @Override 299 public void merge( 300 Range<K> range, 301 @CheckForNull V value, 302 BiFunction<? super V, ? super @Nullable V, ? extends @Nullable V> remappingFunction) { 303 checkNotNull(range); 304 checkNotNull(remappingFunction); 305 306 if (range.isEmpty()) { 307 return; 308 } 309 split(range.lowerBound); 310 split(range.upperBound); 311 312 // Due to the splitting of any entries spanning the range bounds, we know that any entry with a 313 // lower bound in the merge range is entirely contained by the merge range. 314 Set<Entry<Cut<K>, RangeMapEntry<K, V>>> entriesInMergeRange = 315 entriesByLowerBound.subMap(range.lowerBound, range.upperBound).entrySet(); 316 317 // Create entries mapping any unmapped ranges in the merge range to the specified value. 318 ImmutableMap.Builder<Cut<K>, RangeMapEntry<K, V>> gaps = ImmutableMap.builder(); 319 if (value != null) { 320 final Iterator<Entry<Cut<K>, RangeMapEntry<K, V>>> backingItr = 321 entriesInMergeRange.iterator(); 322 Cut<K> lowerBound = range.lowerBound; 323 while (backingItr.hasNext()) { 324 RangeMapEntry<K, V> entry = backingItr.next().getValue(); 325 Cut<K> upperBound = entry.getLowerBound(); 326 if (!lowerBound.equals(upperBound)) { 327 gaps.put(lowerBound, new RangeMapEntry<K, V>(lowerBound, upperBound, value)); 328 } 329 lowerBound = entry.getUpperBound(); 330 } 331 if (!lowerBound.equals(range.upperBound)) { 332 gaps.put(lowerBound, new RangeMapEntry<K, V>(lowerBound, range.upperBound, value)); 333 } 334 } 335 336 // Remap all existing entries in the merge range. 337 final Iterator<Entry<Cut<K>, RangeMapEntry<K, V>>> backingItr = entriesInMergeRange.iterator(); 338 while (backingItr.hasNext()) { 339 Entry<Cut<K>, RangeMapEntry<K, V>> entry = backingItr.next(); 340 V newValue = remappingFunction.apply(entry.getValue().getValue(), value); 341 if (newValue == null) { 342 backingItr.remove(); 343 } else { 344 entry.setValue( 345 new RangeMapEntry<K, V>( 346 entry.getValue().getLowerBound(), entry.getValue().getUpperBound(), newValue)); 347 } 348 } 349 350 entriesByLowerBound.putAll(gaps.build()); 351 } 352 353 @Override 354 public Map<Range<K>, V> asMapOfRanges() { 355 return new AsMapOfRanges(entriesByLowerBound.values()); 356 } 357 358 @Override 359 public Map<Range<K>, V> asDescendingMapOfRanges() { 360 return new AsMapOfRanges(entriesByLowerBound.descendingMap().values()); 361 } 362 363 private final class AsMapOfRanges extends IteratorBasedAbstractMap<Range<K>, V> { 364 365 final Iterable<Entry<Range<K>, V>> entryIterable; 366 367 @SuppressWarnings("unchecked") // it's safe to upcast iterables 368 AsMapOfRanges(Iterable<RangeMapEntry<K, V>> entryIterable) { 369 this.entryIterable = (Iterable) entryIterable; 370 } 371 372 @Override 373 public boolean containsKey(@CheckForNull Object key) { 374 return get(key) != null; 375 } 376 377 @Override 378 @CheckForNull 379 public V get(@CheckForNull Object key) { 380 if (key instanceof Range) { 381 Range<?> range = (Range<?>) key; 382 RangeMapEntry<K, V> rangeMapEntry = entriesByLowerBound.get(range.lowerBound); 383 if (rangeMapEntry != null && rangeMapEntry.getKey().equals(range)) { 384 return rangeMapEntry.getValue(); 385 } 386 } 387 return null; 388 } 389 390 @Override 391 public int size() { 392 return entriesByLowerBound.size(); 393 } 394 395 @Override 396 Iterator<Entry<Range<K>, V>> entryIterator() { 397 return entryIterable.iterator(); 398 } 399 } 400 401 @Override 402 public RangeMap<K, V> subRangeMap(Range<K> subRange) { 403 if (subRange.equals(Range.all())) { 404 return this; 405 } else { 406 return new SubRangeMap(subRange); 407 } 408 } 409 410 @SuppressWarnings("unchecked") 411 private RangeMap<K, V> emptySubRangeMap() { 412 return (RangeMap<K, V>) (RangeMap<?, ?>) EMPTY_SUB_RANGE_MAP; 413 } 414 415 @SuppressWarnings("ConstantCaseForConstants") // This RangeMap is immutable. 416 private static final RangeMap<Comparable<?>, Object> EMPTY_SUB_RANGE_MAP = 417 new RangeMap<Comparable<?>, Object>() { 418 @Override 419 @CheckForNull 420 public Object get(Comparable<?> key) { 421 return null; 422 } 423 424 @Override 425 @CheckForNull 426 public Entry<Range<Comparable<?>>, Object> getEntry(Comparable<?> key) { 427 return null; 428 } 429 430 @Override 431 public Range<Comparable<?>> span() { 432 throw new NoSuchElementException(); 433 } 434 435 @Override 436 public void put(Range<Comparable<?>> range, Object value) { 437 checkNotNull(range); 438 throw new IllegalArgumentException( 439 "Cannot insert range " + range + " into an empty subRangeMap"); 440 } 441 442 @Override 443 public void putCoalescing(Range<Comparable<?>> range, Object value) { 444 checkNotNull(range); 445 throw new IllegalArgumentException( 446 "Cannot insert range " + range + " into an empty subRangeMap"); 447 } 448 449 @Override 450 public void putAll(RangeMap<Comparable<?>, ? extends Object> rangeMap) { 451 if (!rangeMap.asMapOfRanges().isEmpty()) { 452 throw new IllegalArgumentException( 453 "Cannot putAll(nonEmptyRangeMap) into an empty subRangeMap"); 454 } 455 } 456 457 @Override 458 public void clear() {} 459 460 @Override 461 public void remove(Range<Comparable<?>> range) { 462 checkNotNull(range); 463 } 464 465 @Override 466 // https://github.com/jspecify/jspecify-reference-checker/issues/162 467 @SuppressWarnings("nullness") 468 public void merge( 469 Range<Comparable<?>> range, 470 @CheckForNull Object value, 471 BiFunction<? super Object, ? super @Nullable Object, ? extends @Nullable Object> 472 remappingFunction) { 473 checkNotNull(range); 474 throw new IllegalArgumentException( 475 "Cannot merge range " + range + " into an empty subRangeMap"); 476 } 477 478 @Override 479 public Map<Range<Comparable<?>>, Object> asMapOfRanges() { 480 return emptyMap(); 481 } 482 483 @Override 484 public Map<Range<Comparable<?>>, Object> asDescendingMapOfRanges() { 485 return emptyMap(); 486 } 487 488 @Override 489 public RangeMap<Comparable<?>, Object> subRangeMap(Range<Comparable<?>> range) { 490 checkNotNull(range); 491 return this; 492 } 493 }; 494 495 private class SubRangeMap implements RangeMap<K, V> { 496 497 private final Range<K> subRange; 498 499 SubRangeMap(Range<K> subRange) { 500 this.subRange = subRange; 501 } 502 503 @Override 504 @CheckForNull 505 public V get(K key) { 506 return subRange.contains(key) ? TreeRangeMap.this.get(key) : null; 507 } 508 509 @Override 510 @CheckForNull 511 public Entry<Range<K>, V> getEntry(K key) { 512 if (subRange.contains(key)) { 513 Entry<Range<K>, V> entry = TreeRangeMap.this.getEntry(key); 514 if (entry != null) { 515 return immutableEntry(entry.getKey().intersection(subRange), entry.getValue()); 516 } 517 } 518 return null; 519 } 520 521 @Override 522 public Range<K> span() { 523 Cut<K> lowerBound; 524 Entry<Cut<K>, RangeMapEntry<K, V>> lowerEntry = 525 entriesByLowerBound.floorEntry(subRange.lowerBound); 526 if (lowerEntry != null 527 && lowerEntry.getValue().getUpperBound().compareTo(subRange.lowerBound) > 0) { 528 lowerBound = subRange.lowerBound; 529 } else { 530 lowerBound = entriesByLowerBound.ceilingKey(subRange.lowerBound); 531 if (lowerBound == null || lowerBound.compareTo(subRange.upperBound) >= 0) { 532 throw new NoSuchElementException(); 533 } 534 } 535 536 Cut<K> upperBound; 537 Entry<Cut<K>, RangeMapEntry<K, V>> upperEntry = 538 entriesByLowerBound.lowerEntry(subRange.upperBound); 539 if (upperEntry == null) { 540 throw new NoSuchElementException(); 541 } else if (upperEntry.getValue().getUpperBound().compareTo(subRange.upperBound) >= 0) { 542 upperBound = subRange.upperBound; 543 } else { 544 upperBound = upperEntry.getValue().getUpperBound(); 545 } 546 return Range.create(lowerBound, upperBound); 547 } 548 549 @Override 550 public void put(Range<K> range, V value) { 551 checkArgument( 552 subRange.encloses(range), "Cannot put range %s into a subRangeMap(%s)", range, subRange); 553 TreeRangeMap.this.put(range, value); 554 } 555 556 @Override 557 public void putCoalescing(Range<K> range, V value) { 558 if (entriesByLowerBound.isEmpty() || !subRange.encloses(range)) { 559 put(range, value); 560 return; 561 } 562 563 Range<K> coalescedRange = coalescedRange(range, checkNotNull(value)); 564 // only coalesce ranges within the subRange 565 put(coalescedRange.intersection(subRange), value); 566 } 567 568 @Override 569 public void putAll(RangeMap<K, ? extends V> rangeMap) { 570 if (rangeMap.asMapOfRanges().isEmpty()) { 571 return; 572 } 573 Range<K> span = rangeMap.span(); 574 checkArgument( 575 subRange.encloses(span), 576 "Cannot putAll rangeMap with span %s into a subRangeMap(%s)", 577 span, 578 subRange); 579 TreeRangeMap.this.putAll(rangeMap); 580 } 581 582 @Override 583 public void clear() { 584 TreeRangeMap.this.remove(subRange); 585 } 586 587 @Override 588 public void remove(Range<K> range) { 589 if (range.isConnected(subRange)) { 590 TreeRangeMap.this.remove(range.intersection(subRange)); 591 } 592 } 593 594 @Override 595 public void merge( 596 Range<K> range, 597 @CheckForNull V value, 598 BiFunction<? super V, ? super @Nullable V, ? extends @Nullable V> remappingFunction) { 599 checkArgument( 600 subRange.encloses(range), 601 "Cannot merge range %s into a subRangeMap(%s)", 602 range, 603 subRange); 604 TreeRangeMap.this.merge(range, value, remappingFunction); 605 } 606 607 @Override 608 public RangeMap<K, V> subRangeMap(Range<K> range) { 609 if (!range.isConnected(subRange)) { 610 return emptySubRangeMap(); 611 } else { 612 return TreeRangeMap.this.subRangeMap(range.intersection(subRange)); 613 } 614 } 615 616 @Override 617 public Map<Range<K>, V> asMapOfRanges() { 618 return new SubRangeMapAsMap(); 619 } 620 621 @Override 622 public Map<Range<K>, V> asDescendingMapOfRanges() { 623 return new SubRangeMapAsMap() { 624 625 @Override 626 Iterator<Entry<Range<K>, V>> entryIterator() { 627 if (subRange.isEmpty()) { 628 return emptyIterator(); 629 } 630 final Iterator<RangeMapEntry<K, V>> backingItr = 631 entriesByLowerBound 632 .headMap(subRange.upperBound, false) 633 .descendingMap() 634 .values() 635 .iterator(); 636 return new AbstractIterator<Entry<Range<K>, V>>() { 637 638 @Override 639 @CheckForNull 640 protected Entry<Range<K>, V> computeNext() { 641 if (backingItr.hasNext()) { 642 RangeMapEntry<K, V> entry = backingItr.next(); 643 if (entry.getUpperBound().compareTo(subRange.lowerBound) <= 0) { 644 return endOfData(); 645 } 646 return immutableEntry(entry.getKey().intersection(subRange), entry.getValue()); 647 } 648 return endOfData(); 649 } 650 }; 651 } 652 }; 653 } 654 655 @Override 656 public boolean equals(@CheckForNull Object o) { 657 if (o instanceof RangeMap) { 658 RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o; 659 return asMapOfRanges().equals(rangeMap.asMapOfRanges()); 660 } 661 return false; 662 } 663 664 @Override 665 public int hashCode() { 666 return asMapOfRanges().hashCode(); 667 } 668 669 @Override 670 public String toString() { 671 return asMapOfRanges().toString(); 672 } 673 674 class SubRangeMapAsMap extends AbstractMap<Range<K>, V> { 675 676 @Override 677 public boolean containsKey(@CheckForNull Object key) { 678 return get(key) != null; 679 } 680 681 @Override 682 @CheckForNull 683 public V get(@CheckForNull Object key) { 684 try { 685 if (key instanceof Range) { 686 @SuppressWarnings("unchecked") // we catch ClassCastExceptions 687 Range<K> r = (Range<K>) key; 688 if (!subRange.encloses(r) || r.isEmpty()) { 689 return null; 690 } 691 RangeMapEntry<K, V> candidate = null; 692 if (r.lowerBound.compareTo(subRange.lowerBound) == 0) { 693 // r could be truncated on the left 694 Entry<Cut<K>, RangeMapEntry<K, V>> entry = 695 entriesByLowerBound.floorEntry(r.lowerBound); 696 if (entry != null) { 697 candidate = entry.getValue(); 698 } 699 } else { 700 candidate = entriesByLowerBound.get(r.lowerBound); 701 } 702 703 if (candidate != null 704 && candidate.getKey().isConnected(subRange) 705 && candidate.getKey().intersection(subRange).equals(r)) { 706 return candidate.getValue(); 707 } 708 } 709 } catch (ClassCastException e) { 710 return null; 711 } 712 return null; 713 } 714 715 @Override 716 @CheckForNull 717 public V remove(@CheckForNull Object key) { 718 V value = get(key); 719 if (value != null) { 720 // it's definitely in the map, so the cast and requireNonNull are safe 721 @SuppressWarnings("unchecked") 722 Range<K> range = (Range<K>) requireNonNull(key); 723 TreeRangeMap.this.remove(range); 724 return value; 725 } 726 return null; 727 } 728 729 @Override 730 public void clear() { 731 SubRangeMap.this.clear(); 732 } 733 734 private boolean removeEntryIf(Predicate<? super Entry<Range<K>, V>> predicate) { 735 List<Range<K>> toRemove = Lists.newArrayList(); 736 for (Entry<Range<K>, V> entry : entrySet()) { 737 if (predicate.apply(entry)) { 738 toRemove.add(entry.getKey()); 739 } 740 } 741 for (Range<K> range : toRemove) { 742 TreeRangeMap.this.remove(range); 743 } 744 return !toRemove.isEmpty(); 745 } 746 747 @Override 748 public Set<Range<K>> keySet() { 749 return new Maps.KeySet<Range<K>, V>(SubRangeMapAsMap.this) { 750 @Override 751 public boolean remove(@CheckForNull Object o) { 752 return SubRangeMapAsMap.this.remove(o) != null; 753 } 754 755 @Override 756 public boolean retainAll(Collection<?> c) { 757 return removeEntryIf(compose(not(in(c)), Maps.<Range<K>>keyFunction())); 758 } 759 }; 760 } 761 762 @Override 763 public Set<Entry<Range<K>, V>> entrySet() { 764 return new Maps.EntrySet<Range<K>, V>() { 765 @Override 766 Map<Range<K>, V> map() { 767 return SubRangeMapAsMap.this; 768 } 769 770 @Override 771 public Iterator<Entry<Range<K>, V>> iterator() { 772 return entryIterator(); 773 } 774 775 @Override 776 public boolean retainAll(Collection<?> c) { 777 return removeEntryIf(not(in(c))); 778 } 779 780 @Override 781 public int size() { 782 return Iterators.size(iterator()); 783 } 784 785 @Override 786 public boolean isEmpty() { 787 return !iterator().hasNext(); 788 } 789 }; 790 } 791 792 Iterator<Entry<Range<K>, V>> entryIterator() { 793 if (subRange.isEmpty()) { 794 return emptyIterator(); 795 } 796 Cut<K> cutToStart = 797 MoreObjects.firstNonNull( 798 entriesByLowerBound.floorKey(subRange.lowerBound), subRange.lowerBound); 799 final Iterator<RangeMapEntry<K, V>> backingItr = 800 entriesByLowerBound.tailMap(cutToStart, true).values().iterator(); 801 return new AbstractIterator<Entry<Range<K>, V>>() { 802 803 @Override 804 @CheckForNull 805 protected Entry<Range<K>, V> computeNext() { 806 while (backingItr.hasNext()) { 807 RangeMapEntry<K, V> entry = backingItr.next(); 808 if (entry.getLowerBound().compareTo(subRange.upperBound) >= 0) { 809 return endOfData(); 810 } else if (entry.getUpperBound().compareTo(subRange.lowerBound) > 0) { 811 // this might not be true e.g. at the start of the iteration 812 return immutableEntry(entry.getKey().intersection(subRange), entry.getValue()); 813 } 814 } 815 return endOfData(); 816 } 817 }; 818 } 819 820 @Override 821 public Collection<V> values() { 822 return new Maps.Values<Range<K>, V>(this) { 823 @Override 824 public boolean removeAll(Collection<?> c) { 825 return removeEntryIf(compose(in(c), Maps.<V>valueFunction())); 826 } 827 828 @Override 829 public boolean retainAll(Collection<?> c) { 830 return removeEntryIf(compose(not(in(c)), Maps.<V>valueFunction())); 831 } 832 }; 833 } 834 } 835 } 836 837 @Override 838 public boolean equals(@CheckForNull Object o) { 839 if (o instanceof RangeMap) { 840 RangeMap<?, ?> rangeMap = (RangeMap<?, ?>) o; 841 return asMapOfRanges().equals(rangeMap.asMapOfRanges()); 842 } 843 return false; 844 } 845 846 @Override 847 public int hashCode() { 848 return asMapOfRanges().hashCode(); 849 } 850 851 @Override 852 public String toString() { 853 return entriesByLowerBound.values().toString(); 854 } 855}