    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     * @author Kevin Bourrillion
    066     * @author Gregory Kick
    067     * @since 10.0
    068     */
    069    @GwtCompatible
    070    @Beta
    071    public final class Ranges {
    072      private Ranges() {}
    073
    074      static <C extends Comparable<?>> Range<C> create(
    075          Cut<C> lowerBound, Cut<C> upperBound) {
    076        return new Range<C>(lowerBound, upperBound);
    077      }
    078
    079      /**
    080       * Returns a range that contains all values strictly greater than {@code
    081       * lower} and strictly less than {@code upper}.
    082       *
    083       * @throws IllegalArgumentException if {@code lower} is greater than <i>or
    084       *     equal to</i> {@code upper}
    085       */
    086      public static <C extends Comparable<?>> Range<C> open(C lower, C upper) {
    087        return create(Cut.aboveValue(lower), Cut.belowValue(upper));
    088      }
    089
    090      /**
    091       * Returns a range that contains all values greater than or equal to
    092       * {@code lower} and less than or equal to {@code upper}.
    093       *
    094       * @throws IllegalArgumentException if {@code lower} is greater than {@code
    095       *     upper}
    096       */
    097      public static <C extends Comparable<?>> Range<C> closed(C lower, C upper) {
    098        return create(Cut.belowValue(lower), Cut.aboveValue(upper));
    099      }
    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    }