All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.collect.TreeRangeSet Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * 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
 *
 * @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
 */
@Beta
@GwtIncompatible("uses NavigableMap")
@Deprecated(since = "2022-12-01")
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;
    }

    // @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
    @Deprecated(since = "2022-12-01")
    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;
    }

    // @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
    @VisibleForTesting
    @Deprecated(since = "2022-12-01")
    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> 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 {
                    // we catch CCEs
                    @SuppressWarnings("unchecked")
                    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();
        }
    }

    // @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
    @Deprecated(since = "2022-12-01")
    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> 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;
        }
    }

    // @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
    @Deprecated(since = "2022-12-01")
    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;
        }
    }

    // @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
    @Deprecated(since = "2022-12-01")
    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> 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 {
                    // we catch CCE's
                    @SuppressWarnings("unchecked")
                    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);
    }

    // @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
    @Deprecated(since = "2022-12-01")
    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 rangeContaining(C value) {
            if (!restriction.contains(value)) {
                return null;
            }
            Range result = TreeRangeSet.this.rangeContaining(value);
            return (result == null) ? null : result.intersection(restriction);
        }

        @Override
        public void add(Range rangeToAdd) {
            checkArgument(restriction.encloses(rangeToAdd), "Cannot add range %s to subRangeSet(%s)", rangeToAdd, restriction);
            super.add(rangeToAdd);
        }

        @Override
        public void remove(Range 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 subRangeSet(Range view) {
            if (view.encloses(restriction)) {
                return this;
            } else if (view.isConnected(restriction)) {
                return new SubRangeSet(restriction.intersection(view));
            } else {
                return ImmutableRangeSet.of();
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy