using System.Runtime.CompilerServices;
namespace PKHeX.Core
{
public struct Xoroshiro128Plus
{
public const ulong XOROSHIRO_CONST = 0x82A2B175229D6A5B;
private ulong s0, s1;
public Xoroshiro128Plus(ulong seed)
{
s0 = seed;
s1 = XOROSHIRO_CONST;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong RotateLeft(ulong x, int k)
{
return (x << k) | (x >> (64 - k));
}
///
/// Gets the next random .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong Next()
{
var _s0 = s0;
var _s1 = s1;
ulong result = _s0 + _s1;
_s1 ^= _s0;
// Final calculations and store back to fields
s0 = RotateLeft(_s0, 24) ^ _s1 ^ (_s1 << 16);
s1 = RotateLeft(_s1, 37);
return result;
}
///
/// Gets a random value that is less than
///
/// Maximum value (exclusive). Generates a bitmask for the loop.
/// Random value
public ulong NextInt(ulong MOD = 0xFFFFFFFF)
{
ulong mask = GetBitmask(MOD);
ulong res;
do
{
res = Next() & mask;
} while (res >= MOD);
return res;
}
///
/// Next Power of Two
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong GetBitmask(ulong x)
{
x--; // comment out to always take the next biggest power of two, even if x is already a power of two
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x;
}
// ReSharper disable once NonReadonlyMemberInGetHashCode
// ReSharper disable once NonReadonlyMemberInGetHashCode
public override int GetHashCode() => (int)s0;
public override bool Equals(object obj) => obj is Xoroshiro128Plus s && Equals(s);
public bool Equals(Xoroshiro128Plus obj) => obj.s0 == s0 && obj.s1 == s1;
public static bool operator ==(Xoroshiro128Plus left, Xoroshiro128Plus right) => left.Equals(right);
public static bool operator !=(Xoroshiro128Plus left, Xoroshiro128Plus right) => !(left == right);
}
}