diff options
Diffstat (limited to 'guava/src/com/google/common/collect/TreeRangeSet.java')
-rw-r--r-- | guava/src/com/google/common/collect/TreeRangeSet.java | 851 |
1 files changed, 0 insertions, 851 deletions
diff --git a/guava/src/com/google/common/collect/TreeRangeSet.java b/guava/src/com/google/common/collect/TreeRangeSet.java deleted file mode 100644 index d67c5f4..0000000 --- a/guava/src/com/google/common/collect/TreeRangeSet.java +++ /dev/null @@ -1,851 +0,0 @@ -/* - * 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 com.google.common.annotations.Beta; -import com.google.common.annotations.GwtIncompatible; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.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<C extends Comparable<?>> - extends AbstractRangeSet<C> { - - @VisibleForTesting - final NavigableMap<Cut<C>, Range<C>> rangesByLowerBound; - - /** - * Creates an empty {@code TreeRangeSet} instance. - */ - public static <C extends Comparable<?>> TreeRangeSet<C> create() { - return new TreeRangeSet<C>(new TreeMap<Cut<C>, Range<C>>()); - } - - /** - * Returns a {@code 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.rangesByLowerBound = rangesByLowerCut; - } - - private transient Set<Range<C>> asRanges; - - @Override - public Set<Range<C>> asRanges() { - Set<Range<C>> result = asRanges; - return (result == null) ? asRanges = new AsRanges() : result; - } - - final class AsRanges extends ForwardingCollection<Range<C>> implements Set<Range<C>> { - @Override - protected Collection<Range<C>> 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<C> rangeContaining(C value) { - checkNotNull(value); - Entry<Cut<C>, Range<C>> 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<C> range) { - checkNotNull(range); - Entry<Cut<C>, Range<C>> floorEntry = rangesByLowerBound.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 = rangesByLowerBound.floorEntry(range.lowerBound); - return (floorEntry != null && floorEntry.getValue().encloses(range)) - ? floorEntry.getValue() - : null; - } - - @Override - public Range<C> span() { - Entry<Cut<C>, Range<C>> firstEntry = rangesByLowerBound.firstEntry(); - Entry<Cut<C>, Range<C>> lastEntry = rangesByLowerBound.lastEntry(); - if (firstEntry == null) { - throw new NoSuchElementException(); - } - return Range.create(firstEntry.getValue().lowerBound, lastEntry.getValue().upperBound); - } - - @Override - 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 = rangesByLowerBound.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 = rangesByLowerBound.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. - rangesByLowerBound.subMap(lbToAdd, ubToAdd).clear(); - - replaceRangeWithSameLowerBound(Range.create(lbToAdd, ubToAdd)); - } - - @Override - 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 = rangesByLowerBound.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) { - // { < > } - replaceRangeWithSameLowerBound( - Range.create(rangeToRemove.upperBound, rangeBelowLB.upperBound)); - } - replaceRangeWithSameLowerBound( - Range.create(rangeBelowLB.lowerBound, rangeToRemove.lowerBound)); - } - } - - Entry<Cut<C>, Range<C>> entryBelowUB = rangesByLowerBound.floorEntry(rangeToRemove.upperBound); - if (entryBelowUB != null) { - // { > - Range<C> 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<C> range) { - if (range.isEmpty()) { - rangesByLowerBound.remove(range.lowerBound); - } else { - rangesByLowerBound.put(range.lowerBound, range); - } - } - - private transient RangeSet<C> complement; - - @Override - public RangeSet<C> complement() { - RangeSet<C> result = complement; - return (result == null) ? complement = new Complement() : result; - } - - @VisibleForTesting - 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 = rangesByLowerBound; - this.upperBoundWindow = Range.all(); - } - - private RangesByUpperBound( - NavigableMap<Cut<C>, Range<C>> rangesByLowerBound, Range<Cut<C>> upperBoundWindow) { - this.rangesByLowerBound = rangesByLowerBound; - this.upperBoundWindow = upperBoundWindow; - } - - private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) { - if (window.isConnected(upperBoundWindow)) { - return new RangesByUpperBound<C>(rangesByLowerBound, window.intersection(upperBoundWindow)); - } else { - return ImmutableSortedMap.of(); - } - } - - @Override - public NavigableMap<Cut<C>, Range<C>> subMap( - Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) { - return subMap(Range.range( - fromKey, BoundType.forBoolean(fromInclusive), - toKey, BoundType.forBoolean(toInclusive))); - } - - @Override - public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) { - return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive))); - } - - @Override - public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean 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 (!upperBoundWindow.contains(cut)) { - return null; - } - Entry<Cut<C>, Range<C>> candidate = rangesByLowerBound.lowerEntry(cut); - if (candidate != null && candidate.getValue().upperBound.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 (!upperBoundWindow.hasLowerBound()) { - backingItr = rangesByLowerBound.values().iterator(); - } else { - Entry<Cut<C>, Range<C>> 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<Entry<Cut<C>, Range<C>>>() { - @Override - protected Entry<Cut<C>, Range<C>> computeNext() { - if (!backingItr.hasNext()) { - return endOfData(); - } - Range<C> range = backingItr.next(); - if (upperBoundWindow.upperBound.isLessThan(range.upperBound)) { - return endOfData(); - } else { - return Maps.immutableEntry(range.upperBound, range); - } - } - }; - } - - @Override - Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() { - Collection<Range<C>> candidates; - if (upperBoundWindow.hasUpperBound()) { - candidates = rangesByLowerBound.headMap(upperBoundWindow.upperEndpoint(), false) - .descendingMap().values(); - } else { - candidates = rangesByLowerBound.descendingMap().values(); - } - final PeekingIterator<Range<C>> backingItr = Iterators.peekingIterator(candidates.iterator()); - if (backingItr.hasNext() - && upperBoundWindow.upperBound.isLessThan(backingItr.peek().upperBound)) { - 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 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<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 = positiveRangesByLowerBound; - this.positiveRangesByUpperBound = new RangesByUpperBound<C>(positiveRangesByLowerBound); - this.complementLowerBoundWindow = window; - } - - private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> subWindow) { - if (!complementLowerBoundWindow.isConnected(subWindow)) { - return ImmutableSortedMap.of(); - } else { - subWindow = subWindow.intersection(complementLowerBoundWindow); - return new ComplementRangesByLowerBound<C>(positiveRangesByLowerBound, subWindow); - } - } - - @Override - public NavigableMap<Cut<C>, Range<C>> subMap( - Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) { - return subMap(Range.range( - fromKey, BoundType.forBoolean(fromInclusive), - toKey, BoundType.forBoolean(toInclusive))); - } - - @Override - public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) { - return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive))); - } - - @Override - public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean 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; - if (complementLowerBoundWindow.hasLowerBound()) { - positiveRanges = positiveRangesByUpperBound.tailMap( - complementLowerBoundWindow.lowerEndpoint(), - complementLowerBoundWindow.lowerBoundType() == BoundType.CLOSED).values(); - } else { - positiveRanges = positiveRangesByUpperBound.values(); - } - final PeekingIterator<Range<C>> positiveItr = Iterators.peekingIterator( - positiveRanges.iterator()); - final Cut<C> firstComplementRangeLowerBound; - if (complementLowerBoundWindow.contains(Cut.<C>belowAll()) && - (!positiveItr.hasNext() || positiveItr.peek().lowerBound != Cut.<C>belowAll())) { - firstComplementRangeLowerBound = Cut.belowAll(); - } else if (positiveItr.hasNext()) { - firstComplementRangeLowerBound = positiveItr.next().upperBound; - } else { - return Iterators.emptyIterator(); - } - return new AbstractIterator<Entry<Cut<C>, Range<C>>>() { - Cut<C> nextComplementRangeLowerBound = firstComplementRangeLowerBound; - - @Override - protected Entry<Cut<C>, Range<C>> computeNext() { - if (complementLowerBoundWindow.upperBound.isLessThan(nextComplementRangeLowerBound) - || nextComplementRangeLowerBound == Cut.<C>aboveAll()) { - return endOfData(); - } - Range<C> negativeRange; - if (positiveItr.hasNext()) { - Range<C> positiveRange = positiveItr.next(); - negativeRange = Range.create(nextComplementRangeLowerBound, positiveRange.lowerBound); - nextComplementRangeLowerBound = positiveRange.upperBound; - } else { - negativeRange = Range.create(nextComplementRangeLowerBound, Cut.<C>aboveAll()); - nextComplementRangeLowerBound = Cut.aboveAll(); - } - return Maps.immutableEntry(negativeRange.lowerBound, negativeRange); - } - }; - } - - @Override - Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() { - 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 = complementLowerBoundWindow.hasUpperBound() - ? complementLowerBoundWindow.upperEndpoint() - : Cut.<C>aboveAll(); - boolean inclusive = complementLowerBoundWindow.hasUpperBound() - && complementLowerBoundWindow.upperBoundType() == BoundType.CLOSED; - final PeekingIterator<Range<C>> positiveItr = - Iterators.peekingIterator(positiveRangesByUpperBound.headMap(startingPoint, inclusive) - .descendingMap().values().iterator()); - Cut<C> cut; - if (positiveItr.hasNext()) { - cut = (positiveItr.peek().upperBound == Cut.<C>aboveAll()) - ? positiveItr.next().lowerBound - : positiveRangesByLowerBound.higherKey(positiveItr.peek().upperBound); - } else if (!complementLowerBoundWindow.contains(Cut.<C>belowAll()) - || positiveRangesByLowerBound.containsKey(Cut.belowAll())) { - return Iterators.emptyIterator(); - } else { - cut = positiveRangesByLowerBound.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 (nextComplementRangeUpperBound == Cut.<C>belowAll()) { - return endOfData(); - } else if (positiveItr.hasNext()) { - Range<C> positiveRange = positiveItr.next(); - Range<C> 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.<C>belowAll())) { - Range<C> negativeRange = - Range.create(Cut.<C>belowAll(), nextComplementRangeUpperBound); - nextComplementRangeUpperBound = 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(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<C> { - Complement() { - super(new ComplementRangesByLowerBound<C>(TreeRangeSet.this.rangesByLowerBound)); - } - - @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>> lowerBoundWindow, Range<C> restriction, - NavigableMap<Cut<C>, Range<C>> rangesByLowerBound) { - this.lowerBoundWindow = checkNotNull(lowerBoundWindow); - this.restriction = checkNotNull(restriction); - this.rangesByLowerBound = checkNotNull(rangesByLowerBound); - this.rangesByUpperBound = new RangesByUpperBound<C>(rangesByLowerBound); - } - - private NavigableMap<Cut<C>, Range<C>> subMap(Range<Cut<C>> window) { - if (!window.isConnected(lowerBoundWindow)) { - return ImmutableSortedMap.of(); - } else { - return new SubRangeSetRangesByLowerBound<C>( - lowerBoundWindow.intersection(window), restriction, rangesByLowerBound); - } - } - - @Override - public NavigableMap<Cut<C>, Range<C>> subMap( - Cut<C> fromKey, boolean fromInclusive, Cut<C> toKey, boolean toInclusive) { - return subMap(Range.range( - fromKey, BoundType.forBoolean(fromInclusive), toKey, BoundType.forBoolean(toInclusive))); - } - - @Override - public NavigableMap<Cut<C>, Range<C>> headMap(Cut<C> toKey, boolean inclusive) { - return subMap(Range.upTo(toKey, BoundType.forBoolean(inclusive))); - } - - @Override - public NavigableMap<Cut<C>, Range<C>> tailMap(Cut<C> fromKey, boolean 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 (!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<C> candidate = Maps.valueOrNull(rangesByLowerBound.floorEntry(cut)); - if (candidate != null && candidate.upperBound.compareTo(restriction.lowerBound) > 0) { - return candidate.intersection(restriction); - } - } else { - Range<C> result = rangesByLowerBound.get(cut); - if (result != null) { - return result.intersection(restriction); - } - } - } catch (ClassCastException e) { - return null; - } - } - return null; - } - - @Override - Iterator<Entry<Cut<C>, Range<C>>> entryIterator() { - if (restriction.isEmpty()) { - return Iterators.emptyIterator(); - } - final Iterator<Range<C>> 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<Cut<C>> upperBoundOnLowerBounds = Ordering.natural() - .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound)); - 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(restriction); - return Maps.immutableEntry(nextRange.lowerBound, nextRange); - } - } - }; - } - - @Override - Iterator<Entry<Cut<C>, Range<C>>> descendingEntryIterator() { - if (restriction.isEmpty()) { - return Iterators.emptyIterator(); - } - Cut<Cut<C>> upperBoundOnLowerBounds = Ordering.natural() - .min(lowerBoundWindow.upperBound, Cut.belowValue(restriction.upperBound)); - final Iterator<Range<C>> completeRangeItr = rangesByLowerBound.headMap( - upperBoundOnLowerBounds.endpoint(), - upperBoundOnLowerBounds.typeAsUpperBound() == BoundType.CLOSED) - .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 (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<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(), restriction, TreeRangeSet.this.rangesByLowerBound)); - this.restriction = restriction; - } - - @Override - public boolean encloses(Range<C> range) { - if (!restriction.isEmpty() && restriction.encloses(range)) { - Range<C> enclosing = TreeRangeSet.this.rangeEnclosing(range); - return enclosing != null && !enclosing.intersection(restriction).isEmpty(); - } - return false; - } - - @Override - @Nullable - public Range<C> rangeContaining(C value) { - if (!restriction.contains(value)) { - return null; - } - Range<C> result = TreeRangeSet.this.rangeContaining(value); - return (result == null) ? null : result.intersection(restriction); - } - - @Override - public void add(Range<C> rangeToAdd) { - checkArgument(restriction.encloses(rangeToAdd), "Cannot add range %s to subRangeSet(%s)", - rangeToAdd, restriction); - super.add(rangeToAdd); - } - - @Override - public void remove(Range<C> rangeToRemove) { - if (rangeToRemove.isConnected(restriction)) { - TreeRangeSet.this.remove(rangeToRemove.intersection(restriction)); - } - } - - @Override - public boolean contains(C value) { - return restriction.contains(value) && TreeRangeSet.this.contains(value); - } - - @Override - public void clear() { - TreeRangeSet.this.remove(restriction); - } - - @Override - public RangeSet<C> subRangeSet(Range<C> view) { - if (view.encloses(restriction)) { - return this; - } else if (view.isConnected(restriction)) { - return new SubRangeSet(restriction.intersection(view)); - } else { - return ImmutableRangeSet.of(); - } - } - } -} |