/*
* Copyright (C) 2011 Virginia Tech Department of Computer Science
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sofia.util;
//-------------------------------------------------------------------------
/**
* This subclass of {@link java.util.Random} adds extra methods useful
* for testing purposes. Normally, you might generate a new random number
* by calling {@link #nextInt()}, {@link #nextDouble()}, or one of the
* other generation methods provided by {@link java.util.Random}. Normally,
* this intentionally makes your code behave in a random way, which may
* make it harder to test. This class allows you to control directly
* the sequence of numbers that will be generated by such calls.
*
* <p>Suppose your code is written this way:</p>
* <pre>
* Random random = Random.generator(); // or new Random()
* ...
* int x = random.nextInt(64);</pre>
*
* <p>You can then write test cases that look like this:</p>
* <pre>
* public void testSomeFeature()
* {
* // Set the return values for the next 6 calls to nextInt(),
* // No matter which instance of TestableRandom the method is called on
* Random.setNextInts(5, 10, 22, 13, 12, 47);
*
* // Perform tests, knowing in advance the exact sequence of numbers
* // That will now be generated
* }</pre>
*
* <p>This class provides separate methods to preset the sequence of
* booleans, ints, doubles, floats, bytes, or Gaussian-distributed doubles
* that will be generated. You can pass in as many specific values to
* the setNext...() methods that you like, or you can even pass in an
* array:</p>
*
* <pre>
* int[] someValues = new int[] { 1, 2, 3, 4, 5, 6, 7 };
* Random.setNextInts(someValues);</pre>
*
* @author Stephen Edwards
*/
public class Random
extends java.util.Random
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Returns a {@code Random} instance that is shared across
* all classes in an application. Using this shared instance of the
* generator is preferable to allocating new instances of
* {@code Random}. If you create several random generators in
* succession, they will typically generate the same sequence of values.
* @return A shared {@code Random} object.
*/
public static Random generator()
{
if (instance == null)
{
instance = new Random();
}
return instance;
}
// ----------------------------------------------------------
/**
* Creates a new random number generator. This constructor sets the seed
* of the random number generator to a value very likely to be distinct
* from any other invocation of this constructor.
*
* <p>Most clients will not use the constructor directly but will
* instead call {@link #generator()} to obtain a {@code Random}
* object that is shared by all classes in the application.
*/
public Random()
{
super();
}
// ----------------------------------------------------------
/**
* Creates a new random number generator using a single long seed. The
* seed is the initial value of the internal state of the pseudorandom
* number generator which is maintained by method {@link #next(int)}.
*
* <p>The invocation new Random(seed) is equivalent to:</p>
* <pre>
* Random rnd = new Random();
* rnd.setSeed(seed);
* </pre>
*
* @param seed the initial seed
* @see java.util.Random#setSeed(long)
*/
public Random(long seed)
{
super(seed);
}
//~ Public static methods .................................................
// ----------------------------------------------------------
/**
* This method allows one to provide a predefined series of values that
* will override the results provided by {@link #nextInt()} and
* {@link #nextInt(int)}. This is useful during testing, when you want
* to control the results generated by a random number generator. If
* you do not use this method, {@link #nextInt()} and {@link #nextInt(int)}
* behave normally.
*
* <p>Note that the sequence of int values you provide will be shared
* by all instances of this class--so, no matter how many TestableRandom
* instances you have created, the sequence of random numbers generated
* by calls to their methods will be determined by what you pass in
* here.</p>
*
* <p>If previous values from an earlier call to this method have not
* yet been used, they will be replaced by any parameters you provide
* in the next call to this method. If previous values from an earlier
* call to this method have not yet been used, and you provide no
* arguments in your next call to this method, those unused values will
* be replaced with nothing, so normal pseudorandom generation behavior
* will resume immediately.</p>
*
* @param values a sequence of int values to use as the results in
* subsequent calls to {@link #nextInt()} or {@link #nextInt(int)}
*/
public static void setNextInts(int ... values)
{
synchronized (nextValues)
{
if (values != null && values.length > 0)
{
nextValues.nextInts = values;
}
else
{
nextValues.nextInts = null;
}
nextValues.nextIntPos = 0;
}
}
// ----------------------------------------------------------
/**
* This method allows one to provide a predefined series of values that
* will override the results provided by {@link #nextLong()}. This is
* useful during testing, when you want to control the results generated
* by a random number generator. If you do not use this method,
* {@link #nextLong()} behaves normally.
*
* <p>Note that the sequence of long values you provide will be shared
* by all instances of this class--so, no matter how many TestableRandom
* instances you have created, the sequence of random numbers generated
* by calls to their methods will be determined by what you pass in
* here.</p>
*
* <p>If previous values from an earlier call to this method have not
* yet been used, they will be replaced by any parameters you provide
* in the next call to this method. If previous values from an earlier
* call to this method have not yet been used, and you provide no
* arguments in your next call to this method, those unused values will
* be replaced with nothing, so normal pseudorandom generation behavior
* will resume immediately.</p>
*
* @param values a sequence of long values to use as the results in
* subsequent calls to {@link #nextLong()}
*/
public static void setNextLongs(long ... values)
{
synchronized (nextValues)
{
if (values != null && values.length > 0)
{
nextValues.nextLongs = values;
}
else
{
nextValues.nextLongs = null;
}
nextValues.nextLongPos = 0;
}
}
// ----------------------------------------------------------
/**
* This method allows one to provide a predefined series of values that
* will override the results provided by {@link #nextBoolean()}. This is
* useful during testing, when you want to control the results generated
* by a random number generator. If you do not use this method,
* {@link #nextBoolean()} behaves normally.
*
* <p>Note that the sequence of boolean values you provide will be shared
* by all instances of this class--so, no matter how many TestableRandom
* instances you have created, the sequence of random booleans generated
* by calls to their methods will be determined by what you pass in
* here.</p>
*
* <p>If previous values from an earlier call to this method have not
* yet been used, they will be replaced by any parameters you provide
* in the next call to this method. If previous values from an earlier
* call to this method have not yet been used, and you provide no
* arguments in your next call to this method, those unused values will
* be replaced with nothing, so normal pseudorandom generation behavior
* will resume immediately.</p>
*
* @param values a sequence of boolean values to use as the results in
* subsequent calls to {@link #nextBoolean()}
*/
public static void setNextBooleans(boolean ... values)
{
synchronized (nextValues)
{
if (values != null && values.length > 0)
{
nextValues.nextBooleans = values;
}
else
{
nextValues.nextBooleans = null;
}
nextValues.nextBooleanPos = 0;
}
}
// ----------------------------------------------------------
/**
* This method allows one to provide a predefined series of values that
* will override the results provided by {@link #nextFloat()}. This is
* useful during testing, when you want to control the results generated
* by a random number generator. If you do not use this method,
* {@link #nextFloat()} behaves normally.
*
* <p>Note that the sequence of float values you provide will be shared
* by all instances of this class--so, no matter how many TestableRandom
* instances you have created, the sequence of random numbers generated
* by calls to their methods will be determined by what you pass in
* here.</p>
*
* <p>If previous values from an earlier call to this method have not
* yet been used, they will be replaced by any parameters you provide
* in the next call to this method. If previous values from an earlier
* call to this method have not yet been used, and you provide no
* arguments in your next call to this method, those unused values will
* be replaced with nothing, so normal pseudorandom generation behavior
* will resume immediately.</p>
*
* @param values a sequence of float values to use as the results in
* subsequent calls to {@link #nextFloat()}
*/
public static void setNextFloats(float ... values)
{
synchronized (nextValues)
{
if (values != null && values.length > 0)
{
nextValues.nextFloats = values;
}
else
{
nextValues.nextFloats = null;
}
nextValues.nextFloatPos = 0;
}
}
// ----------------------------------------------------------
/**
* This method allows one to provide a predefined series of values that
* will override the results provided by {@link #nextDouble()}. This is
* useful during testing, when you want to control the results generated
* by a random number generator. If you do not use this method,
* {@link #nextDouble()} behaves normally.
*
* <p>Note that the sequence of double values you provide will be shared
* by all instances of this class--so, no matter how many TestableRandom
* instances you have created, the sequence of random numbers generated
* by calls to their methods will be determined by what you pass in
* here.</p>
*
* <p>If previous values from an earlier call to this method have not
* yet been used, they will be replaced by any parameters you provide
* in the next call to this method. If previous values from an earlier
* call to this method have not yet been used, and you provide no
* arguments in your next call to this method, those unused values will
* be replaced with nothing, so normal pseudorandom generation behavior
* will resume immediately.</p>
*
* @param values a sequence of double values to use as the results in
* subsequent calls to {@link #nextDouble()}
*/
public static void setNextDoubles(double ... values)
{
synchronized (nextValues)
{
if (values != null && values.length > 0)
{
nextValues.nextDoubles = values;
}
else
{
nextValues.nextDoubles = null;
}
nextValues.nextDoublePos = 0;
}
}
// ----------------------------------------------------------
/**
* This method allows one to provide a predefined series of values that
* will override the results provided by {@link #nextGaussian()}. This is
* useful during testing, when you want to control the results generated
* by a random number generator. If you do not use this method,
* {@link #nextGaussian()} behaves normally.
*
* <p>Note that the sequence of double values you provide will be shared
* by all instances of this class--so, no matter how many TestableRandom
* instances you have created, the sequence of random numbers generated
* by calls to their methods will be determined by what you pass in
* here.</p>
*
* <p>If previous values from an earlier call to this method have not
* yet been used, they will be replaced by any parameters you provide
* in the next call to this method. If previous values from an earlier
* call to this method have not yet been used, and you provide no
* arguments in your next call to this method, those unused values will
* be replaced with nothing, so normal pseudorandom generation behavior
* will resume immediately.</p>
*
* @param values a sequence of double values to use as the results in
* subsequent calls to {@link #nextGaussian()}
*/
public static void setNextGaussians(double ... values)
{
synchronized (nextValues)
{
if (values != null && values.length > 0)
{
nextValues.nextGaussians = values;
}
else
{
nextValues.nextGaussians = null;
}
nextValues.nextGaussianPos = 0;
}
}
// ----------------------------------------------------------
/**
* This method allows one to provide a predefined series of values that
* will override the results provided by {@link #nextBytes(byte[])}.
* This is useful during testing, when you want to control the results
* generated by a random number generator. If you do not use this method,
* {@link #nextBytes(byte[])} behaves normally.
*
* <p>Note that the sequence of byte values you provide will be shared
* by all instances of this class--so, no matter how many TestableRandom
* instances you have created, the sequence of random numbers generated
* by calls to their methods will be determined by what you pass in
* here.</p>
*
* <p>If previous values from an earlier call to this method have not
* yet been used, they will be replaced by any parameters you provide
* in the next call to this method. If previous values from an earlier
* call to this method have not yet been used, and you provide no
* arguments in your next call to this method, those unused values will
* be replaced with nothing, so normal pseudorandom generation behavior
* will resume immediately.</p>
*
* @param values a sequence of byte values to use as the results in
* subsequent calls to {@link #nextBytes(byte[])}
*/
public static void setNextBytes(byte ... values)
{
synchronized (nextValues)
{
if (values != null && values.length > 0)
{
nextValues.nextBytes = values;
}
else
{
nextValues.nextBytes = null;
}
nextValues.nextBytePos = 0;
}
}
//~ Public instance methods ...............................................
// ----------------------------------------------------------
/**
* Returns the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence. The general
* contract of {@code nextInt} is that one {@code int} value is
* pseudorandomly generated and returned. All 2<font size="-1"><sup>32
* </sup></font> possible {@code int} values are produced with
* (approximately) equal probability.
*
* <p>If {@link #setNextInts(int...)} has been called, the next available
* value from the provided sequence will be returned until that sequence
* is exhausted. One all provided values have been returned, then
* true pseudorandom generation will resume.</p>
*
* @return the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence
*/
public int nextInt()
{
synchronized (nextValues)
{
if (nextValues.nextInts != null)
{
int result = nextValues.nextInts[nextValues.nextIntPos++];
if (nextValues.nextIntPos >= nextValues.nextInts.length)
{
nextValues.nextInts = null;
nextValues.nextIntPos = 0;
}
return result;
}
}
return super.nextInt();
}
// ----------------------------------------------------------
/**
* Returns a pseudorandom, uniformly distributed {@code int} value
* between 0 (inclusive) and the specified value (exclusive), drawn from
* this random number generator's sequence. The general contract of
* {@code nextInt} is that one {@code int} value in the specified range
* is pseudorandomly generated and returned. All {@code n} possible
* {@code int} values are produced with (approximately) equal
* probability.
*
* <p>If {@link #setNextInts(int...)} has been called, the next available
* value from the provided sequence (modulo n) will be returned until that
* sequence is exhausted. One all provided values have been returned, then
* true pseudorandom generation will resume.</p>
*
* @param n the bound on the random number to be returned. Must be
* positive.
* @return the next pseudorandom, uniformly distributed {@code int}
* value between {@code 0} (inclusive) and {@code n} (exclusive)
* from this random number generator's sequence
* @exception IllegalArgumentException if n is not positive
*/
public int nextInt(int n)
{
if (n <= 0)
{
throw new IllegalArgumentException("n must be positive");
}
synchronized (nextValues)
{
if (nextValues.nextInts != null)
{
int result = nextValues.nextInts[nextValues.nextIntPos++];
if (nextValues.nextIntPos >= nextValues.nextInts.length)
{
nextValues.nextInts = null;
nextValues.nextIntPos = 0;
}
return result % n;
}
}
return super.nextInt(n);
}
// ----------------------------------------------------------
/**
* Returns the next random integer in the specified range. For example,
* you can generate the roll of a six-sided die by calling:
* <pre>
* generator.nextInt(1, 6);
* </pre>
*
* <p>or a random decimal digit by calling::</p>
*
* <pre>
* generator.nextInt(0, 9);
* </pre>
*
* @param low The low end of the range.
* @param high The high end of the range.
* @return The next random {@code int} between {@code low} and
* {@code high}, inclusive.
*/
public int nextInt(int low, int high)
{
if (nextValues.nextInts != null || nextValues.nextDoubles != null)
{
int raw = nextInt();
if (low <= raw && raw <= high)
{
return raw;
}
else
{
return low + raw % (high - low + 1);
}
}
else
{
return low + (int) ((high - low + 1) * nextDouble());
}
}
// ----------------------------------------------------------
/**
* Returns the next pseudorandom, uniformly distributed {@code long}
* value from this random number generator's sequence. The general
* contract of {@code nextLong} is that one {@code long} value is
* pseudorandomly generated and returned.
*
* <p>If {@link #setNextLongs(long...)} has been called, the next available
* value from the provided sequence will be returned until that sequence
* is exhausted. One all provided values have been returned, then
* true pseudorandom generation will resume.</p>
*
* @return the next pseudorandom, uniformly distributed {@code long}
* value from this random number generator's sequence
*/
public long nextLong()
{
synchronized (nextValues)
{
if (nextValues.nextLongs != null)
{
long result = nextValues.nextLongs[nextValues.nextLongPos++];
if (nextValues.nextLongPos >= nextValues.nextLongs.length)
{
nextValues.nextLongs = null;
nextValues.nextLongPos = 0;
}
return result;
}
}
return super.nextLong();
}
// ----------------------------------------------------------
/**
* Returns the next random {@code long} in the specified range. Behaves
* exactly like {@link #nextInt(int, int)}, but for {@code long} values.
*
* @param low The low end of the range.
* @param high The high end of the range.
* @return The next random {@code int} between {@code low} and
* {@code high}, inclusive.
*/
public long nextLong(long low, long high)
{
if (nextValues.nextLongs != null || nextValues.nextDoubles != null)
{
long raw = nextLong();
if (low <= raw && raw <= high)
{
return raw;
}
else
{
return low + raw % (high - low + 1);
}
}
else
{
return low + (long) ((high - low + 1) * nextDouble());
}
}
// ----------------------------------------------------------
/**
* Returns the next pseudorandom, uniformly distributed
* {@code boolean} value from this random number generator's
* sequence. The general contract of {@code nextBoolean} is that one
* {@code boolean} value is pseudorandomly generated and returned. The
* values {@code true} and {@code false} are produced with
* (approximately) equal probability.
*
* <p>If {@link #setNextBooleans(boolean...)} has been called, the next
* available value from the provided sequence will be returned until that
* sequence is exhausted. One all provided values have been returned, then
* true pseudorandom generation will resume.</p>
*
* @return the next pseudorandom, uniformly distributed {@code boolean}
* value from this random number generator's sequence
*/
public boolean nextBoolean()
{
synchronized (nextValues)
{
if (nextValues.nextBooleans != null)
{
boolean result =
nextValues.nextBooleans[nextValues.nextBooleanPos++];
if (nextValues.nextBooleanPos >= nextValues.nextBooleans.length)
{
nextValues.nextBooleans = null;
nextValues.nextBooleanPos = 0;
}
return result;
}
}
return super.nextBoolean();
}
// ----------------------------------------------------------
/**
* Returns the next pseudorandom, uniformly distributed
* {@code float} value between {@code 0.0f} and
* {@code 1.0f} from this random number generator's sequence.
*
* <p>If {@link #setNextFloats(float...)} has been called, the next
* available value from the provided sequence will be returned until that
* sequence is exhausted. One all provided values have been returned, then
* true pseudorandom generation will resume.</p>
*
* @return the next pseudorandom, uniformly distributed {@code float}
* value from this random number generator's sequence
*/
public float nextFloat()
{
synchronized (nextValues)
{
if (nextValues.nextFloats != null)
{
float result =
nextValues.nextFloats[nextValues.nextFloatPos++];
if (nextValues.nextFloatPos >= nextValues.nextFloats.length)
{
nextValues.nextFloats = null;
nextValues.nextFloatPos = 0;
}
return result;
}
}
return super.nextFloat();
}
// ----------------------------------------------------------
/**
* Returns the next random real number in the specified range. The
* resulting value is always at least {@code low} but always strictly
* less than {@code high}. You can use this method to generate continuous
* random values. For example, you can set the variables {@code x} and
* {@code y} to specify a random point inside the unit square as follows:
*
* <pre>
* float x = generator.nextFloat(0.0f, 1.0f);
* float y = generator.nextFloat(0.0f, 1.0f);
* </pre>
*
* @param low The low end of the range.
* @param high The high end of the range.
* @return A random {@code float} value <i>d</i> in the range
* {@code low} ≤ <i>d</i> < {@code high}.
*/
public float nextFloat(float low, float high)
{
float raw = nextFloat();
return low + (high - low) * raw;
}
// ----------------------------------------------------------
/**
* Returns the next pseudorandom, uniformly distributed
* {@code double} value between {@code 0.0} and
* {@code 1.0} from this random number generator's sequence.
*
* <p>If {@link #setNextDoubles(double...)} has been called, the next
* available value from the provided sequence will be returned until that
* sequence is exhausted. One all provided values have been returned, then
* true pseudorandom generation will resume.</p>
*
* @return the next pseudorandom, uniformly distributed {@code double}
* value from this random number generator's sequence
*/
public double nextDouble()
{
synchronized (nextValues)
{
if (nextValues.nextDoubles != null)
{
double result =
nextValues.nextDoubles[nextValues.nextDoublePos++];
if (nextValues.nextDoublePos >= nextValues.nextDoubles.length)
{
nextValues.nextDoubles = null;
nextValues.nextDoublePos = 0;
}
return result;
}
}
return super.nextDouble();
}
// ----------------------------------------------------------
/**
* Returns the next random real number in the specified range. The
* resulting value is always at least {@code low} but always strictly
* less than {@code high}. You can use this method to generate continuous
* random values. For example, you can set the variables {@code x} and
* {@code y} to specify a random point inside the unit square as follows:
*
* <pre>
* double x = generator.nextDouble(0.0, 1.0);
* double y = generator.nextDouble(0.0, 1.0);
* </pre>
*
* @param low The low end of the range.
* @param high The high end of the range.
* @return A random {@code double} value <i>d</i> in the range
* {@code low} ≤ <i>d</i> < {@code high}.
*/
public double nextDouble(double low, double high)
{
double raw = nextDouble();
return low + (high - low) * raw;
}
// ----------------------------------------------------------
/**
* Returns the next pseudorandom, Gaussian ("normally") distributed
* {@code double} value with mean {@code 0.0} and standard
* deviation {@code 1.0} from this random number generator's sequence.
*
* <p>If {@link #setNextGaussians(double...)} has been called, the next
* available value from the provided sequence will be returned until that
* sequence is exhausted. One all provided values have been returned, then
* true pseudorandom generation will resume.</p>
*
* @return the next pseudorandom, Gaussian ("normally") distributed
* {@code double} value with mean {@code 0.0} and
* standard deviation {@code 1.0} from this random number
* generator's sequence
*/
public double nextGaussian()
{
synchronized (nextValues)
{
if (nextValues.nextGaussians != null)
{
double result =
nextValues.nextGaussians[nextValues.nextGaussianPos++];
if (nextValues.nextGaussianPos
>= nextValues.nextGaussians.length)
{
nextValues.nextGaussians = null;
nextValues.nextGaussianPos = 0;
}
return result;
}
}
return super.nextGaussian();
}
// ----------------------------------------------------------
/**
* Generates random bytes and places them into a user-supplied
* byte array. The number of random bytes produced is equal to
* the length of the byte array.
*
* <p>If {@link #setNextBytes(byte...)} has been called, unused
* values from the provided sequence will be used to fill the provided
* array until that sequence is exhausted. One all provided values have
* been used up, true pseudorandom generation will resume for filling
* any remaining slots in this or future calls.</p>
*
* @param bytes the byte array to fill with random bytes
* @throws NullPointerException if the byte array is null
*/
public void nextBytes(byte[] bytes)
{
synchronized (nextValues)
{
if (nextValues.nextBytes != null)
{
int remaining =
nextValues.nextBytes.length - nextValues.nextBytePos;
if (remaining >= bytes.length)
{
System.arraycopy(
nextValues.nextBytes,
nextValues.nextBytePos,
bytes,
0,
bytes.length);
nextValues.nextBytePos += bytes.length;
}
else
{
int size =
nextValues.nextBytes.length - nextValues.nextBytePos;
System.arraycopy(
nextValues.nextBytes,
nextValues.nextBytePos,
bytes,
0,
size);
nextValues.nextBytePos += size;
byte[] remainder = new byte[bytes.length - size];
super.nextBytes(remainder);
System.arraycopy(
remainder,
0,
bytes,
bytes.length - remainder.length,
remainder.length);
}
if (nextValues.nextBytePos
>= nextValues.nextBytes.length)
{
nextValues.nextBytes = null;
nextValues.nextBytePos = 0;
}
return;
}
}
super.nextBytes(bytes);
}
//~ Private declarations ..................................................
private static class NextValues
{
byte[] nextBytes;
int nextBytePos;
int[] nextInts;
int nextIntPos;
long[] nextLongs;
int nextLongPos;
boolean[] nextBooleans;
int nextBooleanPos;
float[] nextFloats;
int nextFloatPos;
double[] nextDoubles;
int nextDoublePos;
double[] nextGaussians;
int nextGaussianPos;
}
//~ Instance/static variables .............................................
private static volatile NextValues nextValues = new NextValues();
private static volatile Random instance;
private static final long serialVersionUID = 6662016631254672060L;
}