Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2011 The Guava Authors
   *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
   * in compliance with the License. You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software distributed under the License
  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
 
 package com.google.common.collect;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 
 import java.util.Set;
 
 import  javax.annotation.Nullable;

An implementation of RangeSet backed by a TreeMap.

Author(s):
Louis Wasserman
Since:
14.0
 
 @GwtIncompatible("uses NavigableMap")
 public class TreeRangeSet<C extends Comparable<?>>
     extends AbstractRangeSet<C> {
 
   final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;

  
Creates an empty TreeRangeSet instance.
 
   public static <C extends Comparable<?>> TreeRangeSet<C> create() {
     return new TreeRangeSet<C>(new TreeMap<Cut<C>, Range<C>>());
   }
  
  
Returns a TreeRangeSet initialized with the ranges in the specified range set.
 
   public static <C extends Comparable<?>> TreeRangeSet<C> create(RangeSet<C> rangeSet) {
     TreeRangeSet<C> result = create();
     result.addAll(rangeSet);
     return result;
   }
 
   private TreeRangeSet(NavigableMap<Cut<C>, Range<C>> rangesByLowerCut) {
     this. = rangesByLowerCut;
   }
 
   private transient Set<Range<C>> asRanges;
 
   @Override
   public Set<Range<C>> asRanges() {
     Set<Range<C>> result = ;
     return (result == null) ?  = new AsRanges() : result;
   }
 
   final class AsRanges extends ForwardingCollection<Range<C>> implements Set<Range<C>> {
     @Override
     protected Collection<Range<C>> delegate() {
       return .values();
     }
 
     @Override
     public int hashCode() {
       return Sets.hashCodeImpl(this);
     }
 
     @Override
     public boolean equals(@Nullable Object o) {
       return Sets.equalsImpl(thiso);
     }
   }
 
   @Override
   @Nullable
   public Range<C> rangeContaining(C value) {
     checkNotNull(value);
     Entry<Cut<C>, Range<C>> floorEntry = .floorEntry(Cut.belowValue(value));
    if (floorEntry != null && floorEntry.getValue().contains(value)) {
      return floorEntry.getValue();
    } else {
      // TODO(kevinb): revisit this design choice
      return null;
    }
  }
  public boolean encloses(Range<C> range) {
    checkNotNull(range);
    Entry<Cut<C>, Range<C>> floorEntry = .floorEntry(range.lowerBound);
    return floorEntry != null && floorEntry.getValue().encloses(range);
  }
  
  @Nullable
  private Range<C> rangeEnclosing(Range<C> range) {
    checkNotNull(range);
    Entry<Cut<C>, Range<C>> floorEntry = .floorEntry(range.lowerBound);
    return (floorEntry != null && floorEntry.getValue().encloses(range))
        ? floorEntry.getValue()
        : null;
  }
  public Range<C> span() {
    Entry<Cut<C>, Range<C>> firstEntry = .firstEntry();
    Entry<Cut<C>, Range<C>> lastEntry = .lastEntry();
    if (firstEntry == null) {
      throw new NoSuchElementException();
    }
    return Range.create(firstEntry.getValue().lastEntry.getValue().);
  }
  public void add(Range<C> rangeToAdd) {
    checkNotNull(rangeToAdd);
    if (rangeToAdd.isEmpty()) {
      return;
    }
    // We will use { } to illustrate ranges currently in the range set, and < >
    // to illustrate rangeToAdd.
    Cut<C> lbToAdd = rangeToAdd.lowerBound;
    Cut<C> ubToAdd = rangeToAdd.upperBound;
    Entry<Cut<C>, Range<C>> entryBelowLB = .lowerEntry(lbToAdd);
    if (entryBelowLB != null) {
      // { <
      Range<C> rangeBelowLB = entryBelowLB.getValue();
      if (rangeBelowLB.upperBound.compareTo(lbToAdd) >= 0) {
        // { < }, and we will need to coalesce
        if (rangeBelowLB.upperBound.compareTo(ubToAdd) >= 0) {
          // { < > }
          ubToAdd = rangeBelowLB.upperBound;
          /*
           * TODO(cpovirk): can we just "return;" here? Or, can we remove this if() entirely? If
           * not, add tests to demonstrate the problem with each approach
           */
        }
        lbToAdd = rangeBelowLB.lowerBound;
      }
    }
    Entry<Cut<C>, Range<C>> entryBelowUB = .floorEntry(ubToAdd);
    if (entryBelowUB != null) {
      // { >
      Range<C> rangeBelowUB = entryBelowUB.getValue();
      if (rangeBelowUB.upperBound.compareTo(ubToAdd) >= 0) {
        // { > }, and we need to coalesce
        ubToAdd = rangeBelowUB.upperBound;
      }
    }
    // Remove ranges which are strictly enclosed.
    .subMap(lbToAddubToAdd).clear();
    replaceRangeWithSameLowerBound(Range.create(lbToAddubToAdd));
  }
  public void remove(Range<C> rangeToRemove) {
    checkNotNull(rangeToRemove);
    if (rangeToRemove.isEmpty()) {
      return;
    }
    // We will use { } to illustrate ranges currently in the range set, and < >
    // to illustrate rangeToRemove.
    Entry<Cut<C>, Range<C>> entryBelowLB = .lowerEntry(rangeToRemove.lowerBound);
    if (entryBelowLB != null) {
      // { <
      Range<C> rangeBelowLB = entryBelowLB.getValue();
      if (rangeBelowLB.upperBound.compareTo(rangeToRemove.lowerBound) >= 0) {
        // { < }, and we will need to subdivide
        if (rangeToRemove.hasUpperBound()
            && rangeBelowLB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
          // { < > }
              Range.create(rangeToRemove.upperBoundrangeBelowLB.upperBound));
        }
            Range.create(rangeBelowLB.lowerBoundrangeToRemove.lowerBound));
      }
    }
    Entry<Cut<C>, Range<C>> entryBelowUB = .floorEntry(rangeToRemove.upperBound);
    if (entryBelowUB != null) {
      // { >
      Range<C> rangeBelowUB = entryBelowUB.getValue();
      if (rangeToRemove.hasUpperBound()
          && rangeBelowUB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
        // { > }
            Range.create(rangeToRemove.upperBoundrangeBelowUB.upperBound));
      }
    }
    .subMap(rangeToRemove.lowerBoundrangeToRemove.upperBound).clear();
  }
  private void replaceRangeWithSameLowerBound(Range<C> range) {
    if (range.isEmpty()) {
      .remove(range.lowerBound);
    } else {
      .put(range.lowerBoundrange);
    }
  }
  private transient RangeSet<C> complement;
  public RangeSet<C> complement() {
    RangeSet<C> result = ;
    return (result == null) ?  = new Complement() : result;
  }
  
  static final class RangesByUpperBound<C extends Comparable<?>>
      extends AbstractNavigableMap<Cut<C>, Range<C>> {
    private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
    
    
upperBoundWindow represents the headMap/subMap/tailMap view of the entire "ranges by upper bound" map; it's a constraint on the *keys*, and does not affect the values.
    private final Range<Cut<C>> upperBoundWindow;
    
    RangesByUpperBound(NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
      this. = rangesByLowerBound;
      this. = Range.all();
    }
    private RangesByUpperBound(
        NavigableMap<Cut<C>, Range<C>> rangesByLowerBoundRange<Cut<C>> upperBoundWindow) {
      this. = rangesByLowerBound;
      this. = upperBoundWindow;
    }
    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
      if (window.isConnected()) {
        return new RangesByUpperBound<C>(window.intersection());
      } else {
        return ImmutableSortedMap.of();
      }
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> subMap(
        Cut<C> fromKeyboolean fromInclusiveCut<C> toKeyboolean toInclusive) {
      return subMap(Range.range(
          fromKey, BoundType.forBoolean(fromInclusive),
          toKey, BoundType.forBoolean(toInclusive)));
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKeyboolean inclusive) {
      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKeyboolean inclusive) {
      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
    }
    @Override
    public Comparator<? super Cut<C>> comparator() {
      return Ordering.<Cut<C>>natural();
    }
    @Override
    public boolean containsKey(@Nullable Object key) {
      return get(key) != null;
    }
    @Override
    public Range<C> get(@Nullable Object key) {
      if (key instanceof Cut) {
        try {
          @SuppressWarnings("unchecked"// we catch CCEs
          Cut<C> cut = (Cut<C>) key;
          if (!.contains(cut)) {
            return null;
          }
          Entry<Cut<C>, Range<C>> candidate = .lowerEntry(cut);
          if (candidate != null && candidate.getValue()..equals(cut)) {
            return candidate.getValue();
          }
        } catch (ClassCastException e) {
          return null;
        }
      }
      return null;
    }
    @Override
    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
      /*
       * We want to start the iteration at the first range where the upper bound is in
       * upperBoundWindow.
       */
      final Iterator<Range<C>> backingItr;
      if (!.hasLowerBound()) {
        backingItr = .values().iterator();
      } else {
        Entry<Cut<C>, Range<C>> lowerEntry =
        if (lowerEntry == null) {
          backingItr = .values().iterator();
        } else if (..isLessThan(lowerEntry.getValue().)) {
          backingItr = .tailMap(lowerEntry.getKey(), true).values().iterator();
        } else {
          backingItr = .tailMap(.lowerEndpoint(), true)
              .values().iterator();
        }
      }
      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
        @Override
        protected Entry<Cut<C>, Range<C>> computeNext() {
          if (!backingItr.hasNext()) {
            return endOfData();
          }
          Range<C> range = backingItr.next();
          if (..isLessThan(range.upperBound)) {
            return endOfData();
          } else {
            return Maps.immutableEntry(range.upperBoundrange);
          }
        }
      };
    }
    @Override
      Collection<Range<C>> candidates;
      if (.hasUpperBound()) {
        candidates = .headMap(.upperEndpoint(), false)
            .descendingMap().values();
      } else {
        candidates = .descendingMap().values();
      }
      final PeekingIterator<Range<C>> backingItr = Iterators.peekingIterator(candidates.iterator());
      if (backingItr.hasNext()
          && ..isLessThan(backingItr.peek().)) {
        backingItr.next();
      }
      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
        @Override
        protected Entry<Cut<C>, Range<C>> computeNext() {
          if (!backingItr.hasNext()) {
            return endOfData();
          }
          Range<C> range = backingItr.next();
          return ..isLessThan(range.upperBound
              ? Maps.immutableEntry(range.upperBoundrange)
              : endOfData();
        }
      };
    }
    @Override
    public int size() {
      if (.equals(Range.all())) {
        return .size();
      }
      return Iterators.size(entryIterator());
    }
    
    @Override
    public boolean isEmpty() {
      return .equals(Range.all())
          ? .isEmpty()
          : !entryIterator().hasNext();
    }
  }
  
  private static final class ComplementRangesByLowerBound<C extends Comparable<?>>
      extends AbstractNavigableMap<Cut<C>, Range<C>> {
    private final NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound;
    private final NavigableMap<Cut<C>, Range<C>> positiveRangesByUpperBound;
    
    
complementLowerBoundWindow represents the headMap/subMap/tailMap view of the entire "complement ranges by lower bound" map; it's a constraint on the *keys*, and does not affect the values.
    private final Range<Cut<C>> complementLowerBoundWindow;
    
    ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound) {
      this(positiveRangesByLowerBound, Range.<Cut<C>>all());
    }
    private ComplementRangesByLowerBound(NavigableMap<Cut<C>, Range<C>> positiveRangesByLowerBound,
        Range<Cut<C>> window) {
      this. = positiveRangesByLowerBound;
      this. = new RangesByUpperBound<C>(positiveRangesByLowerBound);
      this. = window;
    }
    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> subWindow) {
      if (!.isConnected(subWindow)) {
        return ImmutableSortedMap.of(); 
      } else {
        subWindow = subWindow.intersection();
        return new ComplementRangesByLowerBound<C>(subWindow);
      }
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> subMap(
        Cut<C> fromKeyboolean fromInclusiveCut<C> toKeyboolean toInclusive) {
      return subMap(Range.range(
          fromKey, BoundType.forBoolean(fromInclusive),
          toKey, BoundType.forBoolean(toInclusive)));
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKeyboolean inclusive) {
      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKeyboolean inclusive) {
      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
    }
    @Override
    public Comparator<? super Cut<C>> comparator() {
      return Ordering.<Cut<C>>natural();
    }
    @Override
    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
      /*
       * firstComplementRangeLowerBound is the first complement range lower bound inside
       * complementLowerBoundWindow. Complement range lower bounds are either positive range upper
       * bounds, or Cut.belowAll().
       *
       * positiveItr starts at the first positive range with lower bound greater than
       * firstComplementRangeLowerBound. (Positive range lower bounds correspond to complement range
       * upper bounds.)
       */
      Collection<Range<C>> positiveRanges;
        positiveRanges = .tailMap(
            .lowerEndpoint(),
      } else {
        positiveRanges = .values();
      }
      final PeekingIterator<Range<C>> positiveItr = Iterators.peekingIterator(
          positiveRanges.iterator());
      final Cut<C> firstComplementRangeLowerBound;
      if (.contains(Cut.<C>belowAll()) && 
          (!positiveItr.hasNext() || positiveItr.peek(). != Cut.<C>belowAll())) {
        firstComplementRangeLowerBound = Cut.belowAll();
      } else if (positiveItr.hasNext()) {
        firstComplementRangeLowerBound = positiveItr.next().;
      } else {
        return Iterators.emptyIterator();
      }
      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
        Cut<C> nextComplementRangeLowerBound = firstComplementRangeLowerBound;
        @Override
        protected Entry<Cut<C>, Range<C>> computeNext() {
              ||  == Cut.<C>aboveAll()) {
            return endOfData();
          }
          Range<C> negativeRange;
          if (positiveItr.hasNext()) {
            Range<C> positiveRange = positiveItr.next();
            negativeRange = Range.create(positiveRange.lowerBound);
             = positiveRange.upperBound;
          } else {
            negativeRange = Range.create(, Cut.<C>aboveAll());
             = Cut.aboveAll();
          }
          return Maps.immutableEntry(negativeRange.lowerBoundnegativeRange);
        }
      };
    }
    @Override
      Iterator<Range<C>> itr;
      /*
       * firstComplementRangeUpperBound is the upper bound of the last complement range with lower
       * bound inside complementLowerBoundWindow.
       *
       * positiveItr starts at the first positive range with upper bound less than
       * firstComplementRangeUpperBound. (Positive range upper bounds correspond to complement range
       * lower bounds.)
       */
      Cut<C> startingPoint = .hasUpperBound()
          : Cut.<C>aboveAll();
      boolean inclusive = .hasUpperBound()
      final PeekingIterator<Range<C>> positiveItr =
          Iterators.peekingIterator(.headMap(startingPointinclusive)
              .descendingMap().values().iterator());
      Cut<C> cut;
      if (positiveItr.hasNext()) {
        cut = (positiveItr.peek(). == Cut.<C>aboveAll()) 
            ? positiveItr.next(). 
            : .higherKey(positiveItr.peek().);
      } else if (!.contains(Cut.<C>belowAll())
          || .containsKey(Cut.belowAll())) {
        return Iterators.emptyIterator();
      } else {
        cut = .higherKey(Cut.<C>belowAll());
      }
      final Cut<C> firstComplementRangeUpperBound = Objects.firstNonNull(cut, Cut.<C>aboveAll());
      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
        Cut<C> nextComplementRangeUpperBound = firstComplementRangeUpperBound;
        @Override
        protected Entry<Cut<C>, Range<C>> computeNext() {
          if ( == Cut.<C>belowAll()) {
            return endOfData();
          } else if (positiveItr.hasNext()) {
            Range<C> positiveRange = positiveItr.next();
            Range<C> negativeRange =
                Range.create(positiveRange.upperBound);
             = positiveRange.lowerBound;
            if (..isLessThan(negativeRange.lowerBound)) {
              return Maps.immutableEntry(negativeRange.lowerBoundnegativeRange);
            }
          } else if (..isLessThan(Cut.<C>belowAll())) {
            Range<C> negativeRange =
                Range.create(Cut.<C>belowAll(), );
             = Cut.belowAll();
            return Maps.immutableEntry(Cut.<C>belowAll(), negativeRange);
          }
          return endOfData();
        }
      };
    }
    @Override
    public int size() {
      return Iterators.size(entryIterator());
    }
    @Override
    @Nullable
    public Range<C> get(Object key) {
      if (key instanceof Cut) {
        try {
          @SuppressWarnings("unchecked")
          Cut<C> cut = (Cut<C>) key;
          // tailMap respects the current window
          Entry<Cut<C>, Range<C>> firstEntry = tailMap(cuttrue).firstEntry();
          if (firstEntry != null && firstEntry.getKey().equals(cut)) {
            return firstEntry.getValue();
          }
        } catch (ClassCastException e) {
          return null;
        }
      }
      return null;
    }
    @Override
    public boolean containsKey(Object key) {
      return get(key) != null;
    }
  }
  private final class Complement extends TreeRangeSet<C> {
    Complement() {
    }
    @Override
    public void add(Range<C> rangeToAdd) {
      TreeRangeSet.this.remove(rangeToAdd);
    }
    @Override
    public void remove(Range<C> rangeToRemove) {
      TreeRangeSet.this.add(rangeToRemove);
    }
    @Override
    public boolean contains(C value) {
      return !TreeRangeSet.this.contains(value);
    }
    
    @Override
    public RangeSet<C> complement() {
      return TreeRangeSet.this;
    }
  }
  private static final class SubRangeSetRangesByLowerBound<C extends Comparable<?>>
      extends AbstractNavigableMap<Cut<C>, Range<C>> {
    
lowerBoundWindow is the headMap/subMap/tailMap view; it only restricts the keys, and does not affect the values.
    private final Range<Cut<C>> lowerBoundWindow;

    
restriction is the subRangeSet view; ranges are truncated to their intersection with restriction.
    private final Range<C> restriction;
    private final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound;
    private final NavigableMap<Cut<C>, Range<C>> rangesByUpperBound;
    private SubRangeSetRangesByLowerBound(Range<Cut<C>> lowerBoundWindowRange<C> restriction,
        NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) {
      this. = checkNotNull(lowerBoundWindow);
      this. = checkNotNull(restriction);
      this. = checkNotNull(rangesByLowerBound);
      this. = new RangesByUpperBound<C>(rangesByLowerBound);
    }
    private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) {
      if (!window.isConnected()) {
        return ImmutableSortedMap.of();
      } else {
        return new SubRangeSetRangesByLowerBound<C>(
            .intersection(window), );
      }
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> subMap(
        Cut<C> fromKeyboolean fromInclusiveCut<C> toKeyboolean toInclusive) {
      return subMap(Range.range(
          fromKey, BoundType.forBoolean(fromInclusive), toKey, BoundType.forBoolean(toInclusive)));
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKeyboolean inclusive) {
      return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
    }
    @Override
    public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKeyboolean inclusive) {
      return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
    }
    @Override
    public Comparator<? super Cut<C>> comparator() {
      return Ordering.<Cut<C>>natural();
    }
    @Override
    public boolean containsKey(@Nullable Object key) {
      return get(key) != null;
    }
    @Override
    @Nullable
    public Range<C> get(@Nullable Object key) {
      if (key instanceof Cut) {
        try {
          @SuppressWarnings("unchecked"// we catch CCE's
          Cut<C> cut = (Cut<C>) key;
          if (!.contains(cut) || cut.compareTo(.) < 0
              || cut.compareTo(.) >= 0) {
            return null;
          } else if (cut.equals(.)) {
            // it might be present, truncated on the left
            Range<C> candidate = Maps.valueOrNull(.floorEntry(cut));
            if (candidate != null && candidate.upperBound.compareTo(.) > 0) {
              return candidate.intersection();
            }
          } else {
            Range<C> result = .get(cut);
            if (result != null) {
              return result.intersection();
            }
          }
        } catch (ClassCastException e) {
          return null;
        }
      }
      return null;
    }
    @Override
    Iterator<Entry<Cut<C>, Range<C>>> entryIterator() {
      if (.isEmpty()) {
        return Iterators.emptyIterator();
      }
      final Iterator<Range<C>> completeRangeItr;
        return Iterators.emptyIterator();
        // starts at the first range with upper bound strictly greater than restriction.lowerBound
        completeRangeItr =
            .tailMap(.false).values().iterator();
      } else {
        // starts at the first range with lower bound above lowerBoundWindow.lowerBound
        completeRangeItr = .tailMap(..endpoint(),
            .lowerBoundType() == .).values().iterator();
      }
      final Cut<Cut<C>> upperBoundOnLowerBounds = Ordering.natural()
      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
        @Override
        protected Entry<Cut<C>, Range<C>> computeNext() {
          if (!completeRangeItr.hasNext()) {
            return endOfData();
          }
          Range<C> nextRange = completeRangeItr.next();
          if (upperBoundOnLowerBounds.isLessThan(nextRange.lowerBound)) {
            return endOfData();
          } else {
            nextRange = nextRange.intersection();
            return Maps.immutableEntry(nextRange.lowerBoundnextRange);
          }
        }
      };
    }
    @Override
      if (.isEmpty()) {
        return Iterators.emptyIterator();
      }
      Cut<Cut<C>> upperBoundOnLowerBounds = Ordering.natural()
      final Iterator<Range<C>> completeRangeItr = .headMap(
          upperBoundOnLowerBounds.endpoint(),
          upperBoundOnLowerBounds.typeAsUpperBound() == .)
          .descendingMap().values().iterator();
      return new AbstractIterator<Entry<Cut<C>, Range<C>>>() {
        @Override
        protected Entry<Cut<C>, Range<C>> computeNext() {
          if (!completeRangeItr.hasNext()) {
            return endOfData();
          }
          Range<C> nextRange = completeRangeItr.next();
          if (..compareTo(nextRange.upperBound) >= 0) {
            return endOfData();
          }
          nextRange = nextRange.intersection();
          if (.contains(nextRange.lowerBound)) {
            return Maps.immutableEntry(nextRange.lowerBoundnextRange);
          } else {
            return endOfData();
          }
        }
      };
    }
    @Override
    public int size() {
      return Iterators.size(entryIterator());
    }
  }
  
  public RangeSet<C> subRangeSet(Range<C> view) {
    return view.equals(Range.<C>all()) ? this : new SubRangeSet(view);
  }
  
  private final class SubRangeSet extends TreeRangeSet<C> {
    private final Range<C> restriction;
    SubRangeSet(Range<C> restriction) {
      super(new SubRangeSetRangesByLowerBound<C>(
          Range.<Cut<C>>all(), restrictionTreeRangeSet.this.));
      this. = restriction;
    }
    @Override
    public boolean encloses(Range<C> range) {
      if (!.isEmpty() && .encloses(range)) {
        Range<C> enclosing = TreeRangeSet.this.rangeEnclosing(range);
        return enclosing != null && !enclosing.intersection().isEmpty();
      }
      return false;
    }
    @Override
    @Nullable
    public Range<C> rangeContaining(C value) {
      if (!.contains(value)) {
        return null;
      }
      Range<C> result = TreeRangeSet.this.rangeContaining(value);
      return (result == null) ? null : result.intersection();
    }
    @Override
    public void add(Range<C> rangeToAdd) {
      checkArgument(.encloses(rangeToAdd), "Cannot add range %s to subRangeSet(%s)",
          rangeToAdd);
      super.add(rangeToAdd);
    }
    @Override
    public void remove(Range<C> rangeToRemove) {
      if (rangeToRemove.isConnected()) {
        TreeRangeSet.this.remove(rangeToRemove.intersection());
      }
    }
    @Override
    public boolean contains(C value) {
      return .contains(value) && TreeRangeSet.this.contains(value);
    }
    @Override
    public void clear() {
    }
    @Override
    public RangeSet<C> subRangeSet(Range<C> view) {
      if (view.encloses()) {
        return this;
      } else if (view.isConnected()) {
        return new SubRangeSet(.intersection(view));
      } else {
        return ImmutableRangeSet.of();
      }
    }
  }