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 } toString()164 @Override public String toString() { 165 return "-\u221e"; 166 } readResolve()167 private Object readResolve() { 168 return INSTANCE; 169 } 170 private static final long serialVersionUID = 0; 171 } 172 173 /* 174 * The implementation neither produces nor consumes any non-null instance of 175 * type C, so casting the type parameter is safe. 176 */ 177 @SuppressWarnings("unchecked") aboveAll()178 static <C extends Comparable> Cut<C> aboveAll() { 179 return (Cut<C>) AboveAll.INSTANCE; 180 } 181 182 private static final class AboveAll extends Cut<Comparable<?>> { 183 private static final AboveAll INSTANCE = new AboveAll(); 184 AboveAll()185 private AboveAll() { 186 super(null); 187 } endpoint()188 @Override Comparable<?> endpoint() { 189 throw new IllegalStateException("range unbounded on this side"); 190 } isLessThan(Comparable<?> value)191 @Override boolean isLessThan(Comparable<?> value) { 192 return false; 193 } typeAsLowerBound()194 @Override BoundType typeAsLowerBound() { 195 throw new AssertionError("this statement should be unreachable"); 196 } typeAsUpperBound()197 @Override BoundType typeAsUpperBound() { 198 throw new IllegalStateException(); 199 } withLowerBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain)200 @Override Cut<Comparable<?>> withLowerBoundType(BoundType boundType, 201 DiscreteDomain<Comparable<?>> domain) { 202 throw new AssertionError("this statement should be unreachable"); 203 } withUpperBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain)204 @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType, 205 DiscreteDomain<Comparable<?>> domain) { 206 throw new IllegalStateException(); 207 } describeAsLowerBound(StringBuilder sb)208 @Override void describeAsLowerBound(StringBuilder sb) { 209 throw new AssertionError(); 210 } describeAsUpperBound(StringBuilder sb)211 @Override void describeAsUpperBound(StringBuilder sb) { 212 sb.append("+\u221e)"); 213 } leastValueAbove( DiscreteDomain<Comparable<?>> domain)214 @Override Comparable<?> leastValueAbove( 215 DiscreteDomain<Comparable<?>> domain) { 216 throw new AssertionError(); 217 } greatestValueBelow( DiscreteDomain<Comparable<?>> domain)218 @Override Comparable<?> greatestValueBelow( 219 DiscreteDomain<Comparable<?>> domain) { 220 return domain.maxValue(); 221 } compareTo(Cut<Comparable<?>> o)222 @Override public int compareTo(Cut<Comparable<?>> o) { 223 return (o == this) ? 0 : 1; 224 } toString()225 @Override public String toString() { 226 return "+\u221e"; 227 } readResolve()228 private Object readResolve() { 229 return INSTANCE; 230 } 231 private static final long serialVersionUID = 0; 232 } 233 belowValue(C endpoint)234 static <C extends Comparable> Cut<C> belowValue(C endpoint) { 235 return new BelowValue<C>(endpoint); 236 } 237 238 private static final class BelowValue<C extends Comparable> extends Cut<C> { BelowValue(C endpoint)239 BelowValue(C endpoint) { 240 super(checkNotNull(endpoint)); 241 } 242 isLessThan(C value)243 @Override boolean isLessThan(C value) { 244 return Range.compareOrThrow(endpoint, value) <= 0; 245 } typeAsLowerBound()246 @Override BoundType typeAsLowerBound() { 247 return BoundType.CLOSED; 248 } typeAsUpperBound()249 @Override BoundType typeAsUpperBound() { 250 return BoundType.OPEN; 251 } withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain)252 @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) { 253 switch (boundType) { 254 case CLOSED: 255 return this; 256 case OPEN: 257 @Nullable C previous = domain.previous(endpoint); 258 return (previous == null) ? Cut.<C>belowAll() : new AboveValue<C>(previous); 259 default: 260 throw new AssertionError(); 261 } 262 } withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain)263 @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) { 264 switch (boundType) { 265 case CLOSED: 266 @Nullable C previous = domain.previous(endpoint); 267 return (previous == null) ? Cut.<C>aboveAll() : new AboveValue<C>(previous); 268 case OPEN: 269 return this; 270 default: 271 throw new AssertionError(); 272 } 273 } describeAsLowerBound(StringBuilder sb)274 @Override void describeAsLowerBound(StringBuilder sb) { 275 sb.append('[').append(endpoint); 276 } describeAsUpperBound(StringBuilder sb)277 @Override void describeAsUpperBound(StringBuilder sb) { 278 sb.append(endpoint).append(')'); 279 } leastValueAbove(DiscreteDomain<C> domain)280 @Override C leastValueAbove(DiscreteDomain<C> domain) { 281 return endpoint; 282 } greatestValueBelow(DiscreteDomain<C> domain)283 @Override C greatestValueBelow(DiscreteDomain<C> domain) { 284 return domain.previous(endpoint); 285 } hashCode()286 @Override public int hashCode() { 287 return endpoint.hashCode(); 288 } toString()289 @Override public String toString() { 290 return "\\" + endpoint + "/"; 291 } 292 private static final long serialVersionUID = 0; 293 } 294 aboveValue(C endpoint)295 static <C extends Comparable> Cut<C> aboveValue(C endpoint) { 296 return new AboveValue<C>(endpoint); 297 } 298 299 private static final class AboveValue<C extends Comparable> extends Cut<C> { AboveValue(C endpoint)300 AboveValue(C endpoint) { 301 super(checkNotNull(endpoint)); 302 } 303 isLessThan(C value)304 @Override boolean isLessThan(C value) { 305 return Range.compareOrThrow(endpoint, value) < 0; 306 } typeAsLowerBound()307 @Override BoundType typeAsLowerBound() { 308 return BoundType.OPEN; 309 } typeAsUpperBound()310 @Override BoundType typeAsUpperBound() { 311 return BoundType.CLOSED; 312 } withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain)313 @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) { 314 switch (boundType) { 315 case OPEN: 316 return this; 317 case CLOSED: 318 @Nullable C next = domain.next(endpoint); 319 return (next == null) ? Cut.<C>belowAll() : belowValue(next); 320 default: 321 throw new AssertionError(); 322 } 323 } withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain)324 @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) { 325 switch (boundType) { 326 case OPEN: 327 @Nullable C next = domain.next(endpoint); 328 return (next == null) ? Cut.<C>aboveAll() : belowValue(next); 329 case CLOSED: 330 return this; 331 default: 332 throw new AssertionError(); 333 } 334 } describeAsLowerBound(StringBuilder sb)335 @Override void describeAsLowerBound(StringBuilder sb) { 336 sb.append('(').append(endpoint); 337 } describeAsUpperBound(StringBuilder sb)338 @Override void describeAsUpperBound(StringBuilder sb) { 339 sb.append(endpoint).append(']'); 340 } leastValueAbove(DiscreteDomain<C> domain)341 @Override C leastValueAbove(DiscreteDomain<C> domain) { 342 return domain.next(endpoint); 343 } greatestValueBelow(DiscreteDomain<C> domain)344 @Override C greatestValueBelow(DiscreteDomain<C> domain) { 345 return endpoint; 346 } canonical(DiscreteDomain<C> domain)347 @Override Cut<C> canonical(DiscreteDomain<C> domain) { 348 C next = leastValueAbove(domain); 349 return (next != null) ? belowValue(next) : Cut.<C>aboveAll(); 350 } hashCode()351 @Override public int hashCode() { 352 return ~endpoint.hashCode(); 353 } toString()354 @Override public String toString() { 355 return "/" + endpoint + "\\"; 356 } 357 private static final long serialVersionUID = 0; 358 } 359 } 360