add utility methods to util.Range, Rational and Size
Bug: 12065651 Bug: 11990470 Change-Id: I0d0929ea0289ac5de5c17cca90f25abc4e9dfd7a
This commit is contained in:
@@ -31334,10 +31334,17 @@ package android.util {
|
||||
|
||||
public final class Range {
|
||||
ctor public Range(T, T);
|
||||
method public T clamp(T);
|
||||
method public boolean contains(T);
|
||||
method public boolean contains(android.util.Range<T>);
|
||||
method public static android.util.Range<T> create(T, T);
|
||||
method public android.util.Range<T> extend(android.util.Range<T>);
|
||||
method public android.util.Range<T> extend(T, T);
|
||||
method public android.util.Range<T> extend(T);
|
||||
method public T getLower();
|
||||
method public T getUpper();
|
||||
method public boolean inRange(T);
|
||||
method public android.util.Range<T> intersect(android.util.Range<T>);
|
||||
method public android.util.Range<T> intersect(T, T);
|
||||
}
|
||||
|
||||
public final class Rational extends java.lang.Number implements java.lang.Comparable {
|
||||
@@ -31353,6 +31360,7 @@ package android.util {
|
||||
method public boolean isNaN();
|
||||
method public boolean isZero();
|
||||
method public long longValue();
|
||||
method public static android.util.Rational parseRational(java.lang.String) throws java.lang.NumberFormatException;
|
||||
field public static final android.util.Rational NEGATIVE_INFINITY;
|
||||
field public static final android.util.Rational NaN;
|
||||
field public static final android.util.Rational POSITIVE_INFINITY;
|
||||
@@ -31363,6 +31371,7 @@ package android.util {
|
||||
ctor public Size(int, int);
|
||||
method public int getHeight();
|
||||
method public int getWidth();
|
||||
method public static android.util.Size parseSize(java.lang.String) throws java.lang.NumberFormatException;
|
||||
}
|
||||
|
||||
public final class SizeF {
|
||||
|
||||
@@ -99,16 +99,16 @@ public final class Range<T extends Comparable<? super T>> {
|
||||
/**
|
||||
* 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 >=} then
|
||||
* the lower endpoint <i>and</i> {@code <=} to the upper endpoint (using the {@link Comparable}
|
||||
* interface.</p>
|
||||
* <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 inRange(T value) {
|
||||
public boolean contains(T value) {
|
||||
checkNotNull(value, "value must not be null");
|
||||
|
||||
boolean gteLower = value.compareTo(mLower) >= 0;
|
||||
@@ -117,6 +117,26 @@ public final class Range<T extends Comparable<? super T>> {
|
||||
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.
|
||||
*
|
||||
@@ -139,6 +159,182 @@ public final class Range<T extends Comparable<? super T>> {
|
||||
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]"}.
|
||||
*
|
||||
|
||||
@@ -536,8 +536,67 @@ public final class Rational extends Number implements Comparable<Rational> {
|
||||
} else { // finite value
|
||||
if (gcd(mNumerator, mDenominator) > 1) {
|
||||
throw new InvalidObjectException(
|
||||
"Rational must be deserialized from a reduced form for finite values");
|
||||
"Rational must be deserialized from a reduced form for finite values");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static NumberFormatException invalidRational(String s) {
|
||||
throw new NumberFormatException("Invalid Rational: \"" + s + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified string as a rational value.
|
||||
* <p>The ASCII characters {@code \}{@code u003a} (':') and
|
||||
* {@code \}{@code u002f} ('/') are recognized as separators between
|
||||
* the numerator and denumerator.</p>
|
||||
* <p>
|
||||
* For any {@code Rational r}: {@code Rational.parseRational(r.toString()).equals(r)}.
|
||||
* However, the method also handles rational numbers expressed in the
|
||||
* following forms:</p>
|
||||
* <p>
|
||||
* "<i>num</i>{@code /}<i>den</i>" or
|
||||
* "<i>num</i>{@code :}<i>den</i>" {@code => new Rational(num, den);},
|
||||
* where <i>num</i> and <i>den</i> are string integers potentially
|
||||
* containing a sign, such as "-10", "+7" or "5".</p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* Rational.parseRational("3:+6").equals(new Rational(1, 2)) == true
|
||||
* Rational.parseRational("-3/-6").equals(new Rational(1, 2)) == true
|
||||
* Rational.parseRational("4.56") => throws NumberFormatException
|
||||
* }</pre>
|
||||
*
|
||||
* @param string the string representation of a rational value.
|
||||
* @return the rational value represented by {@code string}.
|
||||
*
|
||||
* @throws NumberFormatException if {@code string} cannot be parsed
|
||||
* as a rational value.
|
||||
* @throws NullPointerException if {@code string} was {@code null}
|
||||
*/
|
||||
public static Rational parseRational(String string)
|
||||
throws NumberFormatException {
|
||||
checkNotNull(string, "string must not be null");
|
||||
|
||||
if (string.equals("NaN")) {
|
||||
return NaN;
|
||||
} else if (string.equals("Infinity")) {
|
||||
return POSITIVE_INFINITY;
|
||||
} else if (string.equals("-Infinity")) {
|
||||
return NEGATIVE_INFINITY;
|
||||
}
|
||||
|
||||
int sep_ix = string.indexOf(':');
|
||||
if (sep_ix < 0) {
|
||||
sep_ix = string.indexOf('/');
|
||||
}
|
||||
if (sep_ix < 0) {
|
||||
throw invalidRational(string);
|
||||
}
|
||||
try {
|
||||
return new Rational(Integer.parseInt(string.substring(0, sep_ix)),
|
||||
Integer.parseInt(string.substring(sep_ix + 1)));
|
||||
} catch (NumberFormatException e) {
|
||||
throw invalidRational(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.util;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Immutable class for describing width and height dimensions in pixels.
|
||||
*/
|
||||
@@ -84,6 +86,58 @@ public final class Size {
|
||||
return mWidth + "x" + mHeight;
|
||||
}
|
||||
|
||||
private static NumberFormatException invalidSize(String s) {
|
||||
throw new NumberFormatException("Invalid Size: \"" + s + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified string as a size value.
|
||||
* <p>
|
||||
* The ASCII characters {@code \}{@code u002a} ('*') and
|
||||
* {@code \}{@code u0078} ('x') are recognized as separators between
|
||||
* the width and height.</p>
|
||||
* <p>
|
||||
* For any {@code Size s}: {@code Size.parseSize(s.toString()).equals(s)}.
|
||||
* However, the method also handles sizes expressed in the
|
||||
* following forms:</p>
|
||||
* <p>
|
||||
* "<i>width</i>{@code x}<i>height</i>" or
|
||||
* "<i>width</i>{@code *}<i>height</i>" {@code => new Size(width, height)},
|
||||
* where <i>width</i> and <i>height</i> are string integers potentially
|
||||
* containing a sign, such as "-10", "+7" or "5".</p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* Size.parseSize("3*+6").equals(new Size(3, 6)) == true
|
||||
* Size.parseSize("-3x-6").equals(new Size(-3, -6)) == true
|
||||
* Size.parseSize("4 by 3") => throws NumberFormatException
|
||||
* }</pre>
|
||||
*
|
||||
* @param string the string representation of a size value.
|
||||
* @return the size value represented by {@code string}.
|
||||
*
|
||||
* @throws NumberFormatException if {@code string} cannot be parsed
|
||||
* as a size value.
|
||||
* @throws NullPointerException if {@code string} was {@code null}
|
||||
*/
|
||||
public static Size parseSize(String string)
|
||||
throws NumberFormatException {
|
||||
checkNotNull(string, "string must not be null");
|
||||
|
||||
int sep_ix = string.indexOf('*');
|
||||
if (sep_ix < 0) {
|
||||
sep_ix = string.indexOf('x');
|
||||
}
|
||||
if (sep_ix < 0) {
|
||||
throw invalidSize(string);
|
||||
}
|
||||
try {
|
||||
return new Size(Integer.parseInt(string.substring(0, sep_ix)),
|
||||
Integer.parseInt(string.substring(sep_ix + 1)));
|
||||
} catch (NumberFormatException e) {
|
||||
throw invalidSize(string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
||||
@@ -137,12 +137,12 @@ public class RangeTest extends junit.framework.TestCase {
|
||||
}
|
||||
|
||||
private static <T extends Comparable<? super T>> void assertInRange(Range<T> object, T needle) {
|
||||
assertAction("in-range", object, needle, true, object.inRange(needle));
|
||||
assertAction("in-range", object, needle, true, object.contains(needle));
|
||||
}
|
||||
|
||||
private static <T extends Comparable<? super T>> void assertOutOfRange(Range<T> object,
|
||||
T needle) {
|
||||
assertAction("out-of-range", object, needle, false, object.inRange(needle));
|
||||
assertAction("out-of-range", object, needle, false, object.contains(needle));
|
||||
}
|
||||
|
||||
private static <T extends Comparable<? super T>> void assertUpper(Range<T> object, T expected) {
|
||||
|
||||
Reference in New Issue
Block a user