From 880bce9092fbef0bcbf101b8ec2e3d2c5af3fb98 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 20 Apr 2019 16:52:50 -0700 Subject: [PATCH] libstrat: add StratosphereRandomUtils --- include/stratosphere.hpp | 4 +- include/stratosphere/random.hpp | 27 +++++++++++ source/random.cpp | 84 +++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 include/stratosphere/random.hpp create mode 100644 source/random.cpp diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp index e0ab6d67..885695c0 100644 --- a/include/stratosphere.hpp +++ b/include/stratosphere.hpp @@ -39,4 +39,6 @@ #include "stratosphere/title_ids.hpp" -#include "stratosphere/on_crash.hpp" \ No newline at end of file +#include "stratosphere/on_crash.hpp" + +#include "stratosphere/random.hpp" \ No newline at end of file diff --git a/include/stratosphere/random.hpp b/include/stratosphere/random.hpp new file mode 100644 index 00000000..9e67dd2c --- /dev/null +++ b/include/stratosphere/random.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +class StratosphereRandomUtils { + public: + static u32 GetRandomU32(u32 max); + static u64 GetRandomU64(u64 max); + + template + static T GetRandom(T max); +}; \ No newline at end of file diff --git a/source/random.cpp b/source/random.cpp new file mode 100644 index 00000000..03439392 --- /dev/null +++ b/source/random.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +/* Official HOS uses TinyMT. This is high effort. Let's just use XorShift. */ +/* https://en.wikipedia.org/wiki/Xorshift */ +class XorShiftGenerator { + public: + using result_type = uint32_t; + static constexpr result_type (min)() { return 0; } + static constexpr result_type (max)() { return UINT32_MAX; } + static constexpr size_t num_seed_dwords = 4; + private: + result_type random_state[num_seed_dwords]; + public: + + explicit XorShiftGenerator() { + /* Seed using process entropy. */ + u64 val = 0; + for (size_t i = 0; i < num_seed_dwords; i++) { + if (R_FAILED(svcGetInfo(&val, 0xB, 0, i))) { + std::abort(); + } + this->random_state[i] = result_type(val); + } + } + + explicit XorShiftGenerator(std::random_device &rd) { + for (size_t i = 0; i < num_seed_dwords; i++) { + this->random_state[i] = result_type(rd()); + } + } + + result_type operator()() { + result_type s, t = this->random_state[3]; + t ^= t << 11; + t ^= t >> 8; + this->random_state[3] = this->random_state[2]; this->random_state[2] = this->random_state[1]; this->random_state[1] = (s = this->random_state[0]); + t ^= s; + t ^= s >> 19; + this->random_state[0] = t; + return t; + } + + void discard(size_t n) { + for (size_t i = 0; i < n; i++) { + operator()(); + } + } +}; + +static XorShiftGenerator g_rnd_generator; + +template +T StratosphereRandomUtils::GetRandom(T max) { + std::uniform_int_distribution rnd(0, max); + return rnd(g_rnd_generator); +} + +/* These are slightly biased, but I think that's totally okay. */ +u32 StratosphereRandomUtils::GetRandomU32(u32 max) { + return GetRandom(max); +} + +u64 StratosphereRandomUtils::GetRandomU64(u64 max) { + return GetRandom(max); +} +