| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * 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 android.util; |
| |
| import static com.android.internal.util.Preconditions.*; |
| |
| import android.annotation.Nullable; |
| import android.hardware.camera2.utils.HashCodeHelpers; |
| |
| /** |
| * Immutable class for describing the range of two numeric values. |
| * <p> |
| * A range (or "interval") defines the inclusive boundaries around a contiguous span of |
| * values of some {@link Comparable} type; for example, |
| * "integers from 1 to 100 inclusive." |
| * </p> |
| * <p> |
| * All ranges are bounded, and the left side of the range is always {@code <=} |
| * the right side of the range. |
| * </p> |
| * |
| * <p>Although the implementation itself is immutable, there is no restriction that objects |
| * stored must also be immutable. If mutable objects are stored here, then the range |
| * effectively becomes mutable. </p> |
| */ |
| public final class Range<T extends Comparable<? super T>> { |
| /** |
| * Create a new immutable range. |
| * |
| * <p> |
| * The endpoints are {@code [lower, upper]}; that |
| * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal} |
| * to {@code upper}. |
| * </p> |
| * |
| * @param lower The lower endpoint (inclusive) |
| * @param upper The upper endpoint (inclusive) |
| * |
| * @throws NullPointerException if {@code lower} or {@code upper} is {@code null} |
| */ |
| public Range(final T lower, final T upper) { |
| mLower = checkNotNull(lower, "lower must not be null"); |
| mUpper = checkNotNull(upper, "upper must not be null"); |
| |
| if (lower.compareTo(upper) > 0) { |
| throw new IllegalArgumentException("lower must be less than or equal to upper"); |
| } |
| } |
| |
| /** |
| * Create a new immutable range, with the argument types inferred. |
| * |
| * <p> |
| * The endpoints are {@code [lower, upper]}; that |
| * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal} |
| * to {@code upper}. |
| * </p> |
| * |
| * @param lower The lower endpoint (inclusive) |
| * @param upper The upper endpoint (inclusive) |
| * |
| * @throws NullPointerException if {@code lower} or {@code upper} is {@code null} |
| */ |
| public static <T extends Comparable<? super T>> Range<T> create(final T lower, final T upper) { |
| return new Range<T>(lower, upper); |
| } |
| |
| /** |
| * Get the lower endpoint. |
| * |
| * @return a non-{@code null} {@code T} reference |
| */ |
| public T getLower() { |
| return mLower; |
| } |
| |
| /** |
| * Get the upper endpoint. |
| * |
| * @return a non-{@code null} {@code T} reference |
| */ |
| public T getUpper() { |
| return mUpper; |
| } |
| |
| /** |
| * Checks if the {@code value} is within the bounds of this range. |
| * |
| * <p>A value is considered to be within this range if it's {@code >=} |
| * the lower endpoint <i>and</i> {@code <=} the upper endpoint (using the {@link Comparable} |
| * interface.)</p> |
| * |
| * @param value a non-{@code null} {@code T} reference |
| * @return {@code true} if the value is within this inclusive range, {@code false} otherwise |
| * |
| * @throws NullPointerException if {@code value} was {@code null} |
| */ |
| public boolean contains(T value) { |
| checkNotNull(value, "value must not be null"); |
| |
| boolean gteLower = value.compareTo(mLower) >= 0; |
| boolean lteUpper = value.compareTo(mUpper) <= 0; |
| |
| return gteLower && lteUpper; |
| } |
| |
| /** |
| * Checks if another {@code range} is within the bounds of this range. |
| * |
| * <p>A range is considered to be within this range if both of its endpoints |
| * are within this range.</p> |
| * |
| * @param range a non-{@code null} {@code T} reference |
| * @return {@code true} if the range is within this inclusive range, {@code false} otherwise |
| * |
| * @throws NullPointerException if {@code range} was {@code null} |
| */ |
| public boolean contains(Range<T> range) { |
| checkNotNull(range, "value must not be null"); |
| |
| boolean gteLower = range.mLower.compareTo(mLower) >= 0; |
| boolean lteUpper = range.mUpper.compareTo(mUpper) <= 0; |
| |
| return gteLower && lteUpper; |
| } |
| |
| /** |
| * Compare two ranges for equality. |
| * |
| * <p>A range is considered equal if and only if both the lower and upper endpoints |
| * are also equal.</p> |
| * |
| * @return {@code true} if the ranges are equal, {@code false} otherwise |
| */ |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| if (obj == null) { |
| return false; |
| } else if (this == obj) { |
| return true; |
| } else if (obj instanceof Range) { |
| @SuppressWarnings("rawtypes") |
| Range other = (Range) obj; |
| return mLower.equals(other.mLower) && mUpper.equals(other.mUpper); |
| } |
| return false; |
| } |
| |
| /** |
| * Clamps {@code value} to this range. |
| * |
| * <p>If the value is within this range, it is returned. Otherwise, if it |
| * is {@code <} than the lower endpoint, the lower endpoint is returned, |
| * else the upper endpoint is returned. Comparisons are performed using the |
| * {@link Comparable} interface.</p> |
| * |
| * @param value a non-{@code null} {@code T} reference |
| * @return {@code value} clamped to this range. |
| */ |
| public T clamp(T value) { |
| checkNotNull(value, "value must not be null"); |
| |
| if (value.compareTo(mLower) < 0) { |
| return mLower; |
| } else if (value.compareTo(mUpper) > 0) { |
| return mUpper; |
| } else { |
| return value; |
| } |
| } |
| |
| /** |
| * Returns the intersection of this range and another {@code range}. |
| * <p> |
| * E.g. if a {@code <} b {@code <} c {@code <} d, the |
| * intersection of [a, c] and [b, d] ranges is [b, c]. |
| * As the endpoints are object references, there is no guarantee |
| * which specific endpoint reference is used from the input ranges:</p> |
| * <p> |
| * E.g. if a {@code ==} a' {@code <} b {@code <} c, the |
| * intersection of [a, b] and [a', c] ranges could be either |
| * [a, b] or ['a, b], where [a, b] could be either the exact |
| * input range, or a newly created range with the same endpoints.</p> |
| * |
| * @param range a non-{@code null} {@code Range<T>} reference |
| * @return the intersection of this range and the other range. |
| * |
| * @throws NullPointerException if {@code range} was {@code null} |
| * @throws IllegalArgumentException if the ranges are disjoint. |
| */ |
| public Range<T> intersect(Range<T> range) { |
| checkNotNull(range, "range must not be null"); |
| |
| int cmpLower = range.mLower.compareTo(mLower); |
| int cmpUpper = range.mUpper.compareTo(mUpper); |
| |
| if (cmpLower <= 0 && cmpUpper >= 0) { |
| // range includes this |
| return this; |
| } else if (cmpLower >= 0 && cmpUpper <= 0) { |
| // this inludes range |
| return range; |
| } else { |
| return Range.create( |
| cmpLower <= 0 ? mLower : range.mLower, |
| cmpUpper >= 0 ? mUpper : range.mUpper); |
| } |
| } |
| |
| /** |
| * Returns the intersection of this range and the inclusive range |
| * specified by {@code [lower, upper]}. |
| * <p> |
| * See {@link #intersect(Range)} for more details.</p> |
| * |
| * @param lower a non-{@code null} {@code T} reference |
| * @param upper a non-{@code null} {@code T} reference |
| * @return the intersection of this range and the other range |
| * |
| * @throws NullPointerException if {@code lower} or {@code upper} was {@code null} |
| * @throws IllegalArgumentException if the ranges are disjoint. |
| */ |
| public Range<T> intersect(T lower, T upper) { |
| checkNotNull(lower, "lower must not be null"); |
| checkNotNull(upper, "upper must not be null"); |
| |
| int cmpLower = lower.compareTo(mLower); |
| int cmpUpper = upper.compareTo(mUpper); |
| |
| if (cmpLower <= 0 && cmpUpper >= 0) { |
| // [lower, upper] includes this |
| return this; |
| } else { |
| return Range.create( |
| cmpLower <= 0 ? mLower : lower, |
| cmpUpper >= 0 ? mUpper : upper); |
| } |
| } |
| |
| /** |
| * Returns the smallest range that includes this range and |
| * another {@code range}. |
| * <p> |
| * E.g. if a {@code <} b {@code <} c {@code <} d, the |
| * extension of [a, c] and [b, d] ranges is [a, d]. |
| * As the endpoints are object references, there is no guarantee |
| * which specific endpoint reference is used from the input ranges:</p> |
| * <p> |
| * E.g. if a {@code ==} a' {@code <} b {@code <} c, the |
| * extension of [a, b] and [a', c] ranges could be either |
| * [a, c] or ['a, c], where ['a, c] could be either the exact |
| * input range, or a newly created range with the same endpoints.</p> |
| * |
| * @param range a non-{@code null} {@code Range<T>} reference |
| * @return the extension of this range and the other range. |
| * |
| * @throws NullPointerException if {@code range} was {@code null} |
| */ |
| public Range<T> extend(Range<T> range) { |
| checkNotNull(range, "range must not be null"); |
| |
| int cmpLower = range.mLower.compareTo(mLower); |
| int cmpUpper = range.mUpper.compareTo(mUpper); |
| |
| if (cmpLower <= 0 && cmpUpper >= 0) { |
| // other includes this |
| return range; |
| } else if (cmpLower >= 0 && cmpUpper <= 0) { |
| // this inludes other |
| return this; |
| } else { |
| return Range.create( |
| cmpLower >= 0 ? mLower : range.mLower, |
| cmpUpper <= 0 ? mUpper : range.mUpper); |
| } |
| } |
| |
| /** |
| * Returns the smallest range that includes this range and |
| * the inclusive range specified by {@code [lower, upper]}. |
| * <p> |
| * See {@link #extend(Range)} for more details.</p> |
| * |
| * @param lower a non-{@code null} {@code T} reference |
| * @param upper a non-{@code null} {@code T} reference |
| * @return the extension of this range and the other range. |
| * |
| * @throws NullPointerException if {@code lower} or {@code |
| * upper} was {@code null} |
| */ |
| public Range<T> extend(T lower, T upper) { |
| checkNotNull(lower, "lower must not be null"); |
| checkNotNull(upper, "upper must not be null"); |
| |
| int cmpLower = lower.compareTo(mLower); |
| int cmpUpper = upper.compareTo(mUpper); |
| |
| if (cmpLower >= 0 && cmpUpper <= 0) { |
| // this inludes other |
| return this; |
| } else { |
| return Range.create( |
| cmpLower >= 0 ? mLower : lower, |
| cmpUpper <= 0 ? mUpper : upper); |
| } |
| } |
| |
| /** |
| * Returns the smallest range that includes this range and |
| * the {@code value}. |
| * <p> |
| * See {@link #extend(Range)} for more details, as this method is |
| * equivalent to {@code extend(Range.create(value, value))}.</p> |
| * |
| * @param value a non-{@code null} {@code T} reference |
| * @return the extension of this range and the value. |
| * |
| * @throws NullPointerException if {@code value} was {@code null} |
| */ |
| public Range<T> extend(T value) { |
| checkNotNull(value, "value must not be null"); |
| return extend(value, value); |
| } |
| |
| /** |
| * Return the range as a string representation {@code "[lower, upper]"}. |
| * |
| * @return string representation of the range |
| */ |
| @Override |
| public String toString() { |
| return String.format("[%s, %s]", mLower, mUpper); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public int hashCode() { |
| return HashCodeHelpers.hashCodeGeneric(mLower, mUpper); |
| } |
| |
| private final T mLower; |
| private final T mUpper; |
| } |