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