8332086: Remove the usage of ServiceLoader in j.u.r.RandomGeneratorFactory
8332476: j.u.r.RandomGeneratorFactor.create(long|byte[]) should throw rather than silently fallback to no-arg create() Reviewed-by: jpai
This commit is contained in:
parent
5cf8288b80
commit
42e3c842ae
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,7 +25,6 @@
|
||||
|
||||
package java.security;
|
||||
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
import sun.security.jca.GetInstance;
|
||||
import sun.security.jca.GetInstance.Instance;
|
||||
import sun.security.jca.Providers;
|
||||
@ -149,10 +148,6 @@ import java.util.regex.Pattern;
|
||||
* @since 1.1
|
||||
*/
|
||||
|
||||
@RandomGeneratorProperties(
|
||||
name = "SecureRandom",
|
||||
isStochastic = true
|
||||
)
|
||||
public class SecureRandom extends java.util.Random {
|
||||
|
||||
private static final Debug pdebug =
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,8 +32,6 @@ import java.util.stream.DoubleStream;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
import jdk.internal.util.random.RandomSupport.*;
|
||||
|
||||
import static jdk.internal.util.random.RandomSupport.*;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
@ -77,11 +75,6 @@ import jdk.internal.misc.Unsafe;
|
||||
* @author Frank Yellin
|
||||
* @since 1.0
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "Random",
|
||||
i = 48, j = 0, k = 0,
|
||||
equidistribution = 0
|
||||
)
|
||||
public class Random implements RandomGenerator, java.io.Serializable {
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -33,7 +33,6 @@ import java.util.stream.LongStream;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A generator of uniform pseudorandom values (with period 2<sup>64</sup>)
|
||||
@ -87,11 +86,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @author Doug Lea
|
||||
* @since 1.8
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "SplittableRandom",
|
||||
i = 64, j = 0, k = 0,
|
||||
equidistribution = 1
|
||||
)
|
||||
public final class SplittableRandom implements RandomGenerator, SplittableGenerator {
|
||||
|
||||
/*
|
||||
|
@ -85,12 +85,6 @@ import jdk.internal.misc.VM;
|
||||
* @since 1.7
|
||||
* @author Doug Lea
|
||||
*/
|
||||
|
||||
@RandomGeneratorProperties(
|
||||
name = "ThreadLocalRandom",
|
||||
i = 64, j = 0, k = 0,
|
||||
equidistribution = 1
|
||||
)
|
||||
public final class ThreadLocalRandom extends Random {
|
||||
/*
|
||||
* This class implements the java.util.Random API (and subclasses
|
||||
|
@ -25,24 +25,30 @@
|
||||
|
||||
package java.util.random;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import jdk.internal.random.L128X1024MixRandom;
|
||||
import jdk.internal.random.L128X128MixRandom;
|
||||
import jdk.internal.random.L128X256MixRandom;
|
||||
import jdk.internal.random.L32X64MixRandom;
|
||||
import jdk.internal.random.L64X1024MixRandom;
|
||||
import jdk.internal.random.L64X128MixRandom;
|
||||
import jdk.internal.random.L64X128StarStarRandom;
|
||||
import jdk.internal.random.L64X256MixRandom;
|
||||
import jdk.internal.random.Xoroshiro128PlusPlus;
|
||||
import jdk.internal.random.Xoshiro256PlusPlus;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.SplittableRandom;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.random.RandomGenerator.ArbitrarilyJumpableGenerator;
|
||||
import java.util.random.RandomGenerator.JumpableGenerator;
|
||||
import java.util.random.RandomGenerator.LeapableGenerator;
|
||||
import java.util.random.RandomGenerator.SplittableGenerator;
|
||||
import java.util.random.RandomGenerator.StreamableGenerator;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.ServiceLoader.Provider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* This is a factory class for generating multiple random number generators
|
||||
@ -107,137 +113,268 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
*
|
||||
*/
|
||||
public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
/**
|
||||
* Instance provider class of random number algorithm.
|
||||
*/
|
||||
private final Provider<? extends RandomGenerator> provider;
|
||||
|
||||
/**
|
||||
* Provider RandomGeneratorProperties annotation.
|
||||
*/
|
||||
private volatile RandomGeneratorProperties properties;
|
||||
private static final String DEFAULT_ALGORITHM = "L32X64MixRandom";
|
||||
|
||||
/**
|
||||
* Default provider constructor.
|
||||
*/
|
||||
private volatile Constructor<T> ctor;
|
||||
private record RandomGeneratorProperties(
|
||||
Class<? extends RandomGenerator> rgClass,
|
||||
String name,
|
||||
String group,
|
||||
int i,
|
||||
int j,
|
||||
int k,
|
||||
int equidistribution,
|
||||
int flags) {
|
||||
|
||||
/**
|
||||
* Provider constructor with long seed.
|
||||
*/
|
||||
private Constructor<T> ctorLong;
|
||||
/* single bit masks composable with operator | */
|
||||
private static final int INSTANTIABLE = 1 << 0;
|
||||
private static final int LONG_SEED = 1 << 1;
|
||||
private static final int BYTE_ARRAY_SEED = 1 << 2;
|
||||
private static final int STOCHASTIC = 1 << 3;
|
||||
private static final int HARDWARE = 1 << 4;
|
||||
private static final int DEPRECATED = 1 << 5;
|
||||
|
||||
/**
|
||||
* Provider constructor with byte[] seed.
|
||||
*/
|
||||
private Constructor<T> ctorBytes;
|
||||
private static final int ALL_CONSTRUCTORS = INSTANTIABLE | LONG_SEED | BYTE_ARRAY_SEED;
|
||||
|
||||
|
||||
private static class FactoryMapHolder {
|
||||
static final Map<String, Provider<? extends RandomGenerator>> FACTORY_MAP = createFactoryMap();
|
||||
private static final Map<String, RandomGeneratorProperties> FACTORY_MAP = createFactoryMap();
|
||||
|
||||
/**
|
||||
* Returns the factory map, lazily constructing map on first use.
|
||||
* Returns the factory map, lazily constructing it on first use.
|
||||
* <p> Although {@link ThreadLocalRandom} can only be accessed via
|
||||
* {@link ThreadLocalRandom#current()}, a map entry is added nevertheless
|
||||
* to record its properties that are otherwise not documented
|
||||
* anywhere else.
|
||||
* <p> Currently, no algorithm is deprecated.
|
||||
*
|
||||
* @return Map of RandomGeneratorFactory classes.
|
||||
* @return Map of RandomGeneratorProperties.
|
||||
*/
|
||||
private static Map<String, Provider<? extends RandomGenerator>> createFactoryMap() {
|
||||
FactoryMapHolder.class.getModule().addUses(RandomGenerator.class);
|
||||
return ServiceLoader
|
||||
.load(RandomGenerator.class, ClassLoader.getPlatformClassLoader())
|
||||
.stream()
|
||||
.filter(p -> !p.type().isInterface())
|
||||
.collect(Collectors.toMap(p -> p.type().getSimpleName(), Function.identity()));
|
||||
private static Map<String, RandomGeneratorProperties> createFactoryMap() {
|
||||
return Map.ofEntries(
|
||||
entry(SecureRandom.class, "SecureRandom", "Legacy",
|
||||
0, 0, 0, Integer.MAX_VALUE,
|
||||
INSTANTIABLE | BYTE_ARRAY_SEED | STOCHASTIC | deprecationBit(SecureRandom.class)),
|
||||
entry(Random.class, "Random", "Legacy",
|
||||
48, 0, 0, 0,
|
||||
INSTANTIABLE | LONG_SEED | deprecationBit(Random.class)),
|
||||
entry(SplittableRandom.class, "SplittableRandom", "Legacy",
|
||||
64, 0, 0, 1,
|
||||
INSTANTIABLE | LONG_SEED | deprecationBit(SplittableRandom.class)),
|
||||
entry(L32X64MixRandom.class, "L32X64MixRandom", "LXM",
|
||||
64, 1, 32, 1,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(L64X128MixRandom.class, "L64X128MixRandom", "LXM",
|
||||
128, 1, 64, 2,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(L64X128StarStarRandom.class, "L64X128StarStarRandom", "LXM",
|
||||
128, 1, 64, 2,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(L64X256MixRandom.class, "L64X256MixRandom", "LXM",
|
||||
256, 1, 64, 4,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(L64X1024MixRandom.class, "L64X1024MixRandom", "LXM",
|
||||
1024, 1, 64, 16,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(L128X128MixRandom.class, "L128X128MixRandom", "LXM",
|
||||
128, 1, 128, 1,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(L128X256MixRandom.class, "L128X256MixRandom", "LXM",
|
||||
256, 1, 128, 1,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(L128X1024MixRandom.class, "L128X1024MixRandom", "LXM",
|
||||
1024, 1, 128, 1,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(Xoroshiro128PlusPlus.class, "Xoroshiro128PlusPlus", "Xoroshiro",
|
||||
128, 1, 0, 1,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(Xoshiro256PlusPlus.class, "Xoshiro256PlusPlus", "Xoshiro",
|
||||
256, 1, 0, 3,
|
||||
ALL_CONSTRUCTORS),
|
||||
entry(ThreadLocalRandom.class, "ThreadLocalRandom", "Legacy",
|
||||
64, 0, 0, 1,
|
||||
deprecationBit(ThreadLocalRandom.class))
|
||||
);
|
||||
}
|
||||
|
||||
private static Map.Entry<String, RandomGeneratorProperties> entry(
|
||||
Class<? extends RandomGenerator> rgClass, String name, String group,
|
||||
int i, int j, int k, int equidistribution,
|
||||
int flags) {
|
||||
return Map.entry(name,
|
||||
new RandomGeneratorProperties(rgClass, name, group,
|
||||
i, j, k, equidistribution,
|
||||
flags));
|
||||
}
|
||||
|
||||
private static int deprecationBit(Class<? extends RandomGenerator> rgClass) {
|
||||
return rgClass.isAnnotationPresent(Deprecated.class) ? DEPRECATED : 0;
|
||||
}
|
||||
|
||||
private RandomGenerator create() {
|
||||
return switch (name) {
|
||||
case "Random" -> new Random();
|
||||
case "SecureRandom" -> new SecureRandom();
|
||||
case "SplittableRandom" -> new SplittableRandom();
|
||||
case "L32X64MixRandom" -> new L32X64MixRandom();
|
||||
case "L64X128MixRandom" -> new L64X128MixRandom();
|
||||
case "L64X128StarStarRandom" -> new L64X128StarStarRandom();
|
||||
case "L64X256MixRandom" -> new L64X256MixRandom();
|
||||
case "L64X1024MixRandom" -> new L64X1024MixRandom();
|
||||
case "L128X128MixRandom" -> new L128X128MixRandom();
|
||||
case "L128X256MixRandom" -> new L128X256MixRandom();
|
||||
case "L128X1024MixRandom" -> new L128X1024MixRandom();
|
||||
case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus();
|
||||
case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus();
|
||||
default -> throw new InternalError("should not happen");
|
||||
};
|
||||
}
|
||||
|
||||
private RandomGenerator create(long seed) {
|
||||
if (isInstantiable() && (flags & LONG_SEED) == 0) {
|
||||
throw new UnsupportedOperationException("Random algorithm "
|
||||
+ name + " does not support a long seed");
|
||||
}
|
||||
return switch (name) {
|
||||
case "Random" -> new Random(seed);
|
||||
case "SplittableRandom" -> new SplittableRandom(seed);
|
||||
case "L32X64MixRandom" -> new L32X64MixRandom(seed);
|
||||
case "L64X128MixRandom" -> new L64X128MixRandom(seed);
|
||||
case "L64X128StarStarRandom" -> new L64X128StarStarRandom(seed);
|
||||
case "L64X256MixRandom" -> new L64X256MixRandom(seed);
|
||||
case "L64X1024MixRandom" -> new L64X1024MixRandom(seed);
|
||||
case "L128X128MixRandom" -> new L128X128MixRandom(seed);
|
||||
case "L128X256MixRandom" -> new L128X256MixRandom(seed);
|
||||
case "L128X1024MixRandom" -> new L128X1024MixRandom(seed);
|
||||
case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus(seed);
|
||||
case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus(seed);
|
||||
default -> throw new InternalError("should not happen");
|
||||
};
|
||||
}
|
||||
|
||||
private RandomGenerator create(byte[] seed) {
|
||||
if (isInstantiable() && (flags & BYTE_ARRAY_SEED) == 0) {
|
||||
throw new UnsupportedOperationException("Random algorithm "
|
||||
+ name + " does not support a byte[] seed");
|
||||
}
|
||||
return switch (name) {
|
||||
case "SecureRandom" -> new SecureRandom(seed);
|
||||
case "L32X64MixRandom" -> new L32X64MixRandom(seed);
|
||||
case "L64X128MixRandom" -> new L64X128MixRandom(seed);
|
||||
case "L64X128StarStarRandom" -> new L64X128StarStarRandom(seed);
|
||||
case "L64X256MixRandom" -> new L64X256MixRandom(seed);
|
||||
case "L64X1024MixRandom" -> new L64X1024MixRandom(seed);
|
||||
case "L128X128MixRandom" -> new L128X128MixRandom(seed);
|
||||
case "L128X256MixRandom" -> new L128X256MixRandom(seed);
|
||||
case "L128X1024MixRandom" -> new L128X1024MixRandom(seed);
|
||||
case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus(seed);
|
||||
case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus(seed);
|
||||
default -> throw new InternalError("should not happen");
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isStochastic() {
|
||||
return (flags & STOCHASTIC) != 0;
|
||||
}
|
||||
|
||||
private boolean isHardware() {
|
||||
return (flags & HARDWARE) != 0;
|
||||
}
|
||||
|
||||
private boolean isInstantiable() {
|
||||
return (flags & INSTANTIABLE) != 0;
|
||||
}
|
||||
|
||||
private boolean isDeprecated() {
|
||||
return (flags & DEPRECATED) != 0;
|
||||
}
|
||||
|
||||
private BigInteger period() {
|
||||
/*
|
||||
* 0 if i = j = k = 0
|
||||
* (2^i - j) 2^k otherwise
|
||||
*/
|
||||
return i == 0 && j == 0 && k == 0
|
||||
? BigInteger.ZERO
|
||||
: BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k);
|
||||
}
|
||||
|
||||
private int stateBits() {
|
||||
return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Random generator properties.
|
||||
*/
|
||||
private final RandomGeneratorProperties properties;
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*
|
||||
* @param provider Provider class to wrap.
|
||||
* @param properties Random generator properties.
|
||||
*/
|
||||
private RandomGeneratorFactory(Provider<? extends RandomGenerator> provider) {
|
||||
this.provider = provider;
|
||||
private RandomGeneratorFactory(RandomGeneratorProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory map, lazily constructing map on first call.
|
||||
* Returns the factory map, lazily constructing the map on first call.
|
||||
*
|
||||
* @return Map of RandomGeneratorFactory classes.
|
||||
* @return Map of random generator classes.
|
||||
*/
|
||||
private static Map<String, Provider<? extends RandomGenerator>> getFactoryMap() {
|
||||
return FactoryMapHolder.FACTORY_MAP;
|
||||
private static Map<String, RandomGeneratorProperties> getFactoryMap() {
|
||||
return RandomGeneratorProperties.FACTORY_MAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the annotation for the specified provider.
|
||||
*
|
||||
* @return RandomGeneratorProperties annotation for the specified provider.
|
||||
*/
|
||||
private RandomGeneratorProperties getProperties() {
|
||||
if (properties == null) {
|
||||
synchronized (provider) {
|
||||
if (properties == null) {
|
||||
properties = provider.type().getDeclaredAnnotation(RandomGeneratorProperties.class);
|
||||
Objects.requireNonNull(properties, provider.type() + " missing annotation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the provider is a subclass of the category.
|
||||
* Return true if the random generator class is a subclass of the category.
|
||||
*
|
||||
* @param category Interface category, sub-interface of {@link RandomGenerator}.
|
||||
*
|
||||
* @return true if the provider is a subclass of the category.
|
||||
* @return true if the random generator class is a subclass of the category.
|
||||
*/
|
||||
private boolean isSubclass(Class<? extends RandomGenerator> category) {
|
||||
return isSubclass(category, provider);
|
||||
return isSubclass(category, properties.rgClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the provider is a subclass of the category.
|
||||
* Return true if rgClass is a subclass of the category.
|
||||
*
|
||||
* @param category Interface category, sub-interface of {@link RandomGenerator}.
|
||||
* @param provider Provider that is being filtered.
|
||||
* @param rgClass Class that is being filtered.
|
||||
*
|
||||
* @return true if the provider is a subclass of the category.
|
||||
* @return true if rgClass is a subclass of the category.
|
||||
*/
|
||||
private static boolean isSubclass(Class<? extends RandomGenerator> category,
|
||||
Provider<? extends RandomGenerator> provider) {
|
||||
return provider != null && category.isAssignableFrom(provider.type());
|
||||
Class<? extends RandomGenerator> rgClass) {
|
||||
return rgClass != null && category.isAssignableFrom(rgClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the provider matching name and category.
|
||||
* Returns a RandomGeneratorProperties instance matching name and category.
|
||||
*
|
||||
* @param name Name of RandomGenerator
|
||||
* @param category Interface category, sub-interface of {@link RandomGenerator}.
|
||||
*
|
||||
* @return A provider matching name and category.
|
||||
*
|
||||
* @throws IllegalArgumentException if provider is not a subclass of category.
|
||||
* @param name Name of RandomGenerator
|
||||
* @param category Interface category, sub-interface of {@link RandomGenerator}.
|
||||
* @return A RandomGeneratorProperties instance matching name and category.
|
||||
* @throws IllegalArgumentException if the resulting type is not a subclass of category.
|
||||
*/
|
||||
private static Provider<? extends RandomGenerator> findProvider(String name,
|
||||
Class<? extends RandomGenerator> category)
|
||||
throws IllegalArgumentException {
|
||||
Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap();
|
||||
Provider<? extends RandomGenerator> provider = fm.get(name);
|
||||
if (provider == null) {
|
||||
private static RandomGeneratorProperties findClass(String name,
|
||||
Class<? extends RandomGenerator> category) throws IllegalArgumentException {
|
||||
RandomGeneratorProperties properties = name != null
|
||||
? getFactoryMap().get(name)
|
||||
: null;
|
||||
if (properties == null || !properties.isInstantiable()) {
|
||||
throw new IllegalArgumentException("No implementation of the random number generator algorithm \"" +
|
||||
name +
|
||||
"\" is available");
|
||||
} else if (!isSubclass(category, provider)) {
|
||||
throw new IllegalArgumentException("The random number generator algorithm \"" +
|
||||
name +
|
||||
"\" is not implemented with the interface \"" +
|
||||
category.getSimpleName() +
|
||||
"\"");
|
||||
name +
|
||||
"\" is available");
|
||||
}
|
||||
return provider;
|
||||
if (!isSubclass(category, properties.rgClass())) {
|
||||
throw new IllegalArgumentException("The random number generator algorithm \"" +
|
||||
name +
|
||||
"\" is not implemented with the interface \"" +
|
||||
category.getSimpleName() +
|
||||
"\"");
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,8 +392,8 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
static <T extends RandomGenerator> T of(String name, Class<T> category)
|
||||
throws IllegalArgumentException {
|
||||
@SuppressWarnings("unchecked")
|
||||
T uncheckedRandomGenerator = (T)findProvider(name, category).get();
|
||||
return uncheckedRandomGenerator;
|
||||
T instance = (T) findClass(name, category).create();
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -273,68 +410,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
*/
|
||||
static <T extends RandomGenerator> RandomGeneratorFactory<T> factoryOf(String name, Class<T> category)
|
||||
throws IllegalArgumentException {
|
||||
Provider<? extends RandomGenerator> uncheckedProvider = findProvider(name, category);
|
||||
return new RandomGeneratorFactory<>(uncheckedProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the required constructors for class of random number algorithm.
|
||||
*
|
||||
* @param randomGeneratorClass class of random number algorithm (provider)
|
||||
*/
|
||||
private void getConstructors(Class<? extends RandomGenerator> randomGeneratorClass) {
|
||||
if (ctor == null) {
|
||||
synchronized (provider) {
|
||||
if (ctor == null) {
|
||||
PrivilegedExceptionAction<Constructor<?>[]> ctorAction = randomGeneratorClass::getConstructors;
|
||||
try {
|
||||
@SuppressWarnings("removal")
|
||||
Constructor<?>[] ctors = AccessController.doPrivileged(ctorAction);
|
||||
|
||||
Constructor<T> tmpCtor = null;
|
||||
Constructor<T> tmpCtorLong = null;
|
||||
Constructor<T> tmpCtorBytes = null;
|
||||
|
||||
|
||||
for (Constructor<?> ctorGeneric : ctors) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Constructor<T> ctorSpecific = (Constructor<T>) ctorGeneric;
|
||||
final Class<?>[] parameterTypes = ctorSpecific.getParameterTypes();
|
||||
|
||||
if (parameterTypes.length == 0) {
|
||||
tmpCtor = ctorSpecific;
|
||||
} else if (parameterTypes.length == 1) {
|
||||
Class<?> argType = parameterTypes[0];
|
||||
|
||||
if (argType == long.class) {
|
||||
tmpCtorLong = ctorSpecific;
|
||||
} else if (argType == byte[].class) {
|
||||
tmpCtorBytes = ctorSpecific;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpCtor == null) {
|
||||
throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor");
|
||||
}
|
||||
|
||||
// Store specialized constructors first, guarded by ctor
|
||||
ctorBytes = tmpCtorBytes;
|
||||
ctorLong = tmpCtorLong;
|
||||
ctor = tmpCtor;
|
||||
} catch (PrivilegedActionException ex) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all the required constructors are fetched.
|
||||
*/
|
||||
private void ensureConstructors() {
|
||||
getConstructors(provider.type());
|
||||
return new RandomGeneratorFactory<>(findClass(name, category));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -355,7 +431,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
Objects.requireNonNull(name);
|
||||
@SuppressWarnings("unchecked")
|
||||
RandomGeneratorFactory<T> factory =
|
||||
(RandomGeneratorFactory<T>)factoryOf(name, RandomGenerator.class);
|
||||
(RandomGeneratorFactory<T>) factoryOf(name, RandomGenerator.class);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@ -369,23 +445,21 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return a {@link RandomGeneratorFactory}
|
||||
*/
|
||||
public static RandomGeneratorFactory<RandomGenerator> getDefault() {
|
||||
return factoryOf("L32X64MixRandom", RandomGenerator.class);
|
||||
return factoryOf(DEFAULT_ALGORITHM, RandomGenerator.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a non-empty stream of available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
|
||||
* <p>
|
||||
*
|
||||
* RandomGenerators that are marked as deprecated are not included in the result.
|
||||
*
|
||||
* @return a non-empty stream of all available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}.
|
||||
*/
|
||||
public static Stream<RandomGeneratorFactory<RandomGenerator>> all() {
|
||||
Map<String, Provider<? extends RandomGenerator>> fm = getFactoryMap();
|
||||
return fm.values()
|
||||
.stream()
|
||||
.filter(p -> !p.type().isAnnotationPresent(Deprecated.class) &&
|
||||
p.type().isAnnotationPresent(RandomGeneratorProperties.class))
|
||||
.map(RandomGeneratorFactory::new);
|
||||
return getFactoryMap().values()
|
||||
.stream()
|
||||
.filter(p -> p.isInstantiable() && !p.isDeprecated())
|
||||
.map(RandomGeneratorFactory::new);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,7 +469,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return Name of the <a href="package-summary.html#algorithms">algorithm</a>.
|
||||
*/
|
||||
public String name() {
|
||||
return provider.type().getSimpleName();
|
||||
return properties.name();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -405,7 +479,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return Group name of the <a href="package-summary.html#algorithms">algorithm</a>.
|
||||
*/
|
||||
public String group() {
|
||||
return getProperties().group();
|
||||
return properties.group();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -416,11 +490,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* to maintain state of seed.
|
||||
*/
|
||||
public int stateBits() {
|
||||
RandomGeneratorProperties properties = getProperties();
|
||||
int i = properties.i();
|
||||
int k = properties.k();
|
||||
|
||||
return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k;
|
||||
return properties.stateBits();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -429,7 +499,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return the equidistribution of the <a href="package-summary.html#algorithms">algorithm</a>.
|
||||
*/
|
||||
public int equidistribution() {
|
||||
return getProperties().equidistribution();
|
||||
return properties.equidistribution();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -440,16 +510,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return BigInteger period.
|
||||
*/
|
||||
public BigInteger period() {
|
||||
RandomGeneratorProperties properties = getProperties();
|
||||
int i = properties.i();
|
||||
int j = properties.j();
|
||||
int k = properties.k();
|
||||
|
||||
if (i == 0 && j == 0 && k == 0) {
|
||||
return BigInteger.ZERO;
|
||||
} else {
|
||||
return BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k);
|
||||
}
|
||||
return properties.period();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -460,7 +521,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return true if random generator is statistical.
|
||||
*/
|
||||
public boolean isStatistical() {
|
||||
return !getProperties().isStochastic();
|
||||
return !properties.isStochastic();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -470,7 +531,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return true if random generator is stochastic.
|
||||
*/
|
||||
public boolean isStochastic() {
|
||||
return getProperties().isStochastic();
|
||||
return properties.isStochastic();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,7 +541,7 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* @return true if random generator is generated by hardware.
|
||||
*/
|
||||
public boolean isHardware() {
|
||||
return getProperties().isHardware();
|
||||
return properties.isHardware();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -547,66 +608,64 @@ public final class RandomGeneratorFactory<T extends RandomGenerator> {
|
||||
* marked for deprecation
|
||||
*/
|
||||
public boolean isDeprecated() {
|
||||
return provider.type().isAnnotationPresent(Deprecated.class);
|
||||
return properties.isDeprecated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link RandomGenerator} based on
|
||||
* Create an instance of {@link RandomGenerator} based on the
|
||||
* <a href="package-summary.html#algorithms">algorithm</a> chosen.
|
||||
*
|
||||
* @return new in instance of {@link RandomGenerator}.
|
||||
*
|
||||
* @return new instance of {@link RandomGenerator}.
|
||||
*/
|
||||
public T create() {
|
||||
try {
|
||||
ensureConstructors();
|
||||
return ctor.newInstance();
|
||||
} catch (Exception ex) {
|
||||
// Should never happen.
|
||||
throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor", ex);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
T instance = (T) properties.create();
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link RandomGenerator} based on
|
||||
* <a href="package-summary.html#algorithms">algorithm</a> chosen
|
||||
* providing a starting long seed. If long seed is not supported by an
|
||||
* algorithm then the no argument form of create is used.
|
||||
* Create an instance of {@link RandomGenerator} based on the
|
||||
* <a href="package-summary.html#algorithms">algorithm</a> chosen,
|
||||
* and the provided {@code seed}.
|
||||
* If the {@link RandomGenerator} doesn't support instantiation through
|
||||
* a {@code seed} of type {@code long} then this method throws
|
||||
* an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param seed long random seed value.
|
||||
*
|
||||
* @return new in instance of {@link RandomGenerator}.
|
||||
* @return new instance of {@link RandomGenerator}.
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if a {@code seed} of type {@code long} in not supported.
|
||||
*/
|
||||
public T create(long seed) {
|
||||
try {
|
||||
ensureConstructors();
|
||||
return ctorLong.newInstance(seed);
|
||||
} catch (Exception ex) {
|
||||
return create();
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
T instance = (T) properties.create(seed);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link RandomGenerator} based on
|
||||
* <a href="package-summary.html#algorithms">algorithm</a> chosen
|
||||
* providing a starting byte[] seed. If byte[] seed is not supported by an
|
||||
* <a href="package-summary.html#algorithms">algorithm</a> then the no
|
||||
* argument form of create is used.
|
||||
* Create an instance of {@link RandomGenerator} based on the
|
||||
* <a href="package-summary.html#algorithms">algorithm</a> chosen,
|
||||
* and the provided {@code seed}.
|
||||
* If the {@link RandomGenerator} doesn't support instantiation through
|
||||
* a {@code seed} of type {@code byte[]} then this method throws
|
||||
* an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param seed byte array random seed value.
|
||||
*
|
||||
* @return new in instance of {@link RandomGenerator}.
|
||||
* @return new instance of {@link RandomGenerator}.
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if a {@code seed} of type {@code byte[]} in not supported.
|
||||
*
|
||||
* @throws NullPointerException if seed is null.
|
||||
*/
|
||||
public T create(byte[] seed) {
|
||||
Objects.requireNonNull(seed, "seed must not be null");
|
||||
try {
|
||||
ensureConstructors();
|
||||
return ctorBytes.newInstance(seed);
|
||||
} catch (Exception ex) {
|
||||
return create();
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
T instance = (T) properties.create(seed);
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -81,8 +81,8 @@
|
||||
* <blockquote>{@code import java.util.random.*;}</blockquote>
|
||||
*
|
||||
* Then one can choose a specific implementation by giving the name of a generator
|
||||
* algorithm to the static method {@link RandomGenerator#of}, in which case the
|
||||
* no-arguments constructor for that implementation is used:
|
||||
* algorithm to the static method {@link RandomGenerator#of}, in which case
|
||||
* a {@link RandomGenerator} is constructed without any seed value:
|
||||
*
|
||||
* <blockquote>{@code RandomGenerator g = RandomGenerator.of("L64X128MixRandom");}</blockquote>
|
||||
*
|
||||
@ -125,8 +125,8 @@
|
||||
*
|
||||
* <h2>Choosing a Random Number Generator Algorithm</h2>
|
||||
*
|
||||
* <p> There are three groups of random number generator algorithm provided
|
||||
* in Java: the Legacy group, the LXM group, and the Xoroshiro/Xoshiro group.
|
||||
* <p> Random number generator algorithms are organized in groups,
|
||||
* as described {@linkplain java.util.random##algorithms below}.
|
||||
*
|
||||
* <p> The legacy group includes random number generators that existed
|
||||
* before JDK 17: Random, ThreadLocalRandom, SplittableRandom, and
|
||||
@ -304,6 +304,13 @@
|
||||
* <td style="text-align:right">1</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row" style="text-align:left">SecureRandom</th>
|
||||
* <td style="text-align:left">Legacy</td>
|
||||
* <td style="text-align:left">BigInteger.ZERO</td>
|
||||
* <td style="text-align:right">Integer.MAX_VALUE</td>
|
||||
* <td style="text-align:right">Integer.MAX_VALUE</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row" style="text-align:left">ThreadLocalRandom <sup>*</sup></th>
|
||||
* <td style="text-align:left">Legacy</td>
|
||||
* <td style="text-align:left">BigInteger.ONE.shiftLeft(64)</td>
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L128X1024MixRandom",
|
||||
group = "LXM",
|
||||
i = 1024, j = 1, k = 128,
|
||||
equidistribution = 1
|
||||
)
|
||||
public final class L128X1024MixRandom extends AbstractSplittableWithBrineGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L128X128MixRandom",
|
||||
group = "LXM",
|
||||
i = 128, j = 1, k = 128,
|
||||
equidistribution = 1
|
||||
)
|
||||
public final class L128X128MixRandom extends AbstractSplittableWithBrineGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L128X256MixRandom",
|
||||
group = "LXM",
|
||||
i = 256, j = 1, k = 128,
|
||||
equidistribution = 1
|
||||
)
|
||||
public final class L128X256MixRandom extends AbstractSplittableWithBrineGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L32X64MixRandom",
|
||||
group = "LXM",
|
||||
i = 64, j = 1, k = 32,
|
||||
equidistribution = 1
|
||||
)
|
||||
public final class L32X64MixRandom extends AbstractSplittableWithBrineGenerator {
|
||||
/*
|
||||
* Implementation Overview.
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L64X1024MixRandom",
|
||||
group = "LXM",
|
||||
i = 1024, j = 1, k = 64,
|
||||
equidistribution = 16
|
||||
)
|
||||
public final class L64X1024MixRandom extends AbstractSplittableWithBrineGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L64X128MixRandom",
|
||||
group = "LXM",
|
||||
i = 128, j = 1, k = 64,
|
||||
equidistribution = 2
|
||||
)
|
||||
public final class L64X128MixRandom extends AbstractSplittableWithBrineGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L64X128StarStarRandom",
|
||||
group = "LXM",
|
||||
i = 128, j = 1, k = 64,
|
||||
equidistribution = 2
|
||||
)
|
||||
public final class L64X128StarStarRandom extends AbstractSplittableWithBrineGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "splittable" pseudorandom number generator (PRNG) whose period
|
||||
@ -75,12 +74,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "L64X256MixRandom",
|
||||
group = "LXM",
|
||||
i = 256, j = 1, k = 64,
|
||||
equidistribution = 4
|
||||
)
|
||||
public final class L64X256MixRandom extends AbstractSplittableWithBrineGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import java.util.random.RandomGenerator.LeapableGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "jumpable and leapable" pseudorandom number generator (PRNG) whose period
|
||||
@ -72,12 +71,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "Xoroshiro128PlusPlus",
|
||||
group = "Xoroshiro",
|
||||
i = 128, j = 1, k = 0,
|
||||
equidistribution = 1
|
||||
)
|
||||
public final class Xoroshiro128PlusPlus implements LeapableGenerator {
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.random.RandomGenerator;
|
||||
import java.util.random.RandomGenerator.LeapableGenerator;
|
||||
import jdk.internal.util.random.RandomSupport;
|
||||
import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
|
||||
/**
|
||||
* A "jumpable and leapable" pseudorandom number generator (PRNG) whose period
|
||||
@ -87,12 +86,6 @@ import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties;
|
||||
* @since 17
|
||||
*
|
||||
*/
|
||||
@RandomGeneratorProperties(
|
||||
name = "Xoshiro256PlusPlus",
|
||||
group = "Xoshiro",
|
||||
i = 256, j = 1, k = 0,
|
||||
equidistribution = 3
|
||||
)
|
||||
public final class Xoshiro256PlusPlus implements LeapableGenerator {
|
||||
|
||||
/*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,10 +25,7 @@
|
||||
|
||||
package jdk.internal.util.random;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.DoubleConsumer;
|
||||
import java.util.function.IntConsumer;
|
||||
@ -53,49 +50,6 @@ import java.util.stream.StreamSupport;
|
||||
* @since 17
|
||||
*/
|
||||
public class RandomSupport {
|
||||
/**
|
||||
* Annotation providing RandomGenerator properties.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface RandomGeneratorProperties {
|
||||
/**
|
||||
* Name of algorithm.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Category of algorithm.
|
||||
*/
|
||||
String group() default "Legacy";
|
||||
|
||||
/**
|
||||
* Algorithm period defined as:
|
||||
*
|
||||
* BigInteger.ONE.shiftLeft(i)
|
||||
* .subtract(j)
|
||||
* .shiftLeft(k)
|
||||
*/
|
||||
int i() default 0;
|
||||
int j() default 0;
|
||||
int k() default 0;
|
||||
|
||||
/**
|
||||
* The equidistribution of the algorithm.
|
||||
*/
|
||||
int equidistribution() default Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Is the algorithm based on entropy (true random.)
|
||||
*/
|
||||
boolean isStochastic() default false;
|
||||
|
||||
/**
|
||||
* Is the algorithm assisted by hardware (fast true random.)
|
||||
*/
|
||||
boolean isHardware() default false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation Overview.
|
||||
*
|
||||
|
@ -419,19 +419,4 @@ module java.base {
|
||||
provides java.nio.file.spi.FileSystemProvider with
|
||||
jdk.internal.jrtfs.JrtFileSystemProvider;
|
||||
|
||||
provides java.util.random.RandomGenerator with
|
||||
java.security.SecureRandom,
|
||||
java.util.Random,
|
||||
java.util.SplittableRandom,
|
||||
jdk.internal.random.L32X64MixRandom,
|
||||
jdk.internal.random.L64X128MixRandom,
|
||||
jdk.internal.random.L64X128StarStarRandom,
|
||||
jdk.internal.random.L64X256MixRandom,
|
||||
jdk.internal.random.L64X1024MixRandom,
|
||||
jdk.internal.random.L128X128MixRandom,
|
||||
jdk.internal.random.L128X256MixRandom,
|
||||
jdk.internal.random.L128X1024MixRandom,
|
||||
jdk.internal.random.Xoroshiro128PlusPlus,
|
||||
jdk.internal.random.Xoshiro256PlusPlus;
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -87,7 +87,7 @@ public class RandomTestCoverage {
|
||||
DoubleStream doubleStream4 = rng.doubles(5, 0.5, 1.0);
|
||||
}
|
||||
|
||||
static void checkPredicates(RandomGeneratorFactory factory) {
|
||||
static void checkPredicates(RandomGeneratorFactory<RandomGenerator> factory) {
|
||||
RandomGenerator rng = factory.create();
|
||||
if (rng instanceof ArbitrarilyJumpableGenerator != factory.isArbitrarilyJumpable()) {
|
||||
throw new RuntimeException("isArbitrarilyJumpable failing");
|
||||
@ -156,7 +156,7 @@ public class RandomTestCoverage {
|
||||
coverFactory(RandomGeneratorFactory.of(name));
|
||||
}
|
||||
|
||||
static void coverFactory(RandomGeneratorFactory factory) {
|
||||
static void coverFactory(RandomGeneratorFactory<RandomGenerator> factory) {
|
||||
String name = factory.name();
|
||||
String group = factory.group();
|
||||
int stateBits = factory.stateBits();
|
||||
@ -171,8 +171,34 @@ public class RandomTestCoverage {
|
||||
boolean isSplittable = factory.isSplittable();
|
||||
|
||||
coverRandomGenerator(factory.create());
|
||||
coverRandomGenerator(factory.create(12345L));
|
||||
coverRandomGenerator(factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}));
|
||||
// test create(long)
|
||||
switch (factory.name()) {
|
||||
// SecureRandom doesn't have long constructors so we expect
|
||||
// UnsupportedOperationException
|
||||
case "SecureRandom" -> {
|
||||
try {
|
||||
factory.create(12345L);
|
||||
throw new AssertionError("RandomGeneratorFactory.create(long) was expected" +
|
||||
"to throw UnsupportedOperationException for " + factory.name() + " but didn't");
|
||||
} catch (UnsupportedOperationException ignored) {
|
||||
}
|
||||
}
|
||||
default -> coverRandomGenerator(factory.create(12345L));
|
||||
}
|
||||
// test create(byte[])
|
||||
switch (factory.name()) {
|
||||
// these don't have byte[] constructors so we expect UnsupportedOperationException
|
||||
case "Random",
|
||||
"SplittableRandom" -> {
|
||||
try {
|
||||
factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8});
|
||||
throw new AssertionError("RandomGeneratorFactory.create(byte[]) was expected" +
|
||||
"to throw UnsupportedOperationException for " + factory.name() + " but didn't");
|
||||
} catch (UnsupportedOperationException ignored) {
|
||||
}
|
||||
}
|
||||
default -> coverRandomGenerator(factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}));
|
||||
}
|
||||
}
|
||||
|
||||
static void coverDefaults() {
|
||||
@ -188,32 +214,35 @@ public class RandomTestCoverage {
|
||||
coverOf(factory.name());
|
||||
});
|
||||
RandomGeneratorFactory.all()
|
||||
.filter(f -> f.isStreamable())
|
||||
.filter(RandomGeneratorFactory::isStreamable)
|
||||
.forEach(factory -> {
|
||||
coverStreamable((StreamableGenerator)factory.create());
|
||||
});
|
||||
RandomGeneratorFactory.all()
|
||||
.filter(f -> f.isSplittable())
|
||||
.filter(RandomGeneratorFactory::isSplittable)
|
||||
.forEach(factory -> {
|
||||
coverSplittable((SplittableGenerator)factory.create());
|
||||
});
|
||||
RandomGeneratorFactory.all()
|
||||
.filter(f -> f.isJumpable())
|
||||
.filter(RandomGeneratorFactory::isJumpable)
|
||||
.forEach(factory -> {
|
||||
coverJumpable((JumpableGenerator)factory.create());
|
||||
});
|
||||
RandomGeneratorFactory.all()
|
||||
.filter(f -> f.isLeapable())
|
||||
.filter(RandomGeneratorFactory::isLeapable)
|
||||
.forEach(factory -> {
|
||||
coverLeapable((LeapableGenerator)factory.create());
|
||||
});
|
||||
RandomGeneratorFactory.all()
|
||||
.filter(f -> f.isArbitrarilyJumpable())
|
||||
.filter(RandomGeneratorFactory::isArbitrarilyJumpable)
|
||||
.forEach(factory -> {
|
||||
coverArbitrarilyJumpable((ArbitrarilyJumpableGenerator)factory.create());
|
||||
});
|
||||
RandomGeneratorFactory.all()
|
||||
.forEach(RandomTestCoverage::checkPredicates);
|
||||
|
||||
coverRandomGenerator(new SecureRandom());
|
||||
coverRandomGenerator(ThreadLocalRandom.current());
|
||||
coverDefaults();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user