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