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