1 /* 2 * Copyright (C) 2009 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.annotations.Beta; 22 import com.google.common.annotations.GwtCompatible; 23 24 import java.util.Iterator; 25 import java.util.NoSuchElementException; 26 27 /** 28 * Static methods pertaining to {@link Range} instances. Each of the 29 * {@link Range nine types of ranges} can be constructed with a corresponding 30 * factory method: 31 * 32 * <dl> 33 * <dt>{@code (a..b)} 34 * <dd>{@link #open} 35 * <dt>{@code [a..b]} 36 * <dd>{@link #closed} 37 * <dt>{@code [a..b)} 38 * <dd>{@link #closedOpen} 39 * <dt>{@code (a..b]} 40 * <dd>{@link #openClosed} 41 * <dt>{@code (a..+∞)} 42 * <dd>{@link #greaterThan} 43 * <dt>{@code [a..+∞)} 44 * <dd>{@link #atLeast} 45 * <dt>{@code (-∞..b)} 46 * <dd>{@link #lessThan} 47 * <dt>{@code (-∞..b]} 48 * <dd>{@link #atMost} 49 * <dt>{@code (-∞..+∞)} 50 * <dd>{@link #all} 51 * </dl> 52 * 53 * <p>Additionally, {@link Range} instances can be constructed by passing the 54 * {@link BoundType bound types} explicitly. 55 * 56 * <dl> 57 * <dt>Bounded on both ends 58 * <dd>{@link #range} 59 * <dt>Unbounded on top ({@code (a..+∞)} or {@code (a..+∞)}) 60 * <dd>{@link #downTo} 61 * <dt>Unbounded on bottom ({@code (-∞..b)} or {@code (-∞..b]}) 62 * <dd>{@link #upTo} 63 * </dl> 64 * 65 * @author Kevin Bourrillion 66 * @author Gregory Kick 67 * @since 10.0 68 */ 69 @GwtCompatible 70 @Beta 71 public final class Ranges { Ranges()72 private Ranges() {} 73 create( Cut<C> lowerBound, Cut<C> upperBound)74 static <C extends Comparable<?>> Range<C> create( 75 Cut<C> lowerBound, Cut<C> upperBound) { 76 return new Range<C>(lowerBound, upperBound); 77 } 78 79 /** 80 * Returns a range that contains all values strictly greater than {@code 81 * lower} and strictly less than {@code upper}. 82 * 83 * @throws IllegalArgumentException if {@code lower} is greater than <i>or 84 * equal to</i> {@code upper} 85 */ open(C lower, C upper)86 public static <C extends Comparable<?>> Range<C> open(C lower, C upper) { 87 return create(Cut.aboveValue(lower), Cut.belowValue(upper)); 88 } 89 90 /** 91 * Returns a range that contains all values greater than or equal to 92 * {@code lower} and less than or equal to {@code upper}. 93 * 94 * @throws IllegalArgumentException if {@code lower} is greater than {@code 95 * upper} 96 */ closed(C lower, C upper)97 public static <C extends Comparable<?>> Range<C> closed(C lower, C upper) { 98 return create(Cut.belowValue(lower), Cut.aboveValue(upper)); 99 } 100 101 /** 102 * Returns a range that contains all values greater than or equal to 103 * {@code lower} and strictly less than {@code upper}. 104 * 105 * @throws IllegalArgumentException if {@code lower} is greater than {@code 106 * upper} 107 */ closedOpen( C lower, C upper)108 public static <C extends Comparable<?>> Range<C> closedOpen( 109 C lower, C upper) { 110 return create(Cut.belowValue(lower), Cut.belowValue(upper)); 111 } 112 113 /** 114 * Returns a range that contains all values strictly greater than {@code 115 * lower} and less than or equal to {@code upper}. 116 * 117 * @throws IllegalArgumentException if {@code lower} is greater than {@code 118 * upper} 119 */ openClosed( C lower, C upper)120 public static <C extends Comparable<?>> Range<C> openClosed( 121 C lower, C upper) { 122 return create(Cut.aboveValue(lower), Cut.aboveValue(upper)); 123 } 124 125 /** 126 * Returns a range that contains any value from {@code lower} to {@code 127 * upper}, where each endpoint may be either inclusive (closed) or exclusive 128 * (open). 129 * 130 * @throws IllegalArgumentException if {@code lower} is greater than {@code 131 * upper} 132 */ range( C lower, BoundType lowerType, C upper, BoundType upperType)133 public static <C extends Comparable<?>> Range<C> range( 134 C lower, BoundType lowerType, C upper, BoundType upperType) { 135 checkNotNull(lowerType); 136 checkNotNull(upperType); 137 138 Cut<C> lowerBound = (lowerType == BoundType.OPEN) 139 ? Cut.aboveValue(lower) 140 : Cut.belowValue(lower); 141 Cut<C> upperBound = (upperType == BoundType.OPEN) 142 ? Cut.belowValue(upper) 143 : Cut.aboveValue(upper); 144 return create(lowerBound, upperBound); 145 } 146 147 /** 148 * Returns a range that contains all values strictly less than {@code 149 * endpoint}. 150 */ lessThan(C endpoint)151 public static <C extends Comparable<?>> Range<C> lessThan(C endpoint) { 152 return create(Cut.<C>belowAll(), Cut.belowValue(endpoint)); 153 } 154 155 /** 156 * Returns a range that contains all values less than or equal to 157 * {@code endpoint}. 158 */ atMost(C endpoint)159 public static <C extends Comparable<?>> Range<C> atMost(C endpoint) { 160 return create(Cut.<C>belowAll(), Cut.aboveValue(endpoint)); 161 } 162 163 /** 164 * Returns a range with no lower bound up to the given endpoint, which may be 165 * either inclusive (closed) or exclusive (open). 166 */ upTo( C endpoint, BoundType boundType)167 public static <C extends Comparable<?>> Range<C> upTo( 168 C endpoint, BoundType boundType) { 169 switch (boundType) { 170 case OPEN: 171 return lessThan(endpoint); 172 case CLOSED: 173 return atMost(endpoint); 174 default: 175 throw new AssertionError(); 176 } 177 } 178 179 /** 180 * Returns a range that contains all values strictly greater than {@code 181 * endpoint}. 182 */ greaterThan(C endpoint)183 public static <C extends Comparable<?>> Range<C> greaterThan(C endpoint) { 184 return create(Cut.aboveValue(endpoint), Cut.<C>aboveAll()); 185 } 186 187 /** 188 * Returns a range that contains all values greater than or equal to 189 * {@code endpoint}. 190 */ atLeast(C endpoint)191 public static <C extends Comparable<?>> Range<C> atLeast(C endpoint) { 192 return create(Cut.belowValue(endpoint), Cut.<C>aboveAll()); 193 } 194 195 /** 196 * Returns a range from the given endpoint, which may be either inclusive 197 * (closed) or exclusive (open), with no upper bound. 198 */ downTo( C endpoint, BoundType boundType)199 public static <C extends Comparable<?>> Range<C> downTo( 200 C endpoint, BoundType boundType) { 201 switch (boundType) { 202 case OPEN: 203 return greaterThan(endpoint); 204 case CLOSED: 205 return atLeast(endpoint); 206 default: 207 throw new AssertionError(); 208 } 209 } 210 211 /** Returns a range that contains every value of type {@code C}. */ all()212 public static <C extends Comparable<?>> Range<C> all() { 213 return create(Cut.<C>belowAll(), Cut.<C>aboveAll()); 214 } 215 216 /** 217 * Returns a range that {@linkplain Range#contains(Comparable) contains} only 218 * the given value. The returned range is {@linkplain BoundType#CLOSED closed} 219 * on both ends. 220 */ singleton(C value)221 public static <C extends Comparable<?>> Range<C> singleton(C value) { 222 return closed(value, value); 223 } 224 225 /** 226 * Returns the minimal range that 227 * {@linkplain Range#contains(Comparable) contains} all of the given values. 228 * The returned range is {@linkplain BoundType#CLOSED closed} on both ends. 229 * 230 * @throws ClassCastException if the parameters are not <i>mutually 231 * comparable</i> 232 * @throws NoSuchElementException if {@code values} is empty 233 * @throws NullPointerException if any of {@code values} is null 234 */ encloseAll( Iterable<C> values)235 public static <C extends Comparable<?>> Range<C> encloseAll( 236 Iterable<C> values) { 237 checkNotNull(values); 238 if (values instanceof ContiguousSet) { 239 return ((ContiguousSet<C>) values).range(); 240 } 241 Iterator<C> valueIterator = values.iterator(); 242 C min = checkNotNull(valueIterator.next()); 243 C max = min; 244 while (valueIterator.hasNext()) { 245 C value = checkNotNull(valueIterator.next()); 246 min = Ordering.natural().min(min, value); 247 max = Ordering.natural().max(max, value); 248 } 249 return closed(min, max); 250 } 251 } 252