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