AuroraRuntime/Source/RNG/AuRandomDevice.cpp

187 lines
4.6 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuRandomDevice.cpp
Date: 2021-9-3
Author: Reece
***/
#include <AuroraRuntime.hpp>
#include "AuRandomDevice.hpp"
namespace Aurora::RNG
{
RandomDevice::RandomDevice()
{
}
RandomDevice::RandomDevice(const RandomDef &def)
{
this->Init(def);
}
void RandomDevice::Init(const RandomDef &def)
{
this->def_ = def;
// Gross...
if (!def.bSecure)
{
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(Memory::MemoryViewWrite view)
{
if (!view)
{
SysPushErrorArg();
return;
}
if (this->def_.bSecure)
{
ReadSecureRNG(view);
}
else
{
WELL_NextBytes(&this->fast_, view.ptr, AuUInt32(view.length));
}
}
AuString RandomDevice::NextString(AuUInt32 uLength, ERngStringCharacters type)
{
AuString ret(uLength, '\00');
NextString(ret.data(), AuUInt32(ret.size()), type);
return ret;
}
void RandomDevice::NextString(char *pString, AuUInt32 uLength, 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}
};
if (!pString)
{
SysPushErrorArg();
return;
}
Read(AuMemoryViewWrite { pString, uLength });
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 < uLength; i++)
{
pString[i] = pair.first[reinterpret_cast<const AuUInt8 *>(pString)[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 uMin, AuInt32 uMax)
{
auto range = uMax - uMin;
return (NextU64() % range) + uMin;
}
AuUInt32 RandomDevice::NextU32(AuUInt32 uMin, AuUInt32 uMax)
{
auto range = uMax - uMin;
return (NextU64() % range) + uMin;
}
double RandomDevice::NextDecimal()
{
return double(NextU32()) * (double(1.0) / double(AuNumericLimits<AuUInt32>::max()));
}
AuUInt32 RandomDevice::NextIndex(AuUInt32 uCount /* = max + 1*/)
{
return NextU32() % uCount;
}
float RandomDevice::NextNumber(float min, float max)
{
auto range = max - min;
return NextDecimal() * range + min;
}
AuMemoryViewRead RandomDevice::ToSeed()
{
if (this->def_.bSecure)
{
return {};
}
return this->fast_.state;
}
AUKN_SYM IRandomDevice *RandomNew(const Aurora::RNG::RandomDef &def)
{
auto pDevice = _new RandomDevice();
if (!pDevice)
{
return nullptr;
}
pDevice->Init(def);
return pDevice;
}
AUKN_SYM void RandomRelease(IRandomDevice *pDevice)
{
AuSafeDelete<RandomDevice *>(pDevice);
}
AUROXTL_INTERFACE_SOO_SRC(Random, RandomDevice, (const RandomDef &, def))
}