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