1
0

mptRandom.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * mptRandom.h
  3. * -----------
  4. * Purpose: PRNG
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "mpt/base/bit.hpp"
  12. #include "mpt/mutex/mutex.hpp"
  13. #ifdef MODPLUG_TRACKER
  14. #include "mpt/random/crand.hpp"
  15. #endif // MODPLUG_TRACKER
  16. #include "mpt/random/default_engines.hpp"
  17. #include "mpt/random/device.hpp"
  18. #include "mpt/random/engine.hpp"
  19. #include "mpt/random/engine_lcg.hpp"
  20. #include "mpt/random/seed.hpp"
  21. #include <limits>
  22. #include <random>
  23. OPENMPT_NAMESPACE_BEGIN
  24. // NOTE:
  25. // We implement our own PRNG and distribution functions as the implementations
  26. // of std::uniform_int_distribution is either wrong (not uniform in MSVC2010) or
  27. // not guaranteed to be livelock-free for bad PRNGs (in GCC, Clang, boost).
  28. // We resort to a simpler implementation with only power-of-2 result ranges for
  29. // both the underlying PRNG and our interface function. This saves us from
  30. // complicated code having to deal with partial bits of entropy.
  31. // Our interface still somewhat follows the mindset of C++11 <random> (with the
  32. // addition of a simple wrapper function mpt::random which saves the caller from
  33. // instantiating distribution objects for the common uniform distribution case.
  34. // We are still using std::random_device for initial seeding when avalable and
  35. // after working around its set of problems.
  36. namespace mpt
  37. {
  38. template <typename Trng>
  39. class thread_safe_prng
  40. : private Trng
  41. {
  42. private:
  43. mpt::mutex m;
  44. public:
  45. typedef typename Trng::result_type result_type;
  46. public:
  47. template <typename Trd>
  48. explicit thread_safe_prng(Trd & rd)
  49. : Trng(mpt::make_prng<Trng>(rd))
  50. {
  51. return;
  52. }
  53. thread_safe_prng(Trng rng)
  54. : Trng(rng)
  55. {
  56. return;
  57. }
  58. public:
  59. static MPT_CONSTEXPRINLINE typename engine_traits<Trng>::result_type min()
  60. {
  61. return Trng::min();
  62. }
  63. static MPT_CONSTEXPRINLINE typename engine_traits<Trng>::result_type max()
  64. {
  65. return Trng::max();
  66. }
  67. static MPT_CONSTEXPRINLINE int result_bits()
  68. {
  69. return engine_traits<Trng>::result_bits();
  70. }
  71. public:
  72. typename engine_traits<Trng>::result_type operator()()
  73. {
  74. mpt::lock_guard<mpt::mutex> l(m);
  75. return Trng::operator()();
  76. }
  77. };
  78. #ifdef MPT_BUILD_FUZZER
  79. // Use deterministic seeding
  80. using random_device = deterministc_random_device;
  81. #else // !MPT_BUILD_FUZZER
  82. // mpt::random_device always generates 32 bits of entropy
  83. using random_device = mpt::sane_random_device;
  84. #endif // MPT_BUILD_FUZZER
  85. #ifdef MPT_BUILD_FUZZER
  86. // Use fast PRNGs in order to not waste time fuzzing more complex PRNG
  87. // implementations.
  88. using fast_prng = deterministic_fast_engine;
  89. using good_prng = deterministic_good_engine;
  90. #else // !MPT_BUILD_FUZZER
  91. // We cannot use std::minstd_rand here because it has not a power-of-2 sized
  92. // output domain which we rely upon.
  93. using fast_prng = fast_engine; // about 3 ALU operations, ~32bit of state, suited for inner loops
  94. using good_prng = good_engine;
  95. #endif // MPT_BUILD_FUZZER
  96. using default_prng = mpt::good_prng;
  97. mpt::random_device & global_random_device();
  98. mpt::thread_safe_prng<mpt::default_prng> & global_prng();
  99. #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
  100. void set_global_random_device(mpt::random_device *rd);
  101. void set_global_prng(mpt::thread_safe_prng<mpt::default_prng> *rng);
  102. #endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
  103. } // namespace mpt
  104. OPENMPT_NAMESPACE_END