com.google.common.collect.Cut Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of guava Show documentation
Show all versions of guava Show documentation
Guava is a suite of core and expanded libraries that include
utility classes, google's collections, io classes, and much
much more.
/*
* Copyright (C) 2009 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.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import com.google.common.primitives.Booleans;
import java.io.Serializable;
import java.util.NoSuchElementException;
import javax.annotation.Nullable;
/**
* Implementation detail for the internal structure of {@link Range} instances. Represents
* a unique way of "cutting" a "number line" (actually of instances of type {@code C}, not
* necessarily "numbers") into two sections; this can be done below a certain value, above
* a certain value, below all values or above all values. With this object defined in this
* way, an interval can always be represented by a pair of {@code Cut} instances.
*
* @author Kevin Bourrillion
*/
@GwtCompatible
abstract class Cut implements Comparable>, Serializable {
final C endpoint;
Cut(@Nullable C endpoint) {
this.endpoint = endpoint;
}
abstract boolean isLessThan(C value);
abstract BoundType typeAsLowerBound();
abstract BoundType typeAsUpperBound();
abstract Cut withLowerBoundType(BoundType boundType, DiscreteDomain domain);
abstract Cut withUpperBoundType(BoundType boundType, DiscreteDomain domain);
abstract void describeAsLowerBound(StringBuilder sb);
abstract void describeAsUpperBound(StringBuilder sb);
abstract C leastValueAbove(DiscreteDomain domain);
abstract C greatestValueBelow(DiscreteDomain domain);
/*
* The canonical form is a BelowValue cut whenever possible, otherwise ABOVE_ALL, or
* (only in the case of types that are unbounded below) BELOW_ALL.
*/
Cut canonical(DiscreteDomain domain) {
return this;
}
// note: overriden by {BELOW,ABOVE}_ALL
@Override
public int compareTo(Cut that) {
if (that == belowAll()) {
return 1;
}
if (that == aboveAll()) {
return -1;
}
int result = Range.compareOrThrow(endpoint, that.endpoint);
if (result != 0) {
return result;
}
// same value. below comes before above
return Booleans.compare(
this instanceof AboveValue, that instanceof AboveValue);
}
C endpoint() {
return endpoint;
}
@SuppressWarnings("unchecked") // catching CCE
@Override public boolean equals(Object obj) {
if (obj instanceof Cut) {
// It might not really be a Cut, but we'll catch a CCE if it's not
Cut that = (Cut) obj;
try {
int compareResult = compareTo(that);
return compareResult == 0;
} catch (ClassCastException ignored) {
}
}
return false;
}
/*
* The implementation neither produces nor consumes any non-null instance of type C, so
* casting the type parameter is safe.
*/
@SuppressWarnings("unchecked")
static Cut belowAll() {
return (Cut) BelowAll.INSTANCE;
}
private static final long serialVersionUID = 0;
private static final class BelowAll extends Cut> {
private static final BelowAll INSTANCE = new BelowAll();
private BelowAll() {
super(null);
}
@Override Comparable> endpoint() {
throw new IllegalStateException("range unbounded on this side");
}
@Override boolean isLessThan(Comparable> value) {
return true;
}
@Override BoundType typeAsLowerBound() {
throw new IllegalStateException();
}
@Override BoundType typeAsUpperBound() {
throw new AssertionError("this statement should be unreachable");
}
@Override Cut> withLowerBoundType(BoundType boundType,
DiscreteDomain> domain) {
throw new IllegalStateException();
}
@Override Cut> withUpperBoundType(BoundType boundType,
DiscreteDomain> domain) {
throw new AssertionError("this statement should be unreachable");
}
@Override void describeAsLowerBound(StringBuilder sb) {
sb.append("(-\u221e");
}
@Override void describeAsUpperBound(StringBuilder sb) {
throw new AssertionError();
}
@Override Comparable> leastValueAbove(
DiscreteDomain> domain) {
return domain.minValue();
}
@Override Comparable> greatestValueBelow(
DiscreteDomain> domain) {
throw new AssertionError();
}
@Override Cut> canonical(
DiscreteDomain> domain) {
try {
return Cut.>belowValue(domain.minValue());
} catch (NoSuchElementException e) {
return this;
}
}
@Override public int compareTo(Cut> o) {
return (o == this) ? 0 : -1;
}
@Override public String toString() {
return "-\u221e";
}
private Object readResolve() {
return INSTANCE;
}
private static final long serialVersionUID = 0;
}
/*
* The implementation neither produces nor consumes any non-null instance of
* type C, so casting the type parameter is safe.
*/
@SuppressWarnings("unchecked")
static Cut aboveAll() {
return (Cut) AboveAll.INSTANCE;
}
private static final class AboveAll extends Cut> {
private static final AboveAll INSTANCE = new AboveAll();
private AboveAll() {
super(null);
}
@Override Comparable> endpoint() {
throw new IllegalStateException("range unbounded on this side");
}
@Override boolean isLessThan(Comparable> value) {
return false;
}
@Override BoundType typeAsLowerBound() {
throw new AssertionError("this statement should be unreachable");
}
@Override BoundType typeAsUpperBound() {
throw new IllegalStateException();
}
@Override Cut> withLowerBoundType(BoundType boundType,
DiscreteDomain> domain) {
throw new AssertionError("this statement should be unreachable");
}
@Override Cut> withUpperBoundType(BoundType boundType,
DiscreteDomain> domain) {
throw new IllegalStateException();
}
@Override void describeAsLowerBound(StringBuilder sb) {
throw new AssertionError();
}
@Override void describeAsUpperBound(StringBuilder sb) {
sb.append("+\u221e)");
}
@Override Comparable> leastValueAbove(
DiscreteDomain> domain) {
throw new AssertionError();
}
@Override Comparable> greatestValueBelow(
DiscreteDomain> domain) {
return domain.maxValue();
}
@Override public int compareTo(Cut> o) {
return (o == this) ? 0 : 1;
}
@Override public String toString() {
return "+\u221e";
}
private Object readResolve() {
return INSTANCE;
}
private static final long serialVersionUID = 0;
}
static Cut belowValue(C endpoint) {
return new BelowValue(endpoint);
}
private static final class BelowValue extends Cut {
BelowValue(C endpoint) {
super(checkNotNull(endpoint));
}
@Override boolean isLessThan(C value) {
return Range.compareOrThrow(endpoint, value) <= 0;
}
@Override BoundType typeAsLowerBound() {
return BoundType.CLOSED;
}
@Override BoundType typeAsUpperBound() {
return BoundType.OPEN;
}
@Override Cut withLowerBoundType(BoundType boundType, DiscreteDomain domain) {
switch (boundType) {
case CLOSED:
return this;
case OPEN:
@Nullable C previous = domain.previous(endpoint);
return (previous == null) ? Cut.belowAll() : new AboveValue(previous);
default:
throw new AssertionError();
}
}
@Override Cut withUpperBoundType(BoundType boundType, DiscreteDomain domain) {
switch (boundType) {
case CLOSED:
@Nullable C previous = domain.previous(endpoint);
return (previous == null) ? Cut.aboveAll() : new AboveValue(previous);
case OPEN:
return this;
default:
throw new AssertionError();
}
}
@Override void describeAsLowerBound(StringBuilder sb) {
sb.append('[').append(endpoint);
}
@Override void describeAsUpperBound(StringBuilder sb) {
sb.append(endpoint).append(')');
}
@Override C leastValueAbove(DiscreteDomain domain) {
return endpoint;
}
@Override C greatestValueBelow(DiscreteDomain domain) {
return domain.previous(endpoint);
}
@Override public int hashCode() {
return endpoint.hashCode();
}
@Override public String toString() {
return "\\" + endpoint + "/";
}
private static final long serialVersionUID = 0;
}
static Cut aboveValue(C endpoint) {
return new AboveValue(endpoint);
}
private static final class AboveValue extends Cut {
AboveValue(C endpoint) {
super(checkNotNull(endpoint));
}
@Override boolean isLessThan(C value) {
return Range.compareOrThrow(endpoint, value) < 0;
}
@Override BoundType typeAsLowerBound() {
return BoundType.OPEN;
}
@Override BoundType typeAsUpperBound() {
return BoundType.CLOSED;
}
@Override Cut withLowerBoundType(BoundType boundType, DiscreteDomain domain) {
switch (boundType) {
case OPEN:
return this;
case CLOSED:
@Nullable C next = domain.next(endpoint);
return (next == null) ? Cut.belowAll() : belowValue(next);
default:
throw new AssertionError();
}
}
@Override Cut withUpperBoundType(BoundType boundType, DiscreteDomain domain) {
switch (boundType) {
case OPEN:
@Nullable C next = domain.next(endpoint);
return (next == null) ? Cut.aboveAll() : belowValue(next);
case CLOSED:
return this;
default:
throw new AssertionError();
}
}
@Override void describeAsLowerBound(StringBuilder sb) {
sb.append('(').append(endpoint);
}
@Override void describeAsUpperBound(StringBuilder sb) {
sb.append(endpoint).append(']');
}
@Override C leastValueAbove(DiscreteDomain domain) {
return domain.next(endpoint);
}
@Override C greatestValueBelow(DiscreteDomain domain) {
return endpoint;
}
@Override Cut canonical(DiscreteDomain domain) {
C next = leastValueAbove(domain);
return (next != null) ? belowValue(next) : Cut.aboveAll();
}
@Override public int hashCode() {
return ~endpoint.hashCode();
}
@Override public String toString() {
return "/" + endpoint + "\\";
}
private static final long serialVersionUID = 0;
}
}