/*
* Copyright (C) 2004-2015 L2J Server
*
* This file is part of L2J Server.
*
* L2J Server is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* L2J Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package com.l2jserver.util;
import java.security.SecureRandom;
import java.util.Random;
/**
* @author Forsaiken
*/
public final class Rnd
{
/**
* This class extends {@link java.util.Random} but do not compare and store atomically.
* Instead it`s using a simple volatile flag to ensure reading and storing the whole 64bit seed chunk.
* This implementation is much faster on parallel access, but may generate the same seed for 2 threads.
* @author Forsaiken
* @see java.util.Random
*/
public static final class NonAtomicRandom extends Random
{
private static final long serialVersionUID = 1L;
private volatile long _seed;
public NonAtomicRandom()
{
this(++SEED_UNIQUIFIER + System.nanoTime());
}
public NonAtomicRandom(final long seed)
{
setSeed(seed);
}
@Override
public final int next(final int bits)
{
return (int) ((_seed = ((_seed * MULTIPLIER) + ADDEND) & MASK) >>> (48 - bits));
}
@Override
public final void setSeed(final long seed)
{
_seed = (seed ^ MULTIPLIER) & MASK;
}
}
/**
* @author Forsaiken
*/
protected static final class RandomContainer
{
private final Random _random;
protected RandomContainer(final Random random)
{
_random = random;
}
public final Random directRandom()
{
return _random;
}
/**
* Get a random double number from 0 to 1
* @return A random double number from 0 to 1
* @see com.l2jserver.util.Rnd#nextDouble()
*/
public final double get()
{
return _random.nextDouble();
}
/**
* Gets a random integer number from 0(inclusive) to n(exclusive)
* @param n The superior limit (exclusive)
* @return A random integer number from 0 to n-1
*/
public final int get(final int n)
{
return (int) (_random.nextDouble() * n);
}
/**
* Gets a random integer number from min(inclusive) to max(inclusive)
* @param min The minimum value
* @param max The maximum value
* @return A random integer number from min to max
*/
public final int get(final int min, final int max)
{
return min + (int) (_random.nextDouble() * ((max - min) + 1));
}
/**
* Gets a random long number from min(inclusive) to max(inclusive)
* @param min The minimum value
* @param max The maximum value
* @return A random long number from min to max
*/
public final long get(final long min, final long max)
{
return min + (long) (_random.nextDouble() * ((max - min) + 1));
}
/**
* Get a random boolean state (true or false)
* @return A random boolean state (true or false)
* @see java.util.Random#nextBoolean()
*/
public final boolean nextBoolean()
{
return _random.nextBoolean();
}
/**
* Fill the given array with random byte numbers from Byte.MIN_VALUE(inclusive) to Byte.MAX_VALUE(inclusive)
* @param array The array to be filled with random byte numbers
* @see java.util.Random#nextBytes(byte[] bytes)
*/
public final void nextBytes(final byte[] array)
{
_random.nextBytes(array);
}
/**
* Get a random double number from 0 to 1
* @return A random double number from 0 to 1
* @see java.util.Random#nextDouble()
*/
public final double nextDouble()
{
return _random.nextDouble();
}
/**
* Get a random float number from 0 to 1
* @return A random integer number from 0 to 1
* @see java.util.Random#nextFloat()
*/
public final float nextFloat()
{
return _random.nextFloat();
}
/**
* Get a random gaussian double number from 0 to 1
* @return A random gaussian double number from 0 to 1
* @see java.util.Random#nextGaussian()
*/
public final double nextGaussian()
{
return _random.nextGaussian();
}
/**
* Get a random integer number from Integer.MIN_VALUE(inclusive) to Integer.MAX_VALUE(inclusive)
* @return A random integer number from Integer.MIN_VALUE to Integer.MAX_VALUE
* @see java.util.Random#nextInt()
*/
public final int nextInt()
{
return _random.nextInt();
}
/**
* Get a random long number from Long.MIN_VALUE(inclusive) to Long.MAX_VALUE(inclusive)
* @return A random integer number from Long.MIN_VALUE to Long.MAX_VALUE
* @see java.util.Random#nextLong()
*/
public final long nextLong()
{
return _random.nextLong();
}
}
/**
* @author Forsaiken
*/
public static enum RandomType
{
/**
* For best random quality.
* @see java.security.SecureRandom
*/
SECURE,
/**
* For average random quality.
* @see java.util.Random
*/
UNSECURE_ATOMIC,
/**
* Like {@link com.l2jserver.util.Rnd.RandomType#UNSECURE_ATOMIC}.
* Each thread has it`s own random instance.
* Provides best parallel access speed.
* @see com.l2jserver.util.Rnd.ThreadLocalRandom
*/
UNSECURE_THREAD_LOCAL,
/**
* Like {@link com.l2jserver.util.Rnd.RandomType#UNSECURE_ATOMIC}.
* Provides much faster parallel access speed.
* @see com.l2jserver.util.Rnd.NonAtomicRandom
*/
UNSECURE_VOLATILE
}
/**
* This class extends {@link java.util.Random} but do not compare and store atomically.
* Instead it`s using thread local ensure reading and storing the whole 64bit seed chunk.
* This implementation is the fastest, never generates the same seed for 2 threads.
* Each thread has it`s own random instance.
* @author Forsaiken
* @see java.util.Random
*/
public static final class ThreadLocalRandom extends Random
{
private static final class Seed
{
long _seed;
Seed(final long seed)
{
setSeed(seed);
}
final int next(final int bits)
{
return (int) ((_seed = ((_seed * MULTIPLIER) + ADDEND) & MASK) >>> (48 - bits));
}
final void setSeed(final long seed)
{
_seed = (seed ^ MULTIPLIER) & MASK;
}
}
private static final long serialVersionUID = 1L;
private final ThreadLocal _seedLocal;
public ThreadLocalRandom()
{
_seedLocal = new ThreadLocal()
{
@Override
public final Seed initialValue()
{
return new Seed(++SEED_UNIQUIFIER + System.nanoTime());
}
};
}
public ThreadLocalRandom(final long seed)
{
_seedLocal = new ThreadLocal()
{
@Override
public final Seed initialValue()
{
return new Seed(seed);
}
};
}
@Override
public final int next(final int bits)
{
return _seedLocal.get().next(bits);
}
@Override
public final void setSeed(final long seed)
{
if (_seedLocal != null)
{
_seedLocal.get().setSeed(seed);
}
}
}
private static final long ADDEND = 0xBL;
private static final long MASK = (1L << 48) - 1;
private static final long MULTIPLIER = 0x5DEECE66DL;
private static final RandomContainer rnd = newInstance(RandomType.UNSECURE_THREAD_LOCAL);
protected static volatile long SEED_UNIQUIFIER = 8682522807148012L;
public static final Random directRandom()
{
return rnd.directRandom();
}
/**
* Get a random double number from 0 to 1
* @return A random double number from 0 to 1
* @see com.l2jserver.util.Rnd#nextDouble()
*/
public static final double get()
{
return rnd.nextDouble();
}
/**
* Gets a random integer number from 0(inclusive) to n(exclusive)
* @param n The superior limit (exclusive)
* @return A random integer number from 0 to n-1
*/
public static final int get(final int n)
{
return rnd.get(n);
}
/**
* Gets a random integer number from min(inclusive) to max(inclusive)
* @param min The minimum value
* @param max The maximum value
* @return A random integer number from min to max
*/
public static final int get(final int min, final int max)
{
return rnd.get(min, max);
}
/**
* Gets a random long number from min(inclusive) to max(inclusive)
* @param min The minimum value
* @param max The maximum value
* @return A random long number from min to max
*/
public static final long get(final long min, final long max)
{
return rnd.get(min, max);
}
public static final RandomContainer newInstance(final RandomType type)
{
switch (type)
{
case UNSECURE_ATOMIC:
return new RandomContainer(new Random());
case UNSECURE_VOLATILE:
return new RandomContainer(new NonAtomicRandom());
case UNSECURE_THREAD_LOCAL:
return new RandomContainer(new ThreadLocalRandom());
case SECURE:
return new RandomContainer(new SecureRandom());
}
throw new IllegalArgumentException();
}
/**
* Get a random boolean state (true or false)
* @return A random boolean state (true or false)
* @see java.util.Random#nextBoolean()
*/
public static final boolean nextBoolean()
{
return rnd.nextBoolean();
}
/**
* Fill the given array with random byte numbers from Byte.MIN_VALUE(inclusive) to Byte.MAX_VALUE(inclusive)
* @param array The array to be filled with random byte numbers
* @see java.util.Random#nextBytes(byte[] bytes)
*/
public static final void nextBytes(final byte[] array)
{
rnd.nextBytes(array);
}
/**
* Get a random double number from 0 to 1
* @return A random double number from 0 to 1
* @see java.util.Random#nextDouble()
*/
public static final double nextDouble()
{
return rnd.nextDouble();
}
/**
* Get a random float number from 0 to 1
* @return A random integer number from 0 to 1
* @see java.util.Random#nextFloat()
*/
public static final float nextFloat()
{
return rnd.nextFloat();
}
/**
* Get a random gaussian double number from 0 to 1
* @return A random gaussian double number from 0 to 1
* @see java.util.Random#nextGaussian()
*/
public static final double nextGaussian()
{
return rnd.nextGaussian();
}
/**
* Get a random integer number from Integer.MIN_VALUE(inclusive) to Integer.MAX_VALUE(inclusive)
* @return A random integer number from Integer.MIN_VALUE to Integer.MAX_VALUE
* @see java.util.Random#nextInt()
*/
public static final int nextInt()
{
return rnd.nextInt();
}
/**
* @param n
* @return
* @see com.l2jserver.util.Rnd#get(int n)
*/
public static final int nextInt(final int n)
{
return get(n);
}
/**
* Get a random long number from Long.MIN_VALUE(inclusive) to Long.MAX_VALUE(inclusive)
* @return A random integer number from Long.MIN_VALUE to Long.MAX_VALUE
* @see java.util.Random#nextLong()
*/
public static final long nextLong()
{
return rnd.nextLong();
}
}