qtbase/src/corelib/global/qrandom.cpp

1068 lines
35 KiB
C++

/****************************************************************************
**
** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
// for rand_s
#define _CRT_RAND_S
#include "qrandom.h"
#include "qrandom_p.h"
#include <qobjectdefs.h>
#include <qthreadstorage.h>
#include <private/qsimd_p.h>
#include <errno.h>
#if QT_CONFIG(getentropy)
# include <sys/random.h>
#else
# if QT_CONFIG(cxx11_random)
# include <random>
# include "qdeadlinetimer.h"
# include "qhashfunctions.h"
# endif
# if QT_CONFIG(getauxval)
# include <sys/auxv.h>
# endif
#endif // !QT_CONFIG(getentropy)
#ifdef Q_OS_UNIX
# include <fcntl.h>
# include <private/qcore_unix_p.h>
#else
# include <qt_windows.h>
// RtlGenRandom is not exported by its name in advapi32.dll, but as SystemFunction036
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx
// Implementation inspired on https://hg.mozilla.org/mozilla-central/file/722fdbff1efc/security/nss/lib/freebl/win_rand.c#l146
// Argument why this is safe to use: https://bugzilla.mozilla.org/show_bug.cgi?id=504270
extern "C" {
DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength);
}
#endif
#if defined(Q_OS_ANDROID)
# include <private/qjni_p.h>
#endif
// This file is too low-level for regular Q_ASSERT (the logging framework may
// recurse back), so use regular assert()
#undef NDEBUG
#undef Q_ASSERT_X
#undef Q_ASSERT
#define Q_ASSERT(cond) assert(cond)
#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
# define NDEBUG 1
#endif
#include <assert.h>
QT_BEGIN_NAMESPACE
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
static qssize_t qt_random_cpu(void *buffer, qssize_t count);
# ifdef Q_PROCESSOR_X86_64
# define _rdrandXX_step _rdrand64_step
# else
# define _rdrandXX_step _rdrand32_step
# endif
static QT_FUNCTION_TARGET(RDRND) qssize_t qt_random_cpu(void *buffer, qssize_t count)
{
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
unsigned *end = ptr + count;
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)) == 0)
goto out;
ptr += sizeof(qregisteruint)/sizeof(*ptr);
}
if (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
if (_rdrand32_step(ptr))
goto out;
++ptr;
}
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
#endif
namespace {
#if QT_CONFIG(getentropy)
class SystemRandom
{
public:
enum { EfficientBufferFill = true };
static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
{
// getentropy can read at most 256 bytes, so break the reading
qssize_t read = 0;
while (count - read > 256) {
// getentropy can't fail under normal circumstances
int ret = getentropy(reinterpret_cast<uchar *>(buffer) + read, 256);
Q_ASSERT(ret == 0);
read += 256;
}
int ret = getentropy(reinterpret_cast<uchar *>(buffer) + read, count - read);
Q_ASSERT(ret == 0);
return count;
}
};
#elif defined(Q_OS_UNIX)
class SystemRandom
{
static QBasicAtomicInt s_fdp1; // "file descriptor plus 1"
static int openDevice();
SystemRandom() {}
~SystemRandom();
public:
enum { EfficientBufferFill = true };
static qssize_t fillBuffer(void *buffer, qssize_t count);
};
QBasicAtomicInt SystemRandom::s_fdp1 = Q_BASIC_ATOMIC_INITIALIZER(0);
SystemRandom::~SystemRandom()
{
int fd = s_fdp1.loadAcquire() - 1;
if (fd >= 0)
qt_safe_close(fd);
}
int SystemRandom::openDevice()
{
int fd = s_fdp1.loadAcquire() - 1;
if (fd != -1)
return fd;
fd = qt_safe_open("/dev/urandom", O_RDONLY);
if (fd == -1)
fd = qt_safe_open("/dev/random", O_RDONLY | O_NONBLOCK);
if (fd == -1) {
// failed on both, set to -2 so we won't try again
fd = -2;
}
int opened_fdp1;
if (s_fdp1.testAndSetOrdered(0, fd + 1, opened_fdp1)) {
if (fd >= 0) {
static const SystemRandom closer;
Q_UNUSED(closer);
}
return fd;
}
// failed, another thread has opened the file descriptor
if (fd >= 0)
qt_safe_close(fd);
return opened_fdp1 - 1;
}
qssize_t SystemRandom::fillBuffer(void *buffer, qssize_t count)
{
int fd = openDevice();
if (Q_UNLIKELY(fd < 0))
return 0;
qint64 n = qt_safe_read(fd, buffer, count);
return qMax<qssize_t>(n, 0); // ignore any errors
}
#endif // Q_OS_UNIX
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
class SystemRandom
{
public:
enum { EfficientBufferFill = true };
static qssize_t fillBuffer(void *buffer, qssize_t count)
{
auto RtlGenRandom = SystemFunction036;
return RtlGenRandom(buffer, ULONG(count)) ? count: 0;
}
};
#elif defined(Q_OS_WINRT)
class SystemRandom
{
public:
enum { EfficientBufferFill = false };
static qssize_t fillBuffer(void *, qssize_t)
{
// always use the fallback
return 0;
}
};
#endif // Q_OS_WINRT
} // unnamed namespace
#if defined(Q_OS_WIN)
static void fallback_update_seed(unsigned) {}
static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
{
// on Windows, rand_s is a high-quality random number generator
// and it requires no seeding
std::generate(ptr, ptr + left, []() {
unsigned value;
rand_s(&value);
return value;
});
}
#elif QT_CONFIG(getentropy)
static void fallback_update_seed(unsigned) {}
static void fallback_fill(quint32 *, qssize_t) Q_DECL_NOTHROW
{
// no fallback necessary, getentropy cannot fail under normal circumstances
}
#elif defined(Q_OS_BSD4)
static void fallback_update_seed(unsigned) {}
static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
{
// BSDs have arc4random(4) and these work even in chroot(2)
arc4random_buf(ptr, left * sizeof(*ptr));
}
#elif QT_CONFIG(cxx11_random)
static QBasicAtomicInteger<unsigned> seed = Q_BASIC_ATOMIC_INITIALIZER(0U);
static void fallback_update_seed(unsigned value)
{
// Update the seed to be used for the fallback mechansim, if we need to.
// We can't use QtPrivate::QHashCombine here because that is not an atomic
// operation. A simple XOR will have to do then.
seed.fetchAndXorRelaxed(value);
}
Q_NEVER_INLINE
#ifdef Q_CC_GNU
__attribute__((cold)) // this function is pretty big, so optimize for size
#endif
static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
{
quint32 scratch[12]; // see element count below
quint32 *end = scratch;
auto foldPointer = [](quintptr v) {
if (sizeof(quintptr) == sizeof(quint32)) {
// For 32-bit systems, we simply return the pointer.
return quint32(v);
} else {
// For 64-bit systems, we try to return the variable part of the
// pointer. On current x86-64 and AArch64, the top 17 bits are
// architecturally required to be the same, but in reality the top
// 24 bits on Linux are likely to be the same for all processes.
return quint32(v >> (32 - 24));
}
};
Q_ASSERT(left);
*end++ = foldPointer(quintptr(&seed)); // 1: variable in this library/executable's .data
*end++ = foldPointer(quintptr(&scratch)); // 2: variable in the stack
*end++ = foldPointer(quintptr(&errno)); // 3: veriable either in libc or thread-specific
*end++ = foldPointer(quintptr(reinterpret_cast<void*>(strerror))); // 4: function in libc (and unlikely to be a macro)
#ifndef QT_BOOTSTRAPPED
quint64 nsecs = QDeadlineTimer::current(Qt::PreciseTimer).deadline();
*end++ = quint32(nsecs); // 5
#endif
if (quint32 v = seed.load())
*end++ = v; // 6
#if QT_CONFIG(getauxval)
// works on Linux -- all modern libc have getauxval
# ifdef AT_RANDOM
// ELF's auxv AT_RANDOM has 16 random bytes
// (other ELF-based systems don't seem to have AT_RANDOM)
ulong auxvSeed = getauxval(AT_RANDOM);
if (auxvSeed) {
memcpy(scratch, reinterpret_cast<void *>(auxvSeed), 16);
end += 4; // 7 to 10
}
# endif
// Both AT_BASE and AT_SYSINFO_EHDR have some randomness in them due to the
// system's ASLR, even if many bits are the same. They also have randomness
// between them.
# ifdef AT_BASE
// present at least on the BSDs too, indicates the address of the loader
ulong base = getauxval(AT_BASE);
if (base)
*end++ = foldPointer(base); // 11
# endif
# ifdef AT_SYSINFO_EHDR
// seems to be Linux-only, indicates the global page of the sysinfo
ulong sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
if (sysinfo_ehdr)
*end++ = foldPointer(sysinfo_ehdr); // 12
# endif
#endif
Q_ASSERT(end <= std::end(scratch));
// this is highly inefficient, we should save the generator across calls...
std::seed_seq sseq(scratch, end);
std::mt19937 generator(sseq);
std::generate(ptr, ptr + left, generator);
fallback_update_seed(*ptr);
}
#else
static void fallback_update_seed(unsigned) {}
static Q_NORETURN void fallback_fill(quint32 *, qssize_t)
{
qFatal("Random number generator failed and no high-quality backup available");
}
#endif
static qssize_t fill_cpu(quint32 *buffer, qssize_t count)
{
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
if (qCpuHasFeature(RDRND) && (uint(qt_randomdevice_control) & SkipHWRNG) == 0)
return qt_random_cpu(buffer, count);
#else
Q_UNUSED(buffer);
Q_UNUSED(count);
#endif
return 0;
}
static void fill_internal(quint32 *buffer, qssize_t count)
{
if (Q_UNLIKELY(uint(qt_randomdevice_control) & SetRandomData)) {
uint value = uint(qt_randomdevice_control) & RandomDataMask;
std::fill_n(buffer, count, value);
return;
}
qssize_t filled = fill_cpu(buffer, count);
if (filled != count && (uint(qt_randomdevice_control) & SkipSystemRNG) == 0) {
qssize_t bytesFilled =
SystemRandom::fillBuffer(buffer + filled, (count - filled) * qssize_t(sizeof(*buffer)));
filled += bytesFilled / qssize_t(sizeof(*buffer));
}
if (filled)
fallback_update_seed(*buffer);
if (Q_UNLIKELY(filled != count)) {
// failed to fill the entire buffer, try the faillback mechanism
fallback_fill(buffer + filled, count - filled);
}
}
static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
{
struct ThreadState {
enum {
DesiredBufferByteSize = 32,
BufferCount = DesiredBufferByteSize / sizeof(quint32)
};
quint32 buffer[BufferCount];
int idx = BufferCount;
};
// Verify that the pointers are properly aligned for 32-bit
Q_ASSERT(quintptr(buffer) % sizeof(quint32) == 0);
Q_ASSERT(quintptr(bufferEnd) % sizeof(quint32) == 0);
quint32 *ptr = reinterpret_cast<quint32 *>(buffer);
quint32 * const end = reinterpret_cast<quint32 *>(bufferEnd);
#if defined(Q_COMPILER_THREAD_LOCAL) && !defined(QT_BOOTSTRAPPED)
if (SystemRandom::EfficientBufferFill && (end - ptr) < ThreadState::BufferCount
&& uint(qt_randomdevice_control) == 0) {
thread_local ThreadState state;
qssize_t itemsAvailable = ThreadState::BufferCount - state.idx;
// copy as much as we already have
qssize_t itemsToCopy = qMin(qssize_t(end - ptr), itemsAvailable);
memcpy(ptr, state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
ptr += itemsToCopy;
if (ptr != end) {
// refill the buffer and try again
fill_internal(state.buffer, ThreadState::BufferCount);
state.idx = 0;
itemsToCopy = end - ptr;
memcpy(ptr, state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
ptr = end;
}
// erase what we copied and advance
# ifdef Q_OS_WIN
// Microsoft recommends this
SecureZeroMemory(state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
# else
// We're quite confident the compiler will not optimize this out because
// we're writing to a thread-local buffer
memset(state.buffer + state.idx, 0, size_t(itemsToCopy) * sizeof(*ptr));
# endif
state.idx += itemsToCopy;
}
#endif // Q_COMPILER_THREAD_LOCAL && !QT_BOOTSTRAPPED
if (ptr != end) {
// fill directly in the user buffer
fill_internal(ptr, end - ptr);
}
}
/*!
\class QRandomGenerator
\inmodule QtCore
\since 5.10
\brief The QRandomGenerator class allows one to obtain random values from a
high-quality, seed-less Random Number Generator.
QRandomGenerator may be used to generate random values from a high-quality
random number generator. Unlike qrand(), QRandomGenerator does not need to be
seeded. That also means it is not possible to force it to produce a
reliable sequence, which may be needed for debugging.
The class can generate 32-bit or 64-bit quantities, or fill an array of
those. The most common way of generating new values is to call the generate(),
get64() or fillRange() functions. One would use it as:
\code
quint32 value = QRandomGenerator::generate();
\endcode
Additionally, it provides a floating-point function generateDouble() that returns
a number in the range [0, 1) (that is, inclusive of zero and exclusive of
1). There's also a set of convenience functions that facilitate obtaining a
random number in a bounded, integral range.
\warning This class is not suitable for bulk data creation. See below for the
technical reasons.
\section1 Frequency and entropy exhaustion
QRandomGenerator does not need to be seeded and instead uses operating system
or hardware facilities to generate random numbers. On some systems and with
certain hardware, those facilities are true Random Number Generators.
However, if they are true RNGs, those facilities have finite entropy source
and thus may fail to produce any results if the entropy pool is exhausted.
If that happens, first the operating system then QRandomGenerator will fall
back to Pseudo Random Number Generators of decreasing qualities (Qt's
fallback generator being the simplest). Therefore, QRandomGenerator should
not be used for high-frequency random number generation, lest the entropy
pool become empty. As a rule of thumb, this class should not be called upon
to generate more than a kilobyte per second of random data (note: this may
vary from system to system).
If an application needs true RNG data in bulk, it should use the operating
system facilities (such as \c{/dev/random} on Unix systems) directly and
wait for entropy to become available. If true RNG is not required,
applications should instead use a PRNG engines and can use QRandomGenerator to
seed those.
\section1 Standard C++ Library compatibility
QRandomGenerator is modeled after
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
and may be used in almost all contexts that the Standard Library can.
QRandomGenerator attempts to use either the same engine that backs
\c{std::random_device} or a better one. Note that \c{std::random_device} is
also allowed to fail if the source entropy pool becomes exhausted, in which
case it will throw an exception. QRandomGenerator never throws, but may abort
program execution instead.
Like the Standard Library class, QRandomGenerator can be used to seed Standard
Library deterministic random engines from \c{<random>}, such as the
Mersenne Twister. Unlike \c{std::random_device}, QRandomGenerator also
implements the API of
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/seed_seq}{std::seed_seq}},
allowing it to seed the deterministic engines directly.
The following code can be used to create and seed the
implementation-defined default deterministic PRNG, then use it to fill a
block range:
\code
QRandomGenerator rd;
std::default_random_engine rng(rd);
std::generate(block.begin(), block.end(), rng);
// equivalent to:
for (auto &v : block)
v = rng();
\endcode
QRandomGenerator is also compatible with the uniform distribution classes
\c{std::uniform_int_distribution} and \c{std:uniform_real_distribution}, as
well as the free function \c{std::generate_canonical}. For example, the
following code may be used to generate a floating-point number in the range
[1, 2.5):
\code
QRandomGenerator64 rd;
std::uniform_real_distribution dist(1, 2.5);
return dist(rd);
\endcode
Note the use of the QRandomGenerator64 class instead of QRandomGenerator to
obtain 64 bits of random data in a single call, though it is not required
to make the algorithm work (the Standard Library functions will make as
many calls as required to obtain enough bits of random data for the desired
range).
\sa QRandomGenerator64, qrand()
*/
/*!
\fn QRandomGenerator::QRandomGenerator()
\internal
Defaulted constructor, does nothing.
*/
/*!
\typedef QRandomGenerator::result_type
A typedef to the type that operator()() returns. That is, quint32.
\sa operator()()
*/
/*!
\fn result_type QRandomGenerator::operator()()
Generates a 32-bit random quantity and returns it.
\sa QRandomGenerator::generate(), QRandomGenerator::generate64()
*/
/*!
\fn double QRandomGenerator::entropy() const
Returns the estimate of the entropy in the random generator source.
This function exists to comply with the Standard Library requirements for
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
but it does not and cannot ever work. It is not possible to obtain a
reliable entropy value in a shared entropy pool in a multi-tasking system,
as other processes or threads may use that entropy. Any value non-zero
value that this function could return would be obsolete by the time the
user code reached it.
Since QRandomGenerator attempts to use a hardware Random Number Generator,
this function always returns 0.0.
*/
/*!
\fn result_type QRandomGenerator::min()
Returns the minimum value that QRandomGenerator may ever generate. That is, 0.
\sa max(), QRandomGenerator64::max()
*/
/*!
\fn result_type QRandomGenerator::max()
Returns the maximum value that QRandomGenerator may ever generate. That is,
\c {std::numeric_limits<result_type>::max()}.
\sa min(), QRandomGenerator64::max()
*/
/*!
\fn void QRandomGenerator::generate(ForwardIterator begin, ForwardIterator end)
Generates 32-bit quantities and stores them in the range between \a begin
and \a end. This function is equivalent to (and is implemented as):
\code
std::generate(begin, end, []() { return generate(); });
\endcode
This function complies with the requirements for the function
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/seed_seq/generate}{std::seed_seq::generate}},
which requires unsigned 32-bit integer values.
Note that if the [begin, end) range refers to an area that can store more
than 32 bits per element, the elements will still be initialized with only
32 bits of data. Any other bits will be zero. To fill the range with 64 bit
quantities, one can write:
\code
std::generate(begin, end, []() { return get64(); });
\endcode
If the range refers to contiguous memory (such as an array or the data from
a QVector), the fillRange() function may be used too.
\sa fillRange()
*/
/*!
\fn void QRandomGenerator::generate(quint32 *begin, quint32 *end)
\overload
\internal
Same as the other overload, but more efficiently fills \a begin to \a end.
*/
/*!
\fn void QRandomGenerator::fillRange(UInt *buffer, qssize_t count)
Generates \a count 32- or 64-bit quantities (depending on the type \c UInt)
and stores them in the buffer pointed by \a buffer. This is the most
efficient way to obtain more than one quantity at a time, as it reduces the
number of calls into the Random Number Generator source.
For example, to fill a vector of 16 entries with random values, one may
write:
\code
QVector<quint32> vector;
vector.resize(16);
QRandomGenerator::fillRange(vector.data(), vector.size());
\endcode
\sa generate()
*/
/*!
\fn void QRandomGenerator::fillRange(UInt (&buffer)[N})
Generates \c N 32- or 64-bit quantities (depending on the type \c UInt) and
stores them in the \a buffer array. This is the most efficient way to
obtain more than one quantity at a time, as it reduces the number of calls
into the Random Number Generator source.
For example, to fill generate two 32-bit quantities, one may write:
\code
quint32 array[2];
QRandomGenerator::fillRange(array);
\endcode
It would have also been possible to make one call to get64() and then split
the two halves of the 64-bit value.
\sa generate()
*/
/*!
\fn qreal QRandomGenerator::generateReal()
Generates one random qreal in the canonical range [0, 1) (that is,
inclusive of zero and exclusive of 1).
This function is equivalent to:
\code
QRandomGenerator64 rd;
return std::generate_canonical<qreal, std::numeric_limits<qreal>::digits>(rd);
\endcode
The same may also be obtained by using
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution}{std::uniform_real_distribution}}
with parameters 0 and 1.
\sa generate(), get64(), bounded()
*/
/*!
\fn qreal QRandomGenerator::bounded(qreal sup)
Generates one random qreal in the range between 0 (inclusive) and \a
sup (exclusive). This function is equivalent to and is implemented as:
\code
return generateDouble() * sup;
\endcode
\sa generateDouble(), bounded()
*/
/*!
\fn quint32 QRandomGenerator::bounded(quint32 sup)
\overload
Generates one random 32-bit quantity in the range between 0 (inclusive) and
\a sup (exclusive). The same result may also be obtained by using
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{std::uniform_int_distribution}}
with parameters 0 and \c{sup - 1}. That class can also be used to obtain
quantities larger than 32 bits.
For example, to obtain a value between 0 and 255 (inclusive), one would write:
\code
quint32 v = QRandomGenerator::bounded(256);
\endcode
Naturally, the same could also be obtained by masking the result of generate()
to only the lower 8 bits. Either solution is as efficient.
Note that this function cannot be used to obtain values in the full 32-bit
range of quint32. Instead, use generate().
\sa generate(), get64(), generateDouble()
*/
/*!
\fn quint32 QRandomGenerator::bounded(int sup)
\overload
Generates one random 32-bit quantity in the range between 0 (inclusive) and
\a sup (exclusive). \a sup must not be negative.
Note that this function cannot be used to obtain values in the full 32-bit
range of int. Instead, use generate() and cast to int.
\sa generate(), get64(), generateDouble()
*/
/*!
\fn quint32 QRandomGenerator::bounded(quint32 min, quint32 sup)
\overload
Generates one random 32-bit quantity in the range between \a min (inclusive)
and \a sup (exclusive). The same result may also be obtained by using
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{std::uniform_int_distribution}}
with parameters \a min and \c{\a sup - 1}. That class can also be used to
obtain quantities larger than 32 bits.
For example, to obtain a value between 1000 (incl.) and 2000 (excl.), one
would write:
\code
quint32 v = QRandomGenerator::bounded(1000, 2000);
\endcode
Note that this function cannot be used to obtain values in the full 32-bit
range of quint32. Instead, use generate().
\sa generate(), get64(), generateDouble()
*/
/*!
\fn quint32 QRandomGenerator::bounded(int min, int sup)
\overload
Generates one random 32-bit quantity in the range between \a min
(inclusive) and \a sup (exclusive), both of which may be negative.
Note that this function cannot be used to obtain values in the full 32-bit
range of int. Instead, use generate() and cast to int.
\sa generate(), get64(), generateDouble()
*/
/*!
\class QRandomGenerator64
\inmodule QtCore
\since 5.10
\brief The QRandomGenerator64 class allows one to obtain 64-bit random values
from a high-quality, seed-less Random Number Generator.
QRandomGenerator64 is a simple adaptor class around QRandomGenerator, making the
QRandomGenerator::generate64() function the default for operator()(), instead of the
function that returns 32-bit quantities. This class is intended to be used
in conjunction with Standard Library algorithms that need 64-bit quantities
instead of 32-bit ones.
In all other aspects, the class is the same. Please refer to
QRandomGenerator's documentation for more information.
\sa QRandomGenerator
*/
/*!
\fn QRandomGenerator64::QRandomGenerator64()
\internal
Defaulted constructor, does nothing.
*/
/*!
\typedef QRandomGenerator64::result_type
A typedef to the type that operator()() returns. That is, quint64.
\sa operator()()
*/
/*!
\fn quint64 QRandomGenerator64::generate()
Generates one 64-bit random value and returns it.
Note about casting to a signed integer: all bits returned by this function
are random, so there's a 50% chance that the most significant bit will be
set. If you wish to cast the returned value to qint64 and keep it positive,
you should mask the sign bit off:
\code
qint64 value = QRandomGenerator64::generate() & std::numeric_limits<qint64>::max();
\endcode
\sa QRandomGenerator, QRandomGenerator::generate64()
*/
/*!
\fn result_type QRandomGenerator64::operator()()
Generates a 64-bit random quantity and returns it.
\sa QRandomGenerator::generate(), QRandomGenerator::generate64()
*/
/*!
\fn double QRandomGenerator64::entropy() const
Returns the estimate of the entropy in the random generator source.
This function exists to comply with the Standard Library requirements for
\c{\l{http://en.cppreference.com/w/cpp/numeric/random/random_device}{std::random_device}}
but it does not and cannot ever work. It is not possible to obtain a
reliable entropy value in a shared entropy pool in a multi-tasking system,
as other processes or threads may use that entropy. Any value non-zero
value that this function could return would be obsolete by the time the
user code reached it.
Since QRandomGenerator64 attempts to use a hardware Random Number Generator,
this function always returns 0.0.
*/
/*!
\fn result_type QRandomGenerator64::min()
Returns the minimum value that QRandomGenerator64 may ever generate. That is, 0.
\sa max(), QRandomGenerator::max()
*/
/*!
\fn result_type QRandomGenerator64::max()
Returns the maximum value that QRandomGenerator64 may ever generate. That is,
\c {std::numeric_limits<result_type>::max()}.
\sa min(), QRandomGenerator::max()
*/
/*!
Generates one 32-bit random value and returns it.
Note about casting to a signed integer: all bits returned by this function
are random, so there's a 50% chance that the most significant bit will be
set. If you wish to cast the returned value to int and keep it positive,
you should mask the sign bit off:
\code
int value = QRandomGenerator::generate() & std::numeric_limits<int>::max();
\endcode
\sa get64(), generateDouble()
*/
quint32 QRandomGenerator::generate()
{
quint32 ret;
fill(&ret, &ret + 1);
return ret;
}
/*!
Generates one 64-bit random value and returns it.
Note about casting to a signed integer: all bits returned by this function
are random, so there's a 50% chance that the most significant bit will be
set. If you wish to cast the returned value to qint64 and keep it positive,
you should mask the sign bit off:
\code
qint64 value = QRandomGenerator::generate64() & std::numeric_limits<qint64>::max();
\endcode
\sa generate(), generateDouble(), QRandomGenerator64
*/
quint64 QRandomGenerator::generate64()
{
quint64 ret;
fill(&ret, &ret + 1);
return ret;
}
/*!
\internal
Fills the range pointed by \a buffer and \a bufferEnd with 32-bit random
values. The buffer must be correctly aligned.
*/
void QRandomGenerator::fillRange_helper(void *buffer, void *bufferEnd)
{
fill(buffer, bufferEnd);
}
#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21)
typedef QThreadStorage<QJNIObjectPrivate> AndroidRandomStorage;
Q_GLOBAL_STATIC(AndroidRandomStorage, randomTLS)
#elif defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
using SeedStorageType = QtPrivate::FunctionPointer<decltype(&srand)>::Arguments::Car;
typedef QThreadStorage<SeedStorageType *> SeedStorage;
Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value
#endif
/*!
\relates <QtGlobal>
\since 4.2
Thread-safe version of the standard C++ \c srand() function.
Sets the argument \a seed to be used to generate a new random number sequence of
pseudo random integers to be returned by qrand().
The sequence of random numbers generated is deterministic per thread. For example,
if two threads call qsrand(1) and subsequently call qrand(), the threads will get
the same random number sequence.
\sa qrand(), QRandomGenerator
*/
void qsrand(uint seed)
{
#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21)
if (randomTLS->hasLocalData()) {
randomTLS->localData().callMethod<void>("setSeed", "(J)V", jlong(seed));
return;
}
QJNIObjectPrivate random("java/util/Random",
"(J)V",
jlong(seed));
if (!random.isValid()) {
srand(seed);
return;
}
randomTLS->setLocalData(random);
#elif defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
SeedStorage *seedStorage = randTLS();
if (seedStorage) {
SeedStorageType *pseed = seedStorage->localData();
if (!pseed)
seedStorage->setLocalData(pseed = new SeedStorageType);
*pseed = seed;
} else {
//global static seed storage should always exist,
//except after being deleted by QGlobalStaticDeleter.
//But since it still can be called from destructor of another
//global static object, fallback to srand(seed)
srand(seed);
}
#else
// On Windows srand() and rand() already use Thread-Local-Storage
// to store the seed between calls
// this is also valid for QT_NO_THREAD
srand(seed);
#endif
}
/*!
\relates <QtGlobal>
\since 4.2
Thread-safe version of the standard C++ \c rand() function.
Returns a value between 0 and \c RAND_MAX (defined in \c <cstdlib> and
\c <stdlib.h>), the next number in the current sequence of pseudo-random
integers.
Use \c qsrand() to initialize the pseudo-random number generator with a
seed value. Seeding must be performed at least once on each thread. If that
step is skipped, then the sequence will be pre-seeded with a constant
value.
\sa qsrand(), QRandomGenerator
*/
int qrand()
{
#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21)
AndroidRandomStorage *randomStorage = randomTLS();
if (!randomStorage)
return rand();
if (randomStorage->hasLocalData()) {
return randomStorage->localData().callMethod<jint>("nextInt",
"(I)I",
RAND_MAX);
}
QJNIObjectPrivate random("java/util/Random",
"(J)V",
jlong(1));
if (!random.isValid())
return rand();
randomStorage->setLocalData(random);
return random.callMethod<jint>("nextInt", "(I)I", RAND_MAX);
#elif defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
SeedStorage *seedStorage = randTLS();
if (seedStorage) {
SeedStorageType *pseed = seedStorage->localData();
if (!pseed) {
seedStorage->setLocalData(pseed = new SeedStorageType);
*pseed = 1;
}
return rand_r(pseed);
} else {
//global static seed storage should always exist,
//except after being deleted by QGlobalStaticDeleter.
//But since it still can be called from destructor of another
//global static object, fallback to rand()
return rand();
}
#else
// On Windows srand() and rand() already use Thread-Local-Storage
// to store the seed between calls
// this is also valid for QT_NO_THREAD
return rand();
#endif
}
QT_END_NAMESPACE