#ifndef __AMSXOROSHIRO_CUH__
#define __AMSXOROSHIRO_CUH__

//implementations of the xoroshiro family of PRNGs
//Described by: https://prng.di.unimi.it/
//ref: https://prng.di.unimi.it/xoroshiro64star.c
//ref: David Blackman and Sebastiano Vigna. Scrambled linear pseudorandom number generators. ACM Trans. Math. Softw., 47:1−32, 2021. 

namespace amscuda
{
namespace random
{
namespace xoroshiro
{

//https://github.com/joelkp/ranoise/blob/main/splitmix32.c
__device__ __host__ uint32_t splitmix32_next(uint32_t *splitmix32_state);
__host__ __device__ void splitmix64_next(uint64_t *state);
__host__ __device__ uint64_t splitmix64_nextint(uint64_t *state);

struct xs64ss_state
{
    public:
    uint32_t low;
    uint32_t high;
    __device__ __host__ xs64ss_state();
    __device__ __host__ xs64ss_state(const uint32_t seed);
    __device__ __host__ xs64ss_state(const uint32_t _low, const uint32_t _high);
};

extern xs64ss_state xs64ss_globalstate;

__host__ void xs64ss_seed(const uint32_t q);
// __host__ void xs64ss_seed(const uint32_t _a, const uint32_t _b);

//implements the xoroshiro64** PRNG 
__host__ __device__ uint32_t xs64ss_next(xs64ss_state *state);


//The problem with xoroshiro128+ is that 64 bit integer operations on GPUs are 20 (multiplication) to 80 times slower
//than the native 32 bit integer opeations. Everywhere a 64 bit integer shows up and is multiplied by anything, things slow down

struct xs128pp_state
{
    public:
    uint64_t low;
    uint64_t high;
    __device__ __host__ xs128pp_state();
    __device__ __host__ xs128pp_state(const uint64_t seed);
    __device__ __host__ xs128pp_state(const uint64_t _low, const uint64_t _high);
};

extern xs128pp_state xs128pp_globalstate;

__host__ __device__ uint64_t xs128pp_rotl(const uint64_t x, int k);
__host__ __device__ uint64_t xs128pp_next(xs128pp_state* state);

//equivalent to 2^64 calls to xs128pp_next()
__device__ __host__ void xs128pp_jump(xs128pp_state* state);

__host__ void xs128pp_seed(uint64_t seed);


};
};
};

#endif

