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