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 }