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