1 /* 2 * Copyright (C) 2009 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.collect; 16 17 import static com.google.common.base.Preconditions.checkNotNull; 18 19 import com.google.common.annotations.GwtCompatible; 20 import com.google.common.primitives.Booleans; 21 22 import java.io.Serializable; 23 import java.util.NoSuchElementException; 24 25 import javax.annotation.Nullable; 26 27 /** 28 * Implementation detail for the internal structure of {@link Range} instances. Represents 29 * a unique way of "cutting" a "number line" (actually of instances of type {@code C}, not 30 * necessarily "numbers") into two sections; this can be done below a certain value, above 31 * a certain value, below all values or above all values. With this object defined in this 32 * way, an interval can always be represented by a pair of {@code Cut} instances. 33 * 34 * @author Kevin Bourrillion 35 */ 36 @GwtCompatible 37 abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializable { 38 final C endpoint; 39 Cut(@ullable C endpoint)40 Cut(@Nullable C endpoint) { 41 this.endpoint = endpoint; 42 } 43 isLessThan(C value)44 abstract boolean isLessThan(C value); 45 typeAsLowerBound()46 abstract BoundType typeAsLowerBound(); typeAsUpperBound()47 abstract BoundType typeAsUpperBound(); 48 withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain)49 abstract Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain); withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain)50 abstract Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain); 51 describeAsLowerBound(StringBuilder sb)52 abstract void describeAsLowerBound(StringBuilder sb); describeAsUpperBound(StringBuilder sb)53 abstract void describeAsUpperBound(StringBuilder sb); 54 leastValueAbove(DiscreteDomain<C> domain)55 abstract C leastValueAbove(DiscreteDomain<C> domain); greatestValueBelow(DiscreteDomain<C> domain)56 abstract C greatestValueBelow(DiscreteDomain<C> domain); 57 58 /* 59 * The canonical form is a BelowValue cut whenever possible, otherwise ABOVE_ALL, or 60 * (only in the case of types that are unbounded below) BELOW_ALL. 61 */ canonical(DiscreteDomain<C> domain)62 Cut<C> canonical(DiscreteDomain<C> domain) { 63 return this; 64 } 65 66 // note: overriden by {BELOW,ABOVE}_ALL 67 @Override compareTo(Cut<C> that)68 public int compareTo(Cut<C> that) { 69 if (that == belowAll()) { 70 return 1; 71 } 72 if (that == aboveAll()) { 73 return -1; 74 } 75 int result = Range.compareOrThrow(endpoint, that.endpoint); 76 if (result != 0) { 77 return result; 78 } 79 // same value. below comes before above 80 return Booleans.compare( 81 this instanceof AboveValue, that instanceof AboveValue); 82 } 83 endpoint()84 C endpoint() { 85 return endpoint; 86 } 87 88 @SuppressWarnings("unchecked") // catching CCE equals(Object obj)89 @Override public boolean equals(Object obj) { 90 if (obj instanceof Cut) { 91 // It might not really be a Cut<C>, but we'll catch a CCE if it's not 92 Cut<C> that = (Cut<C>) obj; 93 try { 94 int compareResult = compareTo(that); 95 return compareResult == 0; 96 } catch (ClassCastException ignored) { 97 } 98 } 99 return false; 100 } 101 102 /* 103 * The implementation neither produces nor consumes any non-null instance of type C, so 104 * casting the type parameter is safe. 105 */ 106 @SuppressWarnings("unchecked") belowAll()107 static <C extends Comparable> Cut<C> belowAll() { 108 return (Cut<C>) BelowAll.INSTANCE; 109 } 110 111 private static final long serialVersionUID = 0; 112 113 private static final class BelowAll extends Cut<Comparable<?>> { 114 private static final BelowAll INSTANCE = new BelowAll(); 115 BelowAll()116 private BelowAll() { 117 super(null); 118 } endpoint()119 @Override Comparable<?> endpoint() { 120 throw new IllegalStateException("range unbounded on this side"); 121 } isLessThan(Comparable<?> value)122 @Override boolean isLessThan(Comparable<?> value) { 123 return true; 124 } typeAsLowerBound()125 @Override BoundType typeAsLowerBound() { 126 throw new IllegalStateException(); 127 } typeAsUpperBound()128 @Override BoundType typeAsUpperBound() { 129 throw new AssertionError("this statement should be unreachable"); 130 } withLowerBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain)131 @Override Cut<Comparable<?>> withLowerBoundType(BoundType boundType, 132 DiscreteDomain<Comparable<?>> domain) { 133 throw new IllegalStateException(); 134 } withUpperBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain)135 @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType, 136 DiscreteDomain<Comparable<?>> domain) { 137 throw new AssertionError("this statement should be unreachable"); 138 } describeAsLowerBound(StringBuilder sb)139 @Override void describeAsLowerBound(StringBuilder sb) { 140 sb.append("(-\u221e"); 141 } describeAsUpperBound(StringBuilder sb)142 @Override void describeAsUpperBound(StringBuilder sb) { 143 throw new AssertionError(); 144 } leastValueAbove( DiscreteDomain<Comparable<?>> domain)145 @Override Comparable<?> leastValueAbove( 146 DiscreteDomain<Comparable<?>> domain) { 147 return domain.minValue(); 148 } greatestValueBelow( DiscreteDomain<Comparable<?>> domain)149 @Override Comparable<?> greatestValueBelow( 150 DiscreteDomain<Comparable<?>> domain) { 151 throw new AssertionError(); 152 } canonical( DiscreteDomain<Comparable<?>> domain)153 @Override Cut<Comparable<?>> canonical( 154 DiscreteDomain<Comparable<?>> domain) { 155 try { 156 return Cut.<Comparable<?>>belowValue(domain.minValue()); 157 } catch (NoSuchElementException e) { 158 return this; 159 } 160 } compareTo(Cut<Comparable<?>> o)161 @Override public int compareTo(Cut<Comparable<?>> o) { 162 return (o == this) ? 0 : -1; 163 } readResolve()164 private Object readResolve() { 165 return INSTANCE; 166 } 167 private static final long serialVersionUID = 0; 168 } 169 170 /* 171 * The implementation neither produces nor consumes any non-null instance of 172 * type C, so casting the type parameter is safe. 173 */ 174 @SuppressWarnings("unchecked") aboveAll()175 static <C extends Comparable> Cut<C> aboveAll() { 176 return (Cut<C>) AboveAll.INSTANCE; 177 } 178 179 private static final class AboveAll extends Cut<Comparable<?>> { 180 private static final AboveAll INSTANCE = new AboveAll(); 181 AboveAll()182 private AboveAll() { 183 super(null); 184 } endpoint()185 @Override Comparable<?> endpoint() { 186 throw new IllegalStateException("range unbounded on this side"); 187 } isLessThan(Comparable<?> value)188 @Override boolean isLessThan(Comparable<?> value) { 189 return false; 190 } typeAsLowerBound()191 @Override BoundType typeAsLowerBound() { 192 throw new AssertionError("this statement should be unreachable"); 193 } typeAsUpperBound()194 @Override BoundType typeAsUpperBound() { 195 throw new IllegalStateException(); 196 } withLowerBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain)197 @Override Cut<Comparable<?>> withLowerBoundType(BoundType boundType, 198 DiscreteDomain<Comparable<?>> domain) { 199 throw new AssertionError("this statement should be unreachable"); 200 } withUpperBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain)201 @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType, 202 DiscreteDomain<Comparable<?>> domain) { 203 throw new IllegalStateException(); 204 } describeAsLowerBound(StringBuilder sb)205 @Override void describeAsLowerBound(StringBuilder sb) { 206 throw new AssertionError(); 207 } describeAsUpperBound(StringBuilder sb)208 @Override void describeAsUpperBound(StringBuilder sb) { 209 sb.append("+\u221e)"); 210 } leastValueAbove( DiscreteDomain<Comparable<?>> domain)211 @Override Comparable<?> leastValueAbove( 212 DiscreteDomain<Comparable<?>> domain) { 213 throw new AssertionError(); 214 } greatestValueBelow( DiscreteDomain<Comparable<?>> domain)215 @Override Comparable<?> greatestValueBelow( 216 DiscreteDomain<Comparable<?>> domain) { 217 return domain.maxValue(); 218 } compareTo(Cut<Comparable<?>> o)219 @Override public int compareTo(Cut<Comparable<?>> o) { 220 return (o == this) ? 0 : 1; 221 } readResolve()222 private Object readResolve() { 223 return INSTANCE; 224 } 225 private static final long serialVersionUID = 0; 226 } 227 belowValue(C endpoint)228 static <C extends Comparable> Cut<C> belowValue(C endpoint) { 229 return new BelowValue<C>(endpoint); 230 } 231 232 private static final class BelowValue<C extends Comparable> extends Cut<C> { BelowValue(C endpoint)233 BelowValue(C endpoint) { 234 super(checkNotNull(endpoint)); 235 } 236 isLessThan(C value)237 @Override boolean isLessThan(C value) { 238 return Range.compareOrThrow(endpoint, value) <= 0; 239 } typeAsLowerBound()240 @Override BoundType typeAsLowerBound() { 241 return BoundType.CLOSED; 242 } typeAsUpperBound()243 @Override BoundType typeAsUpperBound() { 244 return BoundType.OPEN; 245 } withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain)246 @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) { 247 switch (boundType) { 248 case CLOSED: 249 return this; 250 case OPEN: 251 @Nullable C previous = domain.previous(endpoint); 252 return (previous == null) ? Cut.<C>belowAll() : new AboveValue<C>(previous); 253 default: 254 throw new AssertionError(); 255 } 256 } withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain)257 @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) { 258 switch (boundType) { 259 case CLOSED: 260 @Nullable C previous = domain.previous(endpoint); 261 return (previous == null) ? Cut.<C>aboveAll() : new AboveValue<C>(previous); 262 case OPEN: 263 return this; 264 default: 265 throw new AssertionError(); 266 } 267 } describeAsLowerBound(StringBuilder sb)268 @Override void describeAsLowerBound(StringBuilder sb) { 269 sb.append('[').append(endpoint); 270 } describeAsUpperBound(StringBuilder sb)271 @Override void describeAsUpperBound(StringBuilder sb) { 272 sb.append(endpoint).append(')'); 273 } leastValueAbove(DiscreteDomain<C> domain)274 @Override C leastValueAbove(DiscreteDomain<C> domain) { 275 return endpoint; 276 } greatestValueBelow(DiscreteDomain<C> domain)277 @Override C greatestValueBelow(DiscreteDomain<C> domain) { 278 return domain.previous(endpoint); 279 } hashCode()280 @Override public int hashCode() { 281 return endpoint.hashCode(); 282 } 283 private static final long serialVersionUID = 0; 284 } 285 aboveValue(C endpoint)286 static <C extends Comparable> Cut<C> aboveValue(C endpoint) { 287 return new AboveValue<C>(endpoint); 288 } 289 290 private static final class AboveValue<C extends Comparable> extends Cut<C> { AboveValue(C endpoint)291 AboveValue(C endpoint) { 292 super(checkNotNull(endpoint)); 293 } 294 isLessThan(C value)295 @Override boolean isLessThan(C value) { 296 return Range.compareOrThrow(endpoint, value) < 0; 297 } typeAsLowerBound()298 @Override BoundType typeAsLowerBound() { 299 return BoundType.OPEN; 300 } typeAsUpperBound()301 @Override BoundType typeAsUpperBound() { 302 return BoundType.CLOSED; 303 } withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain)304 @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) { 305 switch (boundType) { 306 case OPEN: 307 return this; 308 case CLOSED: 309 @Nullable C next = domain.next(endpoint); 310 return (next == null) ? Cut.<C>belowAll() : belowValue(next); 311 default: 312 throw new AssertionError(); 313 } 314 } withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain)315 @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) { 316 switch (boundType) { 317 case OPEN: 318 @Nullable C next = domain.next(endpoint); 319 return (next == null) ? Cut.<C>aboveAll() : belowValue(next); 320 case CLOSED: 321 return this; 322 default: 323 throw new AssertionError(); 324 } 325 } describeAsLowerBound(StringBuilder sb)326 @Override void describeAsLowerBound(StringBuilder sb) { 327 sb.append('(').append(endpoint); 328 } describeAsUpperBound(StringBuilder sb)329 @Override void describeAsUpperBound(StringBuilder sb) { 330 sb.append(endpoint).append(']'); 331 } leastValueAbove(DiscreteDomain<C> domain)332 @Override C leastValueAbove(DiscreteDomain<C> domain) { 333 return domain.next(endpoint); 334 } greatestValueBelow(DiscreteDomain<C> domain)335 @Override C greatestValueBelow(DiscreteDomain<C> domain) { 336 return endpoint; 337 } canonical(DiscreteDomain<C> domain)338 @Override Cut<C> canonical(DiscreteDomain<C> domain) { 339 C next = leastValueAbove(domain); 340 return (next != null) ? belowValue(next) : Cut.<C>aboveAll(); 341 } hashCode()342 @Override public int hashCode() { 343 return ~endpoint.hashCode(); 344 } 345 private static final long serialVersionUID = 0; 346 } 347 } 348