RngServiceImpl.java
package space.sunqian.common.base.random;
import space.sunqian.annotations.Nonnull;
import space.sunqian.common.Check;
import space.sunqian.common.base.bytes.BytesKit;
import space.sunqian.common.base.math.MathKit;
import space.sunqian.common.collect.StreamKit;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier;
import java.util.function.LongSupplier;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
enum RngServiceImpl implements RngService {
INST;
@Override
public @Nonnull Rng random(@Nonnull Random random) {
return new RandomRng(random);
}
@Override
public @Nonnull Rng threadLocalRandom() {
return ThreadLocalRandomRng.INST;
}
private static final class RandomRng extends AbsRngImpl {
private final @Nonnull Random random;
private RandomRng(@Nonnull Random random) {
this.random = random;
}
@Override
protected @Nonnull Random random() {
return random;
}
@Override
public void reset(long seed) {
random.setSeed(seed);
}
@Override
public void reset(byte @Nonnull [] seed) {
if (random instanceof SecureRandom) {
((SecureRandom) random).setSeed(seed);
} else {
random.setSeed(BytesKit.bytesToLong(seed));
}
}
@Override
public int nextInt() {
return random.nextInt();
}
@Override
public int nextInt(int startInclusive, int endExclusive) throws IllegalArgumentException {
return ints(startInclusive, endExclusive).iterator().nextInt();
}
@Override
public long nextLong() {
return random.nextLong();
}
@Override
public long nextLong(long startInclusive, long endExclusive) throws IllegalArgumentException {
return longs(startInclusive, endExclusive).iterator().nextLong();
}
@Override
public float nextFloat() {
double value = nextDouble();
return MathKit.makeIn((float) value, 0.0f, 1.0f);
}
@Override
public float nextFloat(float startInclusive, float endExclusive) throws IllegalArgumentException {
double value = nextDouble(startInclusive, endExclusive);
return MathKit.makeIn((float) value, startInclusive, endExclusive);
}
@Override
public double nextDouble() {
return random.nextDouble();
}
@Override
public double nextDouble(double startInclusive, double endExclusive) throws IllegalArgumentException {
return doubles(startInclusive, endExclusive).iterator().nextDouble();
}
}
private static final class ThreadLocalRandomRng extends AbsRngImpl {
private static final @Nonnull ThreadLocalRandomRng INST = new ThreadLocalRandomRng();
@Override
protected @Nonnull ThreadLocalRandom random() {
return ThreadLocalRandom.current();
}
@Override
public void reset(long seed) {
}
@Override
public void reset(byte @Nonnull [] seed) {
}
@Override
public int nextInt() {
return random().nextInt();
}
@Override
public int nextInt(int startInclusive, int endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return startInclusive;
}
return random().nextInt(startInclusive, endExclusive);
}
@Override
public long nextLong() {
return random().nextLong();
}
@Override
public long nextLong(long startInclusive, long endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return startInclusive;
}
return random().nextLong(startInclusive, endExclusive);
}
@Override
public float nextFloat() {
double value = nextDouble();
return MathKit.makeIn((float) value, 0.0f, 1.0f);
}
@Override
public float nextFloat(float startInclusive, float endExclusive) throws IllegalArgumentException {
double value = nextDouble(startInclusive, endExclusive);
return MathKit.makeIn((float) value, startInclusive, endExclusive);
}
@Override
public double nextDouble() {
return random().nextDouble();
}
@Override
public double nextDouble(double startInclusive, double endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return startInclusive;
}
return random().nextDouble(startInclusive, endExclusive);
}
}
private static abstract class AbsRngImpl implements Rng {
protected abstract @Nonnull Random random();
@Override
public void nextBytes(byte @Nonnull [] bytes) {
random().nextBytes(bytes);
}
@Override
public void nextBytes(byte @Nonnull [] bytes, int off, int len) throws IndexOutOfBoundsException {
if (off == 0 && len == bytes.length) {
random().nextBytes(bytes);
return;
}
Check.checkOffLen(off, len, bytes.length);
int i = off;
int end = off + len;
for (int words = len >> 3; words-- > 0; ) {
long rnd = nextLong();
for (int n = 8; n-- > 0; rnd >>>= Byte.SIZE) {
bytes[i++] = (byte) rnd;
}
}
if (i < end) {
for (long rnd = nextLong(); i < end; rnd >>>= Byte.SIZE) {
bytes[i++] = (byte) rnd;
}
}
}
@Override
public @Nonnull IntStream ints() {
return random().ints();
}
@Override
public @Nonnull IntStream ints(int startInclusive, int endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return IntStream.generate(() -> startInclusive);
}
return random().ints(startInclusive, endExclusive);
}
@Override
public @Nonnull IntStream ints(long size) throws IllegalArgumentException {
return random().ints(size);
}
@Override
public @Nonnull IntStream ints(long size, int startInclusive, int endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return IntStream.generate(() -> startInclusive).limit(size);
}
return random().ints(size, startInclusive, endExclusive);
}
@Override
public @Nonnull IntSupplier intSupplier(int startInclusive, int endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return () -> startInclusive;
}
return StreamKit.toSupplier(random().ints(startInclusive, endExclusive));
}
@Override
public @Nonnull LongStream longs() {
return random().longs();
}
@Override
public @Nonnull LongStream longs(long startInclusive, long endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return LongStream.generate(() -> startInclusive);
}
return random().longs(startInclusive, endExclusive);
}
@Override
public @Nonnull LongStream longs(long size) throws IllegalArgumentException {
return random().longs(size);
}
@Override
public @Nonnull LongStream longs(long size, long startInclusive, long endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return LongStream.generate(() -> startInclusive).limit(size);
}
return random().longs(size, startInclusive, endExclusive);
}
@Override
public @Nonnull LongSupplier longSupplier(long startInclusive, long endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return () -> startInclusive;
}
return StreamKit.toSupplier(random().longs(startInclusive, endExclusive));
}
@Override
public @Nonnull DoubleStream doubles() {
return random().doubles();
}
@Override
public @Nonnull DoubleStream doubles(double startInclusive, double endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return DoubleStream.generate(() -> startInclusive);
}
return random().doubles(startInclusive, endExclusive);
}
@Override
public @Nonnull DoubleStream doubles(long size) throws IllegalArgumentException {
return random().doubles(size);
}
@Override
public @Nonnull DoubleStream doubles(long size, double startInclusive, double endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return DoubleStream.generate(() -> startInclusive).limit(size);
}
return random().doubles(size, startInclusive, endExclusive);
}
@Override
public @Nonnull DoubleSupplier doubleSupplier(double startInclusive, double endExclusive) throws IllegalArgumentException {
if (startInclusive == endExclusive) {
return () -> startInclusive;
}
return StreamKit.toSupplier(random().doubles(startInclusive, endExclusive));
}
}
}