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