001/*
002 * Copyright (C) 2011 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.collect;
016
017import static com.google.common.base.MoreObjects.firstNonNull;
018import static com.google.common.base.Preconditions.checkArgument;
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.collect.Iterators.emptyIterator;
021import static com.google.common.collect.Iterators.peekingIterator;
022import static com.google.common.collect.Maps.immutableEntry;
023import static com.google.common.collect.Maps.valueOrNull;
024import static com.google.common.collect.Sets.equalsImpl;
025import static com.google.common.collect.Sets.hashCodeImpl;
026
027import com.google.common.annotations.GwtIncompatible;
028import com.google.common.annotations.VisibleForTesting;
029import com.google.common.collect.ForwardingCollection.SimpleForwardingCollection;
030import com.google.errorprone.annotations.concurrent.LazyInit;
031import java.io.Serializable;
032import java.util.Collection;
033import java.util.Comparator;
034import java.util.Iterator;
035import java.util.Map.Entry;
036import java.util.NavigableMap;
037import java.util.NoSuchElementException;
038import java.util.Set;
039import java.util.TreeMap;
040import org.jspecify.annotations.Nullable;
041
042/**
043 * An implementation of {@link RangeSet} backed by a {@link TreeMap}.
044 *
045 * @author Louis Wasserman
046 * @since 14.0
047 */
048@GwtIncompatible // uses NavigableMap
049public class TreeRangeSet<C extends Comparable<?>> extends AbstractRangeSet<C>
050    implements Serializable {
051
052  @VisibleForTesting final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
053
054  /** Creates an empty {@code TreeRangeSet} instance. */
055  public static <C extends Comparable<?>> TreeRangeSet<C> create() {
056    return new TreeRangeSet<>(new TreeMap<Cut<C>, Range<C>>());
057  }
058
059  /** Returns a {@code TreeRangeSet} initialized with the ranges in the specified range set. */
060  public static <C extends Comparable<?>> TreeRangeSet<C> create(RangeSet<C> rangeSet) {
061    TreeRangeSet<C> result = create();
062    result.addAll(rangeSet);
063    return result;
064  }
065
066  /**
067   * Returns a {@code TreeRangeSet} representing the union of the specified ranges.
068   *
069   * <p>This is the smallest {@code RangeSet} which encloses each of the specified ranges. An
070   * element will be contained in this {@code RangeSet} if and only if it is contained in at least
071   * one {@code Range} in {@code ranges}.
072   *
073   * @since 21.0
074   */
075  public static <C extends Comparable<?>> TreeRangeSet<C> create(Iterable<Range<C>> ranges) {
076    TreeRangeSet<C> result = create();
077    result.addAll(ranges);
078    return result;
079  }
080
081  private TreeRangeSet(NavigableMap<Cut<C>, Range<C>> rangesByLowerCut) {
082    this.rangesByLowerBound = rangesByLowerCut;
083  }
084
085  @Override
086  public Set<Range<C>> asRanges() {
087    return new AsRanges(rangesByLowerBound.values());
088  }
089
090  @Override
091  public Set<Range<C>> asDescendingSetOfRanges() {
092    return new AsRanges(rangesByLowerBound.descendingMap().values());
093  }
094
095  final class AsRanges extends SimpleForwardingCollection<Range<C>> implements Set<Range<C>> {
096    AsRanges(Collection<Range<C>> delegate) {
097      super(delegate);
098    }
099
100    @Override
101    public int hashCode() {
102      return hashCodeImpl(this);
103    }
104
105    @Override
106    public boolean equals(@Nullable Object o) {
107      return equalsImpl(this, o);
108    }
109  }
110
111  @Override
112  public @Nullable Range<C> rangeContaining(C value) {
113    checkNotNull(value);
114    Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(Cut.belowValue(value));
115    if (floorEntry != null && floorEntry.getValue().contains(value)) {
116      return floorEntry.getValue();
117    } else {
118      // TODO(kevinb): revisit this design choice
119      return null;
120    }
121  }
122
123  @Override
124  public boolean intersects(Range<C> range) {
125    checkNotNull(range);
126    Entry<Cut<C>, Range<C>> ceilingEntry = rangesByLowerBound.ceilingEntry(range.lowerBound);
127    if (ceilingEntry != null
128        && ceilingEntry.getValue().isConnected(range)
129        && !ceilingEntry.getValue().intersection(range).isEmpty()) {
130      return true;
131    }
132    Entry<Cut<C>, Range<C>> priorEntry = rangesByLowerBound.lowerEntry(range.lowerBound);
133    return priorEntry != null
134        && priorEntry.getValue().isConnected(range)
135        && !priorEntry.getValue().intersection(range).isEmpty();
136  }
137
138  @Override
139  public boolean encloses(Range<C> range) {
140    checkNotNull(range);
141    Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
142    return floorEntry != null && floorEntry.getValue().encloses(range);
143  }
144
145  private @Nullable Range<C> rangeEnclosing(Range<C> range) {
146    checkNotNull(range);
147    Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
148    return (floorEntry != null && floorEntry.getValue().encloses(range))
149        ? floorEntry.getValue()
150        : null;
151  }
152
153  @Override
154  public Range<C> span() {
155    Entry<Cut<C>, Range<C>> firstEntry = rangesByLowerBound.firstEntry();
156    Entry<Cut<C>, Range<C>> lastEntry = rangesByLowerBound.lastEntry();
157    if (firstEntry == null || lastEntry == null) {
158      /*
159       * Either both are null or neither is: Either the set is empty, or it's not. But we check both
160       * to make the nullness checker happy.
161       */
162      throw new NoSuchElementException();
163    }
164    return Range.create(firstEntry.getValue().lowerBound, lastEntry.getValue().upperBound);
165  }
166
167  @Override
168  public void add(Range<C> rangeToAdd) {
169    checkNotNull(rangeToAdd);
170
171    if (rangeToAdd.isEmpty()) {
172      return;
173    }
174
175    // We will use { } to illustrate ranges currently in the range set, and < >
176    // to illustrate rangeToAdd.
177    Cut<C> lbToAdd = rangeToAdd.lowerBound;
178    Cut<C> ubToAdd = rangeToAdd.upperBound;
179
180    Entry<Cut<C>, Range<C>> entryBelowLb = rangesByLowerBound.lowerEntry(lbToAdd);
181    if (entryBelowLb != null) {
182      // { <
183      Range<C> rangeBelowLb = entryBelowLb.getValue();
184      if (rangeBelowLb.upperBound.compareTo(lbToAdd) >= 0) {
185        // { < }, and we will need to coalesce
186        if (rangeBelowLb.upperBound.compareTo(ubToAdd) >= 0) {
187          // { < > }
188          ubToAdd = rangeBelowLb.upperBound;
189          /*
190           * TODO(cpovirk): can we just "return;" here? Or, can we remove this if() entirely? If
191           * not, add tests to demonstrate the problem with each approach
192           */
193        }
194        lbToAdd = rangeBelowLb.lowerBound;
195      }
196    }
197
198    Entry<Cut<C>, Range<C>> entryBelowUb = rangesByLowerBound.floorEntry(ubToAdd);
199    if (entryBelowUb != null) {
200      // { >
201      Range<C> rangeBelowUb = entryBelowUb.getValue();
202      if (rangeBelowUb.upperBound.compareTo(ubToAdd) >= 0) {
203        // { > }, and we need to coalesce
204        ubToAdd = rangeBelowUb.upperBound;
205      }
206    }
207
208    // Remove ranges which are strictly enclosed.
209    rangesByLowerBound.subMap(lbToAdd, ubToAdd).clear();
210
211    replaceRangeWithSameLowerBound(Range.create(lbToAdd, ubToAdd));
212  }
213
214  @Override
215  public void remove(Range<C> rangeToRemove) {
216    checkNotNull(rangeToRemove);
217
218    if (rangeToRemove.isEmpty()) {
219      return;
220    }
221
222    // We will use { } to illustrate ranges currently in the range set, and < >
223    // to illustrate rangeToRemove.
224
225    Entry<Cut<C>, Range<C>> entryBelowLb = rangesByLowerBound.lowerEntry(rangeToRemove.lowerBound);
226    if (entryBelowLb != null) {
227      // { <
228      Range<C> rangeBelowLb = entryBelowLb.getValue();
229      if (rangeBelowLb.upperBound.compareTo(rangeToRemove.lowerBound) >= 0) {
230        // { < }, and we will need to subdivide
231        if (rangeToRemove.hasUpperBound()
232            && rangeBelowLb.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
233          // { < > }
234          replaceRangeWithSameLowerBound(
235              Range.create(rangeToRemove.upperBound, rangeBelowLb.upperBound));
236        }
237        replaceRangeWithSameLowerBound(
238            Range.create(rangeBelowLb.lowerBound, rangeToRemove.lowerBound));
239      }
240    }
241
242    Entry<Cut<C>, Range<C>> entryBelowUb = rangesByLowerBound.floorEntry(rangeToRemove.upperBound);
243    if (entryBelowUb != null) {
244      // { >
245      Range<C> rangeBelowUb = entryBelowUb.getValue();
246      if (rangeToRemove.hasUpperBound()
247          && rangeBelowUb.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
248        // { > }
249        replaceRangeWithSameLowerBound(
250            Range.create(rangeToRemove.upperBound, rangeBelowUb.upperBound));
251      }
252    }
253
254    rangesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear();
255  }
256
257  private void replaceRangeWithSameLowerBound(Range<C> range) {
258    if (range.isEmpty()) {
259      rangesByLowerBound.remove(range.lowerBound);
260    } else {
261      rangesByLowerBound.put(range.lowerBound, range);
262    }
263  }
264
265  @LazyInit private transient @Nullable RangeSet<C> complement;
266
267  @Override
268  public RangeSet<C> complement() {
269    RangeSet<C> result = complement;
270    if (result == null) {
271      result = complement = new Complement();
272    }
273    return result;
274  }
275
276  @VisibleForTesting
277  static final class RangesByUpperBound<C extends Comparable<?>>
278      extends AbstractNavigableMap<Cut<C>, Range<C>> {
279    private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
280
281    /**
282     * upperBoundWindow represents the headMap/subMap/tailMap view of the entire "ranges by upper
283     * bound" map; it's a constraint on the *keys*, and does not affect the values.
284     */
285    private final Range<Cut<C>> upperBoundWindow;
286
287    RangesByUpperBound(NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
288      this.rangesByLowerBound = rangesByLowerBound;
289      this.upperBoundWindow = Range.all();
290    }
291
292    private RangesByUpperBound(
293        NavigableMap<Cut<C>, Range<C>> rangesByLowerBound, Range<Cut<C>> upperBoundWindow) {
294      this.rangesByLowerBound = rangesByLowerBound;
295      this.upperBoundWindow = upperBoundWindow;
296    }
297
298    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
299      if (window.isConnected(upperBoundWindow)) {
300        return new RangesByUpperBound<>(rangesByLowerBound, window.intersection(upperBoundWindow));
301      } else {
302        return ImmutableSortedMap.of();
303      }
304    }
305
306    @Override
307    public NavigableMap<Cut<C>, Range<C>> subMap(
308        Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
309      return subMap(
310          Range.range(
311              fromKey, BoundType.forBoolean(fromInclusive),
312              toKey, BoundType.forBoolean(toInclusive)));
313    }
314
315    @Override
316    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
317      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
318    }
319
320    @Override
321    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
322      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
323    }
324
325    @Override
326    public Comparator<? super Cut<C>> comparator() {
327      return Ordering.natural();
328    }
329
330    @Override
331    public boolean containsKey(@Nullable Object key) {
332      return get(key) != null;
333    }
334
335    @Override
336    public @Nullable Range<C> get(@Nullable Object key) {
337      if (key instanceof Cut) {
338        try {
339          @SuppressWarnings("unchecked") // we catch CCEs
340          Cut<C> cut = (Cut<C>) key;
341          if (!upperBoundWindow.contains(cut)) {
342            return null;
343          }
344          Entry<Cut<C>, Range<C>> candidate = rangesByLowerBound.lowerEntry(cut);
345          if (candidate != null && candidate.getValue().upperBound.equals(cut)) {
346            return candidate.getValue();
347          }
348        } catch (ClassCastException e) {
349          return null;
350        }
351      }
352      return null;
353    }
354
355    @Override
356    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
357      /*
358       * We want to start the iteration at the first range where the upper bound is in
359       * upperBoundWindow.
360       */
361      Iterator<Range<C>> backingItr;
362      if (!upperBoundWindow.hasLowerBound()) {
363        backingItr = rangesByLowerBound.values().iterator();
364      } else {
365        Entry<Cut<C>, Range<C>> lowerEntry =
366            rangesByLowerBound.lowerEntry(upperBoundWindow.lowerEndpoint());
367        if (lowerEntry == null) {
368          backingItr = rangesByLowerBound.values().iterator();
369        } else if (upperBoundWindow.lowerBound.isLessThan(lowerEntry.getValue().upperBound)) {
370          backingItr = rangesByLowerBound.tailMap(lowerEntry.getKey(), true).values().iterator();
371        } else {
372          backingItr =
373              rangesByLowerBound
374                  .tailMap(upperBoundWindow.lowerEndpoint(), true)
375                  .values()
376                  .iterator();
377        }
378      }
379      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
380        @Override
381        protected @Nullable Entry<Cut<C>, Range<C>> computeNext() {
382          if (!backingItr.hasNext()) {
383            return endOfData();
384          }
385          Range<C> range = backingItr.next();
386          if (upperBoundWindow.upperBound.isLessThan(range.upperBound)) {
387            return endOfData();
388          } else {
389            return immutableEntry(range.upperBound, range);
390          }
391        }
392      };
393    }
394
395    @Override
396    Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
397      Collection<Range<C>> candidates;
398      if (upperBoundWindow.hasUpperBound()) {
399        candidates =
400            rangesByLowerBound
401                .headMap(upperBoundWindow.upperEndpoint(), false)
402                .descendingMap()
403                .values();
404      } else {
405        candidates = rangesByLowerBound.descendingMap().values();
406      }
407      PeekingIterator<Range<C>> backingItr = peekingIterator(candidates.iterator());
408      if (backingItr.hasNext()
409          && upperBoundWindow.upperBound.isLessThan(backingItr.peek().upperBound)) {
410        backingItr.next();
411      }
412      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
413        @Override
414        protected @Nullable Entry<Cut<C>, Range<C>> computeNext() {
415          if (!backingItr.hasNext()) {
416            return endOfData();
417          }
418          Range<C> range = backingItr.next();
419          return upperBoundWindow.lowerBound.isLessThan(range.upperBound)
420              ? immutableEntry(range.upperBound, range)
421              : endOfData();
422        }
423      };
424    }
425
426    @Override
427    public int size() {
428      if (upperBoundWindow.equals(Range.all())) {
429        return rangesByLowerBound.size();
430      }
431      return Iterators.size(entryIterator());
432    }
433
434    @Override
435    public boolean isEmpty() {
436      return upperBoundWindow.equals(Range.all())
437          ? rangesByLowerBound.isEmpty()
438          : !entryIterator().hasNext();
439    }
440  }
441
442  private static final class ComplementRangesByLowerBound<C extends Comparable<?>>
443      extends AbstractNavigableMap<Cut<C>, Range<C>> {
444    private final NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound;
445    private final NavigableMap<Cut<C>, Range<C>> positiveRangesByUpperBound;
446
447    /**
448     * complementLowerBoundWindow represents the headMap/subMap/tailMap view of the entire
449     * "complement ranges by lower bound" map; it's a constraint on the *keys*, and does not affect
450     * the values.
451     */
452    private final Range<Cut<C>> complementLowerBoundWindow;
453
454    ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound) {
455      this(positiveRangesByLowerBound, Range.all());
456    }
457
458    private ComplementRangesByLowerBound(
459        NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound, Range<Cut<C>> window) {
460      this.positiveRangesByLowerBound = positiveRangesByLowerBound;
461      this.positiveRangesByUpperBound = new RangesByUpperBound<>(positiveRangesByLowerBound);
462      this.complementLowerBoundWindow = window;
463    }
464
465    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> subWindow) {
466      if (!complementLowerBoundWindow.isConnected(subWindow)) {
467        return ImmutableSortedMap.of();
468      } else {
469        subWindow = subWindow.intersection(complementLowerBoundWindow);
470        return new ComplementRangesByLowerBound<>(positiveRangesByLowerBound, subWindow);
471      }
472    }
473
474    @Override
475    public NavigableMap<Cut<C>, Range<C>> subMap(
476        Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
477      return subMap(
478          Range.range(
479              fromKey, BoundType.forBoolean(fromInclusive),
480              toKey, BoundType.forBoolean(toInclusive)));
481    }
482
483    @Override
484    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
485      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
486    }
487
488    @Override
489    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
490      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
491    }
492
493    @Override
494    public Comparator<? super Cut<C>> comparator() {
495      return Ordering.natural();
496    }
497
498    @Override
499    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
500      /*
501       * firstComplementRangeLowerBound is the first complement range lower bound inside
502       * complementLowerBoundWindow. Complement range lower bounds are either positive range upper
503       * bounds, or Cut.belowAll().
504       *
505       * positiveItr starts at the first positive range with lower bound greater than
506       * firstComplementRangeLowerBound. (Positive range lower bounds correspond to complement range
507       * upper bounds.)
508       */
509      Collection<Range<C>> positiveRanges;
510      if (complementLowerBoundWindow.hasLowerBound()) {
511        positiveRanges =
512            positiveRangesByUpperBound
513                .tailMap(
514                    complementLowerBoundWindow.lowerEndpoint(),
515                    complementLowerBoundWindow.lowerBoundType() == BoundType.CLOSED)
516                .values();
517      } else {
518        positiveRanges = positiveRangesByUpperBound.values();
519      }
520      PeekingIterator<Range<C>> positiveItr = peekingIterator(positiveRanges.iterator());
521      Cut<C> firstComplementRangeLowerBound;
522      if (complementLowerBoundWindow.contains(Cut.belowAll())
523          && (!positiveItr.hasNext() || positiveItr.peek().lowerBound != Cut.<C>belowAll())) {
524        firstComplementRangeLowerBound = Cut.belowAll();
525      } else if (positiveItr.hasNext()) {
526        firstComplementRangeLowerBound = positiveItr.next().upperBound;
527      } else {
528        return emptyIterator();
529      }
530      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
531        Cut<C> nextComplementRangeLowerBound = firstComplementRangeLowerBound;
532
533        @Override
534        protected @Nullable Entry<Cut<C>, Range<C>> computeNext() {
535          if (complementLowerBoundWindow.upperBound.isLessThan(nextComplementRangeLowerBound)
536              || nextComplementRangeLowerBound == Cut.<C>aboveAll()) {
537            return endOfData();
538          }
539          Range<C> negativeRange;
540          if (positiveItr.hasNext()) {
541            Range<C> positiveRange = positiveItr.next();
542            negativeRange = Range.create(nextComplementRangeLowerBound, positiveRange.lowerBound);
543            nextComplementRangeLowerBound = positiveRange.upperBound;
544          } else {
545            negativeRange = Range.create(nextComplementRangeLowerBound, Cut.aboveAll());
546            nextComplementRangeLowerBound = Cut.aboveAll();
547          }
548          return immutableEntry(negativeRange.lowerBound, negativeRange);
549        }
550      };
551    }
552
553    @Override
554    Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
555      /*
556       * firstComplementRangeUpperBound is the upper bound of the last complement range with lower
557       * bound inside complementLowerBoundWindow.
558       *
559       * positiveItr starts at the first positive range with upper bound less than
560       * firstComplementRangeUpperBound. (Positive range upper bounds correspond to complement range
561       * lower bounds.)
562       */
563      Cut<C> startingPoint =
564          complementLowerBoundWindow.hasUpperBound()
565              ? complementLowerBoundWindow.upperEndpoint()
566              : Cut.aboveAll();
567      boolean inclusive =
568          complementLowerBoundWindow.hasUpperBound()
569              && complementLowerBoundWindow.upperBoundType() == BoundType.CLOSED;
570      PeekingIterator<Range<C>> positiveItr =
571          peekingIterator(
572              positiveRangesByUpperBound
573                  .headMap(startingPoint, inclusive)
574                  .descendingMap()
575                  .values()
576                  .iterator());
577      Cut<C> cut;
578      if (positiveItr.hasNext()) {
579        cut =
580            (positiveItr.peek().upperBound == Cut.<C>aboveAll())
581                ? positiveItr.next().lowerBound
582                : positiveRangesByLowerBound.higherKey(positiveItr.peek().upperBound);
583      } else if (!complementLowerBoundWindow.contains(Cut.belowAll())
584          || positiveRangesByLowerBound.containsKey(Cut.belowAll())) {
585        return emptyIterator();
586      } else {
587        cut = positiveRangesByLowerBound.higherKey(Cut.belowAll());
588      }
589      Cut<C> firstComplementRangeUpperBound = firstNonNull(cut, Cut.aboveAll());
590      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
591        Cut<C> nextComplementRangeUpperBound = firstComplementRangeUpperBound;
592
593        @Override
594        protected @Nullable Entry<Cut<C>, Range<C>> computeNext() {
595          if (nextComplementRangeUpperBound == Cut.<C>belowAll()) {
596            return endOfData();
597          } else if (positiveItr.hasNext()) {
598            Range<C> positiveRange = positiveItr.next();
599            Range<C> negativeRange =
600                Range.create(positiveRange.upperBound, nextComplementRangeUpperBound);
601            nextComplementRangeUpperBound = positiveRange.lowerBound;
602            if (complementLowerBoundWindow.lowerBound.isLessThan(negativeRange.lowerBound)) {
603              return immutableEntry(negativeRange.lowerBound, negativeRange);
604            }
605          } else if (complementLowerBoundWindow.lowerBound.isLessThan(Cut.belowAll())) {
606            Range<C> negativeRange = Range.create(Cut.belowAll(), nextComplementRangeUpperBound);
607            nextComplementRangeUpperBound = Cut.belowAll();
608            return immutableEntry(Cut.belowAll(), negativeRange);
609          }
610          return endOfData();
611        }
612      };
613    }
614
615    @Override
616    public int size() {
617      return Iterators.size(entryIterator());
618    }
619
620    @Override
621    public @Nullable Range<C> get(@Nullable Object key) {
622      if (key instanceof Cut) {
623        try {
624          @SuppressWarnings("unchecked")
625          Cut<C> cut = (Cut<C>) key;
626          // tailMap respects the current window
627          Entry<Cut<C>, Range<C>> firstEntry = tailMap(cut, true).firstEntry();
628          if (firstEntry != null && firstEntry.getKey().equals(cut)) {
629            return firstEntry.getValue();
630          }
631        } catch (ClassCastException e) {
632          return null;
633        }
634      }
635      return null;
636    }
637
638    @Override
639    public boolean containsKey(@Nullable Object key) {
640      return get(key) != null;
641    }
642  }
643
644  private final class Complement extends TreeRangeSet<C> {
645    Complement() {
646      super(new ComplementRangesByLowerBound<C>(TreeRangeSet.this.rangesByLowerBound));
647    }
648
649    @Override
650    public void add(Range<C> rangeToAdd) {
651      TreeRangeSet.this.remove(rangeToAdd);
652    }
653
654    @Override
655    public void remove(Range<C> rangeToRemove) {
656      TreeRangeSet.this.add(rangeToRemove);
657    }
658
659    @Override
660    public boolean contains(C value) {
661      return !TreeRangeSet.this.contains(value);
662    }
663
664    @Override
665    public RangeSet<C> complement() {
666      return TreeRangeSet.this;
667    }
668  }
669
670  private static final class SubRangeSetRangesByLowerBound<C extends Comparable<?>>
671      extends AbstractNavigableMap<Cut<C>, Range<C>> {
672    /**
673     * lowerBoundWindow is the headMap/subMap/tailMap view; it only restricts the keys, and does not
674     * affect the values.
675     */
676    private final Range<Cut<C>> lowerBoundWindow;
677
678    /**
679     * restriction is the subRangeSet view; ranges are truncated to their intersection with
680     * restriction.
681     */
682    private final Range<C> restriction;
683
684    private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
685    private final NavigableMap<Cut<C>, Range<C>> rangesByUpperBound;
686
687    private SubRangeSetRangesByLowerBound(
688        Range<Cut<C>> lowerBoundWindow,
689        Range<C> restriction,
690        NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
691      this.lowerBoundWindow = checkNotNull(lowerBoundWindow);
692      this.restriction = checkNotNull(restriction);
693      this.rangesByLowerBound = checkNotNull(rangesByLowerBound);
694      this.rangesByUpperBound = new RangesByUpperBound<>(rangesByLowerBound);
695    }
696
697    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
698      if (!window.isConnected(lowerBoundWindow)) {
699        return ImmutableSortedMap.of();
700      } else {
701        return new SubRangeSetRangesByLowerBound<>(
702            lowerBoundWindow.intersection(window), restriction, rangesByLowerBound);
703      }
704    }
705
706    @Override
707    public NavigableMap<Cut<C>, Range<C>> subMap(
708        Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) {
709      return subMap(
710          Range.range(
711              fromKey,
712              BoundType.forBoolean(fromInclusive),
713              toKey,
714              BoundType.forBoolean(toInclusive)));
715    }
716
717    @Override
718    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) {
719      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
720    }
721
722    @Override
723    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean inclusive) {
724      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
725    }
726
727    @Override
728    public Comparator<? super Cut<C>> comparator() {
729      return Ordering.natural();
730    }
731
732    @Override
733    public boolean containsKey(@Nullable Object key) {
734      return get(key) != null;
735    }
736
737    @Override
738    public @Nullable Range<C> get(@Nullable Object key) {
739      if (key instanceof Cut) {
740        try {
741          @SuppressWarnings("unchecked") // we catch CCE's
742          Cut<C> cut = (Cut<C>) key;
743          if (!lowerBoundWindow.contains(cut)
744              || cut.compareTo(restriction.lowerBound) < 0
745              || cut.compareTo(restriction.upperBound) >= 0) {
746            return null;
747          } else if (cut.equals(restriction.lowerBound)) {
748            // it might be present, truncated on the left
749            Range<C> candidate = valueOrNull(rangesByLowerBound.floorEntry(cut));
750            if (candidate != null && candidate.upperBound.compareTo(restriction.lowerBound) > 0) {
751              return candidate.intersection(restriction);
752            }
753          } else {
754            Range<C> result = rangesByLowerBound.get(cut);
755            if (result != null) {
756              return result.intersection(restriction);
757            }
758          }
759        } catch (ClassCastException e) {
760          return null;
761        }
762      }
763      return null;
764    }
765
766    @Override
767    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
768      if (restriction.isEmpty()) {
769        return emptyIterator();
770      }
771      Iterator<Range<C>> completeRangeItr;
772      if (lowerBoundWindow.upperBound.isLessThan(restriction.lowerBound)) {
773        return emptyIterator();
774      } else if (lowerBoundWindow.lowerBound.isLessThan(restriction.lowerBound)) {
775        // starts at the first range with upper bound strictly greater than restriction.lowerBound
776        completeRangeItr =
777            rangesByUpperBound.tailMap(restriction.lowerBound, false).values().iterator();
778      } else {
779        // starts at the first range with lower bound above lowerBoundWindow.lowerBound
780        completeRangeItr =
781            rangesByLowerBound
782                .tailMap(
783                    lowerBoundWindow.lowerBound.endpoint(),
784                    lowerBoundWindow.lowerBoundType() == BoundType.CLOSED)
785                .values()
786                .iterator();
787      }
788      Cut<Cut<C>> upperBoundOnLowerBounds =
789          Ordering.<Cut<Cut<C>>>natural()
790              .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
791      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
792        @Override
793        protected @Nullable Entry<Cut<C>, Range<C>> computeNext() {
794          if (!completeRangeItr.hasNext()) {
795            return endOfData();
796          }
797          Range<C> nextRange = completeRangeItr.next();
798          if (upperBoundOnLowerBounds.isLessThan(nextRange.lowerBound)) {
799            return endOfData();
800          } else {
801            nextRange = nextRange.intersection(restriction);
802            return immutableEntry(nextRange.lowerBound, nextRange);
803          }
804        }
805      };
806    }
807
808    @Override
809    Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() {
810      if (restriction.isEmpty()) {
811        return emptyIterator();
812      }
813      Cut<Cut<C>> upperBoundOnLowerBounds =
814          Ordering.<Cut<Cut<C>>>natural()
815              .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
816      Iterator<Range<C>> completeRangeItr =
817          rangesByLowerBound
818              .headMap(
819                  upperBoundOnLowerBounds.endpoint(),
820                  upperBoundOnLowerBounds.typeAsUpperBound() == BoundType.CLOSED)
821              .descendingMap()
822              .values()
823              .iterator();
824      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
825        @Override
826        protected @Nullable Entry<Cut<C>, Range<C>> computeNext() {
827          if (!completeRangeItr.hasNext()) {
828            return endOfData();
829          }
830          Range<C> nextRange = completeRangeItr.next();
831          if (restriction.lowerBound.compareTo(nextRange.upperBound) >= 0) {
832            return endOfData();
833          }
834          nextRange = nextRange.intersection(restriction);
835          if (lowerBoundWindow.contains(nextRange.lowerBound)) {
836            return immutableEntry(nextRange.lowerBound, nextRange);
837          } else {
838            return endOfData();
839          }
840        }
841      };
842    }
843
844    @Override
845    public int size() {
846      return Iterators.size(entryIterator());
847    }
848  }
849
850  @Override
851  public RangeSet<C> subRangeSet(Range<C> view) {
852    return view.equals(Range.all()) ? this : new SubRangeSet(view);
853  }
854
855  private final class SubRangeSet extends TreeRangeSet<C> {
856    private final Range<C> restriction;
857
858    SubRangeSet(Range<C> restriction) {
859      super(
860          new SubRangeSetRangesByLowerBound<C>(
861              Range.all(), restriction, TreeRangeSet.this.rangesByLowerBound));
862      this.restriction = restriction;
863    }
864
865    @Override
866    public boolean encloses(Range<C> range) {
867      if (!restriction.isEmpty() && restriction.encloses(range)) {
868        Range<C> enclosing = TreeRangeSet.this.rangeEnclosing(range);
869        return enclosing != null && !enclosing.intersection(restriction).isEmpty();
870      }
871      return false;
872    }
873
874    @Override
875    public @Nullable Range<C> rangeContaining(C value) {
876      if (!restriction.contains(value)) {
877        return null;
878      }
879      Range<C> result = TreeRangeSet.this.rangeContaining(value);
880      return (result == null) ? null : result.intersection(restriction);
881    }
882
883    @Override
884    public void add(Range<C> rangeToAdd) {
885      checkArgument(
886          restriction.encloses(rangeToAdd),
887          "Cannot add range %s to subRangeSet(%s)",
888          rangeToAdd,
889          restriction);
890      TreeRangeSet.this.add(rangeToAdd);
891    }
892
893    @Override
894    public void remove(Range<C> rangeToRemove) {
895      if (rangeToRemove.isConnected(restriction)) {
896        TreeRangeSet.this.remove(rangeToRemove.intersection(restriction));
897      }
898    }
899
900    @Override
901    public boolean contains(C value) {
902      return restriction.contains(value) && TreeRangeSet.this.contains(value);
903    }
904
905    @Override
906    public void clear() {
907      TreeRangeSet.this.remove(restriction);
908    }
909
910    @Override
911    public RangeSet<C> subRangeSet(Range<C> view) {
912      if (view.encloses(restriction)) {
913        return this;
914      } else if (view.isConnected(restriction)) {
915        return new SubRangeSet(restriction.intersection(view));
916      } else {
917        return ImmutableRangeSet.of();
918      }
919    }
920  }
921
922  private static final long serialVersionUID = 25682166307111266L;
923}