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