001 /* 002 * Copyright (C) 2009 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.collect; 018 019 import static com.google.common.base.Preconditions.checkNotNull; 020 021 import com.google.common.annotations.Beta; 022 import com.google.common.annotations.GwtCompatible; 023 024 import java.util.Iterator; 025 import java.util.NoSuchElementException; 026 027 /** 028 * Static methods pertaining to {@link Range} instances. Each of the 029 * {@link Range nine types of ranges} can be constructed with a corresponding 030 * factory method: 031 * 032 * <dl> 033 * <dt>{@code (a..b)} 034 * <dd>{@link #open} 035 * <dt>{@code [a..b]} 036 * <dd>{@link #closed} 037 * <dt>{@code [a..b)} 038 * <dd>{@link #closedOpen} 039 * <dt>{@code (a..b]} 040 * <dd>{@link #openClosed} 041 * <dt>{@code (a..+∞)} 042 * <dd>{@link #greaterThan} 043 * <dt>{@code [a..+∞)} 044 * <dd>{@link #atLeast} 045 * <dt>{@code (-∞..b)} 046 * <dd>{@link #lessThan} 047 * <dt>{@code (-∞..b]} 048 * <dd>{@link #atMost} 049 * <dt>{@code (-∞..+∞)} 050 * <dd>{@link #all} 051 * </dl> 052 * 053 * <p>Additionally, {@link Range} instances can be constructed by passing the 054 * {@link BoundType bound types} explicitly. 055 * 056 * <dl> 057 * <dt>Bounded on both ends 058 * <dd>{@link #range} 059 * <dt>Unbounded on top ({@code (a..+∞)} or {@code (a..+∞)}) 060 * <dd>{@link #downTo} 061 * <dt>Unbounded on bottom ({@code (-∞..b)} or {@code (-∞..b]}) 062 * <dd>{@link #upTo} 063 * </dl> 064 * 065 * <p>See the Guava User Guide article on <a href= 066 * "http://code.google.com/p/guava-libraries/wiki/RangesExplained"> 067 * {@code Range}</a>. 068 * 069 * @author Kevin Bourrillion 070 * @author Gregory Kick 071 * @since 10.0 072 */ 073 @GwtCompatible 074 @Beta 075 public final class Ranges { 076 private Ranges() {} 077 078 static <C extends Comparable<?>> Range<C> create( 079 Cut<C> lowerBound, Cut<C> upperBound) { 080 return new Range<C>(lowerBound, upperBound); 081 } 082 083 /** 084 * Returns a range that contains all values strictly greater than {@code 085 * lower} and strictly less than {@code upper}. 086 * 087 * @throws IllegalArgumentException if {@code lower} is greater than <i>or 088 * equal to</i> {@code upper} 089 */ 090 public static <C extends Comparable<?>> Range<C> open(C lower, C upper) { 091 return create(Cut.aboveValue(lower), Cut.belowValue(upper)); 092 } 093 094 /** 095 * Returns a range that contains all values greater than or equal to 096 * {@code lower} and less than or equal to {@code upper}. 097 * 098 * @throws IllegalArgumentException if {@code lower} is greater than {@code 099 * upper} 100 */ 101 public static <C extends Comparable<?>> Range<C> closed(C lower, C upper) { 102 return create(Cut.belowValue(lower), Cut.aboveValue(upper)); 103 } 104 105 /** 106 * Returns a range that contains all values greater than or equal to 107 * {@code lower} and strictly less than {@code upper}. 108 * 109 * @throws IllegalArgumentException if {@code lower} is greater than {@code 110 * upper} 111 */ 112 public static <C extends Comparable<?>> Range<C> closedOpen( 113 C lower, C upper) { 114 return create(Cut.belowValue(lower), Cut.belowValue(upper)); 115 } 116 117 /** 118 * Returns a range that contains all values strictly greater than {@code 119 * lower} and less than or equal to {@code upper}. 120 * 121 * @throws IllegalArgumentException if {@code lower} is greater than {@code 122 * upper} 123 */ 124 public static <C extends Comparable<?>> Range<C> openClosed( 125 C lower, C upper) { 126 return create(Cut.aboveValue(lower), Cut.aboveValue(upper)); 127 } 128 129 /** 130 * Returns a range that contains any value from {@code lower} to {@code 131 * upper}, where each endpoint may be either inclusive (closed) or exclusive 132 * (open). 133 * 134 * @throws IllegalArgumentException if {@code lower} is greater than {@code 135 * upper} 136 */ 137 public static <C extends Comparable<?>> Range<C> range( 138 C lower, BoundType lowerType, C upper, BoundType upperType) { 139 checkNotNull(lowerType); 140 checkNotNull(upperType); 141 142 Cut<C> lowerBound = (lowerType == BoundType.OPEN) 143 ? Cut.aboveValue(lower) 144 : Cut.belowValue(lower); 145 Cut<C> upperBound = (upperType == BoundType.OPEN) 146 ? Cut.belowValue(upper) 147 : Cut.aboveValue(upper); 148 return create(lowerBound, upperBound); 149 } 150 151 /** 152 * Returns a range that contains all values strictly less than {@code 153 * endpoint}. 154 */ 155 public static <C extends Comparable<?>> Range<C> lessThan(C endpoint) { 156 return create(Cut.<C>belowAll(), Cut.belowValue(endpoint)); 157 } 158 159 /** 160 * Returns a range that contains all values less than or equal to 161 * {@code endpoint}. 162 */ 163 public static <C extends Comparable<?>> Range<C> atMost(C endpoint) { 164 return create(Cut.<C>belowAll(), Cut.aboveValue(endpoint)); 165 } 166 167 /** 168 * Returns a range with no lower bound up to the given endpoint, which may be 169 * either inclusive (closed) or exclusive (open). 170 */ 171 public static <C extends Comparable<?>> Range<C> upTo( 172 C endpoint, BoundType boundType) { 173 switch (boundType) { 174 case OPEN: 175 return lessThan(endpoint); 176 case CLOSED: 177 return atMost(endpoint); 178 default: 179 throw new AssertionError(); 180 } 181 } 182 183 /** 184 * Returns a range that contains all values strictly greater than {@code 185 * endpoint}. 186 */ 187 public static <C extends Comparable<?>> Range<C> greaterThan(C endpoint) { 188 return create(Cut.aboveValue(endpoint), Cut.<C>aboveAll()); 189 } 190 191 /** 192 * Returns a range that contains all values greater than or equal to 193 * {@code endpoint}. 194 */ 195 public static <C extends Comparable<?>> Range<C> atLeast(C endpoint) { 196 return create(Cut.belowValue(endpoint), Cut.<C>aboveAll()); 197 } 198 199 /** 200 * Returns a range from the given endpoint, which may be either inclusive 201 * (closed) or exclusive (open), with no upper bound. 202 */ 203 public static <C extends Comparable<?>> Range<C> downTo( 204 C endpoint, BoundType boundType) { 205 switch (boundType) { 206 case OPEN: 207 return greaterThan(endpoint); 208 case CLOSED: 209 return atLeast(endpoint); 210 default: 211 throw new AssertionError(); 212 } 213 } 214 215 /** Returns a range that contains every value of type {@code C}. */ 216 public static <C extends Comparable<?>> Range<C> all() { 217 return create(Cut.<C>belowAll(), Cut.<C>aboveAll()); 218 } 219 220 /** 221 * Returns a range that {@linkplain Range#contains(Comparable) contains} only 222 * the given value. The returned range is {@linkplain BoundType#CLOSED closed} 223 * on both ends. 224 */ 225 public static <C extends Comparable<?>> Range<C> singleton(C value) { 226 return closed(value, value); 227 } 228 229 /** 230 * Returns the minimal range that 231 * {@linkplain Range#contains(Comparable) contains} all of the given values. 232 * The returned range is {@linkplain BoundType#CLOSED closed} on both ends. 233 * 234 * @throws ClassCastException if the parameters are not <i>mutually 235 * comparable</i> 236 * @throws NoSuchElementException if {@code values} is empty 237 * @throws NullPointerException if any of {@code values} is null 238 */ 239 public static <C extends Comparable<?>> Range<C> encloseAll( 240 Iterable<C> values) { 241 checkNotNull(values); 242 if (values instanceof ContiguousSet) { 243 return ((ContiguousSet<C>) values).range(); 244 } 245 Iterator<C> valueIterator = values.iterator(); 246 C min = checkNotNull(valueIterator.next()); 247 C max = min; 248 while (valueIterator.hasNext()) { 249 C value = checkNotNull(valueIterator.next()); 250 min = Ordering.natural().min(min, value); 251 max = Ordering.natural().max(max, value); 252 } 253 return closed(min, max); 254 } 255 }