Open Source Repository

Home /guava/guava-10.0 | Repository Home



com/google/common/collect/Ranges.java
/*
 * Copyright (C) 2009 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Static methods pertaining to {@link Range} instances.  Each of the
 {@link Range nine types of ranges} can be constructed with a corresponding
 * factory method:
 *
 <dl>
 <dt>{@code (a..b)}
 <dd>{@link #open}
 <dt>{@code [a..b]}
 <dd>{@link #closed}
 <dt>{@code [a..b)}
 <dd>{@link #closedOpen}
 <dt>{@code (a..b]}
 <dd>{@link #openClosed}
 <dt>{@code (a..+∞)}
 <dd>{@link #greaterThan}
 <dt>{@code [a..+∞)}
 <dd>{@link #atLeast}
 <dt>{@code (-∞..b)}
 <dd>{@link #lessThan}
 <dt>{@code (-∞..b]}
 <dd>{@link #atMost}
 <dt>{@code (-∞..+∞)}
 <dd>{@link #all}
 </dl>
 *
 <p>Additionally, {@link Range} instances can be constructed by passing the
 {@link BoundType bound types} explicitly.
 *
 <dl>
 <dt>Bounded on both ends
 <dd>{@link #range}
 <dt>Unbounded on top ({@code (a..+∞)} or {@code (a..+∞)})
 <dd>{@link #downTo}
 <dt>Unbounded on bottom ({@code (-∞..b)} or {@code (-∞..b]})
 <dd>{@link #upTo}
 </dl>
 *
 @author Kevin Bourrillion
 @author Gregory Kick
 @since 10.0
 */
@GwtCompatible
@Beta
public final class Ranges {
  private Ranges() {}

  static <C extends Comparable<?>> Range<C> create(
      Cut<C> lowerBound, Cut<C> upperBound) {
    return new Range<C>(lowerBound, upperBound);
  }

  /**
   * Returns a range that contains all values strictly greater than {@code
   * lower} and strictly less than {@code upper}.
   *
   @throws IllegalArgumentException if {@code lower} is greater than <i>or
   *     equal to</i> {@code upper}
   */
  public static <C extends Comparable<?>> Range<C> open(C lower, C upper) {
    return create(Cut.aboveValue(lower), Cut.belowValue(upper));
  }

  /**
   * Returns a range that contains all values greater than or equal to
   * {@code lower} and less than or equal to {@code upper}.
   *
   @throws IllegalArgumentException if {@code lower} is greater than {@code
   *     upper}
   */
  public static <C extends Comparable<?>> Range<C> closed(C lower, C upper) {
    return create(Cut.belowValue(lower), Cut.aboveValue(upper));
  }

  /**
   * Returns a range that contains all values greater than or equal to
   * {@code lower} and strictly less than {@code upper}.
   *
   @throws IllegalArgumentException if {@code lower} is greater than {@code
   *     upper}
   */
  public static <C extends Comparable<?>> Range<C> closedOpen(
      C lower, C upper) {
    return create(Cut.belowValue(lower), Cut.belowValue(upper));
  }

  /**
   * Returns a range that contains all values strictly greater than {@code
   * lower} and less than or equal to {@code upper}.
   *
   @throws IllegalArgumentException if {@code lower} is greater than {@code
   *     upper}
   */
  public static <C extends Comparable<?>> Range<C> openClosed(
      C lower, C upper) {
    return create(Cut.aboveValue(lower), Cut.aboveValue(upper));
  }

  /**
   * Returns a range that contains any value from {@code lower} to {@code
   * upper}, where each endpoint may be either inclusive (closed) or exclusive
   * (open).
   *
   @throws IllegalArgumentException if {@code lower} is greater than {@code
   *     upper}
   */
  public static <C extends Comparable<?>> Range<C> range(
      C lower, BoundType lowerType, C upper, BoundType upperType) {
    checkNotNull(lowerType);
    checkNotNull(upperType);

    Cut<C> lowerBound = (lowerType == BoundType.OPEN)
        ? Cut.aboveValue(lower)
        : Cut.belowValue(lower);
    Cut<C> upperBound = (upperType == BoundType.OPEN)
        ? Cut.belowValue(upper)
        : Cut.aboveValue(upper);
    return create(lowerBound, upperBound);
  }

  /**
   * Returns a range that contains all values strictly less than {@code
   * endpoint}.
   */
  public static <C extends Comparable<?>> Range<C> lessThan(C endpoint) {
    return create(Cut.<C>belowAll(), Cut.belowValue(endpoint));
  }

  /**
   * Returns a range that contains all values less than or equal to
   * {@code endpoint}.
   */
  public static <C extends Comparable<?>> Range<C> atMost(C endpoint) {
    return create(Cut.<C>belowAll(), Cut.aboveValue(endpoint));
  }

  /**
   * Returns a range with no lower bound up to the given endpoint, which may be
   * either inclusive (closed) or exclusive (open).
   */
  public static <C extends Comparable<?>> Range<C> upTo(
      C endpoint, BoundType boundType) {
    switch (boundType) {
      case OPEN:
        return lessThan(endpoint);
      case CLOSED:
        return atMost(endpoint);
      default:
        throw new AssertionError();
    }
  }

  /**
   * Returns a range that contains all values strictly greater than {@code
   * endpoint}.
   */
  public static <C extends Comparable<?>> Range<C> greaterThan(C endpoint) {
    return create(Cut.aboveValue(endpoint), Cut.<C>aboveAll());
  }

  /**
   * Returns a range that contains all values greater than or equal to
   * {@code endpoint}.
   */
  public static <C extends Comparable<?>> Range<C> atLeast(C endpoint) {
    return create(Cut.belowValue(endpoint), Cut.<C>aboveAll());
  }

  /**
   * Returns a range from the given endpoint, which may be either inclusive
   * (closed) or exclusive (open), with no upper bound.
   */
  public static <C extends Comparable<?>> Range<C> downTo(
      C endpoint, BoundType boundType) {
    switch (boundType) {
      case OPEN:
        return greaterThan(endpoint);
      case CLOSED:
        return atLeast(endpoint);
      default:
        throw new AssertionError();
    }
  }

  /** Returns a range that contains every value of type {@code C}. */
  public static <C extends Comparable<?>> Range<C> all() {
    return create(Cut.<C>belowAll(), Cut.<C>aboveAll());
  }

  /**
   * Returns a range that {@linkplain Range#contains(Comparable) contains} only
   * the given value. The returned range is {@linkplain BoundType#CLOSED closed}
   * on both ends.
   */
  public static <C extends Comparable<?>> Range<C> singleton(C value) {
    return closed(value, value);
  }

  /**
   * Returns the minimal range that
   {@linkplain Range#contains(Comparable) contains} all of the given values.
   * The returned range is {@linkplain BoundType#CLOSED closed} on both ends.
   *
   @throws ClassCastException if the parameters are not <i>mutually
   *     comparable</i>
   @throws NoSuchElementException if {@code values} is empty
   @throws NullPointerException if any of {@code values} is null
   */
  public static <C extends Comparable<?>> Range<C> encloseAll(
      Iterable<C> values) {
    checkNotNull(values);
    if (values instanceof ContiguousSet) {
      return ((ContiguousSet<C>values).range();
    }
    Iterator<C> valueIterator = values.iterator();
    C min = checkNotNull(valueIterator.next());
    C max = min;
    while (valueIterator.hasNext()) {
      C value = checkNotNull(valueIterator.next());
      min = Ordering.natural().min(min, value);
      max = Ordering.natural().max(max, value);
    }
    return closed(min, max);
  }
}