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
17package com.google.common.collect;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.annotations.Beta;
22import com.google.common.annotations.GwtCompatible;
23
24import java.util.Iterator;
25import 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
71public final class Ranges {
72  private Ranges() {}
73
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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}. */
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   */
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   */
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