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