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