/* * 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<C extends Comparable> implements Comparable<Cut<C>>, Serializable { final C endpoint; Cut(@Nullable C endpoint) { this.endpoint = endpoint; } abstract boolean isLessThan(C value); abstract BoundType typeAsLowerBound(); abstract BoundType typeAsUpperBound(); abstract Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain); abstract Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain); abstract void describeAsLowerBound(StringBuilder sb); abstract void describeAsUpperBound(StringBuilder sb); abstract C leastValueAbove(DiscreteDomain<C> domain); abstract C greatestValueBelow(DiscreteDomain<C> 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<C> canonical(DiscreteDomain<C> domain) { return this; } // note: overriden by {BELOW,ABOVE}_ALL @Override public int compareTo(Cut<C> 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<C>, but we'll catch a CCE if it's not Cut<C> that = (Cut<C>) 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 <C extends Comparable> Cut<C> belowAll() { return (Cut<C>) BelowAll.INSTANCE; } private static final long serialVersionUID = 0; private static final class BelowAll extends Cut<Comparable<?>> { 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<Comparable<?>> withLowerBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain) { throw new IllegalStateException(); } @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> 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<Comparable<?>> domain) { return domain.minValue(); } @Override Comparable<?> greatestValueBelow( DiscreteDomain<Comparable<?>> domain) { throw new AssertionError(); } @Override Cut<Comparable<?>> canonical( DiscreteDomain<Comparable<?>> domain) { try { return Cut.<Comparable<?>>belowValue(domain.minValue()); } catch (NoSuchElementException e) { return this; } } @Override public int compareTo(Cut<Comparable<?>> 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 <C extends Comparable> Cut<C> aboveAll() { return (Cut<C>) AboveAll.INSTANCE; } private static final class AboveAll extends Cut<Comparable<?>> { 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<Comparable<?>> withLowerBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain) { throw new AssertionError("this statement should be unreachable"); } @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain) { throw new IllegalStateException(); } @Override void describeAsLowerBound(StringBuilder sb) { throw new AssertionError(); } @Override void describeAsUpperBound(StringBuilder sb) { sb.append("+\u221e)"); } @Override Comparable<?> leastValueAbove( DiscreteDomain<Comparable<?>> domain) { throw new AssertionError(); } @Override Comparable<?> greatestValueBelow( DiscreteDomain<Comparable<?>> domain) { return domain.maxValue(); } @Override public int compareTo(Cut<Comparable<?>> o) { return (o == this) ? 0 : 1; } @Override public String toString() { return "+\u221e"; } private Object readResolve() { return INSTANCE; } private static final long serialVersionUID = 0; } static <C extends Comparable> Cut<C> belowValue(C endpoint) { return new BelowValue<C>(endpoint); } private static final class BelowValue<C extends Comparable> extends Cut<C> { 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<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) { switch (boundType) { case CLOSED: return this; case OPEN: @Nullable C previous = domain.previous(endpoint); return (previous == null) ? Cut.<C>belowAll() : new AboveValue<C>(previous); default: throw new AssertionError(); } } @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) { switch (boundType) { case CLOSED: @Nullable C previous = domain.previous(endpoint); return (previous == null) ? Cut.<C>aboveAll() : new AboveValue<C>(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<C> domain) { return endpoint; } @Override C greatestValueBelow(DiscreteDomain<C> 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 <C extends Comparable> Cut<C> aboveValue(C endpoint) { return new AboveValue<C>(endpoint); } private static final class AboveValue<C extends Comparable> extends Cut<C> { 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<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) { switch (boundType) { case OPEN: return this; case CLOSED: @Nullable C next = domain.next(endpoint); return (next == null) ? Cut.<C>belowAll() : belowValue(next); default: throw new AssertionError(); } } @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) { switch (boundType) { case OPEN: @Nullable C next = domain.next(endpoint); return (next == null) ? Cut.<C>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<C> domain) { return domain.next(endpoint); } @Override C greatestValueBelow(DiscreteDomain<C> domain) { return endpoint; } @Override Cut<C> canonical(DiscreteDomain<C> domain) { C next = leastValueAbove(domain); return (next != null) ? belowValue(next) : Cut.<C>aboveAll(); } @Override public int hashCode() { return ~endpoint.hashCode(); } @Override public String toString() { return "/" + endpoint + "\\"; } private static final long serialVersionUID = 0; } }