/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: RandomDevice.cpp Date: 2021-9-3 Author: Reece ***/ #include #include "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) { this->fast_ = WELL_SeedRand(def.seed.value_or(Aurora::RNG::RngTmpl())); } } 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 rngSequence[static_cast(ERngStringCharacters::eCount)] = { {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52}, {"abcdefghijklmnopqrstuvwxyz", 26}, {"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26}, {"1234567890", 10}, {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 62}, {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890=-+!$%^*.[];:", 75} }; ReadSecureRNG(string, length); const auto &pair = rngSequence[static_cast(type)]; for (auto i = 0; i < length; i++) { string[i] = pair.first[reinterpret_cast(string)[i] % static_cast(ERngStringCharacters::eCount)]; } } AuUInt8 RandomDevice::NextByte() { return NextTmpl(); } bool RandomDevice::NextBoolean() { return NextByte() > 127; } AuUInt32 RandomDevice::NextU32() { return NextTmpl(); } AuUInt64 RandomDevice::NextU64() { return NextTmpl(); } 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(std::numeric_limits::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) { SafeDelete(stream); } }