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