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