/* * 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(); } }