AuroraRuntime/Source/RNG/RandomDevice.cpp

176 lines
4.9 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: RandomDevice.cpp
Date: 2021-9-3
Author: Reece
***/
#include <AuroraRuntime.hpp>
#include <Source/RNG/WELL.hpp>
#include "RandomDevice.hpp"
namespace Aurora::RNG
{
class RandomDevice : public IRandomDevice
{
public:
void Read(void *in, AuUInt32 length) override;
AuString NextString(AuUInt32 length, ERngStringCharacters type) override;
void NextString(char *string, AuUInt32 length, ERngStringCharacters type) override;
AuUInt8 NextByte() override;
bool NextBoolean() override;
AuUInt32 NextU32() override;
AuUInt64 NextU64() override;
AuInt32 NextInt(AuInt32 min, AuInt32 max) override;
AuUInt32 NextU32(AuUInt32 min, AuUInt32 max) override;
double NextDecimal() override;
float NextNumber(float min, float max) override;
AuUInt32 NextIndex(AuUInt32 count /* = max + 1*/) override;
void Init(const RandomDef &def);
private:
RandomDef def_;
WELLRand fast_;
};
void RandomDevice::Init(const RandomDef &def)
{
this->def_ = def;
if (!def.secure)
{
if (def.seed)
{
this->fast_ = WELL_SeedRand(def.seed.value());
}
else if (def.seed64)
{
this->fast_ = WELL_SeedRand64(def.seed64.value());
}
else if (def.seedMassive)
{
this->fast_ = WELL_SeedRandBig64(def.seedMassive.value());
}
else
{
this->fast_ = {};
RNG::RngFillArray<false>(this->fast_.state);
}
}
// secure rng requires no init -> we just passthrough to the global ReadSecureRNG function
}
void RandomDevice::Read(void *in, AuUInt32 length)
{
if (this->def_.secure)
{
ReadSecureRNG(in, length);
}
else
{
WELL_NextBytes(&this->fast_, in, length);
}
}
AuString RandomDevice::NextString(AuUInt32 length, ERngStringCharacters type)
{
AuString ret(length, '\00');
NextString(ret.data(), AuUInt32(ret.size()), type);
return ret;
}
void RandomDevice::NextString(char *string, AuUInt32 length, ERngStringCharacters type)
{
static AuPair<const char *, int> rngSequence[static_cast<int>(ERngStringCharacters::eEnumCount)] =
{
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52},
{"abcdefghijklmnopqrstuvwxyz", 26},
{"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26},
{"1234567890", 10},
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 62},
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890=-+!$%^*.[];:", 75}
};
ReadSecureRNG(string, length);
if (!ERngStringCharactersIsValid(type))
{
SysPushErrorArg("NextString was called with an invalid ERngStringCharacters {}", (AuUInt)type);
type = ERngStringCharacters::eAlphaNumericCharacters; // guess we cant just return false
}
const auto &pair = rngSequence[static_cast<int>(type)];
for (auto i = 0u; i < length; i++)
{
string[i] = pair.first[reinterpret_cast<const AuUInt8 *>(string)[i] % static_cast<int>(pair.second)];
}
}
AuUInt8 RandomDevice::NextByte()
{
return NextFillTmpl<AuUInt8>();
}
bool RandomDevice::NextBoolean()
{
return NextByte() > 127;
}
AuUInt32 RandomDevice::NextU32()
{
return NextFillTmpl<AuUInt32>();
}
AuUInt64 RandomDevice::NextU64()
{
return NextFillTmpl<AuUInt64>();
}
AuInt32 RandomDevice::NextInt(AuInt32 min, AuInt32 max)
{
auto range = max - min;
return (NextU64() % range) + min;
}
AuUInt32 RandomDevice::NextU32(AuUInt32 min, AuUInt32 max)
{
auto range = max - min;
return (NextU64() % range) + min;
}
double RandomDevice::NextDecimal()
{
return double(NextU32()) * (double(1.0) / double(AuNumericLimits<AuUInt32>::max()));
}
AuUInt32 RandomDevice::NextIndex(AuUInt32 count /* = max + 1*/)
{
return NextU32() % count;
}
float RandomDevice::NextNumber(float min, float max)
{
auto range = max - min;
return NextDecimal() * range + min;
}
AUKN_SYM IRandomDevice *RandomNew(const Aurora::RNG::RandomDef &def)
{
auto device = _new RandomDevice();
if (!device)
{
return nullptr;
}
device->Init(def);
return device;
}
AUKN_SYM void RandomRelease(IRandomDevice *stream)
{
AuSafeDelete<RandomDevice*>(stream);
}
}