    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    }