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