2020-12-31 15:35:46 +03:00

90 lines
3.2 KiB
C++

#pragma once
#include <memory>
#include <mutex>
#include <random>
class XORShiftSeeder; // stolen from https://arvid.io/2018/07/02/better-cxx-prng/
class Randomizer
{
public:
~Randomizer() = default;
static Randomizer& GetInstance();
enum FillType { _0_to_255, _0_to_127, _128_to_255, ANSIdigit, ANSIuppercase, ANSIlowcase, ANSIchar, ANSIfromAtoF, ANSIfromAtoF_lower
};
uint8_t GetSingleByte(FillType type);
private:
Randomizer();
static std::once_flag m_createonceflag;
static std::unique_ptr<Randomizer> m_pInstance;
Randomizer(const Randomizer&) = delete;
Randomizer(Randomizer&&) = delete;
Randomizer& operator=(const Randomizer&) = delete;
Randomizer& operator=(Randomizer&&) = delete;
static XORShiftSeeder m_xorshift;
static std::uniform_int_distribution<unsigned int> m_distrByte;
static std::uniform_int_distribution<unsigned int> m_distrByteHighBit_1;
static std::uniform_int_distribution<unsigned int> m_distrByteHighBit_0;
static std::uniform_int_distribution<unsigned int> m_ANSIdigit;
static std::uniform_int_distribution<unsigned int> m_ANSIuppercase;
static std::uniform_int_distribution<unsigned int> m_ANSIlowcase;
static std::uniform_int_distribution<unsigned int> m_ANSIchar;
static std::uniform_int_distribution<unsigned int> m_ANSIfromAtoF;
static std::uniform_int_distribution<unsigned int> m_ANSIfromAtoF_lower;
};
#define RANDBYTE Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::_0_to_255)
#define RANDBYTEH0 Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::_0_to_127)
#define RANDBYTEH1 Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::_128_to_255)
#define RANDANSIDIGIT Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::ANSIdigit)
#define RANDANSIUPPERCASE Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::ANSIuppercase)
#define RANDANSILOWCASE Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::ANSIlowcase)
#define RANDANSICHAR Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::ANSIchar)
#define RANDHEXSYMBOL (Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::_0_to_127) < 64) ? \
Randomizer::GetInstance().GetSingleByte(Randomizer::FillType::ANSIfromAtoF_lower) : RANDANSIDIGIT
#define RANDALNUM RANDBYTEH0 < 64 ? RANDANSIUPPERCASE : (RANDBYTEH0 < 64 ? RANDANSILOWCASE : RANDANSIDIGIT)
class XORShiftSeeder
{
public:
using result_type = uint32_t;
static constexpr result_type(min)() { return 0; }
static constexpr result_type(max)() { return UINT32_MAX; }
friend bool operator==(XORShiftSeeder const &, XORShiftSeeder const &);
friend bool operator!=(XORShiftSeeder const &, XORShiftSeeder const &);
XORShiftSeeder() : m_seed(0xc1f651c67c62c6e0ull) {}
explicit XORShiftSeeder(std::random_device &rd)
{
seed(rd);
}
void seed(std::random_device &rd)
{
m_seed = uint64_t(rd()) << 31 | uint64_t(rd());
}
result_type operator()()
{
uint64_t result = m_seed * 0xd989bcaef137dcd5ull;
m_seed ^= m_seed >> 11;
m_seed ^= m_seed << 31;
m_seed ^= m_seed >> 18;
return uint32_t(result >> 32ull);
}
void discard(unsigned long long n)
{
for (unsigned long long i = 0; i < n; ++i)
operator()();
}
private:
uint64_t m_seed;
};