org.weakref.jmx.internal.guava.collect.TreeRangeSet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmxutils Show documentation
Show all versions of jmxutils Show documentation
Exporting JMX mbeans made easy
/*
* 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 org.weakref.jmx.internal.guava.collect;
import static org.weakref.jmx.internal.guava.base.Preconditions.checkArgument;
import static org.weakref.jmx.internal.guava.base.Preconditions.checkNotNull;
import org.weakref.jmx.internal.guava.annotations.Beta;
import org.weakref.jmx.internal.guava.annotations.GwtIncompatible;
import org.weakref.jmx.internal.guava.annotations.VisibleForTesting;
import org.weakref.jmx.internal.guava.base.Objects;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;
import javax.annotation.Nullable;
/**
* An implementation of {@link RangeSet} backed by a {@link TreeMap}.
*
* @author Louis Wasserman
* @since 14.0
*/
@Beta
@GwtIncompatible("uses NavigableMap")
public class TreeRangeSet>
extends AbstractRangeSet {
@VisibleForTesting
final NavigableMap, Range> rangesByLowerBound;
/**
* Creates an empty {@code TreeRangeSet} instance.
*/
public static > TreeRangeSet create() {
return new TreeRangeSet(new TreeMap, Range>());
}
/**
* Returns a {@code TreeRangeSet} initialized with the ranges in the specified range set.
*/
public static > TreeRangeSet create(RangeSet rangeSet) {
TreeRangeSet result = create();
result.addAll(rangeSet);
return result;
}
private TreeRangeSet(NavigableMap, Range> rangesByLowerCut) {
this.rangesByLowerBound = rangesByLowerCut;
}
private transient Set> asRanges;
@Override
public Set> asRanges() {
Set> result = asRanges;
return (result == null) ? asRanges = new AsRanges() : result;
}
final class AsRanges extends ForwardingCollection> implements Set> {
@Override
protected Collection> delegate() {
return rangesByLowerBound.values();
}
@Override
public int hashCode() {
return Sets.hashCodeImpl(this);
}
@Override
public boolean equals(@Nullable Object o) {
return Sets.equalsImpl(this, o);
}
}
@Override
@Nullable
public Range rangeContaining(C value) {
checkNotNull(value);
Entry, Range> floorEntry = rangesByLowerBound.floorEntry(Cut.belowValue(value));
if (floorEntry != null && floorEntry.getValue().contains(value)) {
return floorEntry.getValue();
} else {
// TODO(kevinb): revisit this design choice
return null;
}
}
@Override
public boolean encloses(Range range) {
checkNotNull(range);
Entry, Range> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
return floorEntry != null && floorEntry.getValue().encloses(range);
}
@Nullable
private Range rangeEnclosing(Range range) {
checkNotNull(range);
Entry, Range> floorEntry = rangesByLowerBound.floorEntry(range.lowerBound);
return (floorEntry != null && floorEntry.getValue().encloses(range))
? floorEntry.getValue()
: null;
}
@Override
public Range span() {
Entry, Range> firstEntry = rangesByLowerBound.firstEntry();
Entry, Range> lastEntry = rangesByLowerBound.lastEntry();
if (firstEntry == null) {
throw new NoSuchElementException();
}
return Range.create(firstEntry.getValue().lowerBound, lastEntry.getValue().upperBound);
}
@Override
public void add(Range rangeToAdd) {
checkNotNull(rangeToAdd);
if (rangeToAdd.isEmpty()) {
return;
}
// We will use { } to illustrate ranges currently in the range set, and < >
// to illustrate rangeToAdd.
Cut lbToAdd = rangeToAdd.lowerBound;
Cut ubToAdd = rangeToAdd.upperBound;
Entry, Range> entryBelowLB = rangesByLowerBound.lowerEntry(lbToAdd);
if (entryBelowLB != null) {
// { <
Range 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, Range> entryBelowUB = rangesByLowerBound.floorEntry(ubToAdd);
if (entryBelowUB != null) {
// { >
Range rangeBelowUB = entryBelowUB.getValue();
if (rangeBelowUB.upperBound.compareTo(ubToAdd) >= 0) {
// { > }, and we need to coalesce
ubToAdd = rangeBelowUB.upperBound;
}
}
// Remove ranges which are strictly enclosed.
rangesByLowerBound.subMap(lbToAdd, ubToAdd).clear();
replaceRangeWithSameLowerBound(Range.create(lbToAdd, ubToAdd));
}
@Override
public void remove(Range rangeToRemove) {
checkNotNull(rangeToRemove);
if (rangeToRemove.isEmpty()) {
return;
}
// We will use { } to illustrate ranges currently in the range set, and < >
// to illustrate rangeToRemove.
Entry, Range> entryBelowLB = rangesByLowerBound.lowerEntry(rangeToRemove.lowerBound);
if (entryBelowLB != null) {
// { <
Range 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) {
// { < > }
replaceRangeWithSameLowerBound(
Range.create(rangeToRemove.upperBound, rangeBelowLB.upperBound));
}
replaceRangeWithSameLowerBound(
Range.create(rangeBelowLB.lowerBound, rangeToRemove.lowerBound));
}
}
Entry, Range> entryBelowUB = rangesByLowerBound.floorEntry(rangeToRemove.upperBound);
if (entryBelowUB != null) {
// { >
Range rangeBelowUB = entryBelowUB.getValue();
if (rangeToRemove.hasUpperBound()
&& rangeBelowUB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
// { > }
replaceRangeWithSameLowerBound(
Range.create(rangeToRemove.upperBound, rangeBelowUB.upperBound));
}
}
rangesByLowerBound.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear();
}
private void replaceRangeWithSameLowerBound(Range range) {
if (range.isEmpty()) {
rangesByLowerBound.remove(range.lowerBound);
} else {
rangesByLowerBound.put(range.lowerBound, range);
}
}
private transient RangeSet complement;
@Override
public RangeSet complement() {
RangeSet result = complement;
return (result == null) ? complement = new Complement() : result;
}
@VisibleForTesting
static final class RangesByUpperBound>
extends AbstractNavigableMap, Range> {
private final NavigableMap, Range> 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> upperBoundWindow;
RangesByUpperBound(NavigableMap, Range> rangesByLowerBound) {
this.rangesByLowerBound = rangesByLowerBound;
this.upperBoundWindow = Range.all();
}
private RangesByUpperBound(
NavigableMap, Range> rangesByLowerBound, Range> upperBoundWindow) {
this.rangesByLowerBound = rangesByLowerBound;
this.upperBoundWindow = upperBoundWindow;
}
private NavigableMap, Range> subMap(Range> window) {
if (window.isConnected(upperBoundWindow)) {
return new RangesByUpperBound(rangesByLowerBound, window.intersection(upperBoundWindow));
} else {
return ImmutableSortedMap.of();
}
}
@Override
public NavigableMap, Range> subMap(
Cut fromKey, boolean fromInclusive, Cut toKey, boolean toInclusive) {
return subMap(Range.range(
fromKey, BoundType.forBoolean(fromInclusive),
toKey, BoundType.forBoolean(toInclusive)));
}
@Override
public NavigableMap, Range> headMap(Cut toKey, boolean inclusive) {
return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
}
@Override
public NavigableMap, Range> tailMap(Cut fromKey, boolean inclusive) {
return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
}
@Override
public Comparator super Cut> comparator() {
return Ordering.>natural();
}
@Override
public boolean containsKey(@Nullable Object key) {
return get(key) != null;
}
@Override
public Range get(@Nullable Object key) {
if (key instanceof Cut) {
try {
@SuppressWarnings("unchecked") // we catch CCEs
Cut cut = (Cut) key;
if (!upperBoundWindow.contains(cut)) {
return null;
}
Entry, Range> candidate = rangesByLowerBound.lowerEntry(cut);
if (candidate != null && candidate.getValue().upperBound.equals(cut)) {
return candidate.getValue();
}
} catch (ClassCastException e) {
return null;
}
}
return null;
}
@Override
Iterator, Range>> entryIterator() {
/*
* We want to start the iteration at the first range where the upper bound is in
* upperBoundWindow.
*/
final Iterator> backingItr;
if (!upperBoundWindow.hasLowerBound()) {
backingItr = rangesByLowerBound.values().iterator();
} else {
Entry, Range> lowerEntry =
rangesByLowerBound.lowerEntry(upperBoundWindow.lowerEndpoint());
if (lowerEntry == null) {
backingItr = rangesByLowerBound.values().iterator();
} else if (upperBoundWindow.lowerBound.isLessThan(lowerEntry.getValue().upperBound)) {
backingItr = rangesByLowerBound.tailMap(lowerEntry.getKey(), true).values().iterator();
} else {
backingItr = rangesByLowerBound.tailMap(upperBoundWindow.lowerEndpoint(), true)
.values().iterator();
}
}
return new AbstractIterator, Range>>() {
@Override
protected Entry, Range> computeNext() {
if (!backingItr.hasNext()) {
return endOfData();
}
Range range = backingItr.next();
if (upperBoundWindow.upperBound.isLessThan(range.upperBound)) {
return endOfData();
} else {
return Maps.immutableEntry(range.upperBound, range);
}
}
};
}
@Override
Iterator, Range>> descendingEntryIterator() {
Collection> candidates;
if (upperBoundWindow.hasUpperBound()) {
candidates = rangesByLowerBound.headMap(upperBoundWindow.upperEndpoint(), false)
.descendingMap().values();
} else {
candidates = rangesByLowerBound.descendingMap().values();
}
final PeekingIterator> backingItr = Iterators.peekingIterator(candidates.iterator());
if (backingItr.hasNext()
&& upperBoundWindow.upperBound.isLessThan(backingItr.peek().upperBound)) {
backingItr.next();
}
return new AbstractIterator, Range>>() {
@Override
protected Entry, Range> computeNext() {
if (!backingItr.hasNext()) {
return endOfData();
}
Range range = backingItr.next();
return upperBoundWindow.lowerBound.isLessThan(range.upperBound)
? Maps.immutableEntry(range.upperBound, range)
: endOfData();
}
};
}
@Override
public int size() {
if (upperBoundWindow.equals(Range.all())) {
return rangesByLowerBound.size();
}
return Iterators.size(entryIterator());
}
@Override
public boolean isEmpty() {
return upperBoundWindow.equals(Range.all())
? rangesByLowerBound.isEmpty()
: !entryIterator().hasNext();
}
}
private static final class ComplementRangesByLowerBound>
extends AbstractNavigableMap, Range> {
private final NavigableMap, Range> positiveRangesByLowerBound;
private final NavigableMap, Range> 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> complementLowerBoundWindow;
ComplementRangesByLowerBound(NavigableMap, Range> positiveRangesByLowerBound) {
this(positiveRangesByLowerBound, Range.>all());
}
private ComplementRangesByLowerBound(NavigableMap, Range> positiveRangesByLowerBound,
Range> window) {
this.positiveRangesByLowerBound = positiveRangesByLowerBound;
this.positiveRangesByUpperBound = new RangesByUpperBound(positiveRangesByLowerBound);
this.complementLowerBoundWindow = window;
}
private NavigableMap, Range> subMap(Range> subWindow) {
if (!complementLowerBoundWindow.isConnected(subWindow)) {
return ImmutableSortedMap.of();
} else {
subWindow = subWindow.intersection(complementLowerBoundWindow);
return new ComplementRangesByLowerBound(positiveRangesByLowerBound, subWindow);
}
}
@Override
public NavigableMap, Range> subMap(
Cut fromKey, boolean fromInclusive, Cut toKey, boolean toInclusive) {
return subMap(Range.range(
fromKey, BoundType.forBoolean(fromInclusive),
toKey, BoundType.forBoolean(toInclusive)));
}
@Override
public NavigableMap, Range> headMap(Cut toKey, boolean inclusive) {
return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
}
@Override
public NavigableMap, Range> tailMap(Cut fromKey, boolean inclusive) {
return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
}
@Override
public Comparator super Cut> comparator() {
return Ordering.>natural();
}
@Override
Iterator, Range>> 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> positiveRanges;
if (complementLowerBoundWindow.hasLowerBound()) {
positiveRanges = positiveRangesByUpperBound.tailMap(
complementLowerBoundWindow.lowerEndpoint(),
complementLowerBoundWindow.lowerBoundType() == BoundType.CLOSED).values();
} else {
positiveRanges = positiveRangesByUpperBound.values();
}
final PeekingIterator> positiveItr = Iterators.peekingIterator(
positiveRanges.iterator());
final Cut firstComplementRangeLowerBound;
if (complementLowerBoundWindow.contains(Cut.belowAll()) &&
(!positiveItr.hasNext() || positiveItr.peek().lowerBound != Cut.belowAll())) {
firstComplementRangeLowerBound = Cut.belowAll();
} else if (positiveItr.hasNext()) {
firstComplementRangeLowerBound = positiveItr.next().upperBound;
} else {
return Iterators.emptyIterator();
}
return new AbstractIterator, Range>>() {
Cut nextComplementRangeLowerBound = firstComplementRangeLowerBound;
@Override
protected Entry, Range> computeNext() {
if (complementLowerBoundWindow.upperBound.isLessThan(nextComplementRangeLowerBound)
|| nextComplementRangeLowerBound == Cut.aboveAll()) {
return endOfData();
}
Range negativeRange;
if (positiveItr.hasNext()) {
Range positiveRange = positiveItr.next();
negativeRange = Range.create(nextComplementRangeLowerBound, positiveRange.lowerBound);
nextComplementRangeLowerBound = positiveRange.upperBound;
} else {
negativeRange = Range.create(nextComplementRangeLowerBound, Cut.aboveAll());
nextComplementRangeLowerBound = Cut.aboveAll();
}
return Maps.immutableEntry(negativeRange.lowerBound, negativeRange);
}
};
}
@Override
Iterator, Range>> descendingEntryIterator() {
Iterator> 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 startingPoint = complementLowerBoundWindow.hasUpperBound()
? complementLowerBoundWindow.upperEndpoint()
: Cut.aboveAll();
boolean inclusive = complementLowerBoundWindow.hasUpperBound()
&& complementLowerBoundWindow.upperBoundType() == BoundType.CLOSED;
final PeekingIterator> positiveItr =
Iterators.peekingIterator(positiveRangesByUpperBound.headMap(startingPoint, inclusive)
.descendingMap().values().iterator());
Cut cut;
if (positiveItr.hasNext()) {
cut = (positiveItr.peek().upperBound == Cut.aboveAll())
? positiveItr.next().lowerBound
: positiveRangesByLowerBound.higherKey(positiveItr.peek().upperBound);
} else if (!complementLowerBoundWindow.contains(Cut.belowAll())
|| positiveRangesByLowerBound.containsKey(Cut.belowAll())) {
return Iterators.emptyIterator();
} else {
cut = positiveRangesByLowerBound.higherKey(Cut.belowAll());
}
final Cut firstComplementRangeUpperBound = Objects.firstNonNull(cut, Cut.aboveAll());
return new AbstractIterator, Range>>() {
Cut nextComplementRangeUpperBound = firstComplementRangeUpperBound;
@Override
protected Entry, Range> computeNext() {
if (nextComplementRangeUpperBound == Cut.belowAll()) {
return endOfData();
} else if (positiveItr.hasNext()) {
Range positiveRange = positiveItr.next();
Range negativeRange =
Range.create(positiveRange.upperBound, nextComplementRangeUpperBound);
nextComplementRangeUpperBound = positiveRange.lowerBound;
if (complementLowerBoundWindow.lowerBound.isLessThan(negativeRange.lowerBound)) {
return Maps.immutableEntry(negativeRange.lowerBound, negativeRange);
}
} else if (complementLowerBoundWindow.lowerBound.isLessThan(Cut.belowAll())) {
Range negativeRange =
Range.create(Cut.belowAll(), nextComplementRangeUpperBound);
nextComplementRangeUpperBound = Cut.belowAll();
return Maps.immutableEntry(Cut.belowAll(), negativeRange);
}
return endOfData();
}
};
}
@Override
public int size() {
return Iterators.size(entryIterator());
}
@Override
@Nullable
public Range get(Object key) {
if (key instanceof Cut) {
try {
@SuppressWarnings("unchecked")
Cut cut = (Cut) key;
// tailMap respects the current window
Entry, Range> firstEntry = tailMap(cut, true).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 {
Complement() {
super(new ComplementRangesByLowerBound(TreeRangeSet.this.rangesByLowerBound));
}
@Override
public void add(Range rangeToAdd) {
TreeRangeSet.this.remove(rangeToAdd);
}
@Override
public void remove(Range rangeToRemove) {
TreeRangeSet.this.add(rangeToRemove);
}
@Override
public boolean contains(C value) {
return !TreeRangeSet.this.contains(value);
}
@Override
public RangeSet complement() {
return TreeRangeSet.this;
}
}
private static final class SubRangeSetRangesByLowerBound>
extends AbstractNavigableMap, Range> {
/**
* lowerBoundWindow is the headMap/subMap/tailMap view; it only restricts the keys, and does not
* affect the values.
*/
private final Range> lowerBoundWindow;
/**
* restriction is the subRangeSet view; ranges are truncated to their intersection with
* restriction.
*/
private final Range restriction;
private final NavigableMap, Range> rangesByLowerBound;
private final NavigableMap, Range> rangesByUpperBound;
private SubRangeSetRangesByLowerBound(Range> lowerBoundWindow, Range restriction,
NavigableMap, Range> rangesByLowerBound) {
this.lowerBoundWindow = checkNotNull(lowerBoundWindow);
this.restriction = checkNotNull(restriction);
this.rangesByLowerBound = checkNotNull(rangesByLowerBound);
this.rangesByUpperBound = new RangesByUpperBound(rangesByLowerBound);
}
private NavigableMap, Range> subMap(Range> window) {
if (!window.isConnected(lowerBoundWindow)) {
return ImmutableSortedMap.of();
} else {
return new SubRangeSetRangesByLowerBound(
lowerBoundWindow.intersection(window), restriction, rangesByLowerBound);
}
}
@Override
public NavigableMap, Range> subMap(
Cut fromKey, boolean fromInclusive, Cut toKey, boolean toInclusive) {
return subMap(Range.range(
fromKey, BoundType.forBoolean(fromInclusive), toKey, BoundType.forBoolean(toInclusive)));
}
@Override
public NavigableMap, Range> headMap(Cut toKey, boolean inclusive) {
return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive)));
}
@Override
public NavigableMap, Range> tailMap(Cut fromKey, boolean inclusive) {
return subMap(Range.downTo(fromKey, BoundType.forBoolean(inclusive)));
}
@Override
public Comparator super Cut> comparator() {
return Ordering.>natural();
}
@Override
public boolean containsKey(@Nullable Object key) {
return get(key) != null;
}
@Override
@Nullable
public Range get(@Nullable Object key) {
if (key instanceof Cut) {
try {
@SuppressWarnings("unchecked") // we catch CCE's
Cut cut = (Cut) key;
if (!lowerBoundWindow.contains(cut) || cut.compareTo(restriction.lowerBound) < 0
|| cut.compareTo(restriction.upperBound) >= 0) {
return null;
} else if (cut.equals(restriction.lowerBound)) {
// it might be present, truncated on the left
Range candidate = Maps.valueOrNull(rangesByLowerBound.floorEntry(cut));
if (candidate != null && candidate.upperBound.compareTo(restriction.lowerBound) > 0) {
return candidate.intersection(restriction);
}
} else {
Range result = rangesByLowerBound.get(cut);
if (result != null) {
return result.intersection(restriction);
}
}
} catch (ClassCastException e) {
return null;
}
}
return null;
}
@Override
Iterator, Range>> entryIterator() {
if (restriction.isEmpty()) {
return Iterators.emptyIterator();
}
final Iterator> completeRangeItr;
if (lowerBoundWindow.upperBound.isLessThan(restriction.lowerBound)) {
return Iterators.emptyIterator();
} else if (lowerBoundWindow.lowerBound.isLessThan(restriction.lowerBound)) {
// starts at the first range with upper bound strictly greater than restriction.lowerBound
completeRangeItr =
rangesByUpperBound.tailMap(restriction.lowerBound, false).values().iterator();
} else {
// starts at the first range with lower bound above lowerBoundWindow.lowerBound
completeRangeItr = rangesByLowerBound.tailMap(lowerBoundWindow.lowerBound.endpoint(),
lowerBoundWindow.lowerBoundType() == BoundType.CLOSED).values().iterator();
}
final Cut> upperBoundOnLowerBounds = Ordering.natural()
.min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
return new AbstractIterator, Range>>() {
@Override
protected Entry, Range> computeNext() {
if (!completeRangeItr.hasNext()) {
return endOfData();
}
Range nextRange = completeRangeItr.next();
if (upperBoundOnLowerBounds.isLessThan(nextRange.lowerBound)) {
return endOfData();
} else {
nextRange = nextRange.intersection(restriction);
return Maps.immutableEntry(nextRange.lowerBound, nextRange);
}
}
};
}
@Override
Iterator, Range>> descendingEntryIterator() {
if (restriction.isEmpty()) {
return Iterators.emptyIterator();
}
Cut> upperBoundOnLowerBounds = Ordering.natural()
.min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound));
final Iterator> completeRangeItr = rangesByLowerBound.headMap(
upperBoundOnLowerBounds.endpoint(),
upperBoundOnLowerBounds.typeAsUpperBound() == BoundType.CLOSED)
.descendingMap().values().iterator();
return new AbstractIterator, Range>>() {
@Override
protected Entry, Range> computeNext() {
if (!completeRangeItr.hasNext()) {
return endOfData();
}
Range nextRange = completeRangeItr.next();
if (restriction.lowerBound.compareTo(nextRange.upperBound) >= 0) {
return endOfData();
}
nextRange = nextRange.intersection(restriction);
if (lowerBoundWindow.contains(nextRange.lowerBound)) {
return Maps.immutableEntry(nextRange.lowerBound, nextRange);
} else {
return endOfData();
}
}
};
}
@Override
public int size() {
return Iterators.size(entryIterator());
}
}
@Override
public RangeSet subRangeSet(Range view) {
return view.equals(Range.all()) ? this : new SubRangeSet(view);
}
private final class SubRangeSet extends TreeRangeSet {
private final Range restriction;
SubRangeSet(Range restriction) {
super(new SubRangeSetRangesByLowerBound(
Range.>all(), restriction, TreeRangeSet.this.rangesByLowerBound));
this.restriction = restriction;
}
@Override
public boolean encloses(Range range) {
if (!restriction.isEmpty() && restriction.encloses(range)) {
Range enclosing = TreeRangeSet.this.rangeEnclosing(range);
return enclosing != null && !enclosing.intersection(restriction).isEmpty();
}
return false;
}
@Override
@Nullable
public Range