diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2017-10-23 19:16:34 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2017-11-11 08:11:07 +0000 |
commit | 08bf28de03f16e5b014b23e228dfc3cfc2ac7feb (patch) | |
tree | 0919b98368e7f6ed8faf7bb2fa71b1d711d09a27 /src/corelib | |
parent | cfad4e298f4d65fe26c3a4109d19839bdfcd30c2 (diff) |
QRandomGenerator: add more of the std Random Engine API
This brings us to almost parity with the C++11 Random Engine API
requirements (see chapter 26.5.1.4 [rand.req.eng]). We don't implement
the templated Sseq requirements because it would require moving the
implementation details to the public API. And we don't implement the
<iostreams> code because we don't want to.
Change-Id: Icaa86fc7b54d4b368c0efffd14f05ff813ebd759
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/global/qrandom.cpp | 90 | ||||
-rw-r--r-- | src/corelib/global/qrandom.h | 24 |
2 files changed, 101 insertions, 13 deletions
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index 2241dc7095..a9596df432 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -558,7 +558,15 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, QRandomGenerator is modeled after the requirements for random number engines in the C++ Standard Library and may be used in almost all contexts - that the Standard Library engines can. + that the Standard Library engines can. Exceptions to the requirements are + the following: + + \list + \li QRandomGenerator does not support seeding from another seed + sequence-like class besides std::seed_seq itself; + \li QRandomGenerator is not comparable (but is copyable) or + streamable to \c{std::ostream} or from \c{std::istream}. + \endlist QRandomGenerator is also compatible with the uniform distribution classes \c{std::uniform_int_distribution} and \c{std:uniform_real_distribution}, as @@ -575,13 +583,13 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, */ /*! - \fn QRandomGenerator::QRandomGenerator(quint32 seed) + \fn QRandomGenerator::QRandomGenerator(quint32 seedValue) - Initializes this QRandomGenerator object with the value \a seed as - the seed. Two objects constructed with the same seed value will + Initializes this QRandomGenerator object with the value \a seedValue as + the seed. Two objects constructed or reseeded with the same seed value will produce the same number sequence. - \sa securelySeeded() + \sa seed(), securelySeeded() */ /*! @@ -592,7 +600,7 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, array \a seedBuffer as the seed. Two objects constructed or reseeded with the same seed value will produce the same number sequence. - \sa securelySeeded() + \sa seed(), securelySeeded() */ /*! @@ -609,7 +617,7 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, QRandomGenerator generator(sseq); \endcode - \sa securelySeeded() + \sa seed(), securelySeeded() */ /*! @@ -626,7 +634,7 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, QRandomGenerator generator(sseq); \endcode - \sa securelySeeded() + \sa seed(), securelySeeded() */ /*! @@ -637,7 +645,7 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, sseq as the seed. Two objects constructed or reseeded with the same seed value will produce the same number sequence. - \sa securelySeeded() + \sa seed(), securelySeeded() */ /*! @@ -659,6 +667,24 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, */ /*! + \fn bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2) + \relates QRandomGenerator + + Returns true if the two the two engines \a rng1 and \a rng2 are at the same + state or if they are both reading from the operating system facilities, + false otherwise. +*/ + +/*! + \fn bool operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2) + \relates QRandomGenerator + + Returns true if the two the two engines \a rng1 and \a rng2 are at + different states or if one of them is reading from the operating system + facilities and the other is not, false otherwise. +*/ + +/*! \typedef QRandomGenerator::result_type A typedef to the type that operator()() returns. That is, quint32. @@ -692,6 +718,31 @@ Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, */ /*! + \fn void QRandomGenerator::seed(quint32 seed) + + Reseeds this object using the value \a seed as the seed. + */ + +/*! + \fn void QRandomGenerator::seed(std::seed_seq &seed) + \overload + + Reseeds this object using the seed sequence \a sseq as the seed. + */ + +/*! + \fn void QRandomGenerator::discard(unsigned long long z) + + Discards the next \a z entries from the sequence. This method is equivalent + to calling generate() \a z times and discarding the result, as in: + + \code + while (z--) + generator.generate(); + \endcode +*/ + +/*! \fn void QRandomGenerator::generate(ForwardIterator begin, ForwardIterator end) Generates 32-bit quantities and stores them in the range between \a begin @@ -1086,6 +1137,27 @@ QRandomGenerator::QRandomGenerator(const quint32 *begin, const quint32 *end) new (&storage.engine()) RandomEngine(s); } +void QRandomGenerator::discard(unsigned long long z) +{ + if (Q_UNLIKELY(type == SystemRNG)) + return; + + PRNGLocker lock(this); + storage.engine().discard(z); +} + +bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2) +{ + if (rng1.type != rng2.type) + return false; + if (rng1.type == SystemRNG) + return true; + + // Lock global() if either is it (otherwise this locking is a no-op) + PRNGLocker locker(&rng1 == QRandomGenerator::global() ? &rng1 : &rng2); + return rng1.storage.engine() == rng2.storage.engine(); +} + /*! \internal diff --git a/src/corelib/global/qrandom.h b/src/corelib/global/qrandom.h index c25a0ad643..c31c9afddb 100644 --- a/src/corelib/global/qrandom.h +++ b/src/corelib/global/qrandom.h @@ -52,8 +52,8 @@ class QRandomGenerator template <typename UInt> using IfValidUInt = typename std::enable_if<std::is_unsigned<UInt>::value && sizeof(UInt) >= sizeof(uint), bool>::type; public: - QRandomGenerator(quint32 seed = 1) - : QRandomGenerator(&seed, 1) + QRandomGenerator(quint32 seedValue = 1) + : QRandomGenerator(&seedValue, 1) {} template <qssize_t N> QRandomGenerator(const quint32 (&seedBuffer)[N]) : QRandomGenerator(seedBuffer, seedBuffer + N) @@ -68,6 +68,12 @@ public: Q_CORE_EXPORT QRandomGenerator(const QRandomGenerator &other); Q_CORE_EXPORT QRandomGenerator &operator=(const QRandomGenerator &other); + friend Q_CORE_EXPORT bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2); + friend bool operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2) + { + return !(rng1 == rng2); + } + quint32 generate() { quint32 ret; @@ -151,6 +157,9 @@ public: // API like std:: random engines typedef quint32 result_type; result_type operator()() { return generate(); } + void seed(quint32 s = 1) { *this = { s }; } + void seed(std::seed_seq &sseq) Q_DECL_NOTHROW { *this = { sseq }; } + Q_CORE_EXPORT void discard(unsigned long long z); static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); } static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); } @@ -202,8 +211,8 @@ public: result_type operator()() { return generate64(); } #ifndef Q_QDOC - QRandomGenerator64(quint32 seed = 1) - : QRandomGenerator(seed) + QRandomGenerator64(quint32 seedValue = 1) + : QRandomGenerator(seedValue) {} template <qssize_t N> QRandomGenerator64(const quint32 (&seedBuffer)[N]) : QRandomGenerator(seedBuffer) @@ -219,6 +228,13 @@ public: {} QRandomGenerator64(const QRandomGenerator &other) : QRandomGenerator(other) {} + void discard(unsigned long long z) + { + Q_ASSERT_X(z * 2 > z, "QRandomGenerator64::discard", + "Overflow. Are you sure you want to skip over 9 quintillion samples?"); + QRandomGenerator::discard(z * 2); + } + static Q_DECL_CONSTEXPR result_type min() { return (std::numeric_limits<result_type>::min)(); } static Q_DECL_CONSTEXPR result_type max() { return (std::numeric_limits<result_type>::max)(); } static Q_CORE_EXPORT QRandomGenerator64 *system(); |