176 lines
4.9 KiB
C++
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(), 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 = 0; i < length; i++)
|
|
{
|
|
string[i] = pair.first[reinterpret_cast<const AuUInt8 *>(string)[i] % static_cast<int>(ERngStringCharacters::eEnumCount)];
|
|
}
|
|
}
|
|
|
|
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<IRandomDevice*>(stream);
|
|
}
|
|
} |