From ea7a91bd042599132e60482f51087d9669dbe1c4 Mon Sep 17 00:00:00 2001 From: jeefo Date: Thu, 25 Apr 2024 14:46:22 +0300 Subject: [PATCH] random: simplified prng misc: various small changes --- crlib/array.h | 6 +-- crlib/http.h | 4 +- crlib/random.h | 99 +++++++++++++++++++++++--------------------------- crlib/string.h | 26 +++++++------ 4 files changed, 65 insertions(+), 70 deletions(-) diff --git a/crlib/array.h b/crlib/array.h index a25169c..1b5e00a 100644 --- a/crlib/array.h +++ b/crlib/array.h @@ -275,7 +275,7 @@ template c int32_t shuffleLength = length (); for (int32_t i = shuffleLength; i >= 1; --i) { - cr::swap (contents_[i - 1], contents_[rg.get (i, shuffleLength - 2)]); + cr::swap (contents_[i - 1], contents_[rg (i, shuffleLength - 2)]); } } @@ -351,14 +351,14 @@ template c if (length_ <= 1) { return contents_[0]; } - return contents_[rg.get (0, length () - 1)]; + return contents_[rg (0, length () - 1)]; } T &random () { if (length_ <= 1) { return contents_[0]; } - return contents_[rg.get (0, length () - 1)]; + return contents_[rg (0, length () - 1)]; } T *data () { diff --git a/crlib/http.h b/crlib/http.h index 01f4db3..d5493df 100644 --- a/crlib/http.h +++ b/crlib/http.h @@ -318,7 +318,7 @@ class HttpClient final : public Singleton { String respCode = response.substr (responseCodeStart + cr::bufsize ("HTTP 1/1 "), 3); respCode.trim (); - return static_cast (respCode.int_ ()); + return static_cast (respCode.as ()); } return HttpClientResult::NotFound; } @@ -438,7 +438,7 @@ class HttpClient final : public Singleton { if (boundarySlash != String::InvalidIndex) { boundaryName = localPath.substr (boundarySlash + 1); } - StringRef boundaryLine = strings.format ("---crlib_upload_boundary_%d%d%d%d", rg.get (0, 9), rg.get (0, 9), rg.get (0, 9), rg.get (0, 9)); + StringRef boundaryLine = strings.format ("---crlib_upload_boundary_%d%d%d%d", rg (0, 9), rg (0, 9), rg (0, 9), rg (0, 9)); String request, start, end; start.appendf ("--%s\r\n", boundaryLine); diff --git a/crlib/random.h b/crlib/random.h index 4619e5c..38428b7 100644 --- a/crlib/random.h +++ b/crlib/random.h @@ -12,81 +12,74 @@ CR_NAMESPACE_BEGIN -// random number generator, credits goes to https://prng.di.unimi.it/xoshiro128starstar.c -class Xoshiro128 final : public Singleton { +namespace detail { + class SplitMix32 final { + private: + uint32_t state_ {}; + + public: + explicit SplitMix32 (const uint32_t state) noexcept : state_ (state) {} + + public: + [[nodiscard]] decltype (auto) next () noexcept { + auto z = (state_ += 0x9e3779b9); + z = (z ^ (z >> 16)) * 0x85ebca6b; + z = (z ^ (z >> 13)) * 0xc2b2ae35; + return z ^ (z >> 16); + } + }; +} + +// random number generator (xoshiro based) +class RWrand final : public Singleton { private: - uint32_t states_[4] {}; - uint32_t states2_[4] {}; - static constexpr uint64_t limit_ { static_cast (1) << 32ull }; + static constexpr uint64_t kRandMax { static_cast (1) << 32ull }; private: - constexpr uint32_t rotl32 (const uint32_t x, int32_t k) { - return (x << k) | (x >> (32 - k)); - } + uint32_t states_[3] {}; - constexpr uint32_t splitmix32 (uint32_t &x) { - uint32_t z = (x += 0x9e3779b9); - z = (z ^ (z >> 16)) * 0x85ebca6b; - z = (z ^ (z >> 13)) * 0xc2b2ae35; - return z ^ (z >> 16); - } +public: + explicit RWrand () noexcept { + const auto seed = static_cast (time (nullptr)); - constexpr void seeder (uint32_t *state) { - uint32_t seed = 0; + detail::SplitMix32 smix (seed); - state[0] = splitmix32 (seed); - state[1] = splitmix32 (seed); - state[2] = splitmix32 (seed); - state[3] = splitmix32 (seed); + for (auto &state : states_) { + state = smix.next (); + } } + ~RWrand () = default; + private: - constexpr uint32_t scramble (uint32_t *states, const uint32_t result) { - const uint32_t t = states[1] << 9; + [[nodiscard]] decltype (auto) rotl (const uint32_t x, const int32_t k) noexcept { + return (x << k) | (x >> (32 - k)); + } - states[2] ^= states[0]; - states[3] ^= states[1]; - states[1] ^= states[2]; - states[0] ^= states[3]; - states[2] ^= t; - states[3] = rotl32 (states[3], 11); + [[nodiscard]] decltype (auto) next () noexcept { + states_[0] = rotl (states_[0] + states_[1] + states_[2], 16); + states_[1] = states_[0]; + states_[2] = states_[1]; - return result; + return states_[0]; } - template constexpr uint32_t next () { +public: + template [[nodiscard]] decltype (auto) operator () (const U low, const U high) noexcept { if constexpr (cr::is_same ::value) { - return scramble (states_, rotl32 (states_[0] + states_[3], 7) + states_[0]); + return static_cast (next () * (static_cast (high) - static_cast (low) + 1.0) / kRandMax + static_cast (low)); } else if constexpr (cr::is_same ::value) { - return scramble (states2_, states2_[0] + states2_[3]); + return static_cast (next () * (static_cast (high) - static_cast (low)) / (kRandMax - 1) + static_cast (low)); } } -public: - constexpr explicit Xoshiro128 () { - seeder (states_); - seeder (states2_); - } - -public: - template constexpr U get (U, U) = delete; - - template constexpr int32_t get (int32_t low, int32_t high) { - return static_cast (next () * (static_cast (high) - static_cast (low) + 1.0) / limit_ + static_cast (low)); - } - - template constexpr float get (float low, float high) { - return static_cast (next () * (static_cast (high) - static_cast (low)) / (limit_ - 1) + static_cast (low)); - } - -public: - constexpr bool chance (int32_t limit) { - return get (0, 100) < limit; + template [[nodiscard]] decltype (auto) chance (const int32_t limit) noexcept { + return operator () (Low, High) <= limit; } }; // expose global random generator -CR_EXPOSE_GLOBAL_SINGLETON (Xoshiro128, rg); +CR_EXPOSE_GLOBAL_SINGLETON (RWrand, rg); CR_NAMESPACE_END diff --git a/crlib/string.h b/crlib/string.h index f2a57b5..9dc91d6 100644 --- a/crlib/string.h +++ b/crlib/string.h @@ -137,12 +137,13 @@ class StringRef { } public: - int32_t int_ () const { - return atoi (chars ()); - } - - float float_ () const { - return static_cast (atof (chars ())); + template constexpr U as () const { + if constexpr (cr::is_same ::value) { + return static_cast (atof (chars ())); + } + else if constexpr (cr::is_same ::value) { + return atoi (chars ()); + } } bool startsWith (StringRef prefix) const { @@ -692,12 +693,13 @@ class String final { } public: - int32_t int_ () const { - return str ().int_ (); - } - - float float_ () const { - return str ().float_ (); + template constexpr U as () const { + if constexpr (cr::is_same ::value) { + return str ().as (); + } + else if constexpr (cr::is_same ::value) { + return str ().as (); + } } // for range-based loops