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