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

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

There is a newer version: 33.3.0-jre-r3
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 static com.google.common.collect.BoundType.CLOSED;
import static com.google.common.collect.BoundType.OPEN;
import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT;

import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Objects;
import com.google.errorprone.annotations.concurrent.LazyInit;
import java.io.Serializable;
import java.util.Comparator;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A generalized interval on any ordering, for internal use. Supports {@code null}. Unlike {@link
 * Range}, this allows the use of an arbitrary comparator. This is designed for use in the
 * implementation of subcollections of sorted collection types.
 *
 * 

Whenever possible, use {@code Range} instead, which is better supported. * * @author Louis Wasserman */ @GwtCompatible(serializable = true) @ElementTypesAreNonnullByDefault final class GeneralRange implements Serializable { /** Converts a Range to a GeneralRange. */ @SuppressWarnings("rawtypes") // https://github.com/google/guava/issues/989 static GeneralRange from(Range range) { T lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : null; BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : OPEN; T upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : null; BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : OPEN; return new GeneralRange<>( Ordering.natural(), range.hasLowerBound(), lowerEndpoint, lowerBoundType, range.hasUpperBound(), upperEndpoint, upperBoundType); } /** Returns the whole range relative to the specified comparator. */ static GeneralRange all(Comparator comparator) { return new GeneralRange<>(comparator, false, null, OPEN, false, null, OPEN); } /** * Returns everything above the endpoint relative to the specified comparator, with the specified * endpoint behavior. */ static GeneralRange downTo( Comparator comparator, @ParametricNullness T endpoint, BoundType boundType) { return new GeneralRange<>(comparator, true, endpoint, boundType, false, null, OPEN); } /** * Returns everything below the endpoint relative to the specified comparator, with the specified * endpoint behavior. */ static GeneralRange upTo( Comparator comparator, @ParametricNullness T endpoint, BoundType boundType) { return new GeneralRange<>(comparator, false, null, OPEN, true, endpoint, boundType); } /** * Returns everything between the endpoints relative to the specified comparator, with the * specified endpoint behavior. */ static GeneralRange range( Comparator comparator, @ParametricNullness T lower, BoundType lowerType, @ParametricNullness T upper, BoundType upperType) { return new GeneralRange<>(comparator, true, lower, lowerType, true, upper, upperType); } private final Comparator comparator; private final boolean hasLowerBound; @CheckForNull private final T lowerEndpoint; private final BoundType lowerBoundType; private final boolean hasUpperBound; @CheckForNull private final T upperEndpoint; private final BoundType upperBoundType; private GeneralRange( Comparator comparator, boolean hasLowerBound, @CheckForNull T lowerEndpoint, BoundType lowerBoundType, boolean hasUpperBound, @CheckForNull T upperEndpoint, BoundType upperBoundType) { this.comparator = checkNotNull(comparator); this.hasLowerBound = hasLowerBound; this.hasUpperBound = hasUpperBound; this.lowerEndpoint = lowerEndpoint; this.lowerBoundType = checkNotNull(lowerBoundType); this.upperEndpoint = upperEndpoint; this.upperBoundType = checkNotNull(upperBoundType); // Trigger any exception that the comparator would throw for the endpoints. /* * uncheckedCastNullableTToT is safe as long as the callers are careful to pass a "real" T * whenever they pass `true` for the matching `has*Bound` parameter. */ if (hasLowerBound) { int unused = comparator.compare( uncheckedCastNullableTToT(lowerEndpoint), uncheckedCastNullableTToT(lowerEndpoint)); } if (hasUpperBound) { int unused = comparator.compare( uncheckedCastNullableTToT(upperEndpoint), uncheckedCastNullableTToT(upperEndpoint)); } if (hasLowerBound && hasUpperBound) { int cmp = comparator.compare( uncheckedCastNullableTToT(lowerEndpoint), uncheckedCastNullableTToT(upperEndpoint)); // be consistent with Range checkArgument( cmp <= 0, "lowerEndpoint (%s) > upperEndpoint (%s)", lowerEndpoint, upperEndpoint); if (cmp == 0) { checkArgument(lowerBoundType != OPEN || upperBoundType != OPEN); } } } Comparator comparator() { return comparator; } boolean hasLowerBound() { return hasLowerBound; } boolean hasUpperBound() { return hasUpperBound; } boolean isEmpty() { // The casts are safe because of the has*Bound() checks. return (hasUpperBound() && tooLow(uncheckedCastNullableTToT(getUpperEndpoint()))) || (hasLowerBound() && tooHigh(uncheckedCastNullableTToT(getLowerEndpoint()))); } boolean tooLow(@ParametricNullness T t) { if (!hasLowerBound()) { return false; } // The cast is safe because of the hasLowerBound() check. T lbound = uncheckedCastNullableTToT(getLowerEndpoint()); int cmp = comparator.compare(t, lbound); return cmp < 0 | (cmp == 0 & getLowerBoundType() == OPEN); } boolean tooHigh(@ParametricNullness T t) { if (!hasUpperBound()) { return false; } // The cast is safe because of the hasUpperBound() check. T ubound = uncheckedCastNullableTToT(getUpperEndpoint()); int cmp = comparator.compare(t, ubound); return cmp > 0 | (cmp == 0 & getUpperBoundType() == OPEN); } boolean contains(@ParametricNullness T t) { return !tooLow(t) && !tooHigh(t); } /** * Returns the intersection of the two ranges, or an empty range if their intersection is empty. */ @SuppressWarnings("nullness") // TODO(cpovirk): Add casts as needed. Will be noisy and annoying... GeneralRange intersect(GeneralRange other) { checkNotNull(other); checkArgument(comparator.equals(other.comparator)); boolean hasLowBound = this.hasLowerBound; T lowEnd = getLowerEndpoint(); BoundType lowType = getLowerBoundType(); if (!hasLowerBound()) { hasLowBound = other.hasLowerBound; lowEnd = other.getLowerEndpoint(); lowType = other.getLowerBoundType(); } else if (other.hasLowerBound()) { int cmp = comparator.compare(getLowerEndpoint(), other.getLowerEndpoint()); if (cmp < 0 || (cmp == 0 && other.getLowerBoundType() == OPEN)) { lowEnd = other.getLowerEndpoint(); lowType = other.getLowerBoundType(); } } boolean hasUpBound = this.hasUpperBound; T upEnd = getUpperEndpoint(); BoundType upType = getUpperBoundType(); if (!hasUpperBound()) { hasUpBound = other.hasUpperBound; upEnd = other.getUpperEndpoint(); upType = other.getUpperBoundType(); } else if (other.hasUpperBound()) { int cmp = comparator.compare(getUpperEndpoint(), other.getUpperEndpoint()); if (cmp > 0 || (cmp == 0 && other.getUpperBoundType() == OPEN)) { upEnd = other.getUpperEndpoint(); upType = other.getUpperBoundType(); } } if (hasLowBound && hasUpBound) { int cmp = comparator.compare(lowEnd, upEnd); if (cmp > 0 || (cmp == 0 && lowType == OPEN && upType == OPEN)) { // force allowed empty range lowEnd = upEnd; lowType = OPEN; upType = CLOSED; } } return new GeneralRange<>(comparator, hasLowBound, lowEnd, lowType, hasUpBound, upEnd, upType); } @Override public boolean equals(@CheckForNull Object obj) { if (obj instanceof GeneralRange) { GeneralRange r = (GeneralRange) obj; return comparator.equals(r.comparator) && hasLowerBound == r.hasLowerBound && hasUpperBound == r.hasUpperBound && getLowerBoundType().equals(r.getLowerBoundType()) && getUpperBoundType().equals(r.getUpperBoundType()) && Objects.equal(getLowerEndpoint(), r.getLowerEndpoint()) && Objects.equal(getUpperEndpoint(), r.getUpperEndpoint()); } return false; } @Override public int hashCode() { return Objects.hashCode( comparator, getLowerEndpoint(), getLowerBoundType(), getUpperEndpoint(), getUpperBoundType()); } @LazyInit @CheckForNull private transient GeneralRange reverse; /** Returns the same range relative to the reversed comparator. */ GeneralRange reverse() { GeneralRange result = reverse; if (result == null) { result = new GeneralRange<>( Ordering.from(comparator).reverse(), hasUpperBound, getUpperEndpoint(), getUpperBoundType(), hasLowerBound, getLowerEndpoint(), getLowerBoundType()); result.reverse = this; return this.reverse = result; } return result; } @Override public String toString() { return comparator + ":" + (lowerBoundType == CLOSED ? '[' : '(') + (hasLowerBound ? lowerEndpoint : "-\u221e") + ',' + (hasUpperBound ? upperEndpoint : "\u221e") + (upperBoundType == CLOSED ? ']' : ')'); } @CheckForNull T getLowerEndpoint() { return lowerEndpoint; } BoundType getLowerBoundType() { return lowerBoundType; } @CheckForNull T getUpperEndpoint() { return upperEndpoint; } BoundType getUpperBoundType() { return upperBoundType; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy