Added sources from apache commons lang

This commit is contained in:
Claudio Maggioni 2022-12-06 15:35:18 +01:00
commit dfcf4e96b9
11 changed files with 5689 additions and 0 deletions

32
.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

10
README.md Normal file
View File

@ -0,0 +1,10 @@
# SDM assigment 04
Classes come from [https://github.com/apache/commons-lang](https://github.com/apache/commons-lang)
revision `770e72d2f78361b14f3fe27caea41e5977d3c638`
## Run Tests
```
mvn clean test
```

58
pom.xml Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>sdm04</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.23.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,379 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 ch.usi.inf.sdm.sdm04;
import java.io.Serializable;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
/**
* A contiguous range of characters, optionally negated.
*
* <p>Instances are immutable.</p>
*
* <p>#ThreadSafe#</p>
*
* @since 1.0
*/
// TODO: This is no longer public and will be removed later as CharSet is moved
// to depend on Range.
final class CharRange implements Iterable<Character>, Serializable {
/**
* Required for serialization support. Lang version 2.0.
*
* @see Serializable
*/
private static final long serialVersionUID = 8270183163158333422L;
/**
* The first character, inclusive, in the range.
*/
private final char start;
/**
* The last character, inclusive, in the range.
*/
private final char end;
/**
* True if the range is everything except the characters specified.
*/
private final boolean negated;
/**
* Cached toString.
*/
private transient String iToString;
/**
* Empty array.
*/
static final CharRange[] EMPTY_ARRAY = {};
/**
* Constructs a {@link CharRange} over a set of characters,
* optionally negating the range.
*
* <p>A negated range includes everything except that defined by the
* start and end characters.</p>
*
* <p>If start and end are in the wrong order, they are reversed.
* Thus {@code a-e} is the same as {@code e-a}.</p>
*
* @param start first character, inclusive, in this range
* @param end last character, inclusive, in this range
* @param negated true to express everything except the range
*/
private CharRange(char start, char end, final boolean negated) {
if (start > end) {
final char temp = start;
start = end;
end = temp;
}
this.start = start;
this.end = end;
this.negated = negated;
}
/**
* Constructs a {@link CharRange} over a single character.
*
* @param ch only character in this range
* @return the new CharRange object
* @since 2.5
*/
public static CharRange is(final char ch) {
return new CharRange(ch, ch, false);
}
/**
* Constructs a negated {@link CharRange} over a single character.
*
* <p>A negated range includes everything except that defined by the
* single character.</p>
*
* @param ch only character in this range
* @return the new CharRange object
* @since 2.5
*/
public static CharRange isNot(final char ch) {
return new CharRange(ch, ch, true);
}
/**
* Constructs a {@link CharRange} over a set of characters.
*
* <p>If start and end are in the wrong order, they are reversed.
* Thus {@code a-e} is the same as {@code e-a}.</p>
*
* @param start first character, inclusive, in this range
* @param end last character, inclusive, in this range
* @return the new CharRange object
* @since 2.5
*/
public static CharRange isIn(final char start, final char end) {
return new CharRange(start, end, false);
}
/**
* Constructs a negated {@link CharRange} over a set of characters.
*
* <p>A negated range includes everything except that defined by the
* start and end characters.</p>
*
* <p>If start and end are in the wrong order, they are reversed.
* Thus {@code a-e} is the same as {@code e-a}.</p>
*
* @param start first character, inclusive, in this range
* @param end last character, inclusive, in this range
* @return the new CharRange object
* @since 2.5
*/
public static CharRange isNotIn(final char start, final char end) {
return new CharRange(start, end, true);
}
// Accessors
/**
* Gets the start character for this character range.
*
* @return the start char (inclusive)
*/
public char getStart() {
return this.start;
}
/**
* Gets the end character for this character range.
*
* @return the end char (inclusive)
*/
public char getEnd() {
return this.end;
}
/**
* Is this {@link CharRange} negated.
*
* <p>A negated range includes everything except that defined by the
* start and end characters.</p>
*
* @return {@code true} if negated
*/
public boolean isNegated() {
return negated;
}
// Contains
/**
* Is the character specified contained in this range.
*
* @param ch the character to check
* @return {@code true} if this range contains the input character
*/
public boolean contains(final char ch) {
return (ch >= start && ch <= end) != negated;
}
/**
* Are all the characters of the passed in range contained in
* this range.
*
* @param range the range to check against
* @return {@code true} if this range entirely contains the input range
* @throws NullPointerException if {@code null} input
*/
public boolean contains(final CharRange range) {
Objects.requireNonNull(range, "range");
if (negated) {
if (range.negated) {
return start >= range.start && end <= range.end;
}
return range.end < start || range.start > end;
}
if (range.negated) {
return start == 0 && end == Character.MAX_VALUE;
}
return start <= range.start && end >= range.end;
}
// Basics
/**
* Compares two CharRange objects, returning true if they represent
* exactly the same range of characters defined in the same way.
*
* @param obj the object to compare to
* @return true if equal
*/
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof CharRange)) {
return false;
}
final CharRange other = (CharRange) obj;
return start == other.start && end == other.end && negated == other.negated;
}
/**
* Gets a hashCode compatible with the equals method.
*
* @return a suitable hashCode
*/
@Override
public int hashCode() {
return 83 + start + 7 * end + (negated ? 1 : 0);
}
/**
* Gets a string representation of the character range.
*
* @return string representation of this range
*/
@Override
public String toString() {
if (iToString == null) {
final StringBuilder buf = new StringBuilder(4);
if (isNegated()) {
buf.append('^');
}
buf.append(start);
if (start != end) {
buf.append('-');
buf.append(end);
}
iToString = buf.toString();
}
return iToString;
}
/**
* Returns an iterator which can be used to walk through the characters described by this range.
*
* <p>#NotThreadSafe# the iterator is not thread-safe</p>
*
* @return an iterator to the chars represented by this range
* @since 2.5
*/
@Override
public Iterator<Character> iterator() {
return new CharacterIterator(this);
}
/**
* Character {@link Iterator}.
* <p>#NotThreadSafe#</p>
*/
private static class CharacterIterator implements Iterator<Character> {
/**
* The current character
*/
private char current;
private final CharRange range;
private boolean hasNext;
/**
* Constructs a new iterator for the character range.
*
* @param r The character range
*/
private CharacterIterator(final CharRange r) {
range = r;
hasNext = true;
if (range.negated) {
if (range.start == 0) {
if (range.end == Character.MAX_VALUE) {
// This range is an empty set
hasNext = false;
} else {
current = (char) (range.end + 1);
}
} else {
current = 0;
}
} else {
current = range.start;
}
}
/**
* Prepares the next character in the range.
*/
private void prepareNext() {
if (range.negated) {
if (current == Character.MAX_VALUE) {
hasNext = false;
} else if (current + 1 == range.start) {
if (range.end == Character.MAX_VALUE) {
hasNext = false;
} else {
current = (char) (range.end + 1);
}
} else {
current = (char) (current + 1);
}
} else if (current < range.end) {
current = (char) (current + 1);
} else {
hasNext = false;
}
}
/**
* Has the iterator not reached the end character yet?
*
* @return {@code true} if the iterator has yet to reach the character date
*/
@Override
public boolean hasNext() {
return hasNext;
}
/**
* Returns the next character in the iteration
*
* @return {@link Character} for the next character
*/
@Override
public Character next() {
if (!hasNext) {
throw new NoSuchElementException();
}
final char cur = current;
prepareNext();
return Character.valueOf(cur);
}
/**
* Always throws UnsupportedOperationException.
*
* @throws UnsupportedOperationException Always thrown.
* @see Iterator#remove()
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,911 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 ch.usi.inf.sdm.sdm04.math;
import java.math.BigInteger;
import java.util.Objects;
/**
* {@link Fraction} is a {@link Number} implementation that
* stores fractions accurately.
*
* <p>This class is immutable, and interoperable with most methods that accept
* a {@link Number}.</p>
*
* <p>Note that this class is intended for common use cases, it is <i>int</i>
* based and thus suffers from various overflow issues. For a BigInteger based
* equivalent, please see the Commons Math BigFraction class.</p>
*
* @since 2.0
*/
public final class Fraction extends Number implements Comparable<Fraction> {
/**
* Required for serialization support. Lang version 2.0.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 65382027393090L;
/**
* {@link Fraction} representation of 0.
*/
public static final Fraction ZERO = new Fraction(0, 1);
/**
* {@link Fraction} representation of 1.
*/
public static final Fraction ONE = new Fraction(1, 1);
/**
* {@link Fraction} representation of 1/2.
*/
public static final Fraction ONE_HALF = new Fraction(1, 2);
/**
* {@link Fraction} representation of 1/3.
*/
public static final Fraction ONE_THIRD = new Fraction(1, 3);
/**
* {@link Fraction} representation of 2/3.
*/
public static final Fraction TWO_THIRDS = new Fraction(2, 3);
/**
* {@link Fraction} representation of 1/4.
*/
public static final Fraction ONE_QUARTER = new Fraction(1, 4);
/**
* {@link Fraction} representation of 2/4.
*/
public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
/**
* {@link Fraction} representation of 3/4.
*/
public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
/**
* {@link Fraction} representation of 1/5.
*/
public static final Fraction ONE_FIFTH = new Fraction(1, 5);
/**
* {@link Fraction} representation of 2/5.
*/
public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
/**
* {@link Fraction} representation of 3/5.
*/
public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
/**
* {@link Fraction} representation of 4/5.
*/
public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
/**
* The numerator number part of the fraction (the three in three sevenths).
*/
private final int numerator;
/**
* The denominator number part of the fraction (the seven in three sevenths).
*/
private final int denominator;
/**
* Cached output hashCode (class is immutable).
*/
private transient int hashCode;
/**
* Cached output toString (class is immutable).
*/
private transient String toString;
/**
* Cached output toProperString (class is immutable).
*/
private transient String toProperString;
/**
* Constructs a {@link Fraction} instance with the 2 parts
* of a fraction Y/Z.
*
* @param numerator the numerator, for example the three in 'three sevenths'
* @param denominator the denominator, for example the seven in 'three sevenths'
*/
private Fraction(final int numerator, final int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
/**
* Creates a {@link Fraction} instance with the 2 parts
* of a fraction Y/Z.
*
* <p>Any negative signs are resolved to be on the numerator.</p>
*
* @param numerator the numerator, for example the three in 'three sevenths'
* @param denominator the denominator, for example the seven in 'three sevenths'
* @return a new fraction instance
* @throws ArithmeticException if the denominator is {@code zero}
* or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE}
*/
public static Fraction getFraction(int numerator, int denominator) {
if (denominator == 0) {
throw new ArithmeticException("The denominator must not be zero");
}
if (denominator < 0) {
if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: can't negate");
}
numerator = -numerator;
denominator = -denominator;
}
return new Fraction(numerator, denominator);
}
/**
* Creates a {@link Fraction} instance with the 3 parts
* of a fraction X Y/Z.
*
* <p>The negative sign must be passed in on the whole number part.</p>
*
* @param whole the whole number, for example the one in 'one and three sevenths'
* @param numerator the numerator, for example the three in 'one and three sevenths'
* @param denominator the denominator, for example the seven in 'one and three sevenths'
* @return a new fraction instance
* @throws ArithmeticException if the denominator is {@code zero}
* @throws ArithmeticException if the denominator is negative
* @throws ArithmeticException if the numerator is negative
* @throws ArithmeticException if the resulting numerator exceeds
* {@code Integer.MAX_VALUE}
*/
public static Fraction getFraction(final int whole, final int numerator, final int denominator) {
if (denominator == 0) {
throw new ArithmeticException("The denominator must not be zero");
}
if (denominator < 0) {
throw new ArithmeticException("The denominator must not be negative");
}
if (numerator < 0) {
throw new ArithmeticException("The numerator must not be negative");
}
final long numeratorValue;
if (whole < 0) {
numeratorValue = whole * (long) denominator - numerator;
} else {
numeratorValue = whole * (long) denominator + numerator;
}
if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) {
throw new ArithmeticException("Numerator too large to represent as an Integer.");
}
return new Fraction((int) numeratorValue, denominator);
}
/**
* Creates a reduced {@link Fraction} instance with the 2 parts
* of a fraction Y/Z.
*
* <p>For example, if the input parameters represent 2/4, then the created
* fraction will be 1/2.</p>
*
* <p>Any negative signs are resolved to be on the numerator.</p>
*
* @param numerator the numerator, for example the three in 'three sevenths'
* @param denominator the denominator, for example the seven in 'three sevenths'
* @return a new fraction instance, with the numerator and denominator reduced
* @throws ArithmeticException if the denominator is {@code zero}
*/
public static Fraction getReducedFraction(int numerator, int denominator) {
if (denominator == 0) {
throw new ArithmeticException("The denominator must not be zero");
}
if (numerator == 0) {
return ZERO; // normalize zero.
}
// allow 2^k/-2^31 as a valid fraction (where k>0)
if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) {
numerator /= 2;
denominator /= 2;
}
if (denominator < 0) {
if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: can't negate");
}
numerator = -numerator;
denominator = -denominator;
}
// simplify fraction.
final int gcd = greatestCommonDivisor(numerator, denominator);
numerator /= gcd;
denominator /= gcd;
return new Fraction(numerator, denominator);
}
/**
* Creates a {@link Fraction} instance from a {@code double} value.
*
* <p>This method uses the <a href="https://web.archive.org/web/20210516065058/http%3A//archives.math.utk.edu/articles/atuyl/confrac/">
* continued fraction algorithm</a>, computing a maximum of
* 25 convergents and bounding the denominator by 10,000.</p>
*
* @param value the double value to convert
* @return a new fraction instance that is close to the value
* @throws ArithmeticException if {@code |value| &gt; Integer.MAX_VALUE}
* or {@code value = NaN}
* @throws ArithmeticException if the calculated denominator is {@code zero}
* @throws ArithmeticException if the algorithm does not converge
*/
public static Fraction getFraction(double value) {
final int sign = value < 0 ? -1 : 1;
value = Math.abs(value);
if (value > Integer.MAX_VALUE || Double.isNaN(value)) {
throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN");
}
final int wholeNumber = (int) value;
value -= wholeNumber;
int numer0 = 0; // the pre-previous
int denom0 = 1; // the pre-previous
int numer1 = 1; // the previous
int denom1 = 0; // the previous
int numer2; // the current, setup in calculation
int denom2; // the current, setup in calculation
int a1 = (int) value;
int a2;
double x1 = 1;
double x2;
double y1 = value - a1;
double y2;
double delta1, delta2 = Double.MAX_VALUE;
double fraction;
int i = 1;
do {
delta1 = delta2;
a2 = (int) (x1 / y1);
x2 = y1;
y2 = x1 - a2 * y1;
numer2 = a1 * numer1 + numer0;
denom2 = a1 * denom1 + denom0;
fraction = (double) numer2 / (double) denom2;
delta2 = Math.abs(value - fraction);
a1 = a2;
x1 = x2;
y1 = y2;
numer0 = numer1;
denom0 = denom1;
numer1 = numer2;
denom1 = denom2;
i++;
} while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25);
if (i == 25) {
throw new ArithmeticException("Unable to convert double to fraction");
}
return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0);
}
/**
* Creates a Fraction from a {@link String}.
*
* <p>The formats accepted are:</p>
*
* <ol>
* <li>{@code double} String containing a dot</li>
* <li>'X Y/Z'</li>
* <li>'Y/Z'</li>
* <li>'X' (a simple whole number)</li>
* </ol>
* <p>and a .</p>
*
* @param str the string to parse, must not be {@code null}
* @return the new {@link Fraction} instance
* @throws NullPointerException if the string is {@code null}
* @throws NumberFormatException if the number format is invalid
*/
public static Fraction getFraction(String str) {
Objects.requireNonNull(str, "str");
// parse double format
int pos = str.indexOf('.');
if (pos >= 0) {
return getFraction(Double.parseDouble(str));
}
// parse X Y/Z format
pos = str.indexOf(' ');
if (pos > 0) {
final int whole = Integer.parseInt(str.substring(0, pos));
str = str.substring(pos + 1);
pos = str.indexOf('/');
if (pos < 0) {
throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
}
final int numer = Integer.parseInt(str.substring(0, pos));
final int denom = Integer.parseInt(str.substring(pos + 1));
return getFraction(whole, numer, denom);
}
// parse Y/Z format
pos = str.indexOf('/');
if (pos < 0) {
// simple whole number
return getFraction(Integer.parseInt(str), 1);
}
final int numer = Integer.parseInt(str.substring(0, pos));
final int denom = Integer.parseInt(str.substring(pos + 1));
return getFraction(numer, denom);
}
/**
* Gets the numerator part of the fraction.
*
* <p>This method may return a value greater than the denominator, an
* improper fraction, such as the seven in 7/4.</p>
*
* @return the numerator fraction part
*/
public int getNumerator() {
return numerator;
}
/**
* Gets the denominator part of the fraction.
*
* @return the denominator fraction part
*/
public int getDenominator() {
return denominator;
}
/**
* Gets the proper numerator, always positive.
*
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
* This method returns the 3 from the proper fraction.</p>
*
* <p>If the fraction is negative such as -7/4, it can be resolved into
* -1 3/4, so this method returns the positive proper numerator, 3.</p>
*
* @return the numerator fraction part of a proper fraction, always positive
*/
public int getProperNumerator() {
return Math.abs(numerator % denominator);
}
/**
* Gets the proper whole part of the fraction.
*
* <p>An improper fraction 7/4 can be resolved into a proper one, 1 3/4.
* This method returns the 1 from the proper fraction.</p>
*
* <p>If the fraction is negative such as -7/4, it can be resolved into
* -1 3/4, so this method returns the positive whole part -1.</p>
*
* @return the whole fraction part of a proper fraction, that includes the sign
*/
public int getProperWhole() {
return numerator / denominator;
}
/**
* Gets the fraction as an {@code int}. This returns the whole number
* part of the fraction.
*
* @return the whole number fraction part
*/
@Override
public int intValue() {
return numerator / denominator;
}
/**
* Gets the fraction as a {@code long}. This returns the whole number
* part of the fraction.
*
* @return the whole number fraction part
*/
@Override
public long longValue() {
return (long) numerator / denominator;
}
/**
* Gets the fraction as a {@code float}. This calculates the fraction
* as the numerator divided by denominator.
*
* @return the fraction as a {@code float}
*/
@Override
public float floatValue() {
return (float) numerator / (float) denominator;
}
/**
* Gets the fraction as a {@code double}. This calculates the fraction
* as the numerator divided by denominator.
*
* @return the fraction as a {@code double}
*/
@Override
public double doubleValue() {
return (double) numerator / (double) denominator;
}
/**
* Reduce the fraction to the smallest values for the numerator and
* denominator, returning the result.
*
* <p>For example, if this fraction represents 2/4, then the result
* will be 1/2.</p>
*
* @return a new reduced fraction instance, or this if no simplification possible
*/
public Fraction reduce() {
if (numerator == 0) {
return equals(ZERO) ? this : ZERO;
}
final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
if (gcd == 1) {
return this;
}
return getFraction(numerator / gcd, denominator / gcd);
}
/**
* Gets a fraction that is the inverse (1/fraction) of this one.
*
* <p>The returned fraction is not reduced.</p>
*
* @return a new fraction instance with the numerator and denominator
* inverted.
* @throws ArithmeticException if the fraction represents zero.
*/
public Fraction invert() {
if (numerator == 0) {
throw new ArithmeticException("Unable to invert zero.");
}
if (numerator==Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: can't negate numerator");
}
if (numerator<0) {
return new Fraction(-denominator, -numerator);
}
return new Fraction(denominator, numerator);
}
/**
* Gets a fraction that is the negative (-fraction) of this one.
*
* <p>The returned fraction is not reduced.</p>
*
* @return a new fraction instance with the opposite signed numerator
*/
public Fraction negate() {
// the positive range is one smaller than the negative range of an int.
if (numerator==Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: too large to negate");
}
return new Fraction(-numerator, denominator);
}
/**
* Gets a fraction that is the positive equivalent of this one.
* <p>More precisely: {@code (fraction &gt;= 0 ? this : -fraction)}</p>
*
* <p>The returned fraction is not reduced.</p>
*
* @return {@code this} if it is positive, or a new positive fraction
* instance with the opposite signed numerator
*/
public Fraction abs() {
if (numerator >= 0) {
return this;
}
return negate();
}
/**
* Gets a fraction that is raised to the passed in power.
*
* <p>The returned fraction is in reduced form.</p>
*
* @param power the power to raise the fraction to
* @return {@code this} if the power is one, {@link #ONE} if the power
* is zero (even if the fraction equals ZERO) or a new fraction instance
* raised to the appropriate power
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* {@code Integer.MAX_VALUE}
*/
public Fraction pow(final int power) {
if (power == 1) {
return this;
}
if (power == 0) {
return ONE;
}
if (power < 0) {
if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
return this.invert().pow(2).pow(-(power / 2));
}
return this.invert().pow(-power);
}
final Fraction f = this.multiplyBy(this);
if (power % 2 == 0) { // if even...
return f.pow(power / 2);
}
return f.pow(power / 2).multiplyBy(this);
}
/**
* Gets the greatest common divisor of the absolute value of
* two numbers, using the "binary gcd" method which avoids
* division and modulo operations. See Knuth 4.5.2 algorithm B.
* This algorithm is due to Josef Stein (1961).
*
* @param u a non-zero number
* @param v a non-zero number
* @return the greatest common divisor, never zero
*/
private static int greatestCommonDivisor(int u, int v) {
// From Commons Math:
if (u == 0 || v == 0) {
if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) {
throw new ArithmeticException("overflow: gcd is 2^31");
}
return Math.abs(u) + Math.abs(v);
}
// if either operand is abs 1, return 1:
if (Math.abs(u) == 1 || Math.abs(v) == 1) {
return 1;
}
// keep u and v negative, as negative integers range down to
// -2^31, while positive numbers can only be as large as 2^31-1
// (i.e. we can't necessarily negate a negative number without
// overflow)
if (u > 0) {
u = -u;
} // make u negative
if (v > 0) {
v = -v;
} // make v negative
// B1. [Find power of 2]
int k = 0;
while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even...
u /= 2;
v /= 2;
k++; // cast out twos.
}
if (k == 31) {
throw new ArithmeticException("overflow: gcd is 2^31");
}
// B2. Initialize: u and v have been divided by 2^k and at least
// one is odd.
int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */;
// t negative: u was odd, v may be even (t replaces v)
// t positive: u was even, v is odd (t replaces u)
do {
/* assert u<0 && v<0; */
// B4/B3: cast out twos from t.
while ((t & 1) == 0) { // while t is even.
t /= 2; // cast out twos
}
// B5 [reset max(u,v)]
if (t > 0) {
u = -t;
} else {
v = t;
}
// B6/B3. at this point both u and v should be odd.
t = (v - u) / 2;
// |u| larger: t positive (replace u)
// |v| larger: t negative (replace v)
} while (t != 0);
return -u * (1 << k); // gcd is u*2^k
}
/**
* Multiply two integers, checking for overflow.
*
* @param x a factor
* @param y a factor
* @return the product {@code x*y}
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int mulAndCheck(final int x, final int y) {
final long m = (long) x * (long) y;
if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: mul");
}
return (int) m;
}
/**
* Multiply two non-negative integers, checking for overflow.
*
* @param x a non-negative factor
* @param y a non-negative factor
* @return the product {@code x*y}
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int mulPosAndCheck(final int x, final int y) {
/* assert x>=0 && y>=0; */
final long m = (long) x * (long) y;
if (m > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: mulPos");
}
return (int) m;
}
/**
* Add two integers, checking for overflow.
*
* @param x an addend
* @param y an addend
* @return the sum {@code x+y}
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int addAndCheck(final int x, final int y) {
final long s = (long) x + (long) y;
if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: add");
}
return (int) s;
}
/**
* Subtract two integers, checking for overflow.
*
* @param x the minuend
* @param y the subtrahend
* @return the difference {@code x-y}
* @throws ArithmeticException if the result can not be represented as
* an int
*/
private static int subAndCheck(final int x, final int y) {
final long s = (long) x - (long) y;
if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) {
throw new ArithmeticException("overflow: add");
}
return (int) s;
}
/**
* Adds the value of this fraction to another, returning the result in reduced form.
* The algorithm follows Knuth, 4.5.1.
*
* @param fraction the fraction to add, must not be {@code null}
* @return a {@link Fraction} instance with the resulting values
* @throws IllegalArgumentException if the fraction is {@code null}
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* {@code Integer.MAX_VALUE}
*/
public Fraction add(final Fraction fraction) {
return addSub(fraction, true /* add */);
}
/**
* Subtracts the value of another fraction from the value of this one,
* returning the result in reduced form.
*
* @param fraction the fraction to subtract, must not be {@code null}
* @return a {@link Fraction} instance with the resulting values
* @throws IllegalArgumentException if the fraction is {@code null}
* @throws ArithmeticException if the resulting numerator or denominator
* cannot be represented in an {@code int}.
*/
public Fraction subtract(final Fraction fraction) {
return addSub(fraction, false /* subtract */);
}
/**
* Implement add and subtract using algorithm described in Knuth 4.5.1.
*
* @param fraction the fraction to subtract, must not be {@code null}
* @param isAdd true to add, false to subtract
* @return a {@link Fraction} instance with the resulting values
* @throws IllegalArgumentException if the fraction is {@code null}
* @throws ArithmeticException if the resulting numerator or denominator
* cannot be represented in an {@code int}.
*/
private Fraction addSub(final Fraction fraction, final boolean isAdd) {
Objects.requireNonNull(fraction, "fraction");
// zero is identity for addition.
if (numerator == 0) {
return isAdd ? fraction : fraction.negate();
}
if (fraction.numerator == 0) {
return this;
}
// if denominators are randomly distributed, d1 will be 1 about 61%
// of the time.
final int d1 = greatestCommonDivisor(denominator, fraction.denominator);
if (d1 == 1) {
// result is ( (u*v' +/- u'v) / u'v')
final int uvp = mulAndCheck(numerator, fraction.denominator);
final int upv = mulAndCheck(fraction.numerator, denominator);
return new Fraction(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv), mulPosAndCheck(denominator,
fraction.denominator));
}
// the quantity 't' requires 65 bits of precision; see knuth 4.5.1
// exercise 7. we're going to use a BigInteger.
// t = u(v'/d1) +/- v(u'/d1)
final BigInteger uvp = BigInteger.valueOf(numerator).multiply(BigInteger.valueOf(fraction.denominator / d1));
final BigInteger upv = BigInteger.valueOf(fraction.numerator).multiply(BigInteger.valueOf(denominator / d1));
final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
// but d2 doesn't need extra precision because
// d2 = gcd(t,d1) = gcd(t mod d1, d1)
final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1);
// result is (t/d2) / (u'/d1)(v'/d2)
final BigInteger w = t.divide(BigInteger.valueOf(d2));
if (w.bitLength() > 31) {
throw new ArithmeticException("overflow: numerator too large after multiply");
}
return new Fraction(w.intValue(), mulPosAndCheck(denominator / d1, fraction.denominator / d2));
}
/**
* Multiplies the value of this fraction by another, returning the
* result in reduced form.
*
* @param fraction the fraction to multiply by, must not be {@code null}
* @return a {@link Fraction} instance with the resulting values
* @throws NullPointerException if the fraction is {@code null}
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* {@code Integer.MAX_VALUE}
*/
public Fraction multiplyBy(final Fraction fraction) {
Objects.requireNonNull(fraction, "fraction");
if (numerator == 0 || fraction.numerator == 0) {
return ZERO;
}
// knuth 4.5.1
// make sure we don't overflow unless the result *must* overflow.
final int d1 = greatestCommonDivisor(numerator, fraction.denominator);
final int d2 = greatestCommonDivisor(fraction.numerator, denominator);
return getReducedFraction(mulAndCheck(numerator / d1, fraction.numerator / d2),
mulPosAndCheck(denominator / d2, fraction.denominator / d1));
}
/**
* Divide the value of this fraction by another.
*
* @param fraction the fraction to divide by, must not be {@code null}
* @return a {@link Fraction} instance with the resulting values
* @throws NullPointerException if the fraction is {@code null}
* @throws ArithmeticException if the fraction to divide by is zero
* @throws ArithmeticException if the resulting numerator or denominator exceeds
* {@code Integer.MAX_VALUE}
*/
public Fraction divideBy(final Fraction fraction) {
Objects.requireNonNull(fraction, "fraction");
if (fraction.numerator == 0) {
throw new ArithmeticException("The fraction to divide by must not be zero");
}
return multiplyBy(fraction.invert());
}
/**
* Compares this fraction to another object to test if they are equal..
*
* <p>To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.</p>
*
* @param obj the reference object with which to compare
* @return {@code true} if this object is equal
*/
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Fraction)) {
return false;
}
final Fraction other = (Fraction) obj;
return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator();
}
/**
* Gets a hashCode for the fraction.
*
* @return a hash code value for this object
*/
@Override
public int hashCode() {
if (hashCode == 0) {
// hash code update should be atomic.
hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
}
return hashCode;
}
/**
* Compares this object to another based on size.
*
* <p>Note: this class has a natural ordering that is inconsistent
* with equals, because, for example, equals treats 1/2 and 2/4 as
* different, whereas compareTo treats them as equal.
*
* @param other the object to compare to
* @return -1 if this is less, 0 if equal, +1 if greater
* @throws ClassCastException if the object is not a {@link Fraction}
* @throws NullPointerException if the object is {@code null}
*/
@Override
public int compareTo(final Fraction other) {
if (this == other) {
return 0;
}
if (numerator == other.numerator && denominator == other.denominator) {
return 0;
}
// otherwise see which is less
final long first = (long) numerator * (long) other.denominator;
final long second = (long) other.numerator * (long) denominator;
return Long.compare(first, second);
}
/**
* Gets the fraction as a {@link String}.
*
* <p>The format used is '<i>numerator</i>/<i>denominator</i>' always.
*
* @return a {@link String} form of the fraction
*/
@Override
public String toString() {
if (toString == null) {
toString = getNumerator() + "/" + getDenominator();
}
return toString;
}
/**
* Gets the fraction as a proper {@link String} in the format X Y/Z.
*
* <p>The format used in '<i>wholeNumber</i> <i>numerator</i>/<i>denominator</i>'.
* If the whole number is zero it will be omitted. If the numerator is zero,
* only the whole number is returned.</p>
*
* @return a {@link String} form of the fraction
*/
public String toProperString() {
if (toProperString == null) {
if (numerator == 0) {
toProperString = "0";
} else if (numerator == denominator) {
toProperString = "1";
} else if (numerator == -1 * denominator) {
toProperString = "-1";
} else if ((numerator > 0 ? -numerator : numerator) < -denominator) {
// note that we do the magnitude comparison test above with
// NEGATIVE (not positive) numbers, since negative numbers
// have a larger range. otherwise numerator==Integer.MIN_VALUE
// is handled incorrectly.
final int properNumerator = getProperNumerator();
if (properNumerator == 0) {
toProperString = Integer.toString(getProperWhole());
} else {
toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator();
}
} else {
toProperString = getNumerator() + "/" + getDenominator();
}
}
return toProperString;
}
}

View File

@ -0,0 +1,252 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 ch.usi.inf.sdm.sdm04.math;
import org.apache.commons.lang3.Validate;
import java.util.Objects;
/**
* Provides IEEE-754r variants of NumberUtils methods.
*
* <p>See: <a href="https://en.wikipedia.org/wiki/IEEE_754r">https://en.wikipedia.org/wiki/IEEE_754r</a></p>
*
* @since 2.4
*/
public class IEEE754rUtils {
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws NullPointerException if {@code array} is {@code null}
* @throws IllegalArgumentException if {@code array} is empty
* @since 3.4 Changed signature from min(double[]) to min(double...)
*/
public static double min(final double... array) {
Objects.requireNonNull(array, "array");
Validate.isTrue(array.length != 0, "Array cannot be empty.");
// Finds and returns min
double min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* Returns the minimum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws NullPointerException if {@code array} is {@code null}
* @throws IllegalArgumentException if {@code array} is empty
* @since 3.4 Changed signature from min(float[]) to min(float...)
*/
public static float min(final float... array) {
Objects.requireNonNull(array, "array");
Validate.isTrue(array.length != 0, "Array cannot be empty.");
// Finds and returns min
float min = array[0];
for (int i = 1; i < array.length; i++) {
min = min(array[i], min);
}
return min;
}
/**
* Gets the minimum of three {@code double} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static double min(final double a, final double b, final double c) {
return min(min(a, b), c);
}
/**
* Gets the minimum of two {@code double} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static double min(final double a, final double b) {
if (Double.isNaN(a)) {
return b;
}
if (Double.isNaN(b)) {
return a;
}
return Math.min(a, b);
}
/**
* Gets the minimum of three {@code float} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the smallest of the values
*/
public static float min(final float a, final float b, final float c) {
return min(min(a, b), c);
}
/**
* Gets the minimum of two {@code float} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @return the smallest of the values
*/
public static float min(final float a, final float b) {
if (Float.isNaN(a)) {
return b;
}
if (Float.isNaN(b)) {
return a;
}
return Math.min(a, b);
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws NullPointerException if {@code array} is {@code null}
* @throws IllegalArgumentException if {@code array} is empty
* @since 3.4 Changed signature from max(double[]) to max(double...)
*/
public static double max(final double... array) {
Objects.requireNonNull(array, "array");
Validate.isTrue(array.length != 0, "Array cannot be empty.");
// Finds and returns max
double max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* Returns the maximum value in an array.
*
* @param array an array, must not be null or empty
* @return the minimum value in the array
* @throws NullPointerException if {@code array} is {@code null}
* @throws IllegalArgumentException if {@code array} is empty
* @since 3.4 Changed signature from max(float[]) to max(float...)
*/
public static float max(final float... array) {
Objects.requireNonNull(array, "array");
Validate.isTrue(array.length != 0, "Array cannot be empty.");
// Finds and returns max
float max = array[0];
for (int j = 1; j < array.length; j++) {
max = max(array[j], max);
}
return max;
}
/**
* Gets the maximum of three {@code double} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static double max(final double a, final double b, final double c) {
return max(max(a, b), c);
}
/**
* Gets the maximum of two {@code double} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static double max(final double a, final double b) {
if (Double.isNaN(a)) {
return b;
}
if (Double.isNaN(b)) {
return a;
}
return Math.max(a, b);
}
/**
* Gets the maximum of three {@code float} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @param c value 3
* @return the largest of the values
*/
public static float max(final float a, final float b, final float c) {
return max(max(a, b), c);
}
/**
* Gets the maximum of two {@code float} values.
*
* <p>NaN is only returned if all numbers are NaN as per IEEE-754r.</p>
*
* @param a value 1
* @param b value 2
* @return the largest of the values
*/
public static float max(final float a, final float b) {
if (Float.isNaN(a)) {
return b;
}
if (Float.isNaN(b)) {
return a;
}
return Math.max(a, b);
}
}

View File

@ -0,0 +1,611 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 ch.usi.inf.sdm.sdm04.util;
import java.io.Serializable;
import java.util.BitSet;
import java.util.Objects;
import java.util.stream.IntStream;
/**
* A fluent {@link BitSet} with additional operations.
* <p>
* Originally from Apache Commons VFS with more added to act as a fluent replacement for {@link BitSet}.
* </p>
*
* @since 3.13.0
*/
public final class FluentBitSet implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
/**
* Working BitSet.
*/
private final BitSet bitSet;
/**
* Creates a new bit set. All bits are initially {@code false}.
*/
public FluentBitSet() {
this(new BitSet());
}
/**
* Creates a new instance for the given bit set.
*
* @param set The bit set to wrap.
*/
public FluentBitSet(final BitSet set) {
this.bitSet = Objects.requireNonNull(set, "set");
}
/**
* Creates a bit set whose initial size is large enough to explicitly represent bits with indices in the range {@code 0}
* through {@code nbits-1}. All bits are initially {@code false}.
*
* @param nbits the initial size of the bit set.
* @throws NegativeArraySizeException if the specified initial size is negative.
*/
public FluentBitSet(final int nbits) {
this(new BitSet(nbits));
}
/**
* Performs a logical <b>AND</b> of this target bit set with the argument bit set. This bit set is modified so that each
* bit in it has the value {@code true} if and only if it both initially had the value {@code true} and the
* corresponding bit in the bit set argument also had the value {@code true}.
*
* @param set a bit set.
* @return this.
*/
public FluentBitSet and(final BitSet set) {
bitSet.and(set);
return this;
}
/**
* Performs a logical <b>AND</b> of this target bit set with the argument bit set. This bit set is modified so that each
* bit in it has the value {@code true} if and only if it both initially had the value {@code true} and the
* corresponding bit in the bit set argument also had the value {@code true}.
*
* @param set a bit set.
* @return this.
*/
public FluentBitSet and(final FluentBitSet set) {
bitSet.and(set.bitSet);
return this;
}
/**
* Clears all of the bits in this {@link BitSet} whose corresponding bit is set in the specified {@link BitSet}.
*
* @param set the {@link BitSet} with which to mask this {@link BitSet}.
* @return this.
*/
public FluentBitSet andNot(final BitSet set) {
bitSet.andNot(set);
return this;
}
/**
* Clears all of the bits in this {@link BitSet} whose corresponding bit is set in the specified {@link BitSet}.
*
* @param set the {@link BitSet} with which to mask this {@link BitSet}.
* @return this.
*/
public FluentBitSet andNot(final FluentBitSet set) {
this.bitSet.andNot(set.bitSet);
return this;
}
/**
* Gets the wrapped bit set.
*
* @return the wrapped bit set.
*/
public BitSet bitSet() {
return bitSet;
}
/**
* Returns the number of bits set to {@code true} in this {@link BitSet}.
*
* @return the number of bits set to {@code true} in this {@link BitSet}.
*/
public int cardinality() {
return bitSet.cardinality();
}
/**
* Sets all of the bits in this BitSet to {@code false}.
*
* @return this.
*/
public FluentBitSet clear() {
bitSet.clear();
return this;
}
/**
* Sets the bits specified by the indexes to {@code false}.
*
* @param bitIndexArray the index of the bit to be cleared.
* @return this.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public FluentBitSet clear(final int... bitIndexArray) {
for (final int e : bitIndexArray) {
this.bitSet.clear(e);
}
return this;
}
/**
* Sets the bit specified by the index to {@code false}.
*
* @param bitIndex the index of the bit to be cleared.
* @return this.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public FluentBitSet clear(final int bitIndex) {
bitSet.clear(bitIndex);
return this;
}
/**
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to
* {@code false}.
*
* @param fromIndex index of the first bit to be cleared.
* @param toIndex index after the last bit to be cleared.
* @return this.
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
* {@code fromIndex} is larger than {@code toIndex}.
*/
public FluentBitSet clear(final int fromIndex, final int toIndex) {
bitSet.clear(fromIndex, toIndex);
return this;
}
/**
* Cloning this {@link BitSet} produces a new {@link BitSet} that is equal to it. The clone of the bit set is another
* bit set that has exactly the same bits set to {@code true} as this bit set.
*
* @return a clone of this bit set
* @see #size()
*/
@Override
public Object clone() {
return new FluentBitSet((BitSet) bitSet.clone());
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof FluentBitSet)) {
return false;
}
final FluentBitSet other = (FluentBitSet) obj;
return Objects.equals(bitSet, other.bitSet);
}
/**
* Sets the bit at the specified index to the complement of its current value.
*
* @param bitIndex the index of the bit to flip.
* @return this.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public FluentBitSet flip(final int bitIndex) {
bitSet.flip(bitIndex);
return this;
}
/**
* Sets each bit from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to the
* complement of its current value.
*
* @param fromIndex index of the first bit to flip.
* @param toIndex index after the last bit to flip.
* @return this.
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
* {@code fromIndex} is larger than {@code toIndex}.
*/
public FluentBitSet flip(final int fromIndex, final int toIndex) {
bitSet.flip(fromIndex, toIndex);
return this;
}
/**
* Returns the value of the bit with the specified index. The value is {@code true} if the bit with the index
* {@code bitIndex} is currently set in this {@link BitSet}; otherwise, the result is {@code false}.
*
* @param bitIndex the bit index.
* @return the value of the bit with the specified index.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public boolean get(final int bitIndex) {
return bitSet.get(bitIndex);
}
/**
* Returns a new {@link BitSet} composed of bits from this {@link BitSet} from {@code fromIndex} (inclusive) to
* {@code toIndex} (exclusive).
*
* @param fromIndex index of the first bit to include.
* @param toIndex index after the last bit to include.
* @return a new {@link BitSet} from a range of this {@link BitSet}.
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
* {@code fromIndex} is larger than {@code toIndex}.
*/
public FluentBitSet get(final int fromIndex, final int toIndex) {
return new FluentBitSet(bitSet.get(fromIndex, toIndex));
}
@Override
public int hashCode() {
return bitSet.hashCode();
}
/**
* Returns true if the specified {@link BitSet} has any bits set to {@code true} that are also set to {@code true} in
* this {@link BitSet}.
*
* @param set {@link BitSet} to intersect with.
* @return boolean indicating whether this {@link BitSet} intersects the specified {@link BitSet}.
*/
public boolean intersects(final BitSet set) {
return bitSet.intersects(set);
}
/**
* Returns true if the specified {@link BitSet} has any bits set to {@code true} that are also set to {@code true} in
* this {@link BitSet}.
*
* @param set {@link BitSet} to intersect with.
* @return boolean indicating whether this {@link BitSet} intersects the specified {@link BitSet}.
*/
public boolean intersects(final FluentBitSet set) {
return bitSet.intersects(set.bitSet);
}
/**
* Returns true if this {@link BitSet} contains no bits that are set to {@code true}.
*
* @return boolean indicating whether this {@link BitSet} is empty.
*/
public boolean isEmpty() {
return bitSet.isEmpty();
}
/**
* Returns the "logical size" of this {@link BitSet}: the index of the highest set bit in the {@link BitSet} plus one.
* Returns zero if the {@link BitSet} contains no set bits.
*
* @return the logical size of this {@link BitSet}.
*/
public int length() {
return bitSet.length();
}
/**
* Returns the index of the first bit that is set to {@code false} that occurs on or after the specified starting index.
*
* @param fromIndex the index to start checking from (inclusive).
* @return the index of the next clear bit.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public int nextClearBit(final int fromIndex) {
return bitSet.nextClearBit(fromIndex);
}
/**
* Returns the index of the first bit that is set to {@code true} that occurs on or after the specified starting index.
* If no such bit exists then {@code -1} is returned.
* <p>
* To iterate over the {@code true} bits in a {@link BitSet}, use the following loop:
* </p>
*
* <pre>
* {@code
* for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
* // operate on index i here
* if (i == Integer.MAX_VALUE) {
* break; // or (i+1) would overflow
* }
* }}
* </pre>
*
* @param fromIndex the index to start checking from (inclusive).
* @return the index of the next set bit, or {@code -1} if there is no such bit.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public int nextSetBit(final int fromIndex) {
return bitSet.nextSetBit(fromIndex);
}
/**
* Performs a logical <b>OR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
* has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in
* the bit set argument has the value {@code true}.
*
* @param set a bit set.
* @return this.
*/
public FluentBitSet or(final BitSet set) {
bitSet.or(set);
return this;
}
/**
* Performs a logical <b>OR</b> of this bit set with the bit set arguments. This bit set is modified so that a bit in it
* has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in
* the bit set argument has the value {@code true}.
*
* @param set a bit set.
* @return this.
*/
public FluentBitSet or(final FluentBitSet... set) {
for (final FluentBitSet e : set) {
this.bitSet.or(e.bitSet);
}
return this;
}
/**
* Performs a logical <b>OR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
* has the value {@code true} if and only if it either already had the value {@code true} or the corresponding bit in
* the bit set argument has the value {@code true}.
*
* @param set a bit set.
* @return this.
*/
public FluentBitSet or(final FluentBitSet set) {
this.bitSet.or(set.bitSet);
return this;
}
/**
* Returns the index of the nearest bit that is set to {@code false} that occurs on or before the specified starting
* index. If no such bit exists, or if {@code -1} is given as the starting index, then {@code -1} is returned.
*
* @param fromIndex the index to start checking from (inclusive).
* @return the index of the previous clear bit, or {@code -1} if there is no such bit.
* @throws IndexOutOfBoundsException if the specified index is less than {@code -1}.
*/
public int previousClearBit(final int fromIndex) {
return bitSet.previousClearBit(fromIndex);
}
/**
* Returns the index of the nearest bit that is set to {@code true} that occurs on or before the specified starting
* index. If no such bit exists, or if {@code -1} is given as the starting index, then {@code -1} is returned.
*
* <p>
* To iterate over the {@code true} bits in a {@link BitSet}, use the following loop:
*
* <pre>
* {@code
* for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
* // operate on index i here
* }}
* </pre>
*
* @param fromIndex the index to start checking from (inclusive)
* @return the index of the previous set bit, or {@code -1} if there is no such bit
* @throws IndexOutOfBoundsException if the specified index is less than {@code -1}
*/
public int previousSetBit(final int fromIndex) {
return bitSet.previousSetBit(fromIndex);
}
/**
* Sets the bit at the specified indexes to {@code true}.
*
* @param bitIndexArray a bit index array.
* @return this.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public FluentBitSet set(final int... bitIndexArray) {
for (final int e : bitIndexArray) {
bitSet.set(e);
}
return this;
}
/**
* Sets the bit at the specified index to {@code true}.
*
* @param bitIndex a bit index
* @return this.
* @throws IndexOutOfBoundsException if the specified index is negative
*/
public FluentBitSet set(final int bitIndex) {
bitSet.set(bitIndex);
return this;
}
/**
* Sets the bit at the specified index to the specified value.
*
* @param bitIndex a bit index.
* @param value a boolean value to set.
* @return this.
* @throws IndexOutOfBoundsException if the specified index is negative.
*/
public FluentBitSet set(final int bitIndex, final boolean value) {
bitSet.set(bitIndex, value);
return this;
}
/**
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to
* {@code true}.
*
* @param fromIndex index of the first bit to be set.
* @param toIndex index after the last bit to be set.
* @return this.
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
* {@code fromIndex} is larger than {@code toIndex}.
*/
public FluentBitSet set(final int fromIndex, final int toIndex) {
bitSet.set(fromIndex, toIndex);
return this;
}
/**
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to the
* specified value.
*
* @param fromIndex index of the first bit to be set.
* @param toIndex index after the last bit to be set.
* @param value value to set the selected bits to.
* @return this.
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
* {@code fromIndex} is larger than {@code toIndex}.
*/
public FluentBitSet set(final int fromIndex, final int toIndex, final boolean value) {
bitSet.set(fromIndex, toIndex, value);
return this;
}
/**
* Sets the bits from the specified {@code fromIndex} (inclusive) to the specified {@code toIndex} (exclusive) to
* {@code true}.
*
* @param fromIndex index of the first bit to be set
* @param toIndex index of the last bit to be set
* @return this.
* @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code toIndex} is negative, or
* {@code fromIndex} is larger than {@code toIndex}
*/
public FluentBitSet setInclusive(final int fromIndex, final int toIndex) {
bitSet.set(fromIndex, toIndex + 1);
return this;
}
/**
* Returns the number of bits of space actually in use by this {@link BitSet} to represent bit values. The maximum
* element in the set is the size - 1st element.
*
* @return the number of bits currently in this bit set.
*/
public int size() {
return bitSet.size();
}
/**
* Returns a stream of indices for which this {@link BitSet} contains a bit in the set state. The indices are returned
* in order, from lowest to highest. The size of the stream is the number of bits in the set state, equal to the value
* returned by the {@link #cardinality()} method.
*
* <p>
* The bit set must remain constant during the execution of the terminal stream operation. Otherwise, the result of the
* terminal stream operation is undefined.
* </p>
*
* @return a stream of integers representing set indices.
* @since 1.8
*/
public IntStream stream() {
return bitSet.stream();
}
/**
* Returns a new byte array containing all the bits in this bit set.
*
* <p>
* More precisely, if:
* </p>
* <ol>
* <li>{@code byte[] bytes = s.toByteArray();}</li>
* <li>then {@code bytes.length == (s.length()+7)/8} and</li>
* <li>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}</li>
* <li>for all {@code n < 8 * bytes.length}.</li>
* </ol>
*
* @return a byte array containing a little-endian representation of all the bits in this bit set
*/
public byte[] toByteArray() {
return bitSet.toByteArray();
}
/**
* Returns a new byte array containing all the bits in this bit set.
*
* <p>
* More precisely, if:
* </p>
* <ol>
* <li>{@code long[] longs = s.toLongArray();}</li>
* <li>then {@code longs.length == (s.length()+63)/64} and</li>
* <li>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}</li>
* <li>for all {@code n < 64 * longs.length}.</li>
* </ol>
*
* @return a byte array containing a little-endian representation of all the bits in this bit set
*/
public long[] toLongArray() {
return bitSet.toLongArray();
}
@Override
public String toString() {
return bitSet.toString();
}
/**
* Performs a logical <b>XOR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
* has the value {@code true} if and only if one of the following statements holds:
* <ul>
* <li>The bit initially has the value {@code true}, and the corresponding bit in the argument has the value
* {@code false}.
* <li>The bit initially has the value {@code false}, and the corresponding bit in the argument has the value
* {@code true}.
* </ul>
*
* @param set a bit set
* @return this.
*/
public FluentBitSet xor(final BitSet set) {
bitSet.xor(set);
return this;
}
/**
* Performs a logical <b>XOR</b> of this bit set with the bit set argument. This bit set is modified so that a bit in it
* has the value {@code true} if and only if one of the following statements holds:
* <ul>
* <li>The bit initially has the value {@code true}, and the corresponding bit in the argument has the value
* {@code false}.
* <li>The bit initially has the value {@code false}, and the corresponding bit in the argument has the value
* {@code true}.
* </ul>
*
* @param set a bit set
* @return this.
*/
public FluentBitSet xor(final FluentBitSet set) {
bitSet.xor(set.bitSet);
return this;
}
}

View File

@ -0,0 +1,382 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 ch.usi.inf.sdm.sdm04;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.commons.lang3.SerializationUtils;
import org.junit.jupiter.api.Test;
/**
* Unit tests {@link CharRange}.
*/
public class CharRangeTest {
@Test
public void testClass() {
// class changed to non-public in 3.0
assertFalse(Modifier.isPublic(CharRange.class.getModifiers()));
assertTrue(Modifier.isFinal(CharRange.class.getModifiers()));
}
@Test
public void testConstructorAccessors_is() {
final CharRange rangea = CharRange.is('a');
assertEquals('a', rangea.getStart());
assertEquals('a', rangea.getEnd());
assertFalse(rangea.isNegated());
assertEquals("a", rangea.toString());
}
@Test
public void testConstructorAccessors_isNot() {
final CharRange rangea = CharRange.isNot('a');
assertEquals('a', rangea.getStart());
assertEquals('a', rangea.getEnd());
assertTrue(rangea.isNegated());
assertEquals("^a", rangea.toString());
}
@Test
public void testConstructorAccessors_isIn_Same() {
final CharRange rangea = CharRange.isIn('a', 'a');
assertEquals('a', rangea.getStart());
assertEquals('a', rangea.getEnd());
assertFalse(rangea.isNegated());
assertEquals("a", rangea.toString());
}
@Test
public void testConstructorAccessors_isIn_Normal() {
final CharRange rangea = CharRange.isIn('a', 'e');
assertEquals('a', rangea.getStart());
assertEquals('e', rangea.getEnd());
assertFalse(rangea.isNegated());
assertEquals("a-e", rangea.toString());
}
@Test
public void testConstructorAccessors_isIn_Reversed() {
final CharRange rangea = CharRange.isIn('e', 'a');
assertEquals('a', rangea.getStart());
assertEquals('e', rangea.getEnd());
assertFalse(rangea.isNegated());
assertEquals("a-e", rangea.toString());
}
@Test
public void testConstructorAccessors_isNotIn_Same() {
final CharRange rangea = CharRange.isNotIn('a', 'a');
assertEquals('a', rangea.getStart());
assertEquals('a', rangea.getEnd());
assertTrue(rangea.isNegated());
assertEquals("^a", rangea.toString());
}
@Test
public void testConstructorAccessors_isNotIn_Normal() {
final CharRange rangea = CharRange.isNotIn('a', 'e');
assertEquals('a', rangea.getStart());
assertEquals('e', rangea.getEnd());
assertTrue(rangea.isNegated());
assertEquals("^a-e", rangea.toString());
}
@Test
public void testConstructorAccessors_isNotIn_Reversed() {
final CharRange rangea = CharRange.isNotIn('e', 'a');
assertEquals('a', rangea.getStart());
assertEquals('e', rangea.getEnd());
assertTrue(rangea.isNegated());
assertEquals("^a-e", rangea.toString());
}
@Test
public void testEquals_Object() {
final CharRange rangea = CharRange.is('a');
final CharRange rangeae = CharRange.isIn('a', 'e');
final CharRange rangenotbf = CharRange.isIn('b', 'f');
assertNotEquals(null, rangea);
assertEquals(rangea, rangea);
assertEquals(rangea, CharRange.is('a'));
assertEquals(rangeae, rangeae);
assertEquals(rangeae, CharRange.isIn('a', 'e'));
assertEquals(rangenotbf, rangenotbf);
assertEquals(rangenotbf, CharRange.isIn('b', 'f'));
assertNotEquals(rangea, rangeae);
assertNotEquals(rangea, rangenotbf);
assertNotEquals(rangeae, rangea);
assertNotEquals(rangeae, rangenotbf);
assertNotEquals(rangenotbf, rangea);
assertNotEquals(rangenotbf, rangeae);
}
@Test
public void testHashCode() {
final CharRange rangea = CharRange.is('a');
final CharRange rangeae = CharRange.isIn('a', 'e');
final CharRange rangenotbf = CharRange.isIn('b', 'f');
assertEquals(rangea.hashCode(), rangea.hashCode());
assertEquals(rangea.hashCode(), CharRange.is('a').hashCode());
assertEquals(rangeae.hashCode(), rangeae.hashCode());
assertEquals(rangeae.hashCode(), CharRange.isIn('a', 'e').hashCode());
assertEquals(rangenotbf.hashCode(), rangenotbf.hashCode());
assertEquals(rangenotbf.hashCode(), CharRange.isIn('b', 'f').hashCode());
assertNotEquals(rangea.hashCode(), rangeae.hashCode());
assertNotEquals(rangea.hashCode(), rangenotbf.hashCode());
assertNotEquals(rangeae.hashCode(), rangea.hashCode());
assertNotEquals(rangeae.hashCode(), rangenotbf.hashCode());
assertNotEquals(rangenotbf.hashCode(), rangea.hashCode());
assertNotEquals(rangenotbf.hashCode(), rangeae.hashCode());
}
@Test
public void testContains_Char() {
CharRange range = CharRange.is('c');
assertFalse(range.contains('b'));
assertTrue(range.contains('c'));
assertFalse(range.contains('d'));
assertFalse(range.contains('e'));
range = CharRange.isIn('c', 'd');
assertFalse(range.contains('b'));
assertTrue(range.contains('c'));
assertTrue(range.contains('d'));
assertFalse(range.contains('e'));
range = CharRange.isIn('d', 'c');
assertFalse(range.contains('b'));
assertTrue(range.contains('c'));
assertTrue(range.contains('d'));
assertFalse(range.contains('e'));
range = CharRange.isNotIn('c', 'd');
assertTrue(range.contains('b'));
assertFalse(range.contains('c'));
assertFalse(range.contains('d'));
assertTrue(range.contains('e'));
assertTrue(range.contains((char) 0));
assertTrue(range.contains(Character.MAX_VALUE));
}
@Test
public void testContains_Charrange() {
final CharRange a = CharRange.is('a');
final CharRange b = CharRange.is('b');
final CharRange c = CharRange.is('c');
final CharRange c2 = CharRange.is('c');
final CharRange d = CharRange.is('d');
final CharRange e = CharRange.is('e');
final CharRange cd = CharRange.isIn('c', 'd');
final CharRange bd = CharRange.isIn('b', 'd');
final CharRange bc = CharRange.isIn('b', 'c');
final CharRange ab = CharRange.isIn('a', 'b');
final CharRange de = CharRange.isIn('d', 'e');
final CharRange ef = CharRange.isIn('e', 'f');
final CharRange ae = CharRange.isIn('a', 'e');
// normal/normal
assertFalse(c.contains(b));
assertTrue(c.contains(c));
assertTrue(c.contains(c2));
assertFalse(c.contains(d));
assertFalse(c.contains(cd));
assertFalse(c.contains(bd));
assertFalse(c.contains(bc));
assertFalse(c.contains(ab));
assertFalse(c.contains(de));
assertTrue(cd.contains(c));
assertTrue(bd.contains(c));
assertTrue(bc.contains(c));
assertFalse(ab.contains(c));
assertFalse(de.contains(c));
assertTrue(ae.contains(b));
assertTrue(ae.contains(ab));
assertTrue(ae.contains(bc));
assertTrue(ae.contains(cd));
assertTrue(ae.contains(de));
final CharRange notb = CharRange.isNot('b');
final CharRange notc = CharRange.isNot('c');
final CharRange notd = CharRange.isNot('d');
final CharRange notab = CharRange.isNotIn('a', 'b');
final CharRange notbc = CharRange.isNotIn('b', 'c');
final CharRange notbd = CharRange.isNotIn('b', 'd');
final CharRange notcd = CharRange.isNotIn('c', 'd');
final CharRange notde = CharRange.isNotIn('d', 'e');
final CharRange notae = CharRange.isNotIn('a', 'e');
final CharRange all = CharRange.isIn((char) 0, Character.MAX_VALUE);
final CharRange allbutfirst = CharRange.isIn((char) 1, Character.MAX_VALUE);
// normal/negated
assertFalse(c.contains(notc));
assertFalse(c.contains(notbd));
assertTrue(all.contains(notc));
assertTrue(all.contains(notbd));
assertFalse(allbutfirst.contains(notc));
assertFalse(allbutfirst.contains(notbd));
// negated/normal
assertTrue(notc.contains(a));
assertTrue(notc.contains(b));
assertFalse(notc.contains(c));
assertTrue(notc.contains(d));
assertTrue(notc.contains(e));
assertTrue(notc.contains(ab));
assertFalse(notc.contains(bc));
assertFalse(notc.contains(bd));
assertFalse(notc.contains(cd));
assertTrue(notc.contains(de));
assertFalse(notc.contains(ae));
assertFalse(notc.contains(all));
assertFalse(notc.contains(allbutfirst));
assertTrue(notbd.contains(a));
assertFalse(notbd.contains(b));
assertFalse(notbd.contains(c));
assertFalse(notbd.contains(d));
assertTrue(notbd.contains(e));
assertTrue(notcd.contains(ab));
assertFalse(notcd.contains(bc));
assertFalse(notcd.contains(bd));
assertFalse(notcd.contains(cd));
assertFalse(notcd.contains(de));
assertFalse(notcd.contains(ae));
assertTrue(notcd.contains(ef));
assertFalse(notcd.contains(all));
assertFalse(notcd.contains(allbutfirst));
// negated/negated
assertFalse(notc.contains(notb));
assertTrue(notc.contains(notc));
assertFalse(notc.contains(notd));
assertFalse(notc.contains(notab));
assertTrue(notc.contains(notbc));
assertTrue(notc.contains(notbd));
assertTrue(notc.contains(notcd));
assertFalse(notc.contains(notde));
assertFalse(notbd.contains(notb));
assertFalse(notbd.contains(notc));
assertFalse(notbd.contains(notd));
assertFalse(notbd.contains(notab));
assertFalse(notbd.contains(notbc));
assertTrue(notbd.contains(notbd));
assertFalse(notbd.contains(notcd));
assertFalse(notbd.contains(notde));
assertTrue(notbd.contains(notae));
}
@Test
public void testContainsNullArg() {
final CharRange range = CharRange.is('a');
final NullPointerException e = assertThrows(NullPointerException.class, () -> range.contains(null));
assertEquals("range", e.getMessage());
}
@Test
public void testIterator() {
final CharRange a = CharRange.is('a');
final CharRange ad = CharRange.isIn('a', 'd');
final CharRange nota = CharRange.isNot('a');
final CharRange emptySet = CharRange.isNotIn((char) 0, Character.MAX_VALUE);
final CharRange notFirst = CharRange.isNotIn((char) 1, Character.MAX_VALUE);
final CharRange notLast = CharRange.isNotIn((char) 0, (char) (Character.MAX_VALUE - 1));
final Iterator<Character> aIt = a.iterator();
assertNotNull(aIt);
assertTrue(aIt.hasNext());
assertEquals(Character.valueOf('a'), aIt.next());
assertFalse(aIt.hasNext());
final Iterator<Character> adIt = ad.iterator();
assertNotNull(adIt);
assertTrue(adIt.hasNext());
assertEquals(Character.valueOf('a'), adIt.next());
assertEquals(Character.valueOf('b'), adIt.next());
assertEquals(Character.valueOf('c'), adIt.next());
assertEquals(Character.valueOf('d'), adIt.next());
assertFalse(adIt.hasNext());
final Iterator<Character> notaIt = nota.iterator();
assertNotNull(notaIt);
assertTrue(notaIt.hasNext());
while (notaIt.hasNext()) {
final Character c = notaIt.next();
assertNotEquals('a', c.charValue());
}
final Iterator<Character> emptySetIt = emptySet.iterator();
assertNotNull(emptySetIt);
assertFalse(emptySetIt.hasNext());
assertThrows(NoSuchElementException.class, emptySetIt::next);
final Iterator<Character> notFirstIt = notFirst.iterator();
assertNotNull(notFirstIt);
assertTrue(notFirstIt.hasNext());
assertEquals(Character.valueOf((char) 0), notFirstIt.next());
assertFalse(notFirstIt.hasNext());
assertThrows(NoSuchElementException.class, notFirstIt::next);
final Iterator<Character> notLastIt = notLast.iterator();
assertNotNull(notLastIt);
assertTrue(notLastIt.hasNext());
assertEquals(Character.valueOf(Character.MAX_VALUE), notLastIt.next());
assertFalse(notLastIt.hasNext());
assertThrows(NoSuchElementException.class, notLastIt::next);
}
@Test
public void testSerialization() {
CharRange range = CharRange.is('a');
assertEquals(range, SerializationUtils.clone(range));
range = CharRange.isIn('a', 'e');
assertEquals(range, SerializationUtils.clone(range));
range = CharRange.isNotIn('a', 'e');
assertEquals(range, SerializationUtils.clone(range));
}
@Test
public void testIteratorRemove() {
final CharRange a = CharRange.is('a');
final Iterator<Character> aIt = a.iterator();
assertThrows(UnsupportedOperationException.class, aIt::remove);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 ch.usi.inf.sdm.sdm04.math;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
* Unit tests {@link org.apache.commons.lang3.math.IEEE754rUtils}.
*/
public class IEEE754rUtilsTest {
@Test
public void testConstructorExists() {
new IEEE754rUtils();
}
@Test
public void testEnforceExceptions() {
assertThrows(
NullPointerException.class,
() -> IEEE754rUtils.min( (float[]) null),
"IllegalArgumentException expected for null input");
assertThrows(
IllegalArgumentException.class,
IEEE754rUtils::min,
"IllegalArgumentException expected for empty input");
assertThrows(
NullPointerException.class,
() -> IEEE754rUtils.max( (float[]) null),
"IllegalArgumentException expected for null input");
assertThrows(
IllegalArgumentException.class,
IEEE754rUtils::max,
"IllegalArgumentException expected for empty input");
assertThrows(
NullPointerException.class,
() -> IEEE754rUtils.min( (double[]) null),
"IllegalArgumentException expected for null input");
assertThrows(
IllegalArgumentException.class,
IEEE754rUtils::min,
"IllegalArgumentException expected for empty input");
assertThrows(
NullPointerException.class,
() -> IEEE754rUtils.max( (double[]) null),
"IllegalArgumentException expected for null input");
assertThrows(
IllegalArgumentException.class,
IEEE754rUtils::max,
"IllegalArgumentException expected for empty input");
}
@Test
public void testLang381() {
assertEquals(1.2, IEEE754rUtils.min(1.2, 2.5, Double.NaN), 0.01);
assertEquals(2.5, IEEE754rUtils.max(1.2, 2.5, Double.NaN), 0.01);
assertTrue(Double.isNaN(IEEE754rUtils.max(Double.NaN, Double.NaN, Double.NaN)));
assertEquals(1.2f, IEEE754rUtils.min(1.2f, 2.5f, Float.NaN), 0.01);
assertEquals(2.5f, IEEE754rUtils.max(1.2f, 2.5f, Float.NaN), 0.01);
assertTrue(Float.isNaN(IEEE754rUtils.max(Float.NaN, Float.NaN, Float.NaN)));
final double[] a = { 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
assertEquals(42.0, IEEE754rUtils.max(a), 0.01);
assertEquals(1.2, IEEE754rUtils.min(a), 0.01);
final double[] b = { Double.NaN, 1.2, Double.NaN, 3.7, 27.0, 42.0, Double.NaN };
assertEquals(42.0, IEEE754rUtils.max(b), 0.01);
assertEquals(1.2, IEEE754rUtils.min(b), 0.01);
final float[] aF = { 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
assertEquals(1.2f, IEEE754rUtils.min(aF), 0.01);
assertEquals(42.0f, IEEE754rUtils.max(aF), 0.01);
final float[] bF = { Float.NaN, 1.2f, Float.NaN, 3.7f, 27.0f, 42.0f, Float.NaN };
assertEquals(1.2f, IEEE754rUtils.min(bF), 0.01);
assertEquals(42.0f, IEEE754rUtils.max(bF), 0.01);
}
}

File diff suppressed because it is too large Load Diff