summaryrefslogtreecommitdiffstats
path: root/src/corelib/global
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@qt.io>2018-03-08 17:05:14 +0100
committerMorten Johan Sørvig <morten.sorvig@qt.io>2018-03-08 18:14:46 +0100
commit5a7c33dece358090bc8fd3b84567d8bcb0e3b630 (patch)
treef73931fd2416debfecced1676761aabe48d2f319 /src/corelib/global
parentc9908423d33828b15e5ea97bb1ee8deb08f15673 (diff)
parente5a6e9bb80fb2427228f70488b8839b4aa0b4261 (diff)
Merge remote-tracking branch 'gerrit/5.11' into HEAD
Diffstat (limited to 'src/corelib/global')
-rw-r--r--src/corelib/global/global.pri46
-rw-r--r--src/corelib/global/minimum-linux.S34
-rw-r--r--src/corelib/global/minimum-linux_p.h98
-rw-r--r--src/corelib/global/qcompilerdetection.h105
-rw-r--r--src/corelib/global/qconfig-bootstrapped.h8
-rw-r--r--src/corelib/global/qendian.h4
-rw-r--r--src/corelib/global/qendian.qdoc84
-rw-r--r--src/corelib/global/qflags.h50
-rw-r--r--src/corelib/global/qfloat16.cpp99
-rw-r--r--src/corelib/global/qfloat16.h23
-rw-r--r--src/corelib/global/qfloat16_f16c.c91
-rw-r--r--src/corelib/global/qfloat16_p.h4
-rw-r--r--src/corelib/global/qglobal.cpp379
-rw-r--r--src/corelib/global/qglobal.h97
-rw-r--r--src/corelib/global/qglobalstatic.qdoc12
-rw-r--r--src/corelib/global/qlibraryinfo.cpp10
-rw-r--r--src/corelib/global/qlogging.cpp419
-rw-r--r--src/corelib/global/qlogging.h11
-rw-r--r--src/corelib/global/qlogging_p.h64
-rw-r--r--src/corelib/global/qnamespace.h47
-rw-r--r--src/corelib/global/qnamespace.qdoc90
-rw-r--r--src/corelib/global/qnumeric_p.h280
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp4
-rw-r--r--src/corelib/global/qoperatingsystemversion_win.cpp3
-rw-r--r--src/corelib/global/qoperatingsystemversion_win_p.h63
-rw-r--r--src/corelib/global/qrandom.cpp1118
-rw-r--r--src/corelib/global/qrandom.h204
-rw-r--r--src/corelib/global/qrandom_p.h18
-rw-r--r--src/corelib/global/qsysinfo.h2
-rw-r--r--src/corelib/global/qsystemdetection.h35
-rw-r--r--src/corelib/global/qt_windows.h4
-rw-r--r--src/corelib/global/qtrace_p.h126
32 files changed, 2416 insertions, 1216 deletions
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index 78b37755a4..2b4fd6d661 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -39,10 +39,34 @@ SOURCES += \
global/qrandom.cpp \
global/qhooks.cpp
+# Only add global/qfloat16_f16c.c if qfloat16.cpp can't #include it.
+# Any compiler: if it is already generating F16C code, let qfloat16.cpp do it
+# Clang: ICE if not generating F16C code, so use qfloat16_f16c.c
+# ICC: miscompiles if not generating F16C code, so use qfloat16_f16c.c
+# GCC: if it can use F16C intrinsics, let qfloat16.cpp do it
+# MSVC: if it is already generating AVX code, let qfloat16.cpp do it
+# MSVC: otherwise, it generates poorly-performing code, so use qfloat16_f16c.c
+contains(QT_CPU_FEATURES.$$QT_ARCH, f16c): \
+ f16c_cxx = true
+else: clang|intel_icl|intel_icc: \
+ f16c_cxx = false
+else: gcc:f16c:x86SimdAlways: \
+ f16c_cxx = true
+else: msvc:contains(QT_CPU_FEATURES.$$QT_ARCH, avx): \
+ f16c_cxx = true
+else: \
+ f16c_cxx = false
+$$f16c_cxx: DEFINES += QFLOAT16_INCLUDE_FAST
+else: F16C_SOURCES += global/qfloat16_f16c.c
+unset(f16c_cxx)
+
VERSIONTAGGING_SOURCES = global/qversiontagging.cpp
darwin: SOURCES += global/qoperatingsystemversion_darwin.mm
-win32: SOURCES += global/qoperatingsystemversion_win.cpp
+win32 {
+ SOURCES += global/qoperatingsystemversion_win.cpp
+ HEADERS += global/qoperatingsystemversion_win_p.h
+}
# qlibraryinfo.cpp includes qconfig.cpp
INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global
@@ -73,6 +97,7 @@ linux:!static {
} else {
SOURCES += global/minimum-linux.S
}
+ HEADERS += global/minimum-linux_p.h
}
qtConfig(slog2): \
@@ -99,16 +124,13 @@ gcc:ltcg {
SOURCES += $$VERSIONTAGGING_SOURCES
}
-# On AARCH64 the fp16 extension is mandatory, so we don't need the conversion tables.
-!contains(QT_ARCH, "arm64") {
- QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h
+QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h
- qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables)
+qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables)
- qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT}
- qfloat16_tables.output = global/qfloat16tables.cpp
- qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES
- qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE
- qfloat16_tables.variable_out = SOURCES
- QMAKE_EXTRA_COMPILERS += qfloat16_tables
-}
+qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT}
+qfloat16_tables.output = global/qfloat16tables.cpp
+qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES
+qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE
+qfloat16_tables.variable_out = SOURCES
+QMAKE_EXTRA_COMPILERS += qfloat16_tables
diff --git a/src/corelib/global/minimum-linux.S b/src/corelib/global/minimum-linux.S
index c3261288c2..dfc3cec1be 100644
--- a/src/corelib/global/minimum-linux.S
+++ b/src/corelib/global/minimum-linux.S
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "private/qglobal_p.h"
+#include "minimum-linux_p.h"
/* Copied from #include <elf.h>:
*/
@@ -76,32 +76,6 @@
/* Operating systems: */
.long ELF_NOTE_OS_LINUX
-/* Minimum Linux kernel version:
- * We require the following features in Qt (unconditional, no fallback):
- * Feature Added in version Macro
- * - inotify_init1 before 2.6.12-rc12
- * - futex(2) before 2.6.12-rc12
- * - FUTEX_WAKE_OP 2.6.14 FUTEX_OP
- * - linkat(2) 2.6.17 O_TMPFILE
- * - FUTEX_PRIVATE_FLAG 2.6.22
- * - O_CLOEXEC 2.6.23
- * - eventfd 2.6.23
- * - pipe2 & dup3 2.6.27
- * - accept4 2.6.28
- * - renameat2 3.16 QT_CONFIG(renameat2)
- * - getrandom 3.17 QT_CONFIG(getentropy)
- */
-
-#if QT_CONFIG(getentropy)
- .long 3
- .long 17
- .long 0
-#elif QT_CONFIG(renameat2)
- .long 3
- .long 16
- .long 0
-#else
- .long 2
- .long 6
- .long 28
-#endif
+ .long MINLINUX_MAJOR
+ .long MINLINUX_MINOR
+ .long MINLINUX_PATCH
diff --git a/src/corelib/global/minimum-linux_p.h b/src/corelib/global/minimum-linux_p.h
new file mode 100644
index 0000000000..bad2488b4d
--- /dev/null
+++ b/src/corelib/global/minimum-linux_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef MINIMUMLINUX_P_H
+#define MINIMUMLINUX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// EXTRA WARNING
+// -------------
+//
+// This file must also be valid assembler source.
+//
+
+#include "private/qglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/* Minimum Linux kernel version:
+ * We require the following features in Qt (unconditional, no fallback):
+ * Feature Added in version Macro
+ * - inotify_init1 before 2.6.12-rc12
+ * - futex(2) before 2.6.12-rc12
+ * - FUTEX_WAKE_OP 2.6.14 FUTEX_OP
+ * - linkat(2) 2.6.17 O_TMPFILE && QT_CONFIG(linkat)
+ * - FUTEX_PRIVATE_FLAG 2.6.22
+ * - O_CLOEXEC 2.6.23
+ * - eventfd 2.6.23
+ * - pipe2 & dup3 2.6.27
+ * - accept4 2.6.28
+ * - renameat2 3.16 QT_CONFIG(renameat2)
+ * - getrandom 3.17 QT_CONFIG(getentropy)
+ */
+
+#if QT_CONFIG(getentropy)
+# define MINLINUX_MAJOR 3
+# define MINLINUX_MINOR 17
+# define MINLINUX_PATCH 0
+#elif QT_CONFIG(renameat2)
+# define MINLINUX_MAJOR 3
+# define MINLINUX_MINOR 16
+# define MINLINUX_PATCH 0
+#else
+# define MINLINUX_MAJOR 2
+# define MINLINUX_MINOR 6
+# define MINLINUX_PATCH 28
+#endif
+
+#define MINIMUM_LINUX_VERSION QT_VERSION_CHECK(MINLINUX_MAJOR, MINLINUX_MINOR, MINLINUX_PATCH)
+
+QT_END_NAMESPACE
+
+#endif // MINIMUMLINUX_P_H
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index ef0fdbf53b..2ca9595863 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -89,9 +89,6 @@
# define Q_CC_MSVC (_MSC_VER)
# define Q_CC_MSVC_NET
# define Q_OUTOFLINE_TEMPLATE inline
-# if _MSC_VER < 1600
-# define Q_NO_TEMPLATE_FRIENDS
-# endif
# define Q_COMPILER_MANGLES_RETURN_TYPE
# define Q_FUNC_INFO __FUNCSIG__
# define Q_ALIGNOF(type) __alignof(type)
@@ -105,12 +102,8 @@
# endif
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
-# if _MSC_VER >= 1800
-# define QT_MAKE_UNCHECKED_ARRAY_ITERATOR(x) stdext::make_unchecked_array_iterator(x)
-# endif
-# if _MSC_VER >= 1500
-# define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) stdext::make_checked_array_iterator(x, size_t(N))
-# endif
+# define QT_MAKE_UNCHECKED_ARRAY_ITERATOR(x) stdext::make_unchecked_array_iterator(x) // Since _MSC_VER >= 1800
+# define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) stdext::make_checked_array_iterator(x, size_t(N)) // Since _MSC_VER >= 1500
/* Intel C++ disguising as Visual C++: the `using' keyword avoids warnings */
# if defined(__INTEL_COMPILER)
# define Q_DECL_VARIABLE_DEPRECATED
@@ -246,6 +239,7 @@
# define Q_REQUIRED_RESULT __attribute__ ((__warn_unused_result__))
# define Q_DECL_PURE_FUNCTION __attribute__((pure))
# define Q_DECL_CONST_FUNCTION __attribute__((const))
+# define Q_DECL_COLD_FUNCTION __attribute__((cold))
# if !defined(QT_MOC_CPP)
# define Q_PACKED __attribute__ ((__packed__))
# ifndef __ARM_EABI__
@@ -566,7 +560,7 @@
*/
#ifdef __cplusplus
-# if __cplusplus < 201103L && !(defined(Q_CC_MSVC) && Q_CC_MSVC >= 1800)
+# if __cplusplus < 201103L && !defined(Q_CC_MSVC)
# error Qt requires a C++11 compiler and yours does not seem to be that.
# endif
#endif
@@ -638,21 +632,11 @@
# define Q_COMPILER_THREAD_LOCAL
# define Q_COMPILER_UDL
# endif
-# ifdef _MSC_VER
-# if _MSC_VER == 1700
-// <initializer_list> is missing with MSVC 2012 (it's present in 2010, 2013 and up)
-# undef Q_COMPILER_INITIALIZER_LISTS
-# endif
-# if _MSC_VER < 1900
-// ICC disables unicode string support when compatibility mode with MSVC 2013 or lower is active
-# undef Q_COMPILER_UNICODE_STRINGS
-// Even though ICC knows about ref-qualified members, MSVC 2013 or lower doesn't, so
-// certain member functions (like QString::toUpper) may be missing from the DLLs.
-# undef Q_COMPILER_REF_QUALIFIERS
-// Disable constexpr unless the MS headers have constexpr in all the right places too
-// (like std::numeric_limits<T>::max())
-# undef Q_COMPILER_CONSTEXPR
-# endif
+# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L s
+// C11 features supported. Only tested with ICC 17 and up.
+# define Q_COMPILER_STATIC_ASSERT
+# if __has_include(<threads.h>)
+# define Q_COMPILER_THREAD_LOCAL
# endif
# endif
#endif
@@ -806,6 +790,17 @@
# endif
# endif
+# if defined(__STDC_VERSION__)
+# if __has_feature(c_static_assert)
+# define Q_COMPILER_STATIC_ASSERT
+# endif
+# if __has_feature(c_thread_local) && __has_include(<threads.h>)
+# if !defined(__FreeBSD__) /* FreeBSD clang fails on __cxa_thread_atexit */
+# define Q_COMPILER_THREAD_LOCAL
+# endif
+# endif
+# endif
+
# if defined(__has_warning)
# if __has_warning("-Wunused-private-field")
# define Q_DECL_UNUSED_MEMBER Q_DECL_UNUSED
@@ -901,15 +896,25 @@
# define Q_COMPILER_RETURN_TYPE_DEDUCTION
# endif
# endif
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L
+# if Q_CC_GNU >= 407
+ /* C11 features supported in GCC 4.7: */
+# define Q_COMPILER_STATIC_ASSERT
+# endif
+# if Q_CC_GNU >= 409
+ /* C11 features supported in GCC 4.9: */
+# if __has_include(<threads.h>)
+# define Q_COMPILER_THREAD_LOCAL
+# endif
+# endif
+# endif
#endif
#if defined(Q_CC_MSVC)
# if defined(__cplusplus)
-# if _MSC_VER >= 1400
/* C++11 features supported in VC8 = VC2005: */
# define Q_COMPILER_VARIADIC_MACROS
-# ifndef __cplusplus_cli
/* 2005 supports the override and final contextual keywords, in
the same positions as the C++11 variants, but 'final' is
called 'sealed' instead:
@@ -918,12 +923,7 @@
"virtual" keyword to be present too, so don't define for that.
So don't define Q_COMPILER_EXPLICIT_OVERRIDES (since it's not
the same as the C++11 version), but define the Q_DECL_* flags
- accordingly: */
-# define Q_DECL_OVERRIDE override
-# define Q_DECL_FINAL sealed
-# endif
-# endif
-# if _MSC_VER >= 1600
+ accordingly. */
/* C++11 features supported in VC10 = VC2010: */
# define Q_COMPILER_AUTO_FUNCTION
# define Q_COMPILER_AUTO_TYPE
@@ -933,57 +933,31 @@
# define Q_COMPILER_NULLPTR
# define Q_COMPILER_RVALUE_REFS
# define Q_COMPILER_STATIC_ASSERT
-// MSVC's library has std::initializer_list, but the compiler does not support the braces initialization
-//# define Q_COMPILER_INITIALIZER_LISTS
-//# define Q_COMPILER_UNIFORM_INIT
-# endif
-# if _MSC_VER >= 1700
/* C++11 features supported in VC11 = VC2012: */
-# undef Q_DECL_OVERRIDE /* undo 2005/2008 settings... */
-# undef Q_DECL_FINAL /* undo 2005/2008 settings... */
# define Q_COMPILER_EXPLICIT_OVERRIDES /* ...and use std C++11 now */
# define Q_COMPILER_CLASS_ENUM
# define Q_COMPILER_ATOMICS
-# endif /* VC 11 */
-# if _MSC_VER >= 1800
/* C++11 features in VC12 = VC2013 */
-/* Implemented, but can't be used on move special members */
-/* # define Q_COMPILER_DEFAULT_MEMBERS */
# define Q_COMPILER_DELETE_MEMBERS
# define Q_COMPILER_DELEGATING_CONSTRUCTORS
# define Q_COMPILER_EXPLICIT_CONVERSIONS
# define Q_COMPILER_NONSTATIC_MEMBER_INIT
-// implemented, but nested initialization fails (eg tst_qvector): http://connect.microsoft.com/VisualStudio/feedback/details/800364/initializer-list-calls-object-destructor-twice
-// #define Q_COMPILER_INITIALIZER_LISTS
-// implemented in principle, but has a bug that makes it unusable: http://connect.microsoft.com/VisualStudio/feedback/details/802058/c-11-unified-initialization-fails-with-c-style-arrays
-// #define Q_COMPILER_UNIFORM_INIT
# define Q_COMPILER_RAW_STRINGS
# define Q_COMPILER_TEMPLATE_ALIAS
# define Q_COMPILER_VARIADIC_TEMPLATES
-# endif /* VC 12 */
-# if _MSC_FULL_VER >= 180030324 // VC 12 SP 2 RC
-# define Q_COMPILER_INITIALIZER_LISTS
-# endif /* VC 12 SP 2 RC */
-# if _MSC_VER >= 1900
+# define Q_COMPILER_INITIALIZER_LISTS // VC 12 SP 2 RC
/* C++11 features in VC14 = VC2015 */
# define Q_COMPILER_DEFAULT_MEMBERS
# define Q_COMPILER_ALIGNAS
# define Q_COMPILER_ALIGNOF
-// Partial support, insufficient for Qt
-//# define Q_COMPILER_CONSTEXPR
# define Q_COMPILER_INHERITING_CONSTRUCTORS
# define Q_COMPILER_NOEXCEPT
# define Q_COMPILER_RANGE_FOR
# define Q_COMPILER_REF_QUALIFIERS
# define Q_COMPILER_THREAD_LOCAL
-// Broken, see QTBUG-47224 and https://connect.microsoft.com/VisualStudio/feedback/details/1549785
-//# define Q_COMPILER_THREADSAFE_STATICS
# define Q_COMPILER_UDL
# define Q_COMPILER_UNICODE_STRINGS
-// Uniform initialization is not working yet -- build errors with QUuid
-//# define Q_COMPILER_UNIFORM_INIT
# define Q_COMPILER_UNRESTRICTED_UNIONS
-# endif
# if _MSC_FULL_VER >= 190023419
# define Q_COMPILER_ATTRIBUTES
// Almost working, see https://connect.microsoft.com/VisualStudio/feedback/details/2011648
@@ -1249,6 +1223,9 @@
#ifndef Q_DECL_CONST_FUNCTION
# define Q_DECL_CONST_FUNCTION Q_DECL_PURE_FUNCTION
#endif
+#ifndef Q_DECL_COLD_FUNCTION
+# define Q_DECL_COLD_FUNCTION
+#endif
#ifndef QT_MAKE_UNCHECKED_ARRAY_ITERATOR
# define QT_MAKE_UNCHECKED_ARRAY_ITERATOR(x) (x)
#endif
@@ -1285,7 +1262,7 @@
# define QT_WARNING_DISABLE_CLANG(text)
# define QT_WARNING_DISABLE_GCC(text)
# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_INTEL(1478 1786)
-#elif defined(Q_CC_MSVC) && _MSC_VER >= 1500 && !defined(Q_CC_CLANG)
+#elif defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
# undef QT_DO_PRAGMA /* not needed */
# define QT_WARNING_PUSH __pragma(warning(push))
# define QT_WARNING_POP __pragma(warning(pop))
@@ -1350,12 +1327,12 @@
} while (false)
#if defined(__cplusplus)
-#if QT_HAS_CPP_ATTRIBUTE(fallthrough)
-# define Q_FALLTHROUGH() [[fallthrough]]
-#elif QT_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#if QT_HAS_CPP_ATTRIBUTE(clang::fallthrough)
# define Q_FALLTHROUGH() [[clang::fallthrough]]
#elif QT_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
# define Q_FALLTHROUGH() [[gnu::fallthrough]]
+#elif QT_HAS_CPP_ATTRIBUTE(fallthrough)
+# define Q_FALLTHROUGH() [[fallthrough]]
#endif
#endif
#ifndef Q_FALLTHROUGH
diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h
index 2164d7f21f..86ef1a2613 100644
--- a/src/corelib/global/qconfig-bootstrapped.h
+++ b/src/corelib/global/qconfig-bootstrapped.h
@@ -78,6 +78,7 @@
#define QT_FEATURE_cxx11_random (QT_HAS_INCLUDE(<random>) ? 1 : -1)
#define QT_NO_DATASTREAM
#define QT_FEATURE_datetimeparser -1
+#define QT_FEATURE_etw -1
#define QT_FEATURE_getauxval (QT_HAS_INCLUDE(<sys/auxv.h>) ? 1 : -1)
#define QT_FEATURE_getentropy -1
#define QT_NO_GEOM_VARIANT
@@ -87,8 +88,15 @@
#define QT_FEATURE_futimens -1
#define QT_FEATURE_futimes -1
#define QT_FEATURE_library -1
+#ifdef __linux__
+# define QT_FEATURE_linkat 1
+#else
+# define QT_FEATURE_linkat -1
+#endif
+#define QT_FEATURE_lttng -1
#define QT_NO_QOBJECT
#define QT_FEATURE_process -1
+#define QT_FEATURE_regularexpression -1
#define QT_FEATURE_renameat2 -1
#define QT_FEATURE_sharedmemory -1
#define QT_FEATURE_slog2 -1
diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h
index 3337829de0..a14fce23f8 100644
--- a/src/corelib/global/qendian.h
+++ b/src/corelib/global/qendian.h
@@ -272,7 +272,8 @@ public:
static Q_DECL_CONSTEXPR T fromSpecial(T source) { return qFromBigEndian(source); }
};
-#ifdef Q_QDOC
+#ifdef Q_CLANG_QDOC
+template<typename T>
class QLEInteger {
public:
explicit Q_DECL_CONSTEXPR QLEInteger(T i);
@@ -292,6 +293,7 @@ public:
QLEInteger &operator ^=(T i);
};
+template<typename T>
class QBEInteger {
public:
explicit Q_DECL_CONSTEXPR QBEInteger(T i);
diff --git a/src/corelib/global/qendian.qdoc b/src/corelib/global/qendian.qdoc
index 2ccdea5979..65df25a205 100644
--- a/src/corelib/global/qendian.qdoc
+++ b/src/corelib/global/qendian.qdoc
@@ -34,8 +34,8 @@
*/
/*!
+ \fn template <typename T> T qFromUnaligned(const void *ptr)
\internal
- \fn T qFromUnaligned(const void *ptr)
\since 5.5
Loads a \c{T} from address \a ptr, which may be misaligned.
@@ -45,8 +45,8 @@
*/
/*!
+ \fn template <typename T> void qToUnaligned(const T t, void *ptr)
\internal
- \fn void qToUnaligned(T t, void *ptr)
\since 4.5
Stores \a t to address \a ptr, which may be misaligned.
@@ -57,7 +57,7 @@
/*!
- \fn T qFromBigEndian(const void *src)
+ \fn template <typename T> T qFromBigEndian(const void *src)
\since 4.3
\relates <QtEndian>
@@ -78,7 +78,7 @@
\sa qToLittleEndian()
*/
/*!
- \fn T qFromBigEndian(T src)
+ \fn template <typename T> T qFromBigEndian(T src)
\since 4.3
\relates <QtEndian>
\overload
@@ -90,7 +90,7 @@
unmodified.
*/
/*!
- \fn T qFromLittleEndian(const void *src)
+ \fn template <typename T> T qFromLittleEndian(const void *src)
\since 4.3
\relates <QtEndian>
@@ -111,7 +111,7 @@
\sa qToLittleEndian()
*/
/*!
- \fn T qFromLittleEndian(T src)
+ \fn template <typename T> T qFromLittleEndian(T src)
\since 4.3
\relates <QtEndian>
\overload
@@ -123,7 +123,7 @@
unmodified.
*/
/*!
- \fn void qToBigEndian(T src, void *dest)
+ \fn template <typename T> void qToBigEndian(T src, void *dest)
\since 4.3
\relates <QtEndian>
@@ -141,7 +141,7 @@
\sa qToLittleEndian()
*/
/*!
- \fn T qToBigEndian(T src)
+ \fn template <typename T> T qToBigEndian(T src)
\since 4.3
\relates <QtEndian>
\overload
@@ -153,7 +153,7 @@
unmodified.
*/
/*!
- \fn void qToLittleEndian(T src, void *dest)
+ \fn template <typename T> void qToLittleEndian(T src, void *dest)
\since 4.3
\relates <QtEndian>
@@ -171,7 +171,7 @@
\sa qToBigEndian()
*/
/*!
- \fn T qToLittleEndian(T src)
+ \fn template <typename T> T qToLittleEndian(T src)
\since 4.3
\relates <QtEndian>
\overload
@@ -203,100 +203,100 @@
an exact endian is needed.
*/
-/*! \fn QLEInteger::QLEInteger(T value)
+/*! \fn template <typename T> QLEInteger<T>::QLEInteger(T value)
Constructs a QLEInteger with the given \a value.
*/
-/*! \fn QLEInteger &QLEInteger::operator=(T value)
+/*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator=(T i)
- Assigns \a value to this QLEInteger and returns a reference to
+ Assigns \a i to this QLEInteger and returns a reference to
this QLEInteger.
*/
/*!
- \fn QLEInteger::operator T() const
+ \fn template <typename T> QLEInteger<T>::operator T() const
Returns the value of this QLEInteger as a native integer.
*/
/*!
- \fn bool QLEInteger::operator==(QLEInteger other) const
+ \fn template <typename T> bool QLEInteger<T>::operator==(QLEInteger other) const
Returns \c true if the value of this QLEInteger is equal to the value of \a other.
*/
/*!
- \fn bool QLEInteger::operator!=(QLEInteger other) const
+ \fn template <typename T> bool QLEInteger<T>::operator!=(QLEInteger other) const
Returns \c true if the value of this QLEInteger is not equal to the value of \a other.
*/
/*!
- \fn QLEInteger &QLEInteger::operator+=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator+=(T i)
Adds \a i to this QLEInteger and returns a reference to
this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator-=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator-=(T i)
Subtracts \a i from this QLEInteger and returns a reference to
this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator*=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator*=(T i)
Multiplies \a i with this QLEInteger and returns a reference to
this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator/=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator/=(T i)
Divides this QLEInteger with \a i and returns a reference to
this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator%=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator%=(T i)
Sets this QLEInteger to the remainder of a division by \a i and
returns a reference to this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator>>=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator>>=(T i)
Performs a left-shift by \a i on this QLEInteger and returns a
reference to this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator<<=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator<<=(T i)
Performs a right-shift by \a i on this QLEInteger and returns a
reference to this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator|=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator|=(T i)
Performs a bitwise OR with \a i onto this QLEInteger and returns a reference to
this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator&=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator&=(T i)
Performs a bitwise AND with \a i onto this QLEInteger and returns a reference to
this object.
*/
/*!
- \fn QLEInteger &QLEInteger::operator^=(T i)
+ \fn template <typename T> QLEInteger &QLEInteger<T>::operator^=(T i)
Performs a bitwise XOR with \a i onto this QLEInteger and returns a reference to
this object.
@@ -322,100 +322,100 @@
an exact endian is needed.
*/
-/*! \fn QBEInteger::QBEInteger(T value)
+/*! \fn template <typename T> QBEInteger<T>::QBEInteger(T value)
Constructs a QBEInteger with the given \a value.
*/
-/*! \fn QBEInteger &QBEInteger::operator=(T value)
+/*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator=(T i)
- Assigns \a value to this QBEInteger and returns a reference to
+ Assigns \a i to this QBEInteger and returns a reference to
this QBEInteger.
*/
/*!
- \fn QBEInteger::operator T() const
+ \fn template <typename T> QBEInteger<T>::operator T() const
Returns the value of this QBEInteger as a native integer.
*/
/*!
- \fn bool QBEInteger::operator==(QBEInteger other) const
+ \fn template <typename T> bool QBEInteger<T>::operator==(QBEInteger other) const
Returns \c true if the value of this QBEInteger is equal to the value of \a other.
*/
/*!
- \fn bool QBEInteger::operator!=(QBEInteger other) const
+ \fn template <typename T> bool QBEInteger<T>::operator!=(QBEInteger other) const
Returns \c true if the value of this QBEInteger is not equal to the value of \a other.
*/
/*!
- \fn QBEInteger &QBEInteger::operator+=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator+=(T i)
Adds \a i to this QBEInteger and returns a reference to
this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator-=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator-=(T i)
Subtracts \a i from this QBEInteger and returns a reference to
this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator*=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator*=(T i)
Multiplies \a i with this QBEInteger and returns a reference to
this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator/=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator/=(T i)
Divides this QBEInteger with \a i and returns a reference to
this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator%=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator%=(T i)
Sets this QBEInteger to the remainder of a division by \a i and
returns a reference to this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator>>=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator>>=(T i)
Performs a left-shift by \a i on this QBEInteger and returns a
reference to this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator<<=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator<<=(T i)
Performs a right-shift by \a i on this QBEInteger and returns a
reference to this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator|=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator|=(T i)
Performs a bitwise OR with \a i onto this QBEInteger and returns a reference to
this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator&=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator&=(T i)
Performs a bitwise AND with \a i onto this QBEInteger and returns a reference to
this object.
*/
/*!
- \fn QBEInteger &QBEInteger::operator^=(T i)
+ \fn template <typename T> QBEInteger &QBEInteger<T>::operator^=(T i)
Performs a bitwise XOR with \a i onto this QBEInteger and returns a reference to
this object.
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index 4806f6cd74..e9fee5f23e 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -54,20 +54,20 @@ class QFlag
{
int i;
public:
- Q_DECL_CONSTEXPR inline QFlag(int ai) Q_DECL_NOTHROW : i(ai) {}
+ Q_DECL_CONSTEXPR inline QFlag(int value) Q_DECL_NOTHROW : i(value) {}
Q_DECL_CONSTEXPR inline operator int() const Q_DECL_NOTHROW { return i; }
#if !defined(Q_CC_MSVC)
// Microsoft Visual Studio has buggy behavior when it comes to
// unsigned enums: even if the enum is unsigned, the enum tags are
// always signed
-# if !defined(__LP64__) && !defined(Q_QDOC)
- Q_DECL_CONSTEXPR inline QFlag(long ai) Q_DECL_NOTHROW : i(int(ai)) {}
- Q_DECL_CONSTEXPR inline QFlag(ulong ai) Q_DECL_NOTHROW : i(int(long(ai))) {}
+# if !defined(__LP64__) && !defined(Q_CLANG_QDOC)
+ Q_DECL_CONSTEXPR inline QFlag(long value) Q_DECL_NOTHROW : i(int(value)) {}
+ Q_DECL_CONSTEXPR inline QFlag(ulong value) Q_DECL_NOTHROW : i(int(long(value))) {}
# endif
- Q_DECL_CONSTEXPR inline QFlag(uint ai) Q_DECL_NOTHROW : i(int(ai)) {}
- Q_DECL_CONSTEXPR inline QFlag(short ai) Q_DECL_NOTHROW : i(int(ai)) {}
- Q_DECL_CONSTEXPR inline QFlag(ushort ai) Q_DECL_NOTHROW : i(int(uint(ai))) {}
+ Q_DECL_CONSTEXPR inline QFlag(uint value) Q_DECL_NOTHROW : i(int(value)) {}
+ Q_DECL_CONSTEXPR inline QFlag(short value) Q_DECL_NOTHROW : i(int(value)) {}
+ Q_DECL_CONSTEXPR inline QFlag(ushort value) Q_DECL_NOTHROW : i(int(uint(value))) {}
Q_DECL_CONSTEXPR inline operator uint() const Q_DECL_NOTHROW { return uint(i); }
#endif
};
@@ -82,7 +82,7 @@ public:
};
Q_DECLARE_TYPEINFO(QIncompatibleFlag, Q_PRIMITIVE_TYPE);
-Q_DECL_CONSTEXPR inline QIncompatibleFlag::QIncompatibleFlag(int ai) Q_DECL_NOTHROW : i(ai) {}
+Q_DECL_CONSTEXPR inline QIncompatibleFlag::QIncompatibleFlag(int value) Q_DECL_NOTHROW : i(value) {}
#ifndef Q_NO_TYPESAFE_FLAGS
@@ -100,7 +100,7 @@ class QFlags
template <typename E> friend QDataStream &operator>>(QDataStream &, QFlags<E> &);
template <typename E> friend QDataStream &operator<<(QDataStream &, QFlags<E>);
public:
-#if defined(Q_CC_MSVC) || defined(Q_QDOC)
+#if defined(Q_CC_MSVC) || defined(Q_CLANG_QDOC)
// see above for MSVC
// the definition below is too complex for qdoc
typedef int Int;
@@ -113,13 +113,13 @@ public:
#endif
typedef Enum enum_type;
// compiler-generated copy/move ctor/assignment operators are fine!
-#ifdef Q_QDOC
+#ifdef Q_CLANG_QDOC
Q_DECL_CONSTEXPR inline QFlags(const QFlags &other);
Q_DECL_CONSTEXPR inline QFlags &operator=(const QFlags &other);
#endif
- Q_DECL_CONSTEXPR inline QFlags(Enum f) Q_DECL_NOTHROW : i(Int(f)) {}
- Q_DECL_CONSTEXPR inline QFlags(Zero = nullptr) Q_DECL_NOTHROW : i(0) {}
- Q_DECL_CONSTEXPR inline QFlags(QFlag f) Q_DECL_NOTHROW : i(f) {}
+ Q_DECL_CONSTEXPR inline QFlags(Enum flags) Q_DECL_NOTHROW : i(Int(flags)) {}
+ Q_DECL_CONSTEXPR inline QFlags(Zero = Q_NULLPTR) Q_DECL_NOTHROW : i(0) {}
+ Q_DECL_CONSTEXPR inline QFlags(QFlag flag) Q_DECL_NOTHROW : i(flag) {}
#ifdef Q_COMPILER_INITIALIZER_LISTS
Q_DECL_CONSTEXPR inline QFlags(std::initializer_list<Enum> flags) Q_DECL_NOTHROW
@@ -129,28 +129,28 @@ public:
Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator&=(int mask) Q_DECL_NOTHROW { i &= mask; return *this; }
Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator&=(uint mask) Q_DECL_NOTHROW { i &= mask; return *this; }
Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator&=(Enum mask) Q_DECL_NOTHROW { i &= Int(mask); return *this; }
- Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator|=(QFlags f) Q_DECL_NOTHROW { i |= f.i; return *this; }
- Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator|=(Enum f) Q_DECL_NOTHROW { i |= Int(f); return *this; }
- Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator^=(QFlags f) Q_DECL_NOTHROW { i ^= f.i; return *this; }
- Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator^=(Enum f) Q_DECL_NOTHROW { i ^= Int(f); return *this; }
+ Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator|=(QFlags other) Q_DECL_NOTHROW { i |= other.i; return *this; }
+ Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator|=(Enum other) Q_DECL_NOTHROW { i |= Int(other); return *this; }
+ Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator^=(QFlags other) Q_DECL_NOTHROW { i ^= other.i; return *this; }
+ Q_DECL_RELAXED_CONSTEXPR inline QFlags &operator^=(Enum other) Q_DECL_NOTHROW { i ^= Int(other); return *this; }
Q_DECL_CONSTEXPR inline operator Int() const Q_DECL_NOTHROW { return i; }
- Q_DECL_CONSTEXPR inline QFlags operator|(QFlags f) const Q_DECL_NOTHROW { return QFlags(QFlag(i | f.i)); }
- Q_DECL_CONSTEXPR inline QFlags operator|(Enum f) const Q_DECL_NOTHROW { return QFlags(QFlag(i | Int(f))); }
- Q_DECL_CONSTEXPR inline QFlags operator^(QFlags f) const Q_DECL_NOTHROW { return QFlags(QFlag(i ^ f.i)); }
- Q_DECL_CONSTEXPR inline QFlags operator^(Enum f) const Q_DECL_NOTHROW { return QFlags(QFlag(i ^ Int(f))); }
+ Q_DECL_CONSTEXPR inline QFlags operator|(QFlags other) const Q_DECL_NOTHROW { return QFlags(QFlag(i | other.i)); }
+ Q_DECL_CONSTEXPR inline QFlags operator|(Enum other) const Q_DECL_NOTHROW { return QFlags(QFlag(i | Int(other))); }
+ Q_DECL_CONSTEXPR inline QFlags operator^(QFlags other) const Q_DECL_NOTHROW { return QFlags(QFlag(i ^ other.i)); }
+ Q_DECL_CONSTEXPR inline QFlags operator^(Enum other) const Q_DECL_NOTHROW { return QFlags(QFlag(i ^ Int(other))); }
Q_DECL_CONSTEXPR inline QFlags operator&(int mask) const Q_DECL_NOTHROW { return QFlags(QFlag(i & mask)); }
Q_DECL_CONSTEXPR inline QFlags operator&(uint mask) const Q_DECL_NOTHROW { return QFlags(QFlag(i & mask)); }
- Q_DECL_CONSTEXPR inline QFlags operator&(Enum f) const Q_DECL_NOTHROW { return QFlags(QFlag(i & Int(f))); }
+ Q_DECL_CONSTEXPR inline QFlags operator&(Enum other) const Q_DECL_NOTHROW { return QFlags(QFlag(i & Int(other))); }
Q_DECL_CONSTEXPR inline QFlags operator~() const Q_DECL_NOTHROW { return QFlags(QFlag(~i)); }
Q_DECL_CONSTEXPR inline bool operator!() const Q_DECL_NOTHROW { return !i; }
- Q_DECL_CONSTEXPR inline bool testFlag(Enum f) const Q_DECL_NOTHROW { return (i & Int(f)) == Int(f) && (Int(f) != 0 || i == Int(f) ); }
- Q_DECL_RELAXED_CONSTEXPR inline QFlags &setFlag(Enum f, bool on = true) Q_DECL_NOTHROW
+ Q_DECL_CONSTEXPR inline bool testFlag(Enum flag) const Q_DECL_NOTHROW { return (i & Int(flag)) == Int(flag) && (Int(flag) != 0 || i == Int(flag) ); }
+ Q_DECL_RELAXED_CONSTEXPR inline QFlags &setFlag(Enum flag, bool on = true) Q_DECL_NOTHROW
{
- return on ? (*this |= f) : (*this &= ~f);
+ return on ? (*this |= flag) : (*this &= ~Int(flag));
}
private:
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
index 89edfc8787..fd608efe55 100644
--- a/src/corelib/global/qfloat16.cpp
+++ b/src/corelib/global/qfloat16.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qfloat16_p.h"
+#include "private/qsimd_p.h"
QT_BEGIN_NAMESPACE
@@ -113,4 +114,102 @@ Q_REQUIRED_RESULT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW { return qt_is_finit
exactness is stronger the smaller the numbers are.
*/
+#if QT_COMPILER_SUPPORTS(F16C)
+static inline bool hasFastF16()
+{
+ // All processors with F16C also support AVX, but YMM registers
+ // might not be supported by the OS, or they might be disabled.
+ return qCpuHasFeature(F16C) && qCpuHasFeature(AVX);
+}
+
+extern "C" {
+#ifdef QFLOAT16_INCLUDE_FAST
+# define f16cextern static
+#else
+# define f16cextern extern
+#endif
+
+f16cextern void qFloatToFloat16_fast(quint16 *out, const float *in, qsizetype len) Q_DECL_NOTHROW;
+f16cextern void qFloatFromFloat16_fast(float *out, const quint16 *in, qsizetype len) Q_DECL_NOTHROW;
+
+#undef f16cextern
+}
+
+#elif defined(__ARM_FP16_FORMAT_IEEE) && defined(__ARM_NEON__)
+static inline bool hasFastF16()
+{
+ return true;
+}
+
+static void qFloatToFloat16_fast(quint16 *out, const float *in, qsizetype len) Q_DECL_NOTHROW
+{
+ __fp16 *out_f16 = reinterpret_cast<__fp16 *>(out);
+ qsizetype i = 0;
+ for (; i < len - 3; i += 4)
+ vst1_f16(out_f16 + i, vcvt_f16_f32(vld1q_f32(in + i)));
+ SIMD_EPILOGUE(i, len, 3)
+ out_f16[i] = __fp16(in[i]);
+}
+
+static void qFloatFromFloat16_fast(float *out, const quint16 *in, qsizetype len) Q_DECL_NOTHROW
+{
+ const __fp16 *in_f16 = reinterpret_cast<const __fp16 *>(in);
+ qsizetype i = 0;
+ for (; i < len - 3; i += 4)
+ vst1q_f32(out + i, vcvt_f32_f16(vld1_f16(in_f16 + i)));
+ SIMD_EPILOGUE(i, len, 3)
+ out[i] = float(in_f16[i]);
+}
+#else
+static inline bool hasFastF16()
+{
+ return false;
+}
+
+static void qFloatToFloat16_fast(quint16 *, const float *, qsizetype) Q_DECL_NOTHROW
+{
+ Q_UNREACHABLE();
+}
+
+static void qFloatFromFloat16_fast(float *, const quint16 *, qsizetype) Q_DECL_NOTHROW
+{
+ Q_UNREACHABLE();
+}
+#endif
+/*!
+ \since 5.11
+ \relates <QFloat16>
+
+ Converts \a len floats from \a in to qfloat16 and stores them in \a out.
+ Both \a in and \a out must have \a len allocated entries.
+*/
+Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *out, const float *in, qsizetype len) Q_DECL_NOTHROW
+{
+ if (hasFastF16())
+ return qFloatToFloat16_fast(reinterpret_cast<quint16 *>(out), in, len);
+
+ for (qsizetype i = 0; i < len; ++i)
+ out[i] = qfloat16(in[i]);
+}
+
+/*!
+ \since 5.11
+ \relates <QFloat16>
+
+ Converts \a len qfloat16 from \a in to floats and stores them in \a out.
+ Both \a in and \a out must have \a len allocated entries.
+*/
+Q_CORE_EXPORT void qFloatFromFloat16(float *out, const qfloat16 *in, qsizetype len) Q_DECL_NOTHROW
+{
+ if (hasFastF16())
+ return qFloatFromFloat16_fast(out, reinterpret_cast<const quint16 *>(in), len);
+
+ for (qsizetype i = 0; i < len; ++i)
+ out[i] = float(in[i]);
+}
+
QT_END_NAMESPACE
+
+#ifdef QFLOAT16_INCLUDE_FAST
+# include "qfloat16_f16c.c"
+#endif
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
index 89a62a93db..a8befd7adb 100644
--- a/src/corelib/global/qfloat16.h
+++ b/src/corelib/global/qfloat16.h
@@ -44,7 +44,16 @@
#include <QtCore/qmetatype.h>
#include <string.h>
-#if defined __F16C__
+#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__AVX2__) && !defined(__F16C__)
+// All processors that support AVX2 do support F16C too. That doesn't mean
+// we're allowed to use the intrinsics directly, so we'll do it only for
+// the Intel and Microsoft's compilers.
+# if defined(Q_CC_INTEL) || defined(Q_CC_MSVC)
+# define __F16C__ 1
+# endif
+#endif
+
+#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__)
#include <immintrin.h>
#endif
@@ -79,6 +88,9 @@ private:
Q_DECLARE_TYPEINFO(qfloat16, Q_PRIMITIVE_TYPE);
+Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *, const float *, qsizetype length) Q_DECL_NOTHROW;
+Q_CORE_EXPORT void qFloatFromFloat16(float *, const qfloat16 *, qsizetype length) Q_DECL_NOTHROW;
+
Q_REQUIRED_RESULT Q_CORE_EXPORT bool qIsInf(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
Q_REQUIRED_RESULT Q_CORE_EXPORT bool qIsNaN(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
Q_REQUIRED_RESULT Q_CORE_EXPORT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
@@ -116,12 +128,12 @@ QT_WARNING_DISABLE_CLANG("-Wc99-extensions")
QT_WARNING_DISABLE_GCC("-Wold-style-cast")
inline qfloat16::qfloat16(float f) Q_DECL_NOTHROW
{
-#if defined(QT_COMPILER_SUPPORTS_F16C) && (defined(__F16C__) || defined(__AVX2__))
+#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__)
__m128 packsingle = _mm_set_ss(f);
__m128i packhalf = _mm_cvtps_ph(packsingle, 0);
b16 = _mm_extract_epi16(packhalf, 0);
#elif defined (__ARM_FP16_FORMAT_IEEE)
- __fp16 f16 = f;
+ __fp16 f16 = __fp16(f);
memcpy(&b16, &f16, sizeof(quint16));
#else
quint32 u;
@@ -134,7 +146,7 @@ QT_WARNING_POP
inline qfloat16::operator float() const Q_DECL_NOTHROW
{
-#if defined(QT_COMPILER_SUPPORTS_F16C) && (defined(__F16C__) || defined(__AVX2__))
+#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__)
__m128i packhalf = _mm_cvtsi32_si128(b16);
__m128 packsingle = _mm_cvtph_ps(packhalf);
return _mm_cvtss_f32(packsingle);
@@ -167,7 +179,8 @@ inline qfloat16 operator/(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat
inline FP operator OP(qfloat16 lhs, FP rhs) Q_DECL_NOTHROW { return static_cast<FP>(lhs) OP rhs; } \
inline FP operator OP(FP lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<FP>(rhs); }
#define QF16_MAKE_ARITH_OP_EQ_FP(FP, OP_EQ, OP) \
- inline qfloat16& operator OP_EQ(qfloat16& lhs, FP rhs) Q_DECL_NOTHROW { lhs = qfloat16(static_cast<FP>(lhs) OP rhs); return lhs; }
+ inline qfloat16& operator OP_EQ(qfloat16& lhs, FP rhs) Q_DECL_NOTHROW \
+ { lhs = qfloat16(float(static_cast<FP>(lhs) OP rhs)); return lhs; }
#define QF16_MAKE_ARITH_OP(FP) \
QF16_MAKE_ARITH_OP_FP(FP, +) \
QF16_MAKE_ARITH_OP_FP(FP, -) \
diff --git a/src/corelib/global/qfloat16_f16c.c b/src/corelib/global/qfloat16_f16c.c
new file mode 100644
index 0000000000..a7eadc71b7
--- /dev/null
+++ b/src/corelib/global/qfloat16_f16c.c
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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$
+**
+****************************************************************************/
+
+#include "private/qsimd_p.h"
+
+// The x86 F16C instructions operate on AVX registers, so AVX support is
+// required. We don't need to check for __F16C__ because we this file wouldn't
+// have been compiled if the support was missing in the first place, and not
+// all compilers define it. Technically, we didn't need to check for __AVX__
+// either.
+#if !QT_COMPILER_SUPPORTS_HERE(AVX)
+# error "AVX support required"
+#endif
+
+#ifdef __cplusplus
+QT_BEGIN_NAMESPACE
+extern "C" {
+#endif
+
+QT_FUNCTION_TARGET(F16C)
+void qFloatToFloat16_fast(quint16 *out, const float *in, qsizetype len) Q_DECL_NOTHROW
+{
+ qsizetype i = 0;
+ int epilog_i;
+ for (; i < len - 7; i += 8)
+ _mm_storeu_si128((__m128i *)(out + i), _mm256_cvtps_ph(_mm256_loadu_ps(in + i), 0));
+ if (i < len - 3) {
+ _mm_storel_epi64((__m128i *)(out + i), _mm_cvtps_ph(_mm_loadu_ps(in + i), 0));
+ i += 4;
+ }
+ // Inlining "qfloat16::qfloat16(float f)":
+ for (epilog_i = 0; i < len && epilog_i < 3; ++i, ++epilog_i)
+ out[i] = _mm_extract_epi16(_mm_cvtps_ph(_mm_set_ss(in[i]), 0), 0);
+}
+
+QT_FUNCTION_TARGET(F16C)
+void qFloatFromFloat16_fast(float *out, const quint16 *in, qsizetype len) Q_DECL_NOTHROW
+{
+ qsizetype i = 0;
+ int epilog_i;
+ for (; i < len - 7; i += 8)
+ _mm256_storeu_ps(out + i, _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(in + i))));
+ if (i < len - 3) {
+ _mm_storeu_ps(out + i, _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(in + i))));
+ i += 4;
+ }
+ // Inlining "qfloat16::operator float()":
+ for (epilog_i = 0; i < len && epilog_i < 3; ++i, ++epilog_i)
+ out[i] = _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128(in[i])));
+}
+
+#ifdef __cplusplus
+} // extern "C"
+QT_END_NAMESPACE
+#endif
diff --git a/src/corelib/global/qfloat16_p.h b/src/corelib/global/qfloat16_p.h
index ae52e64435..f3fc96e119 100644
--- a/src/corelib/global/qfloat16_p.h
+++ b/src/corelib/global/qfloat16_p.h
@@ -61,9 +61,9 @@ static inline bool qt_is_inf(qfloat16 d) Q_DECL_NOTHROW
bool is_inf;
uchar *ch = (uchar *)&d;
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- is_inf = (ch[0] & 0x7c) == 0x7c;
+ is_inf = (ch[0] & 0x7c) == 0x7c && (ch[0] & 0x02) == 0;
else
- is_inf = (ch[1] & 0x7c) == 0x7c;
+ is_inf = (ch[1] & 0x7c) == 0x7c && (ch[1] & 0x02) == 0;
return is_inf;
}
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index f2f807e1d9..2d8b860c5b 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -46,6 +46,9 @@
#include "qdatetime.h"
#include "qoperatingsystemversion.h"
#include "qoperatingsystemversion_p.h"
+#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) || defined(Q_OS_WINRT)
+#include "qoperatingsystemversion_win_p.h"
+#endif
#include <private/qlocale_tools_p.h>
#include <qmutex.h>
@@ -73,11 +76,15 @@
#include <Ws2tcpip.h>
#endif // Q_OS_WINRT
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+#endif
+
#if defined(Q_OS_VXWORKS) && defined(_WRS_KERNEL)
# include <envLib.h>
#endif
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#include <private/qjni_p.h>
#endif
@@ -160,8 +167,8 @@ Q_STATIC_ASSERT_X(std::numeric_limits<float>::radix == 2,
// not required by the definition of size_t, but we depend on this
Q_STATIC_ASSERT_X(sizeof(size_t) == sizeof(void *), "size_t and a pointer don't have the same size");
-Q_STATIC_ASSERT(sizeof(size_t) == sizeof(qssize_t)); // implied by the definition
-Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
+Q_STATIC_ASSERT(sizeof(size_t) == sizeof(qsizetype)); // implied by the definition
+Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value));
/*!
\class QFlag
@@ -178,28 +185,28 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
/*!
\fn QFlag::QFlag(int value)
- Constructs a QFlag object that stores the given \a value.
+ Constructs a QFlag object that stores the \a value.
*/
/*!
\fn QFlag::QFlag(uint value)
\since 5.3
- Constructs a QFlag object that stores the given \a value.
+ Constructs a QFlag object that stores the \a value.
*/
/*!
\fn QFlag::QFlag(short value)
\since 5.3
- Constructs a QFlag object that stores the given \a value.
+ Constructs a QFlag object that stores the \a value.
*/
/*!
\fn QFlag::QFlag(ushort value)
\since 5.3
- Constructs a QFlag object that stores the given \a value.
+ Constructs a QFlag object that stores the \a value.
*/
/*!
@@ -294,29 +301,28 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags::QFlags(const QFlags &other)
+ \fn template<typename Enum> QFlags<Enum>::QFlags(const QFlags &other)
Constructs a copy of \a other.
*/
/*!
- \fn QFlags::QFlags(Enum flag)
+ \fn template <typename Enum> QFlags<Enum>::QFlags(Enum flags)
- Constructs a QFlags object storing the given \a flag.
+ Constructs a QFlags object storing the \a flags.
*/
/*!
- \fn QFlags::QFlags(Zero zero)
+ \fn template <typename Enum> QFlags<Enum>::QFlags(Zero)
- Constructs a QFlags object with no flags set. \a zero must be a
+ Constructs a QFlags object with no flags set. The parameter must be a
literal 0 value.
*/
/*!
- \fn QFlags::QFlags(QFlag value)
+ \fn template <typename Enum> QFlags<Enum>::QFlags(QFlag flag)
- Constructs a QFlags object initialized with the given integer \a
- value.
+ Constructs a QFlags object initialized with the integer \a flag.
The QFlag type is a helper type. By using it here instead of \c
int, we effectively ensure that arbitrary enum values cannot be
@@ -325,7 +331,7 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags::QFlags(std::initializer_list<Enum> flags)
+ \fn template <typename Enum> QFlags<Enum>::QFlags(std::initializer_list<Enum> flags)
\since 5.4
Constructs a QFlags object initialized with all \a flags
@@ -335,14 +341,14 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags &QFlags::operator=(const QFlags &other)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator=(const QFlags &other)
Assigns \a other to this object and returns a reference to this
object.
*/
/*!
- \fn QFlags &QFlags::operator&=(int mask)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator&=(int mask)
Performs a bitwise AND operation with \a mask and stores the
result in this QFlags object. Returns a reference to this object.
@@ -351,19 +357,19 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags &QFlags::operator&=(uint mask)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator&=(uint mask)
\overload
*/
/*!
- \fn QFlags &QFlags::operator&=(Enum mask)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator&=(Enum mask)
\overload
*/
/*!
- \fn QFlags &QFlags::operator|=(QFlags other)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator|=(QFlags other)
Performs a bitwise OR operation with \a other and stores the
result in this QFlags object. Returns a reference to this object.
@@ -372,13 +378,13 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags &QFlags::operator|=(Enum other)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator|=(Enum other)
\overload
*/
/*!
- \fn QFlags &QFlags::operator^=(QFlags other)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator^=(QFlags other)
Performs a bitwise XOR operation with \a other and stores the
result in this QFlags object. Returns a reference to this object.
@@ -387,13 +393,13 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags &QFlags::operator^=(Enum other)
+ \fn template <typename Enum> QFlags &QFlags<Enum>::operator^=(Enum other)
\overload
*/
/*!
- \fn QFlags::operator Int() const
+ \fn template <typename Enum> QFlags<Enum>::operator Int() const
Returns the value stored in the QFlags object as an integer.
@@ -401,7 +407,7 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags QFlags::operator|(QFlags other) const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator|(QFlags other) const
Returns a QFlags object containing the result of the bitwise OR
operation on this object and \a other.
@@ -410,13 +416,13 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags QFlags::operator|(Enum other) const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator|(Enum other) const
\overload
*/
/*!
- \fn QFlags QFlags::operator^(QFlags other) const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator^(QFlags other) const
Returns a QFlags object containing the result of the bitwise XOR
operation on this object and \a other.
@@ -425,13 +431,13 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags QFlags::operator^(Enum other) const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator^(Enum other) const
\overload
*/
/*!
- \fn QFlags QFlags::operator&(int mask) const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator&(int mask) const
Returns a QFlags object containing the result of the bitwise AND
operation on this object and \a mask.
@@ -440,19 +446,19 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn QFlags QFlags::operator&(uint mask) const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator&(uint mask) const
\overload
*/
/*!
- \fn QFlags QFlags::operator&(Enum mask) const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator&(Enum mask) const
\overload
*/
/*!
- \fn QFlags QFlags::operator~() const
+ \fn template <typename Enum> QFlags QFlags<Enum>::operator~() const
Returns a QFlags object that contains the bitwise negation of
this object.
@@ -461,24 +467,24 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \fn bool QFlags::operator!() const
+ \fn template <typename Enum> bool QFlags<Enum>::operator!() const
Returns \c true if no flag is set (i.e., if the value stored by the
QFlags object is 0); otherwise returns \c false.
*/
/*!
- \fn bool QFlags::testFlag(Enum flag) const
+ \fn template <typename Enum> bool QFlags<Enum>::testFlag(Enum flag) const
\since 4.2
- Returns \c true if the \a flag is set, otherwise \c false.
+ Returns \c true if the flag \a flag is set, otherwise \c false.
*/
/*!
- \fn QFlags QFlags::setFlag(Enum flag, bool on)
+ \fn template <typename Enum> QFlags QFlags<Enum>::setFlag(Enum flag, bool on)
\since 5.7
- Sets the indicated \a flag if \a on is \c true or unsets it if
+ Sets the flag \a flag if \a on is \c true or unsets it if
\a on is \c false. Returns a reference to this object.
*/
@@ -824,7 +830,7 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
*/
/*!
- \typedef qssize_t
+ \typedef qsizetype
\relates <QtGlobal>
\since 5.10
@@ -833,7 +839,7 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
This type is guaranteed to be the same size as a \c size_t on all
platforms supported by Qt.
- Note that qssize_t is signed. Use \c size_t for unsigned values.
+ Note that qsizetype is signed. Use \c size_t for unsigned values.
\sa qptrdiff
*/
@@ -916,11 +922,11 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
\sa quint64, qlonglong
*/
-/*! \fn T qAbs(const T &value)
+/*! \fn template <typename T> T qAbs(const T &t)
\relates <QtGlobal>
- Compares \a value to the 0 of type T and returns the absolute
- value. Thus if T is \e {double}, then \a value is compared to
+ Compares \a t to the 0 of type T and returns the absolute
+ value. Thus if T is \e {double}, then \a t is compared to
\e{(double) 0}.
Example:
@@ -928,50 +934,50 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
\snippet code/src_corelib_global_qglobal.cpp 10
*/
-/*! \fn int qRound(double value)
+/*! \fn int qRound(double d)
\relates <QtGlobal>
- Rounds \a value to the nearest integer.
+ Rounds \a d to the nearest integer.
Example:
\snippet code/src_corelib_global_qglobal.cpp 11A
*/
-/*! \fn int qRound(float value)
+/*! \fn int qRound(float d)
\relates <QtGlobal>
- Rounds \a value to the nearest integer.
+ Rounds \a d to the nearest integer.
Example:
\snippet code/src_corelib_global_qglobal.cpp 11B
*/
-/*! \fn qint64 qRound64(double value)
+/*! \fn qint64 qRound64(double d)
\relates <QtGlobal>
- Rounds \a value to the nearest 64-bit integer.
+ Rounds \a d to the nearest 64-bit integer.
Example:
\snippet code/src_corelib_global_qglobal.cpp 12A
*/
-/*! \fn qint64 qRound64(float value)
+/*! \fn qint64 qRound64(float d)
\relates <QtGlobal>
- Rounds \a value to the nearest 64-bit integer.
+ Rounds \a d to the nearest 64-bit integer.
Example:
\snippet code/src_corelib_global_qglobal.cpp 12B
*/
-/*! \fn const T &qMin(const T &value1, const T &value2)
+/*! \fn template <typename T> const T &qMin(const T &a, const T &b)
\relates <QtGlobal>
- Returns the minimum of \a value1 and \a value2.
+ Returns the minimum of \a a and \a b.
Example:
@@ -980,10 +986,10 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
\sa qMax(), qBound()
*/
-/*! \fn const T &qMax(const T &value1, const T &value2)
+/*! \fn template <typename T> const T &qMax(const T &a, const T &b)
\relates <QtGlobal>
- Returns the maximum of \a value1 and \a value2.
+ Returns the maximum of \a a and \a b.
Example:
@@ -992,11 +998,11 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
\sa qMin(), qBound()
*/
-/*! \fn const T &qBound(const T &min, const T &value, const T &max)
+/*! \fn template <typename T> const T &qBound(const T &min, const T &val, const T &max)
\relates <QtGlobal>
- Returns \a value bounded by \a min and \a max. This is equivalent
- to qMax(\a min, qMin(\a value, \a max)).
+ Returns \a val bounded by \a min and \a max. This is equivalent
+ to qMax(\a min, qMin(\a val, \a max)).
Example:
@@ -1005,7 +1011,7 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
\sa qMin(), qMax()
*/
-/*! \fn auto qOverload(T functionPointer)
+/*! \fn template <typename T> auto qOverload(T functionPointer)
\relates <QtGlobal>
\since 5.7
@@ -1027,7 +1033,7 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
and Functor-Based Connections}
*/
-/*! \fn auto qConstOverload(T memberFunctionPointer)
+/*! \fn template <typename T> auto qConstOverload(T memberFunctionPointer)
\relates <QtGlobal>
\since 5.7
@@ -1039,7 +1045,7 @@ Q_STATIC_ASSERT((std::is_same<qssize_t, qptrdiff>::value));
and Functor-Based Connections}
*/
-/*! \fn auto qNonConstOverload(T memberFunctionPointer)
+/*! \fn template <typename T> auto qNonConstOverload(T memberFunctionPointer)
\relates <QtGlobal>
\since 5.7
@@ -1428,13 +1434,6 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
- \macro Q_OS_ULTRIX
- \relates <QtGlobal>
-
- Defined on DEC Ultrix.
-*/
-
-/*!
\macro Q_OS_LINUX
\relates <QtGlobal>
@@ -1470,41 +1469,6 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
- \macro Q_OS_BSDI
- \relates <QtGlobal>
-
- Defined on BSD/OS.
-*/
-
-/*!
- \macro Q_OS_IRIX
- \relates <QtGlobal>
-
- Defined on SGI Irix.
-*/
-
-/*!
- \macro Q_OS_OSF
- \relates <QtGlobal>
-
- Defined on HP Tru64 UNIX.
-*/
-
-/*!
- \macro Q_OS_SCO
- \relates <QtGlobal>
-
- Defined on SCO OpenServer 5.
-*/
-
-/*!
- \macro Q_OS_UNIXWARE
- \relates <QtGlobal>
-
- Defined on UnixWare 7, Open UNIX 8.
-*/
-
-/*!
\macro Q_OS_AIX
\relates <QtGlobal>
@@ -1519,27 +1483,6 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
- \macro Q_OS_DGUX
- \relates <QtGlobal>
-
- Defined on DG/UX.
-*/
-
-/*!
- \macro Q_OS_RELIANT
- \relates <QtGlobal>
-
- Defined on Reliant UNIX.
-*/
-
-/*!
- \macro Q_OS_DYNIX
- \relates <QtGlobal>
-
- Defined on DYNIX/ptx.
-*/
-
-/*!
\macro Q_OS_QNX
\relates <QtGlobal>
@@ -2355,7 +2298,7 @@ static bool findUnixOsVersion(QUnixOSVersion &v)
# endif // USE_ETC_OS_RELEASE
#endif // Q_OS_UNIX
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
static const char *osVer_helper(QOperatingSystemVersion)
{
/* Data:
@@ -2836,7 +2779,7 @@ QString QSysInfo::productVersion()
*/
QString QSysInfo::prettyProductName()
{
-#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
+#if (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
const auto version = QOperatingSystemVersion::current();
const char *name = osVer_helper(version);
if (name)
@@ -2881,10 +2824,11 @@ QString QSysInfo::prettyProductName()
This function returns the same as QHostInfo::localHostName().
- \sa QHostInfo::localDomainName
+ \sa QHostInfo::localDomainName, machineUniqueId()
*/
QString QSysInfo::machineHostName()
{
+ // the hostname can change, so we can't cache it
#if defined(Q_OS_LINUX)
// gethostname(3) on Linux just calls uname(2), so do it ourselves
// and avoid a memcpy
@@ -2907,6 +2851,119 @@ QString QSysInfo::machineHostName()
}
#endif // QT_BOOTSTRAPPED
+enum {
+ UuidStringLen = sizeof("00000000-0000-0000-0000-000000000000") - 1
+};
+
+/*!
+ \since 5.10
+
+ Returns a unique ID for this machine, if one can be determined. If no
+ unique ID could be determined, this function returns an empty byte array.
+ Unlike machineHostName(), the value returned by this function is likely
+ globally unique.
+
+ A unique ID is useful in network operations to identify this machine for an
+ extended period of time, when the IP address could change or if this
+ machine could have more than one IP address. For example, the ID could be
+ used when communicating with a server or when storing device-specific data
+ in shared network storage.
+
+ Note that on some systems, this value will persist across reboots and on
+ some it will not. Applications should not blindly depend on this fact
+ without verifying the OS capabilities. In particular, on Linux systems,
+ this ID is usually permanent and it matches the D-Bus machine ID, except
+ for nodes without their own storage (replicated nodes).
+
+ \sa machineHostName(), bootUniqueId()
+*/
+QByteArray QSysInfo::machineUniqueId()
+{
+#ifdef Q_OS_BSD4
+ char uuid[UuidStringLen];
+ size_t uuidlen = sizeof(uuid);
+# ifdef KERN_HOSTUUID
+ int name[] = { CTL_KERN, KERN_HOSTUUID };
+ if (sysctl(name, sizeof name / sizeof name[0], &uuid, &uuidlen, nullptr, 0) == 0
+ && uuidlen == sizeof(uuid))
+ return QByteArray(uuid, uuidlen);
+
+# else
+ // Darwin: no fixed value, we need to search by name
+ if (sysctlbyname("kern.uuid", uuid, &uuidlen, nullptr, 0) == 0 && uuidlen == sizeof(uuid))
+ return QByteArray(uuid, uuidlen);
+# endif
+#elif defined(Q_OS_UNIX)
+ // The modern name on Linux is /etc/machine-id, but that path is
+ // unlikely to exist on non-Linux (non-systemd) systems. The old
+ // path is more than enough.
+ static const char fullfilename[] = "/usr/local/var/lib/dbus/machine-id";
+ const char *firstfilename = fullfilename + sizeof("/usr/local") - 1;
+ int fd = qt_safe_open(firstfilename, O_RDONLY);
+ if (fd == -1 && errno == ENOENT)
+ fd = qt_safe_open(fullfilename, O_RDONLY);
+
+ if (fd != -1) {
+ char buffer[32]; // 128 bits, hex-encoded
+ qint64 len = qt_safe_read(fd, buffer, sizeof(buffer));
+ qt_safe_close(fd);
+
+ if (len != -1)
+ return QByteArray(buffer, len);
+ }
+#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ // Let's poke at the registry
+ HKEY key = NULL;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &key)
+ == ERROR_SUCCESS) {
+ wchar_t buffer[UuidStringLen + 1];
+ DWORD size = sizeof(buffer);
+ bool ok = (RegQueryValueEx(key, L"MachineGuid", NULL, NULL, (LPBYTE)buffer, &size) ==
+ ERROR_SUCCESS);
+ RegCloseKey(key);
+ if (ok)
+ return QStringView(buffer, (size - 1) / 2).toLatin1();
+ }
+#endif
+ return QByteArray();
+}
+
+/*!
+ \since 5.10
+
+ Returns a unique ID for this machine's boot, if one can be determined. If
+ no unique ID could be determined, this function returns an empty byte
+ array. This value is expected to change after every boot and can be
+ considered globally unique.
+
+ This function is currently only implemented for Linux and Apple operating
+ systems.
+
+ \sa machineUniqueId()
+*/
+QByteArray QSysInfo::bootUniqueId()
+{
+#ifdef Q_OS_LINUX
+ // use low-level API here for simplicity
+ int fd = qt_safe_open("/proc/sys/kernel/random/boot_id", O_RDONLY);
+ if (fd != -1) {
+ char uuid[UuidStringLen];
+ qint64 len = qt_safe_read(fd, uuid, sizeof(uuid));
+ qt_safe_close(fd);
+ if (len == UuidStringLen)
+ return QByteArray(uuid, UuidStringLen);
+ }
+#elif defined(Q_OS_DARWIN)
+ // "kern.bootsessionuuid" is only available by name
+ char uuid[UuidStringLen];
+ size_t uuidlen = sizeof(uuid);
+ if (sysctlbyname("kern.bootsessionuuid", uuid, &uuidlen, nullptr, 0) == 0
+ && uuidlen == sizeof(uuid))
+ return QByteArray(uuid, uuidlen);
+#endif
+ return QByteArray();
+};
+
/*!
\macro void Q_ASSERT(bool test)
\relates <QtGlobal>
@@ -3050,10 +3107,10 @@ QString QSysInfo::machineHostName()
*/
/*!
- \fn T *q_check_ptr(T *pointer)
+ \fn template <typename T> T *q_check_ptr(T *p)
\relates <QtGlobal>
- Uses Q_CHECK_PTR on \a pointer, then returns \a pointer.
+ Uses Q_CHECK_PTR on \a p, then returns \a p.
This can be used as an inline version of Q_CHECK_PTR.
*/
@@ -3192,7 +3249,7 @@ static QBasicMutex environmentMutex;
QByteArray qgetenv(const char *varName)
{
QMutexLocker locker(&environmentMutex);
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#ifdef Q_CC_MSVC
size_t requiredSize = 0;
QByteArray buffer;
getenv_s(&requiredSize, 0, 0, varName);
@@ -3211,6 +3268,8 @@ QByteArray qgetenv(const char *varName)
/*!
+ QString qEnvironmentVariable(const char *varName, const QString &defaultValue);
+
\relates <QtGlobal>
\since 5.10
@@ -3285,6 +3344,9 @@ QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
#endif
}
+/*!
+ \internal
+*/
QString qEnvironmentVariable(const char *varName)
{
return qEnvironmentVariable(varName, QString());
@@ -3307,7 +3369,7 @@ QString qEnvironmentVariable(const char *varName)
bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT
{
QMutexLocker locker(&environmentMutex);
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#ifdef Q_CC_MSVC
// we provide a buffer that can only hold the empty string, so
// when the env.var isn't empty, we'll get an ERANGE error (buffer
// too small):
@@ -3348,7 +3410,7 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT
(std::numeric_limits<uint>::digits + NumBinaryDigitsPerOctalDigit - 1) / NumBinaryDigitsPerOctalDigit;
QMutexLocker locker(&environmentMutex);
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#ifdef Q_CC_MSVC
// we provide a buffer that can hold any int value:
char buffer[MaxDigitsForOctalInt + 2]; // +1 for NUL +1 for optional '-'
size_t dummy;
@@ -3395,7 +3457,7 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT
bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT
{
QMutexLocker locker(&environmentMutex);
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#ifdef Q_CC_MSVC
size_t requiredSize = 0;
(void)getenv_s(&requiredSize, 0, 0, varName);
return requiredSize != 0;
@@ -3425,7 +3487,7 @@ bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT
bool qputenv(const char *varName, const QByteArray& value)
{
QMutexLocker locker(&environmentMutex);
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#if defined(Q_CC_MSVC)
return _putenv_s(varName, value.constData()) == 0;
#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_HAIKU)
// POSIX.1-2001 has setenv
@@ -3456,7 +3518,7 @@ bool qputenv(const char *varName, const QByteArray& value)
bool qunsetenv(const char *varName)
{
QMutexLocker locker(&environmentMutex);
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#if defined(Q_CC_MSVC)
return _putenv_s(varName, "") == 0;
#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_BSD4) || defined(Q_OS_HAIKU)
// POSIX.1-2001, BSD and Haiku have unsetenv
@@ -3548,7 +3610,7 @@ bool qunsetenv(const char *varName)
*/
/*!
- \fn qAsConst(T &t)
+ \fn template <typename T> typename std::add_const<T>::type &qAsConst(T &t)
\relates <QtGlobal>
\since 5.7
@@ -3600,7 +3662,7 @@ bool qunsetenv(const char *varName)
*/
/*!
- \fn qAsConst(const T &&t)
+ \fn template <typename T> void qAsConst(const T &&t)
\relates <QtGlobal>
\since 5.7
\overload
@@ -4012,43 +4074,6 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
*/
/*!
- \macro Q_GLOBAL_STATIC(type, name)
- \internal
-
- Declares a global static variable with the given \a type and \a name.
-
- Use this macro to instantiate an object in a thread-safe way, creating
- a global pointer that can be used to refer to it.
-
- \warning This macro is subject to a race condition that can cause the object
- to be constructed twice. However, if this occurs, the second instance will
- be immediately deleted.
-
- See also
- \l{http://www.aristeia.com/publications.html}{"C++ and the perils of Double-Checked Locking"}
- by Scott Meyers and Andrei Alexandrescu.
-*/
-
-/*!
- \macro Q_GLOBAL_STATIC_WITH_ARGS(type, name, arguments)
- \internal
-
- Declares a global static variable with the specified \a type and \a name.
-
- Use this macro to instantiate an object using the \a arguments specified
- in a thread-safe way, creating a global pointer that can be used to refer
- to it.
-
- \warning This macro is subject to a race condition that can cause the object
- to be constructed twice. However, if this occurs, the second instance will
- be immediately deleted.
-
- See also
- \l{http://www.aristeia.com/publications.html}{"C++ and the perils of Double-Checked Locking"}
- by Scott Meyers and Andrei Alexandrescu.
-*/
-
-/*!
\macro QT_NAMESPACE
\internal
@@ -4296,6 +4321,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qDebug(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
Calls the message handler with the debug message \a message. If no
message handler has been installed, the message is printed to
@@ -4332,6 +4358,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qInfo(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
\since 5.5
Calls the message handler with the informational message \a message. If no
@@ -4369,6 +4396,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qWarning(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
Calls the message handler with the warning message \a message. If no
message handler has been installed, the message is printed to
@@ -4406,6 +4434,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*!
\macro qCritical(const char *message, ...)
\relates <QtGlobal>
+ \threadsafe
Calls the message handler with the critical message \a message. If no
message handler has been installed, the message is printed to
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index e49bace002..cd4b4a29a9 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -47,6 +47,7 @@
# include <utility>
#endif
#ifndef __ASSEMBLER__
+# include <assert.h>
# include <stddef.h>
#endif
@@ -87,6 +88,11 @@
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
# define QT_NO_UNSHARABLE_CONTAINERS
+# define QT6_VIRTUAL virtual
+# define QT6_NOT_VIRTUAL
+#else
+# define QT6_VIRTUAL
+# define QT6_NOT_VIRTUAL virtual
#endif
/* These two macros makes it possible to turn the builtin line expander into a
@@ -105,6 +111,32 @@
# define Q_OF_MACH_O
#endif
+/*
+ Avoid "unused parameter" warnings
+*/
+#define Q_UNUSED(x) (void)x;
+
+#if defined(__cplusplus) && defined(Q_COMPILER_STATIC_ASSERT)
+# define Q_STATIC_ASSERT(Condition) static_assert(bool(Condition), #Condition)
+# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
+#elif defined(Q_COMPILER_STATIC_ASSERT)
+// C11 mode - using the _S version in case <assert.h> doesn't do the right thing
+# define Q_STATIC_ASSERT(Condition) _Static_assert(!!(Condition), #Condition)
+# define Q_STATIC_ASSERT_X(Condition, Message) _Static_assert(!!(Condition), Message)
+#else
+// C89 & C99 version
+# define Q_STATIC_ASSERT_PRIVATE_JOIN(A, B) Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B)
+# define Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) A ## B
+# ifdef __COUNTER__
+# define Q_STATIC_ASSERT(Condition) \
+ typedef char Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) [(Condition) ? 1 : -1];
+# else
+# define Q_STATIC_ASSERT(Condition) \
+ typedef char Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __LINE__) [(Condition) ? 1 : -1];
+# endif /* __COUNTER__ */
+# define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
+#endif
+
#ifdef __cplusplus
#include <algorithm>
@@ -219,6 +251,15 @@ typedef unsigned long long quint64; /* 64 bit unsigned */
typedef qint64 qlonglong;
typedef quint64 qulonglong;
+#ifndef __cplusplus
+// In C++ mode, we define below using QIntegerForSize template
+Q_STATIC_ASSERT_X(sizeof(ptrdiff_t) == sizeof(size_t), "Weird ptrdiff_t and size_t definitions");
+typedef ptrdiff_t qptrdiff;
+typedef ptrdiff_t qsizetype;
+typedef ptrdiff_t qintptr;
+typedef size_t quintptr;
+#endif
+
/*
Useful type definitions for Qt
*/
@@ -439,7 +480,7 @@ namespace QtPrivate {
sizeof(void *) == sizeof(quintptr)
&& sizeof(void *) == sizeof(qptrdiff)
- size_t and qssize_t are not guaranteed to be the same size as a pointer, but
+ size_t and qsizetype are not guaranteed to be the same size as a pointer, but
they usually are.
*/
template <int> struct QIntegerForSize;
@@ -456,7 +497,7 @@ typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Unsigned qregisteruint;
typedef QIntegerForSizeof<void*>::Unsigned quintptr;
typedef QIntegerForSizeof<void*>::Signed qptrdiff;
typedef qptrdiff qintptr;
-using qssize_t = QIntegerForSizeof<std::size_t>::Signed;
+using qsizetype = QIntegerForSizeof<std::size_t>::Signed;
/* moc compats (signals/slots) */
#ifndef QT_MOC_COMPAT
@@ -472,7 +513,7 @@ using qssize_t = QIntegerForSizeof<std::size_t>::Signed;
# define QT_ASCII_CAST_WARN
#endif
-#if defined(__i386__) || defined(_WIN32)
+#ifdef Q_PROCESSOR_X86_32
# if defined(Q_CC_GNU)
# define QT_FASTCALL __attribute__((regparm(3)))
# elif defined(Q_CC_MSVC)
@@ -508,6 +549,12 @@ using qssize_t = QIntegerForSizeof<std::size_t>::Signed;
# define Q_ALWAYS_INLINE inline
#endif
+#if defined(Q_CC_GNU) && defined(Q_OS_WIN)
+# define QT_INIT_METAOBJECT __attribute__((init_priority(101)))
+#else
+# define QT_INIT_METAOBJECT
+#endif
+
//defines the type for the WNDPROC on windows
//the alignment needs to be forced for sse2 to not crash with mingw
#if defined(Q_OS_WIN)
@@ -670,7 +717,7 @@ inline void qt_noop(void) {}
# define QT_CATCH(A) catch (A)
# define QT_THROW(A) throw A
# define QT_RETHROW throw
-Q_NORETURN Q_CORE_EXPORT void qTerminate() Q_DECL_NOTHROW;
+Q_NORETURN Q_DECL_COLD_FUNCTION Q_CORE_EXPORT void qTerminate() Q_DECL_NOTHROW;
# ifdef Q_COMPILER_NOEXCEPT
# define QT_TERMINATE_ON_EXCEPTION(expr) do { expr; } while (false)
# else
@@ -688,11 +735,6 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qSharedBuild() Q_DECL_NOTHROW;
#endif
/*
- Avoid "unused parameter" warnings
-*/
-#define Q_UNUSED(x) (void)x;
-
-/*
Debugging and error handling
*/
@@ -718,11 +760,13 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qSharedBuild() Q_DECL_NOTHROW;
#endif
class QString;
+Q_DECL_COLD_FUNCTION
Q_CORE_EXPORT QString qt_error_string(int errorCode = -1);
#ifndef Q_CC_MSVC
Q_NORETURN
#endif
+Q_DECL_COLD_FUNCTION
Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line) Q_DECL_NOTHROW;
#if !defined(Q_ASSERT)
@@ -740,6 +784,7 @@ Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line)
#ifndef Q_CC_MSVC
Q_NORETURN
#endif
+Q_DECL_COLD_FUNCTION
Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char *file, int line) Q_DECL_NOTHROW;
#if !defined(Q_ASSERT_X)
@@ -750,28 +795,8 @@ Q_CORE_EXPORT void qt_assert_x(const char *where, const char *what, const char *
# endif
#endif
-
-#ifdef Q_COMPILER_STATIC_ASSERT
-#define Q_STATIC_ASSERT(Condition) static_assert(bool(Condition), #Condition)
-#define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
-#else
-// Intentionally undefined
-template <bool Test> class QStaticAssertFailure;
-template <> class QStaticAssertFailure<true> {};
-
-#define Q_STATIC_ASSERT_PRIVATE_JOIN(A, B) Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B)
-#define Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) A ## B
-#ifdef __COUNTER__
-#define Q_STATIC_ASSERT(Condition) \
- enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
-#else
-#define Q_STATIC_ASSERT(Condition) \
- enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __LINE__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
-#endif /* __COUNTER__ */
-#define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
-#endif
-
Q_NORETURN Q_CORE_EXPORT void qt_check_pointer(const char *, int) Q_DECL_NOTHROW;
+Q_DECL_COLD_FUNCTION
Q_CORE_EXPORT void qBadAlloc();
#ifdef QT_NO_EXCEPTIONS
@@ -913,13 +938,7 @@ QT_WARNING_DISABLE_MSVC(4514) /* unreferenced inline function has been removed *
QT_WARNING_DISABLE_MSVC(4800) /* 'type' : forcing value to bool 'true' or 'false' (performance warning) */
QT_WARNING_DISABLE_MSVC(4097) /* typedef-name 'identifier1' used as synonym for class-name 'identifier2' */
QT_WARNING_DISABLE_MSVC(4706) /* assignment within conditional expression */
-# if _MSC_VER <= 1310 // MSVC 2003
-QT_WARNING_DISABLE_MSVC(4786) /* 'identifier' : identifier was truncated to 'number' characters in the debug information */
-# endif
QT_WARNING_DISABLE_MSVC(4355) /* 'this' : used in base member initializer list */
-# if _MSC_VER < 1800 // MSVC 2013
-QT_WARNING_DISABLE_MSVC(4231) /* nonstandard extension used : 'identifier' before template explicit instantiation */
-# endif
QT_WARNING_DISABLE_MSVC(4710) /* function not inlined */
QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc */
# elif defined(Q_CC_BOR)
@@ -1126,13 +1145,9 @@ template <typename... Args> Q_CONSTEXPR Q_DECL_UNUSED QNonConstOverload<Args...>
class QByteArray;
Q_CORE_EXPORT QByteArray qgetenv(const char *varName);
-#ifdef Q_QDOC
-Q_CORE_EXPORT QString qEnvironmentVariable(const char *varName,
- const QString &defaultValue = QString());
-#else // need it as two functions because QString is only forward-declared here
+// need it as two functions because QString is only forward-declared here
Q_CORE_EXPORT QString qEnvironmentVariable(const char *varName);
Q_CORE_EXPORT QString qEnvironmentVariable(const char *varName, const QString &defaultValue);
-#endif
Q_CORE_EXPORT bool qputenv(const char *varName, const QByteArray& value);
Q_CORE_EXPORT bool qunsetenv(const char *varName);
diff --git a/src/corelib/global/qglobalstatic.qdoc b/src/corelib/global/qglobalstatic.qdoc
index 8c34739d38..63cc968d1c 100644
--- a/src/corelib/global/qglobalstatic.qdoc
+++ b/src/corelib/global/qglobalstatic.qdoc
@@ -368,7 +368,7 @@
*/
/*!
- \fn bool QGlobalStatic::isDestroyed() const
+ \fn template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard> bool QGlobalStatic<T, innerFunction, guard>::isDestroyed() const
This function returns \c true if the global static object has already
completed destruction (that is, if the destructor for the type has already
@@ -398,7 +398,7 @@
*/
/*!
- \fn bool QGlobalStatic::exists() const
+ \fn template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard> bool QGlobalStatic<T, innerFunction, guard>::exists() const
This function returns \c true if the global static object has already
completed initialization (that is, if the constructor for the type has
@@ -447,7 +447,7 @@
*/
/*!
- \fn QGlobalStatic::operator Type*()
+ \fn template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard> QGlobalStatic<T, innerFunction, guard>::operator Type*()
This function returns the address of the contents of this global static. If
the contents have not yet been created, they will be created thread-safely
@@ -480,7 +480,7 @@
*/
/*!
- \fn Type *QGlobalStatic::operator()()
+ \fn template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard> Type *QGlobalStatic<T, innerFunction, guard>::operator()()
\deprecated
This function returns the address of the contents of this global static. If
@@ -495,7 +495,7 @@
*/
/*!
- \fn Type *QGlobalStatic::operator->()
+ \fn template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard> Type *QGlobalStatic<T, innerFunction, guard>::operator->()
This function returns the address of the contents of this global static. If
the contents have not yet been created, they will be created thread-safely
@@ -508,7 +508,7 @@
*/
/*!
- \fn Type &QGlobalStatic::operator*()
+ \fn template <typename T, T *(&innerFunction)(), QBasicAtomicInt &guard> Type &QGlobalStatic<T, innerFunction, guard>::operator*()
This function returns a reference to the contents of this global static. If
the contents have not yet been created, they will be created thread-safely
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index b4ba0b5b2e..422d08f32c 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -318,15 +318,7 @@ QLibraryInfo::buildDate()
#elif defined(Q_CC_GNU)
# define COMPILER_STRING "GCC " __VERSION__
#elif defined(Q_CC_MSVC)
-# if _MSC_VER < 1600
-# define COMPILER_STRING "MSVC 2008"
-# elif _MSC_VER < 1700
-# define COMPILER_STRING "MSVC 2010"
-# elif _MSC_VER < 1800
-# define COMPILER_STRING "MSVC 2012"
-# elif _MSC_VER < 1900
-# define COMPILER_STRING "MSVC 2013"
-# elif _MSC_VER < 1910
+# if _MSC_VER < 1910
# define COMPILER_STRING "MSVC 2015"
# elif _MSC_VER < 2000
# define COMPILER_STRING "MSVC 2017"
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 6602d53b08..99c57c3b7a 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -41,6 +41,7 @@
#include "qglobal_p.h"
#include "qlogging.h"
+#include "qlogging_p.h"
#include "qlist.h"
#include "qbytearray.h"
#include "qstring.h"
@@ -61,13 +62,20 @@
#include <qt_windows.h>
#endif
#if QT_CONFIG(slog2)
-#include <slog2.h>
+#include <sys/slog2.h>
+#endif
+#if QT_HAS_INCLUDE(<paths.h>)
+#include <paths.h>
#endif
#ifdef Q_OS_ANDROID
#include <android/log.h>
#endif
+#ifdef Q_OS_DARWIN
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
#if QT_CONFIG(journald)
# define SD_JOURNAL_SUPPRESS_LOCATION
# include <systemd/sd-journal.h>
@@ -152,6 +160,7 @@ Q_NORETURN
#endif
static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message);
static void qt_message_print(QtMsgType, const QMessageLogContext &context, const QString &message);
+static void qt_message_print(const QString &message);
static int checked_var_value(const char *varname)
{
@@ -191,55 +200,107 @@ static bool isFatal(QtMsgType msgType)
return false;
}
-static bool willLogToConsole()
+static bool isDefaultCategory(const char *category)
+{
+ return !category || strcmp(category, "default") == 0;
+}
+
+/*!
+ Returns true if writing to \c stderr is supported.
+
+ \sa stderrHasConsoleAttached()
+*/
+static bool systemHasStderr()
{
#if defined(Q_OS_WINRT)
- // these systems have no stderr, so always log to the system log
- return false;
-#elif defined(QT_BOOTSTRAPPED)
+ return false; // WinRT has no stderr
+#endif
+
return true;
-#else
- // rules to determine if we'll log preferably to the console:
- // 1) if QT_LOGGING_TO_CONSOLE is set, it determines behavior:
- // - if it's set to 0, we will not log to console
- // - if it's set to 1, we will log to console
- // 2) otherwise, we will log to console if we have a console window (Windows)
- // or a controlling TTY (Unix). This is done even if stderr was redirected
- // to the blackhole device (NUL or /dev/null).
-
- bool ok = true;
- uint envcontrol = qgetenv("QT_LOGGING_TO_CONSOLE").toUInt(&ok);
- if (ok)
- return envcontrol;
-
-# ifdef Q_OS_WIN
- return GetConsoleWindow();
-# elif defined(Q_OS_UNIX)
- // if /dev/tty exists, we can only open it if we have a controlling TTY
- int devtty = qt_safe_open("/dev/tty", O_RDONLY);
- if (devtty == -1 && (errno == ENOENT || errno == EPERM || errno == ENXIO)) {
- // no /dev/tty, fall back to isatty on stderr
- return isatty(STDERR_FILENO);
- } else if (devtty != -1) {
- // there is a /dev/tty and we could open it: we have a controlling TTY
- qt_safe_close(devtty);
- return true;
- }
+}
- // no controlling TTY
- return false;
-# else
-# error "Not Unix and not Windows?"
-# endif
+/*!
+ Returns true if writing to \c stderr will end up in a console/terminal visible to the user.
+
+ This is typically the case if the application was started from the command line.
+
+ If the application is started without a controlling console/terminal, but the parent
+ process reads \c stderr and presents it to the user in some other way, the parent process
+ may override the detection in this function by setting the QT_ASSUME_STDERR_HAS_CONSOLE
+ environment variable to \c 1.
+
+ \note Qt Creator does not implement a pseudo TTY, nor does it launch apps with
+ the override environment variable set, but it will read stderr and print it to
+ the user, so in effect this function can not be used to conclude that stderr
+ output will _not_ be visible to the user, as even if this function returns false,
+ the output might still end up visible to the user. For this reason, we don't guard
+ the stderr output in the default message handler with stderrHasConsoleAttached().
+
+ \sa systemHasStderr()
+*/
+bool stderrHasConsoleAttached()
+{
+ static const bool stderrHasConsoleAttached = []() -> bool {
+ if (!systemHasStderr())
+ return false;
+
+ if (qEnvironmentVariableIntValue("QT_LOGGING_TO_CONSOLE")) {
+ fprintf(stderr, "warning: Environment variable QT_LOGGING_TO_CONSOLE is deprecated, use\n"
+ "QT_ASSUME_STDERR_HAS_CONSOLE and/or QT_FORCE_STDERR_LOGGING instead.\n");
+ return true;
+ }
+
+ if (qEnvironmentVariableIntValue("QT_ASSUME_STDERR_HAS_CONSOLE"))
+ return true;
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ return GetConsoleWindow();
+#elif defined(Q_OS_UNIX)
+# ifndef _PATH_TTY
+# define _PATH_TTY "/dev/tty"
+# endif
+
+ // If we can open /dev/tty, we have a controlling TTY
+ int ttyDevice = -1;
+ if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
+ qt_safe_close(ttyDevice);
+ return true;
+ } else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
+ // Fall back to isatty for some non-critical errors
+ return isatty(STDERR_FILENO);
+ } else {
+ return false;
+ }
+#else
+ return false; // No way to detect if stderr has a console attached
#endif
+ }();
+
+ return stderrHasConsoleAttached;
}
-Q_CORE_EXPORT bool qt_logging_to_console()
+
+namespace QtPrivate {
+
+/*!
+ Returns true if logging \c stderr should be ensured.
+
+ This is normally the case if \c stderr has a console attached, but may be overridden
+ by the user by setting the QT_FORCE_STDERR_LOGGING environment variable to \c 1.
+
+ \sa stderrHasConsoleAttached()
+*/
+bool shouldLogToStderr()
{
- static const bool logToConsole = willLogToConsole();
- return logToConsole;
+ static bool forceStderrLogging = qEnvironmentVariableIntValue("QT_FORCE_STDERR_LOGGING");
+ return forceStderrLogging || stderrHasConsoleAttached();
}
+
+} // QtPrivate
+
+using namespace QtPrivate;
+
/*!
\class QMessageLogContext
\inmodule QtCore
@@ -1203,20 +1264,10 @@ void QMessagePattern::setPattern(const QString &pattern)
error += QLatin1String("QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n");
else if (inIf)
error += QLatin1String("QT_MESSAGE_PATTERN: missing %{endif}\n");
- if (!error.isEmpty()) {
-#if defined(Q_OS_WINRT)
- OutputDebugString(reinterpret_cast<const wchar_t*>(error.utf16()));
- if (0)
-#elif defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB)
- if (!qt_logging_to_console()) {
- OutputDebugString(reinterpret_cast<const wchar_t*>(error.utf16()));
- } else
-#endif
- {
- fprintf(stderr, "%s", error.toLocal8Bit().constData());
- fflush(stderr);
- }
- }
+
+ if (!error.isEmpty())
+ qt_message_print(error);
+
literals = new const char*[literalsVar.size() + 1];
literals[literalsVar.size()] = 0;
memcpy(literals, literalsVar.constData(), literalsVar.size() * sizeof(const char*));
@@ -1244,7 +1295,7 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
static QRegularExpression rx(QStringLiteral("^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"),
QRegularExpression::OptimizeOnFirstUsageOption);
- QVarLengthArray<void*, 32> buffer(7 + frameCount);
+ QVarLengthArray<void*, 32> buffer(8 + frameCount);
int n = backtrace(buffer.data(), buffer.size());
if (n > 0) {
int numberPrinted = 0;
@@ -1306,57 +1357,6 @@ static QString formatBacktraceForLogMessage(const QMessagePattern::BacktracePara
}
#endif // QLOGGING_HAVE_BACKTRACE && !QT_BOOTSTRAPPED
-#if QT_CONFIG(slog2)
-#ifndef QT_LOG_CODE
-#define QT_LOG_CODE 9000
-#endif
-
-static void slog2_default_handler(QtMsgType msgType, const char *message)
-{
- if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
- slog2_buffer_set_config_t buffer_config;
- slog2_buffer_t buffer_handle;
-
- buffer_config.buffer_set_name = __progname;
- buffer_config.num_buffers = 1;
- buffer_config.verbosity_level = SLOG2_DEBUG1;
- buffer_config.buffer_config[0].buffer_name = "default";
- buffer_config.buffer_config[0].num_pages = 8;
-
- if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
- fprintf(stderr, "Error registering slogger2 buffer!\n");
- fprintf(stderr, "%s", message);
- fflush(stderr);
- return;
- }
-
- // Set as the default buffer
- slog2_set_default_buffer(buffer_handle);
- }
- int severity;
- //Determines the severity level
- switch (msgType) {
- case QtDebugMsg:
- severity = SLOG2_DEBUG1;
- break;
- case QtInfoMsg:
- severity = SLOG2_INFO;
- break;
- case QtWarningMsg:
- severity = SLOG2_NOTICE;
- break;
- case QtCriticalMsg:
- severity = SLOG2_WARNING;
- break;
- case QtFatalMsg:
- severity = SLOG2_ERROR;
- break;
- }
- //writes to the slog2 buffer
- slog2c(NULL, QT_LOG_CODE, severity, message);
-}
-#endif // slog2
-
Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
/*!
@@ -1474,7 +1474,7 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
}
#endif // !QT_BOOTSTRAPPED
} else if (token == ifCategoryTokenC) {
- if (!context.category || (strcmp(context.category, "default") == 0))
+ if (isDefaultCategory(context.category))
skip = true;
#define HANDLE_IF_TOKEN(LEVEL) \
} else if (token == if##LEVEL##TokenC) { \
@@ -1506,11 +1506,80 @@ static QBasicAtomicPointer<void (QtMsgType, const char*)> msgHandler = Q_BASIC_A
// pointer to QtMessageHandler debug handler (with context)
static QBasicAtomicPointer<void (QtMsgType, const QMessageLogContext &, const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(qDefaultMessageHandler);
+// ------------------------ Alternate logging sinks -------------------------
+
+#if defined(QT_BOOTSTRAPPED)
+ // Boostrapped tools always print to stderr, so no need for alternate sinks
+#else
+
+#if QT_CONFIG(slog2)
+#ifndef QT_LOG_CODE
+#define QT_LOG_CODE 9000
+#endif
+
+static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+{
+ if (shouldLogToStderr())
+ return false; // Leave logging up to stderr handler
+
+ QString formattedMessage = qFormatLogMessage(type, context, message);
+ formattedMessage.append(QLatin1Char('\n'));
+ if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
+ slog2_buffer_set_config_t buffer_config;
+ slog2_buffer_t buffer_handle;
+
+ buffer_config.buffer_set_name = __progname;
+ buffer_config.num_buffers = 1;
+ buffer_config.verbosity_level = SLOG2_DEBUG1;
+ buffer_config.buffer_config[0].buffer_name = "default";
+ buffer_config.buffer_config[0].num_pages = 8;
+
+ if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
+ fprintf(stderr, "Error registering slogger2 buffer!\n");
+ fprintf(stderr, "%s", formattedMessage.toLocal8Bit().constData());
+ fflush(stderr);
+ return false;
+ }
+
+ // Set as the default buffer
+ slog2_set_default_buffer(buffer_handle);
+ }
+ int severity;
+ //Determines the severity level
+ switch (type) {
+ case QtDebugMsg:
+ severity = SLOG2_DEBUG1;
+ break;
+ case QtInfoMsg:
+ severity = SLOG2_INFO;
+ break;
+ case QtWarningMsg:
+ severity = SLOG2_NOTICE;
+ break;
+ case QtCriticalMsg:
+ severity = SLOG2_WARNING;
+ break;
+ case QtFatalMsg:
+ severity = SLOG2_ERROR;
+ break;
+ }
+ //writes to the slog2 buffer
+ slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
+
+ return true; // Prevent further output to stderr
+}
+#endif // slog2
+
#if QT_CONFIG(journald)
-static void systemd_default_message_handler(QtMsgType type,
+static bool systemd_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
const QString &message)
{
+ if (shouldLogToStderr())
+ return false; // Leave logging up to stderr handler
+
+ QString formattedMessage = qFormatLogMessage(type, context, message);
+
int priority = LOG_INFO; // Informational
switch (type) {
case QtDebugMsg:
@@ -1530,19 +1599,26 @@ static void systemd_default_message_handler(QtMsgType type,
break;
}
- sd_journal_send("MESSAGE=%s", message.toUtf8().constData(),
+ sd_journal_send("MESSAGE=%s", formattedMessage.toUtf8().constData(),
"PRIORITY=%i", priority,
"CODE_FUNC=%s", context.function ? context.function : "unknown",
"CODE_LINE=%d", context.line,
"CODE_FILE=%s", context.file ? context.file : "unknown",
"QT_CATEGORY=%s", context.category ? context.category : "unknown",
NULL);
+
+ return true; // Prevent further output to stderr
}
#endif
#if QT_CONFIG(syslog)
-static void syslog_default_message_handler(QtMsgType type, const char *message)
+static bool syslog_default_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
+ if (shouldLogToStderr())
+ return false; // Leave logging up to stderr handler
+
+ QString formattedMessage = qFormatLogMessage(type, context, message);
+
int priority = LOG_INFO; // Informational
switch (type) {
case QtDebugMsg:
@@ -1562,15 +1638,22 @@ static void syslog_default_message_handler(QtMsgType type, const char *message)
break;
}
- syslog(priority, "%s", message);
+ syslog(priority, "%s", formattedMessage.toUtf8().constData());
+
+ return true; // Prevent further output to stderr
}
#endif
-#ifdef Q_OS_ANDROID
-static void android_default_message_handler(QtMsgType type,
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+static bool android_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
const QString &message)
{
+ if (shouldLogToStderr())
+ return false; // Leave logging up to stderr handler
+
+ QString formattedMessage = qFormatLogMessage(type, context, message);
+
android_LogPriority priority = ANDROID_LOG_DEBUG;
switch (type) {
case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break;
@@ -1582,50 +1665,81 @@ static void android_default_message_handler(QtMsgType type,
__android_log_print(priority, qPrintable(QCoreApplication::applicationName()),
"%s:%d (%s): %s\n", context.file, context.line,
- context.function, qPrintable(message));
+ context.function, qPrintable(formattedMessage));
+
+ return true; // Prevent further output to stderr
}
#endif //Q_OS_ANDROID
-/*!
- \internal
-*/
-static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context,
- const QString &buf)
+#ifdef Q_OS_WIN
+static bool win_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+{
+ if (shouldLogToStderr())
+ return false; // Leave logging up to stderr handler
+
+ QString formattedMessage = qFormatLogMessage(type, context, message);
+ formattedMessage.append(QLatin1Char('\n'));
+ OutputDebugString(reinterpret_cast<const wchar_t *>(formattedMessage.utf16()));
+
+ return true; // Prevent further output to stderr
+}
+#endif
+
+#endif // Bootstrap check
+
+// --------------------------------------------------------------------------
+
+static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
- QString logMessage = qFormatLogMessage(type, context, buf);
+ QString formattedMessage = qFormatLogMessage(type, context, message);
// print nothing if message pattern didn't apply / was empty.
// (still print empty lines, e.g. because message itself was empty)
- if (logMessage.isNull())
+ if (formattedMessage.isNull())
return;
- if (!qt_logging_to_console()) {
-#if defined(Q_OS_WIN)
- logMessage.append(QLatin1Char('\n'));
- OutputDebugString(reinterpret_cast<const wchar_t *>(logMessage.utf16()));
- return;
-#elif QT_CONFIG(slog2)
- logMessage.append(QLatin1Char('\n'));
- slog2_default_handler(type, logMessage.toLocal8Bit().constData());
- return;
-#elif QT_CONFIG(journald)
- systemd_default_message_handler(type, context, logMessage);
- return;
-#elif QT_CONFIG(syslog)
- syslog_default_message_handler(type, logMessage.toUtf8().constData());
- return;
-#elif defined(Q_OS_ANDROID)
- android_default_message_handler(type, context, logMessage);
- return;
-#endif
- }
- fprintf(stderr, "%s\n", logMessage.toLocal8Bit().constData());
+ fprintf(stderr, "%s\n", formattedMessage.toLocal8Bit().constData());
fflush(stderr);
}
/*!
\internal
*/
+static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context,
+ const QString &message)
+{
+ bool handledStderr = false;
+
+ // A message sink logs the message to a structured or unstructured destination,
+ // optionally formatting the message if the latter, and returns true if the sink
+ // handled stderr output as well, which will shortcut our default stderr output.
+ // In the future, if we allow multiple/dynamic sinks, this will be iterating
+ // a list of sinks.
+
+#if !defined(QT_BOOTSTRAPPED)
+# if defined(Q_OS_WIN)
+ handledStderr |= win_message_handler(type, context, message);
+# elif QT_CONFIG(slog2)
+ handledStderr |= slog2_default_handler(type, context, message);
+# elif QT_CONFIG(journald)
+ handledStderr |= systemd_default_message_handler(type, context, message);
+# elif QT_CONFIG(syslog)
+ handledStderr |= syslog_default_message_handler(type, context, message);
+# elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+ handledStderr |= android_default_message_handler(type, context, message);
+# elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
+ if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
+ handledStderr |= AppleUnifiedLogger::messageHandler(type, context, message);
+# endif
+#endif
+
+ if (!handledStderr)
+ stderr_message_handler(type, context, message);
+}
+
+/*!
+ \internal
+*/
static void qDefaultMsgHandler(QtMsgType type, const char *buf)
{
QMessageLogContext emptyContext;
@@ -1659,7 +1773,7 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
{
#ifndef QT_BOOTSTRAPPED
// qDebug, qWarning, ... macros do not check whether category is enabled
- if (!context.category || (strcmp(context.category, "default") == 0)) {
+ if (isDefaultCategory(context.category)) {
if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
if (!defaultCategory->isEnabled(msgType))
return;
@@ -1683,6 +1797,21 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
}
}
+static void qt_message_print(const QString &message)
+{
+#if defined(Q_OS_WINRT)
+ OutputDebugString(reinterpret_cast<const wchar_t*>(message.utf16()));
+ return;
+#elif defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
+ if (!shouldLogToStderr()) {
+ OutputDebugString(reinterpret_cast<const wchar_t*>(message.utf16()));
+ return;
+ }
+#endif
+ fprintf(stderr, "%s", message.toLocal8Bit().constData());
+ fflush(stderr);
+}
+
static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message)
{
#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
@@ -1880,6 +2009,10 @@ void qErrnoWarning(int code, const char *msg, ...)
environment variable; if both \l qSetMessagePattern() is called and QT_MESSAGE_PATTERN is
set, the environment variable takes precedence.
+ \note The message pattern only applies to unstructured logging, such as the default
+ \c stderr output. Structured logging such as systemd will record the message as is,
+ along with as much structured information as can be captured.
+
Custom message handlers can use qFormatLogMessage() to take \a pattern into account.
\sa qInstallMessageHandler(), {Debugging Techniques}, {QLoggingCategory}
diff --git a/src/corelib/global/qlogging.h b/src/corelib/global/qlogging.h
index 0c8d7dab38..16e01183bd 100644
--- a/src/corelib/global/qlogging.h
+++ b/src/corelib/global/qlogging.h
@@ -97,7 +97,9 @@ public:
void noDebug(const char *, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3)
{}
void info(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
+ Q_DECL_COLD_FUNCTION
void warning(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
+ Q_DECL_COLD_FUNCTION
void critical(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
typedef const QLoggingCategory &(*CategoryFunction)();
@@ -106,14 +108,19 @@ public:
void debug(CategoryFunction catFunc, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
void info(const QLoggingCategory &cat, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
void info(CategoryFunction catFunc, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
+ Q_DECL_COLD_FUNCTION
void warning(const QLoggingCategory &cat, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
+ Q_DECL_COLD_FUNCTION
void warning(CategoryFunction catFunc, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
+ Q_DECL_COLD_FUNCTION
void critical(const QLoggingCategory &cat, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
+ Q_DECL_COLD_FUNCTION
void critical(CategoryFunction catFunc, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
#ifndef Q_CC_MSVC
Q_NORETURN
#endif
+ Q_DECL_COLD_FUNCTION
void fatal(const char *msg, ...) const Q_DECL_NOTHROW Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
#ifndef QT_NO_DEBUG_STREAM
@@ -179,8 +186,8 @@ private:
Q_CORE_EXPORT void qt_message_output(QtMsgType, const QMessageLogContext &context,
const QString &message);
-Q_CORE_EXPORT void qErrnoWarning(int code, const char *msg, ...);
-Q_CORE_EXPORT void qErrnoWarning(const char *msg, ...);
+Q_CORE_EXPORT Q_DECL_COLD_FUNCTION void qErrnoWarning(int code, const char *msg, ...);
+Q_CORE_EXPORT Q_DECL_COLD_FUNCTION void qErrnoWarning(const char *msg, ...);
#if QT_DEPRECATED_SINCE(5, 0)// deprecated. Use qInstallMessageHandler instead!
typedef void (*QtMsgHandler)(QtMsgType, const char *);
diff --git a/src/corelib/global/qlogging_p.h b/src/corelib/global/qlogging_p.h
new file mode 100644
index 0000000000..3d0c097ffe
--- /dev/null
+++ b/src/corelib/global/qlogging_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** 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$
+**
+****************************************************************************/
+
+#ifndef QLOGGING_P_H
+#define QLOGGING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+Q_CORE_EXPORT bool shouldLogToStderr();
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QLOGGING_P_H
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index ab83730caa..31b1823690 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -243,7 +243,7 @@ public:
// size of a multi-variant string.
TextLongestVariant = 0x80000
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#if QT_DEPRECATED_SINCE(5, 11) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
, TextBypassShaping = 0x100000
#endif
};
@@ -477,6 +477,8 @@ public:
WA_TabletTracking = 129,
+ WA_ContentsMarginsRespectsSafeArea = 130,
+
// Add new attributes before this line
WA_AttributeCount
};
@@ -846,6 +848,36 @@ public:
Key_Dead_Belowdot = 0x01001260,
Key_Dead_Hook = 0x01001261,
Key_Dead_Horn = 0x01001262,
+ Key_Dead_Stroke = 0x01001263,
+ Key_Dead_Abovecomma = 0x01001264,
+ Key_Dead_Abovereversedcomma = 0x01001265,
+ Key_Dead_Doublegrave = 0x01001266,
+ Key_Dead_Belowring = 0x01001267,
+ Key_Dead_Belowmacron = 0x01001268,
+ Key_Dead_Belowcircumflex = 0x01001269,
+ Key_Dead_Belowtilde = 0x0100126a,
+ Key_Dead_Belowbreve = 0x0100126b,
+ Key_Dead_Belowdiaeresis = 0x0100126c,
+ Key_Dead_Invertedbreve = 0x0100126d,
+ Key_Dead_Belowcomma = 0x0100126e,
+ Key_Dead_Currency = 0x0100126f,
+ Key_Dead_a = 0x01001280,
+ Key_Dead_A = 0x01001281,
+ Key_Dead_e = 0x01001282,
+ Key_Dead_E = 0x01001283,
+ Key_Dead_i = 0x01001284,
+ Key_Dead_I = 0x01001285,
+ Key_Dead_o = 0x01001286,
+ Key_Dead_O = 0x01001287,
+ Key_Dead_u = 0x01001288,
+ Key_Dead_U = 0x01001289,
+ Key_Dead_Small_Schwa = 0x0100128a,
+ Key_Dead_Capital_Schwa = 0x0100128b,
+ Key_Dead_Greek = 0x0100128c,
+ Key_Dead_Lowline = 0x01001290,
+ Key_Dead_Aboveverticalline = 0x01001291,
+ Key_Dead_Belowverticalline = 0x01001292,
+ Key_Dead_Longsolidusoverlay = 0x01001293,
// multimedia/internet keys - ignored by default - see QKeyEvent c'tor
Key_Back = 0x01000061,
@@ -1374,6 +1406,9 @@ public:
ImhMultiLine = 0x400,
+ ImhNoEditMenu = 0x800,
+ ImhNoTextHandles = 0x1000,
+
ImhDigitsOnly = 0x10000,
ImhFormattedNumbersOnly = 0x20000,
ImhUppercaseOnly = 0x40000,
@@ -1829,6 +1864,16 @@ public:
static bool activateCallbacks(Callback, void **);
};
+#if defined(Q_CLANG_QDOC)
+// Declared here for qdoc; actual declarations in qtextdocument.h
+namespace Qt
+{
+ bool mightBeRichText(const QString&);
+ QString convertFromPlainText(const QString &plain, WhiteSpaceMode mode = WhiteSpacePre);
+ QTextCodec *codecForHtml(const QByteArray &ba);
+}
+#endif // Q_CLANG_QDOC
+
QT_END_NAMESPACE
#endif // QNAMESPACE_H
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index e64fb221d3..11c431d015 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -993,12 +993,7 @@
\value WA_LayoutUsesWidgetRect Ignore the layout item rect from the style
when laying out this widget with QLayout.
- \value WA_MacNoClickThrough When a widget that has this attribute set
- is clicked, and its window is inactive, the click will make the window
- active but won't be seen by the widget. Typical use of this attribute
- is on widgets with "destructive" actions, such as a "Delete" button.
- WA_MacNoClickThrough also applies to all child widgets of the widget
- that has it set.
+ \value WA_MacNoClickThrough This value is obsolete and has no effect.
\value WA_MacOpaqueSizeGrip Indicates that the native Carbon size grip
should be opaque instead of transparent (the default). This attribute
@@ -1027,9 +1022,7 @@
alternative sizes for widgets to avoid clipping.
This attribute is only applicable to \macos.
- \value WA_MacBrushedMetal Indicates the widget should be drawn in
- the brushed metal style as supported by the windowing system. This
- attribute is only applicable to \macos.
+ \value WA_MacBrushedMetal This value is obsolete and has no effect.
\omitvalue WA_MacMetalStyle
@@ -1284,9 +1277,7 @@
has no effect on non-X11 platforms. \b Note: Qt automatically sets this
attribute on the feedback widget used during a drag.
- \value WA_MacFrameworkScaled Enables resolution independence aware mode
- on Mac when using Carbon. This attribute has no effect on Cocoa.
- The attribute is off by default and can be enabled on a per-window basis.
+ \value WA_MacFrameworkScaled This value is obsolete and has no effect.
\value WA_AcceptTouchEvents Allows touch events (see QTouchEvent)
to be sent to the widget. Must be set on all widgets that can
@@ -1338,6 +1329,7 @@
\omitvalue WA_WState_WindowOpacitySet
\omitvalue WA_WState_AcceptedTouchBeginEvent
\omitvalue WA_MacNoShadow
+ \omitvalue WA_ContentsMarginsRespectsSafeArea
*/
/*! \typedef Qt::HANDLE
@@ -1613,6 +1605,36 @@
\value Key_Dead_Belowdot
\value Key_Dead_Hook
\value Key_Dead_Horn
+ \value Key_Dead_Stroke
+ \value Key_Dead_Abovecomma
+ \value Key_Dead_Abovereversedcomma
+ \value Key_Dead_Doublegrave
+ \value Key_Dead_Belowring
+ \value Key_Dead_Belowmacron
+ \value Key_Dead_Belowcircumflex
+ \value Key_Dead_Belowtilde
+ \value Key_Dead_Belowbreve
+ \value Key_Dead_Belowdiaeresis
+ \value Key_Dead_Invertedbreve
+ \value Key_Dead_Belowcomma
+ \value Key_Dead_Currency
+ \value Key_Dead_a
+ \value Key_Dead_A
+ \value Key_Dead_e
+ \value Key_Dead_E
+ \value Key_Dead_i
+ \value Key_Dead_I
+ \value Key_Dead_o
+ \value Key_Dead_O
+ \value Key_Dead_u
+ \value Key_Dead_U
+ \value Key_Dead_Small_Schwa
+ \value Key_Dead_Capital_Schwa
+ \value Key_Dead_Greek
+ \value Key_Dead_Lowline
+ \value Key_Dead_Aboveverticalline
+ \value Key_Dead_Belowverticalline
+ \value Key_Dead_Longsolidusoverlay
\value Key_Back
\value Key_Forward
\value Key_Stop
@@ -2129,7 +2151,7 @@
with a somewhat lighter frame. It can also be
combined with Qt::FramelessWindowHint.
On \macos, tool windows correspond to the
- \l{http://developer.apple.com/documentation/Carbon/Conceptual/HandlingWindowsControls/hitb-wind_cont_concept/chapter_2_section_2.html}{Floating}
+ \l{https://developer.apple.com/documentation/appkit/nspanel}{NSPanel}
class of windows. This means that the window lives on a
level above normal windows making it impossible to put a normal
window on top of it. By default, tool windows will disappear
@@ -2564,6 +2586,9 @@
\value ImhMultiLine Multiple lines can be entered into the text field.
+ \value ImhNoEditMenu Do not use built-in edit menu. This flag was introduced in Qt 5.11.
+ \value ImhNoTextHandles Do not use built-in text cursor and selection handles. This flag was introduced in Qt 5.11.
+
Flags that restrict input (exclusive flags):
\value ImhDigitsOnly Only digits are allowed.
@@ -3077,9 +3102,8 @@
it is displayed regardless of device type.
The keypad is used to implement a virtual cursor, unless
the device has an analog mouse type of input device (e.g. touchpad)
-
- \note In 4.6, cursor navigation is only implemented for Symbian OS.
- On other platforms, it behaves as NavigationModeNone.
+ \note Cursor navigation is not currently implemented on any platform
+ and behaves as NavigationModeNone.
\sa QApplication::setNavigationMode()
\sa QApplication::navigationMode()
*/
@@ -3192,3 +3216,37 @@
\value ChecksumItuV41 Checksum calculation based on ITU-V.41.
*/
+
+/*!
+ \fn bool Qt::mightBeRichText(const QString& text)
+
+ Returns \c true if the string \a text is likely to be rich text;
+ otherwise returns \c false.
+
+ This function uses a fast and therefore simple heuristic. It
+ mainly checks whether there is something that looks like a tag
+ before the first line break. Although the result may be correct
+ for common cases, there is no guarantee.
+
+ This function is defined in the \c <QTextDocument> header file.
+*/
+
+/*!
+ \fn QString Qt::convertFromPlainText(const QString &plain, Qt::WhiteSpaceMode mode)
+
+ Converts the plain text string \a plain to an HTML-formatted
+ paragraph while preserving most of its look.
+
+ \a mode defines how whitespace is handled.
+
+ This function is defined in the \c <QTextDocument> header file.
+
+ \sa escape(), mightBeRichText()
+*/
+
+/*!
+ \fn QTextCodec *Qt::codecForHtml(const QByteArray &ba)
+ \internal
+
+ This function is defined in the \c <QTextDocument> header file.
+*/
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 37eddfa9b5..5f8a124bcc 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -58,8 +58,6 @@
#if defined(Q_CC_MSVC)
# include <intrin.h>
-#elif defined(Q_CC_INTEL)
-# include <immintrin.h> // for _addcarry_u<nn>
#endif
#if defined(Q_CC_MSVC)
@@ -163,10 +161,34 @@ Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f)
return qnumeric_std_wrapper::isfinite(f);
}
-//
-// Unsigned overflow math
-//
+#ifndef Q_CLANG_QDOC
namespace {
+// Overflow math.
+// This provides efficient implementations for int, unsigned, qsizetype and
+// size_t. Implementations for 8- and 16-bit types will work but may not be as
+// efficient. Implementations for 64-bit may be missing on 32-bit platforms.
+
+#if (defined(Q_CC_GNU) && (Q_CC_GNU >= 500) || (defined(Q_CC_INTEL) && !defined(Q_OS_WIN))) || QT_HAS_BUILTIN(__builtin_add_overflowx)
+// GCC 5, ICC 18, and Clang 3.8 have builtins to detect overflows
+
+template <typename T> inline
+typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
+add_overflow(T v1, T v2, T *r)
+{ return __builtin_add_overflow(v1, v2, r); }
+
+template <typename T> inline
+typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
+sub_overflow(T v1, T v2, T *r)
+{ return __builtin_sub_overflow(v1, v2, r); }
+
+template <typename T> inline
+typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
+mul_overflow(T v1, T v2, T *r)
+{ return __builtin_mul_overflow(v1, v2, r); }
+
+#else
+// Generic implementations
+
template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
add_overflow(T v1, T v2, T *r)
{
@@ -175,69 +197,92 @@ add_overflow(T v1, T v2, T *r)
return v1 > T(v1 + v2);
}
+template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type
+add_overflow(T v1, T v2, T *r)
+{
+ // Here's how we calculate the overflow:
+ // 1) unsigned addition is well-defined, so we can always execute it
+ // 2) conversion from unsigned back to signed is implementation-
+ // defined and in the implementations we use, it's a no-op.
+ // 3) signed integer overflow happens if the sign of the two input operands
+ // is the same but the sign of the result is different. In other words,
+ // the sign of the result must be the same as the sign of either
+ // operand.
+
+ using U = typename std::make_unsigned<T>::type;
+ *r = T(U(v1) + U(v2));
+
+ // If int is two's complement, assume all integer types are too.
+ if (std::is_same<int32_t, int>::value) {
+ // Two's complement equivalent (generates slightly shorter code):
+ // x ^ y is negative if x and y have different signs
+ // x & y is negative if x and y are negative
+ // (x ^ z) & (y ^ z) is negative if x and z have different signs
+ // AND y and z have different signs
+ return ((v1 ^ *r) & (v2 ^ *r)) < 0;
+ }
+
+ bool s1 = (v1 < 0);
+ bool s2 = (v2 < 0);
+ bool sr = (*r < 0);
+ return s1 != sr && s2 != sr;
+ // also: return s1 == s2 && s1 != sr;
+}
+
template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+sub_overflow(T v1, T v2, T *r)
+{
+ // unsigned subtractions are well-defined
+ *r = v1 - v2;
+ return v1 < v2;
+}
+
+template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type
+sub_overflow(T v1, T v2, T *r)
+{
+ // See above for explanation. This is the same with some signs reversed.
+ // We can't use add_overflow(v1, -v2, r) because it would be UB if
+ // v2 == std::numeric_limits<T>::min().
+
+ using U = typename std::make_unsigned<T>::type;
+ *r = T(U(v1) - U(v2));
+
+ if (std::is_same<int32_t, int>::value)
+ return ((v1 ^ *r) & (~v2 ^ *r)) < 0;
+
+ bool s1 = (v1 < 0);
+ bool s2 = !(v2 < 0);
+ bool sr = (*r < 0);
+ return s1 != sr && s2 != sr;
+ // also: return s1 == s2 && s1 != sr;
+}
+
+template <typename T> inline
+typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
mul_overflow(T v1, T v2, T *r)
{
// use the next biggest type
// Note: for 64-bit systems where __int128 isn't supported, this will cause an error.
- // A fallback is present below.
- typedef typename QIntegerForSize<sizeof(T) * 2>::Unsigned Larger;
+ using LargerInt = QIntegerForSize<sizeof(T) * 2>;
+ using Larger = typename std::conditional<std::is_signed<T>::value,
+ typename LargerInt::Signed, typename LargerInt::Unsigned>::type;
Larger lr = Larger(v1) * Larger(v2);
*r = T(lr);
- return lr > std::numeric_limits<T>::max();
+ return lr > std::numeric_limits<T>::max() || lr < std::numeric_limits<T>::min();
}
-#if defined(__SIZEOF_INT128__)
-# define HAVE_MUL64_OVERFLOW
-#endif
-
-// GCC 5 and Clang have builtins to detect overflows
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_uadd_overflow)
+# if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
+// We can use intrinsics for the unsigned operations with MSVC
template <> inline bool add_overflow(unsigned v1, unsigned v2, unsigned *r)
-{ return __builtin_uadd_overflow(v1, v2, r); }
-#endif
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_uaddl_overflow)
-template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
-{ return __builtin_uaddl_overflow(v1, v2, r); }
-#endif
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_uaddll_overflow)
-template <> inline bool add_overflow(unsigned long long v1, unsigned long long v2, unsigned long long *r)
-{ return __builtin_uaddll_overflow(v1, v2, r); }
-#endif
+{ return _addcarry_u32(0, v1, v2, r); }
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_umul_overflow)
-template <> inline bool mul_overflow(unsigned v1, unsigned v2, unsigned *r)
-{ return __builtin_umul_overflow(v1, v2, r); }
-#endif
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_umull_overflow)
-template <> inline bool mul_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
-{ return __builtin_umull_overflow(v1, v2, r); }
-#endif
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_umulll_overflow)
-template <> inline bool mul_overflow(unsigned long long v1, unsigned long long v2, unsigned long long *r)
-{ return __builtin_umulll_overflow(v1, v2, r); }
-# define HAVE_MUL64_OVERFLOW
-#endif
+// 32-bit mul_overflow is fine with the generic code above
-#if ((defined(Q_CC_MSVC) && _MSC_VER >= 1800) || defined(Q_CC_INTEL)) && defined(Q_PROCESSOR_X86) && !QT_HAS_BUILTIN(__builtin_uadd_overflow)
-template <> inline bool add_overflow(unsigned v1, unsigned v2, unsigned *r)
-{ return _addcarry_u32(0, v1, v2, r); }
-# ifdef Q_CC_MSVC // longs are 32-bit
-template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
-{ return _addcarry_u32(0, v1, v2, reinterpret_cast<unsigned *>(r)); }
-# endif
-#endif
-#if ((defined(Q_CC_MSVC) && _MSC_VER >= 1800) || defined(Q_CC_INTEL)) && defined(Q_PROCESSOR_X86_64) && !QT_HAS_BUILTIN(__builtin_uadd_overflow)
+# if defined(Q_PROCESSOR_X86_64)
template <> inline bool add_overflow(quint64 v1, quint64 v2, quint64 *r)
{ return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r)); }
-# ifndef Q_CC_MSVC // longs are 64-bit
-template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
-{ return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r)); }
-# endif
-#endif
-#if defined(Q_CC_MSVC) && (defined(Q_PROCESSOR_X86_64) || defined(Q_PROCESSOR_IA64)) && !QT_HAS_BUILTIN(__builtin_uadd_overflow)
-#pragma intrinsic(_umul128)
+# pragma intrinsic(_umul128)
template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r)
{
// use 128-bit multiplication with the _umul128 intrinsic
@@ -246,117 +291,30 @@ template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r)
*r = _umul128(v1, v2, &high);
return high;
}
-# define HAVE_MUL64_OVERFLOW
-#endif
-
-#if !defined(HAVE_MUL64_OVERFLOW) && defined(__LP64__)
-// no 128-bit multiplication, we need to figure out with a slow division
-template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r)
-{
- if (v2 && v1 > std::numeric_limits<quint64>::max() / v2)
- return true;
- *r = v1 * v2;
- return false;
-}
-template <> inline bool mul_overflow(unsigned long v1, unsigned long v2, unsigned long *r)
-{
- return mul_overflow<quint64>(v1, v2, reinterpret_cast<quint64 *>(r));
-}
-#else
-# undef HAVE_MUL64_OVERFLOW
-#endif
-
-//
-// Signed overflow math
-//
-// In C++, signed overflow math is Undefined Behavior. However, many CPUs do implement some way to
-// check for overflow. Some compilers expose intrinsics to use this functionality. If the no
-// intrinsic is exposed, overflow checking can be done by widening the result type and "manually"
-// checking for overflow. Or, alternatively, by using inline assembly to use the CPU features.
-//
-// Only int overflow checking is implemented, because it's the only one used.
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_sadd_overflow)
-inline bool add_overflow(int v1, int v2, int *r)
-{ return __builtin_sadd_overflow(v1, v2, r); }
-#elif defined(Q_CC_GNU) && defined(Q_PROCESSOR_X86)
-inline bool add_overflow(int v1, int v2, int *r)
-{
- quint8 overflow = 0;
- int res = v1;
-
- asm ("addl %2, %1\n"
- "seto %0"
- : "=q" (overflow), "=r" (res)
- : "r" (v2), "1" (res)
- : "cc"
- );
- *r = res;
- return overflow;
-}
-#else
-inline bool add_overflow(int v1, int v2, int *r)
-{
- qint64 t = qint64(v1) + v2;
- *r = static_cast<int>(t);
- return t > std::numeric_limits<int>::max() || t < std::numeric_limits<int>::min();
-}
-#endif
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_ssub_overflow)
-inline bool sub_overflow(int v1, int v2, int *r)
-{ return __builtin_ssub_overflow(v1, v2, r); }
-#elif defined(Q_CC_GNU) && defined(Q_PROCESSOR_X86)
-inline bool sub_overflow(int v1, int v2, int *r)
+# pragma intrinsic(_mul128)
+template <> inline bool mul_overflow(qint64 v1, qint64 v2, qint64 *r)
{
- quint8 overflow = 0;
- int res = v1;
-
- asm ("subl %2, %1\n"
- "seto %0"
- : "=q" (overflow), "=r" (res)
- : "r" (v2), "1" (res)
- : "cc"
- );
- *r = res;
- return overflow;
+ // Use 128-bit multiplication with the _mul128 intrinsic
+ // https://msdn.microsoft.com/en-us/library/82cxdw50.aspx
+
+ // This is slightly more complex than the unsigned case above: the sign bit
+ // of 'low' must be replicated as the entire 'high', so the only valid
+ // values for 'high' are 0 and -1.
+
+ qint64 high;
+ *r = _mul128(v1, v2, &high);
+ if (high == 0)
+ return *r < 0;
+ if (high == -1)
+ return *r >= 0;
+ return true;
}
-#else
-inline bool sub_overflow(int v1, int v2, int *r)
-{
- qint64 t = qint64(v1) - v2;
- *r = static_cast<int>(t);
- return t > std::numeric_limits<int>::max() || t < std::numeric_limits<int>::min();
-}
-#endif
-
-#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_smul_overflow)
-inline bool mul_overflow(int v1, int v2, int *r)
-{ return __builtin_smul_overflow(v1, v2, r); }
-#elif defined(Q_CC_GNU) && defined(Q_PROCESSOR_X86)
-inline bool mul_overflow(int v1, int v2, int *r)
-{
- quint8 overflow = 0;
- int res = v1;
-
- asm ("imul %2, %1\n"
- "seto %0"
- : "=q" (overflow), "=r" (res)
- : "r" (v2), "1" (res)
- : "cc"
- );
- *r = res;
- return overflow;
-}
-#else
-inline bool mul_overflow(int v1, int v2, int *r)
-{
- qint64 t = qint64(v1) * v2;
- *r = static_cast<int>(t);
- return t > std::numeric_limits<int>::max() || t < std::numeric_limits<int>::min();
-}
-#endif
-
+# endif // x86-64
+# endif // MSVC x86
+#endif // !GCC
}
+#endif // Q_CLANG_QDOC
QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index 682c9bab61..4d267e328d 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -45,7 +45,7 @@
#include <qversionnumber.h>
#include <qdebug.h>
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#include <private/qjni_p.h>
#endif
@@ -163,7 +163,7 @@ QOperatingSystemVersion QOperatingSystemVersion::current()
{
QOperatingSystemVersion version;
version.m_os = currentType();
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#ifndef QT_BOOTSTRAPPED
const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField(
"android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString());
diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp
index 060ca2f7da..f3662ae1f9 100644
--- a/src/corelib/global/qoperatingsystemversion_win.cpp
+++ b/src/corelib/global/qoperatingsystemversion_win.cpp
@@ -37,7 +37,10 @@
**
****************************************************************************/
+#include "qoperatingsystemversion_win_p.h"
+
#include "qoperatingsystemversion_p.h"
+
#include <qt_windows.h>
#include <qbytearray.h>
diff --git a/src/corelib/global/qoperatingsystemversion_win_p.h b/src/corelib/global/qoperatingsystemversion_win_p.h
new file mode 100644
index 0000000000..446bd286fc
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_win_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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$
+**
+****************************************************************************/
+
+#ifndef QOPERATINGSYSTEMVERSION_WIN_P_H
+#define QOPERATINGSYSTEMVERSION_WIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+OSVERSIONINFOEX qWindowsVersionInfo();
+
+QT_END_NAMESPACE
+
+#endif // QOPERATINGSYSTEMVERSION_WIN_P_H
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index d77ec8075a..9143e04d45 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -43,10 +43,8 @@
#include "qrandom.h"
#include "qrandom_p.h"
#include <qobjectdefs.h>
+#include <qmutex.h>
#include <qthreadstorage.h>
-#include <private/qsimd_p.h>
-
-#include <random>
#include <errno.h>
@@ -76,7 +74,7 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
}
#endif
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
# include <private/qjni_p.h>
#endif
@@ -86,6 +84,7 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
#undef Q_ASSERT_X
#undef Q_ASSERT
#define Q_ASSERT(cond) assert(cond)
+#define Q_ASSERT_X(cond, x, msg) assert(cond && msg)
#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
# define NDEBUG 1
#endif
@@ -94,7 +93,7 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
QT_BEGIN_NAMESPACE
#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
-static qssize_t qt_random_cpu(void *buffer, qssize_t count) Q_DECL_NOTHROW;
+static qsizetype qt_random_cpu(void *buffer, qsizetype count) Q_DECL_NOTHROW;
# ifdef Q_PROCESSOR_X86_64
# define _rdrandXX_step _rdrand64_step
@@ -102,7 +101,7 @@ static qssize_t qt_random_cpu(void *buffer, qssize_t count) Q_DECL_NOTHROW;
# define _rdrandXX_step _rdrand32_step
# endif
-static QT_FUNCTION_TARGET(RDRND) qssize_t qt_random_cpu(void *buffer, qssize_t count) Q_DECL_NOTHROW
+static QT_FUNCTION_TARGET(RDRND) qsizetype qt_random_cpu(void *buffer, qsizetype count) Q_DECL_NOTHROW
{
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
unsigned *end = ptr + count;
@@ -122,18 +121,25 @@ static QT_FUNCTION_TARGET(RDRND) qssize_t qt_random_cpu(void *buffer, qssize_t c
out:
return ptr - reinterpret_cast<unsigned *>(buffer);
}
+#else
+static qsizetype qt_random_cpu(void *, qsizetype)
+{
+ return 0;
+}
#endif
-namespace {
-#if QT_CONFIG(getentropy)
-class SystemRandom
+enum {
+ // may be "overridden" by a member enum
+ FillBufferNoexcept = true
+};
+
+struct QRandomGenerator::SystemGenerator
{
-public:
- enum { EfficientBufferFill = true };
- static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
+#if QT_CONFIG(getentropy)
+ static qsizetype fillBuffer(void *buffer, qsizetype count) Q_DECL_NOTHROW
{
// getentropy can read at most 256 bytes, so break the reading
- qssize_t read = 0;
+ qsizetype read = 0;
while (count - read > 256) {
// getentropy can't fail under normal circumstances
int ret = getentropy(reinterpret_cast<uchar *>(buffer) + read, 256);
@@ -147,96 +153,97 @@ public:
Q_UNUSED(ret);
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);
+ enum { FillBufferNoexcept = false };
-SystemRandom::~SystemRandom()
-{
- int fd = s_fdp1.loadAcquire() - 1;
- if (fd >= 0)
- qt_safe_close(fd);
-}
+ QBasicAtomicInt fdp1; // "file descriptor plus 1"
+ int openDevice()
+ {
+ int fd = 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 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 (fdp1.testAndSetOrdered(0, fd + 1, opened_fdp1))
+ return fd;
+
+ // failed, another thread has opened the file descriptor
+ if (fd >= 0)
+ qt_safe_close(fd);
+ return opened_fdp1 - 1;
}
- int opened_fdp1;
- if (s_fdp1.testAndSetOrdered(0, fd + 1, opened_fdp1)) {
- if (fd >= 0) {
- static const SystemRandom closer;
- Q_UNUSED(closer);
- }
- return fd;
+#ifdef Q_CC_GNU
+ // If it's not GCC or GCC-like, then we'll leak the file descriptor
+ __attribute__((destructor))
+#endif
+ static void closeDevice()
+ {
+ int fd = self().fdp1.load() - 1;
+ if (fd >= 0)
+ qt_safe_close(fd);
}
- // failed, another thread has opened the file descriptor
- if (fd >= 0)
- qt_safe_close(fd);
- return opened_fdp1 - 1;
-}
+ Q_DECL_CONSTEXPR SystemGenerator() : fdp1 Q_BASIC_ATOMIC_INITIALIZER(0) {}
-qssize_t SystemRandom::fillBuffer(void *buffer, qssize_t count)
-{
- int fd = openDevice();
- if (Q_UNLIKELY(fd < 0))
- return 0;
+ qsizetype fillBuffer(void *buffer, qsizetype 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
+ qint64 n = qt_safe_read(fd, buffer, count);
+ return qMax<qsizetype>(n, 0); // ignore any errors
+ }
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
-class SystemRandom
-{
-public:
- enum { EfficientBufferFill = true };
- static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW
+#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ qsizetype fillBuffer(void *buffer, qsizetype count) Q_DECL_NOTHROW
{
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) Q_DECL_NOTHROW
+ qsizetype fillBuffer(void *, qsizetype) Q_DECL_NOTHROW
{
// always use the fallback
return 0;
}
-};
#endif // Q_OS_WINRT
-} // unnamed namespace
+
+ static SystemGenerator &self();
+ void generate(quint32 *begin, quint32 *end) Q_DECL_NOEXCEPT_EXPR(FillBufferNoexcept);
+
+ // For std::mersenne_twister_engine implementations that use something
+ // other than quint32 (unsigned int) to fill their buffers.
+ template <typename T> void generate(T *begin, T *end)
+ {
+ Q_STATIC_ASSERT(sizeof(T) >= sizeof(quint32));
+ if (sizeof(T) == sizeof(quint32)) {
+ // Microsoft Visual Studio uses unsigned long, but that's still 32-bit
+ generate(reinterpret_cast<quint32 *>(begin), reinterpret_cast<quint32 *>(end));
+ } else {
+ // Slow path. Fix your C++ library.
+ std::generate(begin, end, [this]() {
+ quint32 datum;
+ generate(&datum, &datum + 1);
+ return datum;
+ });
+ }
+ }
+};
#if defined(Q_OS_WIN)
static void fallback_update_seed(unsigned) {}
-static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
+static void fallback_fill(quint32 *ptr, qsizetype left) Q_DECL_NOTHROW
{
// on Windows, rand_s is a high-quality random number generator
// and it requires no seeding
@@ -248,13 +255,14 @@ static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
}
#elif QT_CONFIG(getentropy)
static void fallback_update_seed(unsigned) {}
-static void fallback_fill(quint32 *, qssize_t) Q_DECL_NOTHROW
+static void fallback_fill(quint32 *, qsizetype) Q_DECL_NOTHROW
{
// no fallback necessary, getentropy cannot fail under normal circumstances
+ Q_UNREACHABLE();
}
#elif defined(Q_OS_BSD4)
static void fallback_update_seed(unsigned) {}
-static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
+static void fallback_fill(quint32 *ptr, qsizetype left) Q_DECL_NOTHROW
{
// BSDs have arc4random(4) and these work even in chroot(2)
arc4random_buf(ptr, left * sizeof(*ptr));
@@ -273,7 +281,7 @@ 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
+static void fallback_fill(quint32 *ptr, qsizetype left) Q_DECL_NOTHROW
{
quint32 scratch[12]; // see element count below
quint32 *end = scratch;
@@ -346,32 +354,26 @@ static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
}
#endif
-static qssize_t fill_cpu(quint32 *buffer, qssize_t count) Q_DECL_NOTHROW
+Q_NEVER_INLINE void QRandomGenerator::SystemGenerator::generate(quint32 *begin, quint32 *end)
+ Q_DECL_NOEXCEPT_EXPR(FillBufferNoexcept)
{
-#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;
-}
+ quint32 *buffer = begin;
+ qsizetype count = end - begin;
-static void fill_internal(quint32 *buffer, qssize_t count)
- Q_DECL_NOEXCEPT_EXPR(noexcept(SystemRandom::fillBuffer(buffer, 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);
+ qsizetype filled = 0;
+ if (qt_has_hwrng() && (uint(qt_randomdevice_control) & SkipHWRNG) == 0)
+ filled += qt_random_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));
+ qsizetype bytesFilled =
+ fillBuffer(buffer + filled, (count - filled) * qsizetype(sizeof(*buffer)));
+ filled += bytesFilled / qsizetype(sizeof(*buffer));
}
if (filled)
fallback_update_seed(*buffer);
@@ -382,147 +384,262 @@ static void fill_internal(quint32 *buffer, qssize_t count)
}
}
-static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
- Q_DECL_NOEXCEPT_EXPR(noexcept(fill_internal(static_cast<quint32 *>(buffer), 1)))
+struct QRandomGenerator::SystemAndGlobalGenerators
{
- 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);
+ // Construction notes:
+ // 1) The global PRNG state is in a different cacheline compared to the
+ // mutex that protects it. This avoids any false cacheline sharing of
+ // the state in case another thread tries to lock the mutex. It's not
+ // a common scenario, but since sizeof(QRandomGenerator) >= 2560, the
+ // overhead is actually acceptable.
+ // 2) We use both Q_DECL_ALIGN and std::aligned_storage<..., 64> because
+ // some implementations of std::aligned_storage can't align to more
+ // than a primitive type's alignment.
+ // 3) We don't store the entire system QRandomGenerator, only the space
+ // used by the QRandomGenerator::type member. This is fine because we
+ // (ab)use the common initial sequence exclusion to aliasing rules.
+ QBasicMutex globalPRNGMutex;
+ struct ShortenedSystem { uint type; } system_;
+ SystemGenerator sys;
+ Q_DECL_ALIGN(64) std::aligned_storage<sizeof(QRandomGenerator64), 64>::type global_;
+
+#ifdef Q_COMPILER_CONSTEXPR
+ constexpr SystemAndGlobalGenerators()
+ : globalPRNGMutex{}, system_{0}, sys{}, global_{}
+ {}
+#endif
- quint32 *ptr = reinterpret_cast<quint32 *>(buffer);
- quint32 * const end = reinterpret_cast<quint32 *>(bufferEnd);
+ void confirmLiteral()
+ {
+#if defined(Q_COMPILER_CONSTEXPR) && !defined(Q_CC_MSVC) && !defined(Q_OS_INTEGRITY)
+ // Currently fails to compile with MSVC 2017, saying QBasicMutex is not
+ // a literal type. Disassembly with MSVC 2013 and 2015 shows it is
+ // actually a literal; MSVC 2017 has a bug relating to this, so we're
+ // withhold judgement for now. Integrity's compiler is unable to
+ // guarantee g's alignment for some reason.
+
+ constexpr SystemAndGlobalGenerators g = {};
+ Q_UNUSED(g);
+ Q_STATIC_ASSERT(std::is_literal_type<SystemAndGlobalGenerators>::value);
+#endif
+ }
-#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;
+ static SystemAndGlobalGenerators *self()
+ {
+ static SystemAndGlobalGenerators g;
+ Q_STATIC_ASSERT(sizeof(g) > sizeof(QRandomGenerator64));
+ return &g;
+ }
- // 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;
+ static QRandomGenerator64 *system()
+ {
+ // Though we never call the constructor, the system QRandomGenerator is
+ // properly initialized by the zero initialization performed in self().
+ // Though QRandomGenerator is has non-vacuous initialization, we
+ // consider it initialized because of the common initial sequence.
+ return reinterpret_cast<QRandomGenerator64 *>(&self()->system_);
+ }
- if (ptr != end) {
- // refill the buffer and try again
- fill_internal(state.buffer, ThreadState::BufferCount);
- state.idx = 0;
+ static QRandomGenerator64 *globalNoInit()
+ {
+ // This function returns the pointer to the global QRandomGenerator,
+ // but does not initialize it. Only call it directly if you meant to do
+ // a pointer comparison.
+ return reinterpret_cast<QRandomGenerator64 *>(&self()->global_);
+ }
- itemsToCopy = end - ptr;
- memcpy(ptr, state.buffer + state.idx, size_t(itemsToCopy) * sizeof(*ptr));
- ptr = end;
- }
+ static void securelySeed(QRandomGenerator *rng)
+ {
+ // force reconstruction, just to be pedantic
+ new (rng) QRandomGenerator{System{}};
- // 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;
+ rng->type = MersenneTwister;
+ new (&rng->storage.engine()) RandomEngine(self()->sys);
}
-#endif // Q_COMPILER_THREAD_LOCAL && !QT_BOOTSTRAPPED
- if (ptr != end) {
- // fill directly in the user buffer
- fill_internal(ptr, end - ptr);
- }
+ struct PRNGLocker {
+ const bool locked;
+ PRNGLocker(const QRandomGenerator *that)
+ : locked(that == globalNoInit())
+ {
+ if (locked)
+ self()->globalPRNGMutex.lock();
+ }
+ ~PRNGLocker()
+ {
+ if (locked)
+ self()->globalPRNGMutex.unlock();
+ }
+ };
+};
+
+inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::self()
+{
+ return SystemAndGlobalGenerators::self()->sys;
}
/*!
\class QRandomGenerator
\inmodule QtCore
+ \reentrant
\since 5.10
\brief The QRandomGenerator class allows one to obtain random values from a
- high-quality, seed-less Random Number Generator.
+ high-quality 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.
+ random number generator. Like the C++ random engines, QRandomGenerator can
+ be seeded with user-provided values through the constructor.
+ When seeded, the sequence of numbers generated by this
+ class is deterministic. That is to say, given the same seed data,
+ QRandomGenerator will generate the same sequence of numbers. But given
+ different seeds, the results should be considerably different.
+
+ QRandomGenerator::securelySeeded() can be used to create a QRandomGenerator
+ that is securely seeded with QRandomGenerator::system(), meaning that the
+ sequence of numbers it generates cannot be easily predicted. Additionally,
+ QRandomGenerator::global() returns a global instance of QRandomGenerator
+ that Qt will ensure to be securely seeded. This object is thread-safe, may
+ be shared for most uses, and is always seeded from
+ QRandomGenerator::system()
+
+ QRandomGenerator::system() may be used to access the system's
+ cryptographically-safe random generator. On Unix systems, it's equivalent
+ to reading from \c {/dev/urandom} or the \c {getrandom()} or \c
+ {getentropy()} system calls.
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(),
generate64() or fillRange() functions. One would use it as:
\code
- quint32 value = QRandomGenerator::generate();
+ quint32 value = QRandomGenerator::global()->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.
+
+ \section1 Seeding and determinism
+
+ QRandomGenerator may be seeded with specific seed data. When that is done,
+ the numbers generated by the object will always be the same, as in the
+ following example:
+
+ \code
+ QRandomGenerator prng1(1234), prng2(1234);
+ Q_ASSERT(prng1.generate32() == prng2.generate32());
+ Q_ASSERT(prng1.generate64() == prng2.generate64());
\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.
+ The seed data takes the form of one or more 32-bit words. The ideal seed
+ size is approximately equal to the size of the QRandomGenerator class
+ itself. Due to mixing of the seed data, QRandomGenerator cannot guarantee
+ that distinct seeds will produce different sequences.
- \warning This class is not suitable for bulk data creation. See below for the
- technical reasons.
+ QRandomGenerator::global(), like all generators created by
+ QRandomGenerator::securelySeeded(), is always seeded from
+ QRandomGenerator::system(), so it's not possible to make it produce
+ identical sequences.
- \section1 Frequency and entropy exhaustion
+ \section1 Bulk data
- 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.
+ When operating in deterministic mode, QRandomGenerator may be used for bulk
+ data generation. In fact, applications that do not need
+ cryptographically-secure or true random data are advised to use a regular
+ QRandomGenerator instead of QRandomGenerator::system() for their random
+ data needs.
+
+ For ease of use, QRandomGenerator provides a global object that can
+ be easily used, as in the following example:
+
+ \code
+ int x = QRandomGenerator::global()->generate32();
+ int y = QRandomGenerator::global()->generate32();
+ int w = QRandomGenerator::global()->bounded(16384);
+ int h = QRandomGenerator::global()->bounded(16384);
+ \endcode
+
+ \section1 System-wide random number generator
+
+ QRandomGenerator::system() may be used to access the system-wide random
+ number generator, which is cryptographically-safe on all systems that Qt
+ runs on. This function will use hardware facilities to generate random
+ numbers where available. On such systems, those facilities are true Random
+ Number Generators. However, if they are true RNGs, those facilities have
+ finite entropy sources and thus may fail to produce any results if their
+ 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).
+ fallback generator being the simplest). Whether those generators are still
+ of cryptographic quality is implementation-defined. Therefore,
+ QRandomGenerator::system() 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.
+ system facilities (such as \c{/dev/random} on Linux) directly and wait for
+ entropy to become available. If the application requires PRNG engines of
+ cryptographic quality but not of true randomness,
+ QRandomGenerator::system() may still be used (see section below).
+
+ If neither a true RNG nor a cryptographically secure PRNG are required,
+ applications should instead use PRNG engines like QRandomGenerator's
+ deterministic mode and those from the C++ Standard Library.
+ QRandomGenerator::system() can be used to seed those.
+
+ \section2 Fallback quality
+
+ QRandomGenerator::system() uses the operating system facilities to obtain
+ random numbers, which attempt to collect real entropy from the surrounding
+ environment to produce true random numbers. However, it's possible that the
+ entropy pool becomes exhausted, in which case the operating system will
+ fall back to a pseudo-random engine for a time. Under no circumstances will
+ QRandomGenerator::system() block, waiting for more entropy to be collected.
+
+ The following operating systems guarantee that the results from their
+ random-generation API will be of at least cryptographically-safe quality,
+ even if the entropy pool is exhausted: Apple OSes (Darwin), BSDs, Linux,
+ Windows. Barring a system installation problem (such as \c{/dev/urandom}
+ not being readable by the current process), QRandomGenerator::system() will
+ therefore have the same guarantees.
+
+ On other operating systems, QRandomGenerator will fall back to a PRNG of
+ good numeric distribution, but it cannot guarantee proper seeding in all
+ cases. Please consult the OS documentation for more information.
+
+ Applications that require QRandomGenerator not to fall back to
+ non-cryptographic quality generators are advised to check their operating
+ system documentation or restrict their deployment to one of the above.
+
+ \section1 Reentrancy and thread-safety
+
+ QRandomGenerator is reentrant, meaning that multiple threads can operate on
+ this class at the same time, so long as they operate on different objects.
+ If multiple threads need to share one PRNG sequence, external locking by a
+ mutex is required.
+
+ The exceptions are the objects returned by QRandomGenerator::global() and
+ QRandomGenerator::system(): those objects are thread-safe and may be used
+ by any thread without external locking. Note that thread-safety does not
+ extend to copying those objects: they should always be used by reference.
\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);
+ 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. Exceptions to the requirements are
+ the following:
- // equivalent to:
- for (auto &v : block)
- v = rng();
- \endcode
+ \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
@@ -531,32 +648,126 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
[1, 2.5):
\code
- QRandomGenerator64 rd;
std::uniform_real_distribution dist(1, 2.5);
- return dist(rd);
+ return dist(*QRandomGenerator::global());
\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()
+ \enum QRandomGenerator::System
\internal
- Defaulted constructor, does nothing.
+*/
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(quint32 seedValue)
+
+ 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 seed(), securelySeeded()
+ */
+
+/*!
+ \fn template <qsizetype N> QRandomGenerator::QRandomGenerator(const quint32 (&seedBuffer)[N])
+ \overload
+
+ Initializes this QRandomGenerator object with the values found in the
+ array \a seedBuffer as the seed. Two objects constructed or reseeded with
+ the same seed value will produce the same number sequence.
+
+ \sa seed(), securelySeeded()
+ */
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(const quint32 *seedBuffer, qsizetype len)
+ \overload
+
+ Initializes this QRandomGenerator object with \a len values found in
+ the array \a seedBuffer as the seed. Two objects constructed or reseeded
+ with the same seed value will produce the same number sequence.
+
+ This constructor is equivalent to:
+ \code
+ std::seed_seq sseq(seedBuffer, seedBuffer + len);
+ QRandomGenerator generator(sseq);
+ \endcode
+
+ \sa seed(), securelySeeded()
+ */
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(const quint32 *begin, const quint32 *end)
+ \overload
+
+ Initializes this QRandomGenerator object with the values found in the range
+ from \a begin to \a end as the seed. Two objects constructed or reseeded
+ with the same seed value will produce the same number sequence.
+
+ This constructor is equivalent to:
+ \code
+ std::seed_seq sseq(begin, end);
+ QRandomGenerator generator(sseq);
+ \endcode
+
+ \sa seed(), securelySeeded()
*/
/*!
+ \fn QRandomGenerator::QRandomGenerator(std::seed_seq &sseq)
+ \overload
+
+ Initializes this QRandomGenerator object with the seed sequence \a
+ sseq as the seed. Two objects constructed or reseeded with the same seed
+ value will produce the same number sequence.
+
+ \sa seed(), securelySeeded()
+ */
+
+/*!
+ \fn QRandomGenerator::QRandomGenerator(const QRandomGenerator &other)
+
+ Creates a copy of the generator state in the \a other object. If \a other is
+ QRandomGenerator::system() or a copy of that, this object will also read
+ from the operating system random-generating facilities. In that case, the
+ sequences generated by the two objects will be different.
+
+ In all other cases, the new QRandomGenerator object will start at the same
+ position in the deterministic sequence as the \a other object was. Both
+ objects will generate the same sequence from this point on.
+
+ For that reason, it is not adviseable to create a copy of
+ QRandomGenerator::global(). If one needs an exclusive deterministic
+ generator, consider instead using securelySeeded() to obtain a new object
+ that shares no relationship with the QRandomGenerator::global().
+ */
+
+/*!
+ \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.
+ A typedef to the type that operator() returns. That is, quint32.
- \sa operator()()
+ \sa operator()
*/
/*!
@@ -564,24 +775,23 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
Generates a 32-bit random quantity and returns it.
- \sa QRandomGenerator::generate(), QRandomGenerator::generate64()
+ \sa generate(), generate64()
*/
/*!
- \fn double QRandomGenerator::entropy() const
+ \fn quint32 QRandomGenerator::generate()
- Returns the estimate of the entropy in the random generator source.
+ Generates a 32-bit random quantity and returns it.
- 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.
+ \sa {QRandomGenerator::operator()}{operator()()}, generate64()
+ */
- Since QRandomGenerator attempts to use a hardware Random Number Generator,
- this function always returns 0.0.
+/*!
+ \fn quint64 QRandomGenerator::generate64()
+
+ Generates a 64-bit random quantity and returns it.
+
+ \sa {QRandomGenerator::operator()}{operator()()}, generate()
*/
/*!
@@ -589,7 +799,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
Returns the minimum value that QRandomGenerator may ever generate. That is, 0.
- \sa max(), QRandomGenerator64::max()
+ \sa max(), QRandomGenerator64::min()
*/
/*!
@@ -602,17 +812,42 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn void QRandomGenerator::generate(ForwardIterator begin, ForwardIterator end)
+ \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 seed 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 template <typename ForwardIterator> 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(); });
+ std::generate(begin, end, [this]() { 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}},
+ \l{http://en.cppreference.com/w/cpp/numeric/random/seed_seq/generate}{\c 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
@@ -621,7 +856,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
quantities, one can write:
\code
- std::generate(begin, end, []() { return QRandomGenerator::generate64(); });
+ std::generate(begin, end, []() { return QRandomGenerator::global()->generate64(); });
\endcode
If the range refers to contiguous memory (such as an array or the data from
@@ -639,7 +874,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn void QRandomGenerator::fillRange(UInt *buffer, qssize_t count)
+ \fn template <typename UInt> void QRandomGenerator::fillRange(UInt *buffer, qsizetype 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
@@ -659,7 +894,7 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn void QRandomGenerator::fillRange(UInt (&buffer)[N})
+ \fn template <typename UInt, size_t N> 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
@@ -692,33 +927,33 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
\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}}
+ \l{http://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution}{\c std::uniform_real_distribution}
with parameters 0 and 1.
\sa generate(), generate64(), bounded()
*/
/*!
- \fn qreal QRandomGenerator::bounded(qreal sup)
+ \fn double QRandomGenerator::bounded(double highest)
- Generates one random qreal in the range between 0 (inclusive) and \a
- sup (exclusive). This function is equivalent to and is implemented as:
+ Generates one random double in the range between 0 (inclusive) and \a
+ highest (exclusive). This function is equivalent to and is implemented as:
\code
- return generateDouble() * sup;
+ return generateDouble() * highest;
\endcode
\sa generateDouble(), bounded()
*/
/*!
- \fn quint32 QRandomGenerator::bounded(quint32 sup)
+ \fn quint32 QRandomGenerator::bounded(quint32 highest)
\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
+ \a highest (exclusive). The same result may also be obtained by using
+ \l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{\c std::uniform_int_distribution}
+ with parameters 0 and \c{highest - 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:
@@ -737,11 +972,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(int sup)
+ \fn quint32 QRandomGenerator::bounded(int highest)
\overload
Generates one random 32-bit quantity in the range between 0 (inclusive) and
- \a sup (exclusive). \a sup must not be negative.
+ \a highest (exclusive). \a highest 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.
@@ -750,13 +985,13 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(quint32 min, quint32 sup)
+ \fn quint32 QRandomGenerator::bounded(quint32 lowest, quint32 highest)
\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
+ Generates one random 32-bit quantity in the range between \a lowest (inclusive)
+ and \a highest (exclusive). The same result may also be obtained by using
+ \l{http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution}{\c std::uniform_int_distribution}
+ with parameters \a lowest and \c{\a highest - 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
@@ -774,11 +1009,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn quint32 QRandomGenerator::bounded(int min, int sup)
+ \fn quint32 QRandomGenerator::bounded(int lowest, int highest)
\overload
- Generates one random 32-bit quantity in the range between \a min
- (inclusive) and \a sup (exclusive), both of which may be negative.
+ Generates one random 32-bit quantity in the range between \a lowest
+ (inclusive) and \a highest (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.
@@ -787,6 +1022,72 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
+ \fn QRandomGenerator *QRandomGenerator::system()
+ \threadsafe
+
+ Returns a pointer to a shared QRandomGenerator that always uses the
+ facilities provided by the operating system to generate random numbers. The
+ system facilities are considered to be cryptographically safe on at least
+ the following operating systems: Apple OSes (Darwin), BSDs, Linux, Windows.
+ That may also be the case on other operating systems.
+
+ They are also possibly backed by a true hardware random number generator.
+ For that reason, the QRandomGenerator returned by this function should not
+ be used for bulk data generation. Instead, use it to seed QRandomGenerator
+ or a random engine from the <random> header.
+
+ The object returned by this function is thread-safe and may be used in any
+ thread without locks. It may also be copied and the resulting
+ QRandomGenerator will also access the operating system facilities, but they
+ will not generate the same sequence.
+
+ \sa securelySeeded(), global()
+*/
+
+/*!
+ \fn QRandomGenerator *QRandomGenerator::global()
+ \threadsafe
+
+ Returns a pointer to a shared QRandomGenerator that was seeded using
+ securelySeeded(). This function should be used to create random data
+ without the expensive creation of a securely-seeded QRandomGenerator
+ for a specific use or storing the rather large QRandomGenerator object.
+
+ For example, the following creates a random RGB color:
+
+ \code
+ return QColor::fromRgb(QRandomGenerator::global()->generate());
+ \endcode
+
+ Accesses to this object are thread-safe and it may therefore be used in any
+ thread without locks. The object may also be copied and the sequence
+ produced by the copy will be the same as the shared object will produce.
+ Note, however, that if there are other threads accessing the global object,
+ those threads may obtain samples at unpredictable intervals.
+
+ \sa securelySeeded(), system()
+*/
+
+/*!
+ \fn QRandomGenerator QRandomGenerator::securelySeeded()
+
+ Returns a new QRandomGenerator object that was securely seeded with
+ QRandomGenerator::system(). This function will obtain the ideal seed size
+ for the algorithm that QRandomGenerator uses and is therefore the
+ recommended way for creating a new QRandomGenerator object that will be
+ kept for some time.
+
+ Given the amount of data required to securely seed the deterministic
+ engine, this function is somewhat expensive and should not be used for
+ short-term uses of QRandomGenerator (using it to generate fewer than 2600
+ bytes of random data is effectively a waste of resources). If the use
+ doesn't require that much data, consider using QRandomGenerator::global()
+ and not storing a QRandomGenerator object instead.
+
+ \sa global(), system()
+ */
+
+/*!
\class QRandomGenerator64
\inmodule QtCore
\since 5.10
@@ -807,17 +1108,11 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
*/
/*!
- \fn QRandomGenerator64::QRandomGenerator64()
- \internal
- Defaulted constructor, does nothing.
- */
-
-/*!
\typedef QRandomGenerator64::result_type
- A typedef to the type that operator()() returns. That is, quint64.
+ A typedef to the type that operator() returns. That is, quint64.
- \sa operator()()
+ \sa operator()
*/
/*!
@@ -845,80 +1140,121 @@ static Q_NEVER_INLINE void fill(void *buffer, void *bufferEnd)
\sa QRandomGenerator::generate(), QRandomGenerator::generate64()
*/
-/*!
- \fn double QRandomGenerator64::entropy() const
+Q_DECL_CONSTEXPR QRandomGenerator::Storage::Storage()
+ : dummy(0)
+{
+ // nothing
+}
- Returns the estimate of the entropy in the random generator source.
+inline QRandomGenerator64::QRandomGenerator64(System s)
+ : QRandomGenerator(s)
+{
+}
- 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.
+QRandomGenerator64 *QRandomGenerator64::system()
+{
+ auto self = SystemAndGlobalGenerators::system();
+ Q_ASSERT(self->type == SystemRNG);
+ return self;
+}
- Since QRandomGenerator64 attempts to use a hardware Random Number Generator,
- this function always returns 0.0.
- */
+QRandomGenerator64 *QRandomGenerator64::global()
+{
+ auto self = SystemAndGlobalGenerators::globalNoInit();
-/*!
- \fn result_type QRandomGenerator64::min()
+ // Yes, this is a double-checked lock.
+ // We can return even if the type is not completely initialized yet:
+ // any thread trying to actually use the contents of the random engine
+ // will necessarily wait on the lock.
+ if (Q_LIKELY(self->type != SystemRNG))
+ return self;
- Returns the minimum value that QRandomGenerator64 may ever generate. That is, 0.
+ SystemAndGlobalGenerators::PRNGLocker locker(self);
+ if (self->type == SystemRNG)
+ SystemAndGlobalGenerators::securelySeed(self);
- \sa max(), QRandomGenerator::max()
- */
+ return self;
+}
-/*!
- \fn result_type QRandomGenerator64::max()
+QRandomGenerator64 QRandomGenerator64::securelySeeded()
+{
+ QRandomGenerator64 result(System{});
+ SystemAndGlobalGenerators::securelySeed(&result);
+ return result;
+}
- Returns the maximum value that QRandomGenerator64 may ever generate. That is,
- \c {std::numeric_limits<result_type>::max()}.
+/*!
+ \internal
+*/
+inline QRandomGenerator::QRandomGenerator(System)
+ : type(SystemRNG)
+{
+ // don't touch storage
+}
- \sa min(), QRandomGenerator::max()
- */
+QRandomGenerator::QRandomGenerator(const QRandomGenerator &other)
+ : type(other.type)
+{
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
-/*!
- Generates one 32-bit random value and returns it.
+ if (type != SystemRNG) {
+ SystemAndGlobalGenerators::PRNGLocker lock(&other);
+ storage.engine() = other.storage.engine();
+ }
+}
- 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:
+QRandomGenerator &QRandomGenerator::operator=(const QRandomGenerator &other)
+{
+ if (Q_UNLIKELY(this == system()) || Q_UNLIKELY(this == SystemAndGlobalGenerators::globalNoInit()))
+ qFatal("Attempted to overwrite a QRandomGenerator to system() or global().");
- \code
- int value = QRandomGenerator::generate() & std::numeric_limits<int>::max();
- \endcode
+ if ((type = other.type) != SystemRNG) {
+ SystemAndGlobalGenerators::PRNGLocker lock(&other);
+ storage.engine() = other.storage.engine();
+ }
+ return *this;
+}
- \sa generate64(), generateDouble()
- */
-quint32 QRandomGenerator::generate()
+QRandomGenerator::QRandomGenerator(std::seed_seq &sseq) Q_DECL_NOTHROW
+ : type(MersenneTwister)
{
- quint32 ret;
- fill(&ret, &ret + 1);
- return ret;
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
+
+ new (&storage.engine()) RandomEngine(sseq);
}
-/*!
- Generates one 64-bit random value and returns it.
+QRandomGenerator::QRandomGenerator(const quint32 *begin, const quint32 *end)
+ : type(MersenneTwister)
+{
+ Q_ASSERT(this != system());
+ Q_ASSERT(this != SystemAndGlobalGenerators::globalNoInit());
- 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:
+ std::seed_seq s(begin, end);
+ new (&storage.engine()) RandomEngine(s);
+}
- \code
- qint64 value = QRandomGenerator::generate64() & std::numeric_limits<qint64>::max();
- \endcode
+void QRandomGenerator::discard(unsigned long long z)
+{
+ if (Q_UNLIKELY(type == SystemRNG))
+ return;
- \sa generate(), generateDouble(), QRandomGenerator64
- */
-quint64 QRandomGenerator::generate64()
+ SystemAndGlobalGenerators::PRNGLocker lock(this);
+ storage.engine().discard(z);
+}
+
+bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
{
- quint64 ret;
- fill(&ret, &ret + 1);
- return ret;
+ 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)
+ using PRNGLocker = QRandomGenerator::SystemAndGlobalGenerators::PRNGLocker;
+ PRNGLocker locker(&rng1 == QRandomGenerator::global() ? &rng1 : &rng2);
+ return rng1.storage.engine() == rng2.storage.engine();
}
/*!
@@ -927,25 +1263,71 @@ quint64 QRandomGenerator::generate64()
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)
+void QRandomGenerator::_fillRange(void *buffer, void *bufferEnd)
{
- fill(buffer, bufferEnd);
+ // 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 *begin = static_cast<quint32 *>(buffer);
+ quint32 *end = static_cast<quint32 *>(bufferEnd);
+
+ if (type == SystemRNG || Q_UNLIKELY(uint(qt_randomdevice_control) & (UseSystemRNG|SetRandomData)))
+ return SystemGenerator::self().generate(begin, end);
+
+ SystemAndGlobalGenerators::PRNGLocker lock(this);
+ std::generate(begin, end, [this]() { return storage.engine()(); });
}
-#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21)
-typedef QThreadStorage<QJNIObjectPrivate> AndroidRandomStorage;
-Q_GLOBAL_STATIC(AndroidRandomStorage, randomTLS)
+namespace {
+struct QRandEngine
+{
+ std::minstd_rand engine;
+ QRandEngine() : engine(1) {}
-#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;
+ int generate()
+ {
+ std::minstd_rand::result_type v = engine();
+ if (std::numeric_limits<int>::max() != RAND_MAX)
+ v %= uint(RAND_MAX) + 1;
-typedef QThreadStorage<SeedStorageType *> SeedStorage;
-Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value
+ return int(v);
+ }
+ void seed(std::minstd_rand::result_type q)
+ {
+ engine.seed(q);
+ }
+};
+}
+
+#if defined(QT_NO_THREAD) || defined(Q_OS_WIN)
+// On Windows srand() and rand() already use Thread-Local-Storage
+// to store the seed between calls
+static inline QRandEngine *randTLS()
+{
+ return nullptr;
+}
+#elif defined(Q_COMPILER_THREAD_LOCAL)
+static inline QRandEngine *randTLS()
+{
+ thread_local QRandEngine r;
+ return &r;
+}
+#else
+Q_GLOBAL_STATIC(QThreadStorage<QRandEngine>, g_randTLS)
+static inline QRandEngine *randTLS()
+{
+ auto tls = g_randTLS();
+ if (!tls)
+ return nullptr;
+ return &tls->localData();
+
+}
#endif
/*!
\relates <QtGlobal>
+ \deprecated
\since 4.2
Thread-safe version of the standard C++ \c srand() function.
@@ -957,49 +1339,23 @@ Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value
if two threads call qsrand(1) and subsequently call qrand(), the threads will get
the same random number sequence.
+ \note This function is deprecated. In new applications, use
+ QRandomGenerator instead.
+
\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)
+ auto prng = randTLS();
+ if (prng)
+ prng->seed(seed);
+ else
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>
+ \deprecated
\since 4.2
Thread-safe version of the standard C++ \c rand() function.
@@ -1013,52 +1369,18 @@ void qsrand(uint seed)
step is skipped, then the sequence will be pre-seeded with a constant
value.
- \sa qsrand(), QRandomGenerator
+ \note This function is deprecated. In new applications, use
+ QRandomGenerator instead.
+
+ \sa qrand(), QRandomGenerator
*/
int qrand()
{
-#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21)
- AndroidRandomStorage *randomStorage = randomTLS();
- if (!randomStorage)
+ auto prng = randTLS();
+ if (prng)
+ return prng->generate();
+ else
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
diff --git a/src/corelib/global/qrandom.h b/src/corelib/global/qrandom.h
index 7f96cd6749..46d3e0e152 100644
--- a/src/corelib/global/qrandom.h
+++ b/src/corelib/global/qrandom.h
@@ -42,6 +42,14 @@
#include <QtCore/qglobal.h>
#include <algorithm> // for std::generate
+#include <random> // for std::mt19937
+
+#ifdef min
+# undef min
+#endif
+#ifdef max
+# undef max
+#endif
QT_BEGIN_NAMESPACE
@@ -51,104 +59,212 @@ class QRandomGenerator
template <typename UInt> using IfValidUInt =
typename std::enable_if<std::is_unsigned<UInt>::value && sizeof(UInt) >= sizeof(uint), bool>::type;
public:
- QRandomGenerator() = default;
+ QRandomGenerator(quint32 seedValue = 1)
+ : QRandomGenerator(&seedValue, 1)
+ {}
+ template <qsizetype N> QRandomGenerator(const quint32 (&seedBuffer)[N])
+ : QRandomGenerator(seedBuffer, seedBuffer + N)
+ {}
+ QRandomGenerator(const quint32 *seedBuffer, qsizetype len)
+ : QRandomGenerator(seedBuffer, seedBuffer + len)
+ {}
+ Q_CORE_EXPORT QRandomGenerator(std::seed_seq &sseq) Q_DECL_NOTHROW;
+ Q_CORE_EXPORT QRandomGenerator(const quint32 *begin, const quint32 *end);
+
+ // copy constructor & assignment operator (move unnecessary)
+ Q_CORE_EXPORT QRandomGenerator(const QRandomGenerator &other);
+ Q_CORE_EXPORT QRandomGenerator &operator=(const QRandomGenerator &other);
- // ### REMOVE BEFORE 5.10
- static quint32 get32() { return generate(); }
- static quint64 get64() { return generate64(); }
- static qreal getReal() { return generateDouble(); }
+ 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;
+ fillRange(&ret, 1);
+ return ret;
+ }
- static Q_CORE_EXPORT quint32 generate();
- static Q_CORE_EXPORT quint64 generate64();
- static double generateDouble()
+ quint64 generate64()
{
- // use get64() to get enough bits
- return double(generate64()) / ((std::numeric_limits<quint64>::max)() + double(1.0));
+ quint32 buf[2];
+ fillRange(buf);
+ return buf[0] | (quint64(buf[1]) << 32);
}
- static qreal bounded(qreal sup)
+ double generateDouble()
{
- return generateDouble() * sup;
+ // IEEE 754 double precision has:
+ // 1 bit sign
+ // 10 bits exponent
+ // 53 bits mantissa
+ // In order for our result to be normalized in the range [0, 1), we
+ // need exactly 53 bits of random data. Use generate64() to get enough.
+ quint64 x = generate64();
+ quint64 limit = Q_UINT64_C(1) << std::numeric_limits<double>::digits;
+ x >>= std::numeric_limits<quint64>::digits - std::numeric_limits<double>::digits;
+ return double(x) / double(limit);
}
- static quint32 bounded(quint32 sup)
+ double bounded(double highest)
+ {
+ return generateDouble() * highest;
+ }
+
+ quint32 bounded(quint32 highest)
{
quint64 value = generate();
- value *= sup;
+ value *= highest;
value /= (max)() + quint64(1);
return quint32(value);
}
- static int bounded(int sup)
+ int bounded(int highest)
{
- return int(bounded(quint32(sup)));
+ return int(bounded(quint32(highest)));
}
- static quint32 bounded(quint32 min, quint32 sup)
+ quint32 bounded(quint32 lowest, quint32 highest)
{
- return bounded(sup - min) + min;
+ return bounded(highest - lowest) + lowest;
}
- static int bounded(int min, int sup)
+ int bounded(int lowest, int highest)
{
- return bounded(sup - min) + min;
+ return bounded(highest - lowest) + lowest;
}
template <typename UInt, IfValidUInt<UInt> = true>
- static void fillRange(UInt *buffer, qssize_t count)
+ void fillRange(UInt *buffer, qsizetype count)
{
- fillRange_helper(buffer, buffer + count);
+ _fillRange(buffer, buffer + count);
}
template <typename UInt, size_t N, IfValidUInt<UInt> = true>
- static void fillRange(UInt (&buffer)[N])
+ void fillRange(UInt (&buffer)[N])
{
- fillRange_helper(buffer, buffer + N);
+ _fillRange(buffer, buffer + N);
}
// API like std::seed_seq
template <typename ForwardIterator>
void generate(ForwardIterator begin, ForwardIterator end)
{
- auto generator = static_cast<quint32 (*)()>(&QRandomGenerator::generate);
- std::generate(begin, end, generator);
+ std::generate(begin, end, [this]() { return generate(); });
}
void generate(quint32 *begin, quint32 *end)
{
- fillRange_helper(begin, end);
+ _fillRange(begin, end);
}
- // API like std::random_device
+ // API like std:: random engines
typedef quint32 result_type;
result_type operator()() { return generate(); }
- double entropy() const Q_DECL_NOTHROW { return 0.0; }
- 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)(); }
+ 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(); }
+
+ static inline Q_DECL_CONST_FUNCTION QRandomGenerator *system();
+ static inline Q_DECL_CONST_FUNCTION QRandomGenerator *global();
+ static inline QRandomGenerator securelySeeded();
+
+protected:
+ enum System {};
+ QRandomGenerator(System);
private:
- Q_DISABLE_COPY(QRandomGenerator)
- static Q_CORE_EXPORT void fillRange_helper(void *buffer, void *bufferEnd);
+ Q_CORE_EXPORT void _fillRange(void *buffer, void *bufferEnd);
+
+ friend class QRandomGenerator64;
+ struct SystemGenerator;
+ struct SystemAndGlobalGenerators;
+ using RandomEngine = std::mersenne_twister_engine<quint32,
+ 32,624,397,31,0x9908b0df,11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253>;
+
+ union Storage {
+ uint dummy;
+#ifdef Q_COMPILER_UNRESTRICTED_UNIONS
+ RandomEngine twister;
+ RandomEngine &engine() { return twister; }
+ const RandomEngine &engine() const { return twister; }
+#else
+ std::aligned_storage<sizeof(RandomEngine), Q_ALIGNOF(RandomEngine)>::type buffer;
+ RandomEngine &engine() { return reinterpret_cast<RandomEngine &>(buffer); }
+ const RandomEngine &engine() const { return reinterpret_cast<const RandomEngine &>(buffer); }
+#endif
+
+ Q_STATIC_ASSERT_X(std::is_trivially_destructible<RandomEngine>::value,
+ "std::mersenne_twister not trivially destructible as expected");
+ Q_DECL_CONSTEXPR Storage();
+ };
+ uint type;
+ Storage storage;
};
-class QRandomGenerator64
+class QRandomGenerator64 : public QRandomGenerator
{
+ QRandomGenerator64(System);
public:
- QRandomGenerator64() = default;
+ // unshadow generate() overloads, since we'll override.
+ using QRandomGenerator::generate;
+ quint64 generate() { return generate64(); }
- static quint64 generate() { return QRandomGenerator::generate64(); }
-
- // API like std::random_device
typedef quint64 result_type;
- result_type operator()() { return QRandomGenerator::generate64(); }
- double entropy() const Q_DECL_NOTHROW { return 0.0; }
- 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)(); }
+ result_type operator()() { return generate64(); }
-private:
- Q_DISABLE_COPY(QRandomGenerator64)
+#ifndef Q_QDOC
+ QRandomGenerator64(quint32 seedValue = 1)
+ : QRandomGenerator(seedValue)
+ {}
+ template <qsizetype N> QRandomGenerator64(const quint32 (&seedBuffer)[N])
+ : QRandomGenerator(seedBuffer)
+ {}
+ QRandomGenerator64(const quint32 *seedBuffer, qsizetype len)
+ : QRandomGenerator(seedBuffer, len)
+ {}
+ QRandomGenerator64(std::seed_seq &sseq) Q_DECL_NOTHROW
+ : QRandomGenerator(sseq)
+ {}
+ QRandomGenerator64(const quint32 *begin, const quint32 *end)
+ : QRandomGenerator(begin, end)
+ {}
+ 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_DECL_CONST_FUNCTION Q_CORE_EXPORT QRandomGenerator64 *system();
+ static Q_DECL_CONST_FUNCTION Q_CORE_EXPORT QRandomGenerator64 *global();
+ static Q_CORE_EXPORT QRandomGenerator64 securelySeeded();
+#endif // Q_QDOC
};
+inline QRandomGenerator *QRandomGenerator::system()
+{
+ return QRandomGenerator64::system();
+}
+
+inline QRandomGenerator *QRandomGenerator::global()
+{
+ return QRandomGenerator64::global();
+}
+
+QRandomGenerator QRandomGenerator::securelySeeded()
+{
+ return QRandomGenerator64::securelySeeded();
+}
QT_END_NAMESPACE
diff --git a/src/corelib/global/qrandom_p.h b/src/corelib/global/qrandom_p.h
index 6ac2904e1b..917a91098e 100644
--- a/src/corelib/global/qrandom_p.h
+++ b/src/corelib/global/qrandom_p.h
@@ -52,11 +52,12 @@
//
#include "qglobal_p.h"
+#include <private/qsimd_p.h>
QT_BEGIN_NAMESPACE
enum QRandomGeneratorControl {
- SkipMemfill = 1,
+ UseSystemRNG = 1,
SkipSystemRNG = 2,
SkipHWRNG = 4,
SetRandomData = 8,
@@ -65,6 +66,11 @@ enum QRandomGeneratorControl {
RandomDataMask = 0xfffffff0
};
+enum RNGType {
+ SystemRNG = 0,
+ MersenneTwister = 1
+};
+
#if defined(QT_BUILD_INTERNAL) && defined(QT_BUILD_CORE_LIB)
Q_CORE_EXPORT QBasicAtomicInteger<uint> qt_randomdevice_control = Q_BASIC_ATOMIC_INITIALIZER(0U);
#elif defined(QT_BUILD_INTERNAL)
@@ -73,6 +79,16 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<uint> qt_randomdevice_control;
enum { qt_randomdevice_control = 0 };
#endif
+inline bool qt_has_hwrng()
+{
+#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
+ return qCpuHasFeature(RDRND);
+#else
+ return false;
+#endif
+}
+
+
QT_END_NAMESPACE
#endif // QRANDOM_P_H
diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h
index 6b73a17dc5..a3fa0fcb27 100644
--- a/src/corelib/global/qsysinfo.h
+++ b/src/corelib/global/qsysinfo.h
@@ -240,6 +240,8 @@ QT_WARNING_POP
static QString prettyProductName();
static QString machineHostName();
+ static QByteArray machineUniqueId();
+ static QByteArray bootUniqueId();
};
#undef QT_SYSINFO_DEPRECATED_X
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index 0b42f1d698..96dd9aa9bf 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -52,30 +52,18 @@
IOS - iOS
WATCHOS - watchOS
TVOS - tvOS
- MSDOS - MS-DOS and Windows
- OS2 - OS/2
- OS2EMX - XFree86 on OS/2 (not PM)
WIN32 - Win32 (Windows 2000/XP/Vista/7 and Windows Server 2003/2008)
- WINRT - WinRT (Windows 8 Runtime)
+ WINRT - WinRT (Windows Runtime)
CYGWIN - Cygwin
SOLARIS - Sun Solaris
HPUX - HP-UX
- ULTRIX - DEC Ultrix
LINUX - Linux [has variants]
FREEBSD - FreeBSD [has variants]
NETBSD - NetBSD
OPENBSD - OpenBSD
- BSDI - BSD/OS
INTERIX - Interix
- IRIX - SGI Irix
- OSF - HP Tru64 UNIX
- SCO - SCO OpenServer 5
- UNIXWARE - UnixWare 7, Open UNIX 8
AIX - AIX
HURD - GNU Hurd
- DGUX - DG/UX
- RELIANT - Reliant UNIX
- DYNIX - DYNIX/ptx
QNX - QNX [has variants]
QNX6 - QNX RTP 6.1
LYNX - LynxOS
@@ -147,10 +135,6 @@
# define Q_OS_SOLARIS
#elif defined(hpux) || defined(__hpux)
# define Q_OS_HPUX
-#elif defined(__ultrix) || defined(ultrix)
-# define Q_OS_ULTRIX
-#elif defined(sinix)
-# define Q_OS_RELIANT
#elif defined(__native_client__)
# define Q_OS_NACL
#elif defined(__EMSCRIPTEN__)
@@ -169,34 +153,17 @@
#elif defined(__OpenBSD__)
# define Q_OS_OPENBSD
# define Q_OS_BSD4
-#elif defined(__bsdi__)
-# define Q_OS_BSDI
-# define Q_OS_BSD4
#elif defined(__INTERIX)
# define Q_OS_INTERIX
# define Q_OS_BSD4
-#elif defined(__sgi)
-# define Q_OS_IRIX
-#elif defined(__osf__)
-# define Q_OS_OSF
#elif defined(_AIX)
# define Q_OS_AIX
#elif defined(__Lynx__)
# define Q_OS_LYNX
#elif defined(__GNU__)
# define Q_OS_HURD
-#elif defined(__DGUX__)
-# define Q_OS_DGUX
#elif defined(__QNXNTO__)
# define Q_OS_QNX
-#elif defined(_SEQUENT_)
-# define Q_OS_DYNIX
-#elif defined(_SCO_DS) /* SCO OpenServer 5 + GCC */
-# define Q_OS_SCO
-#elif defined(__USLC__) /* all SCO platforms + UDK or OUDK */
-# define Q_OS_UNIXWARE
-#elif defined(__svr4__) && defined(i386) /* Open UNIX 8 + GCC */
-# define Q_OS_UNIXWARE
#elif defined(__INTEGRITY)
# define Q_OS_INTEGRITY
#elif defined(VXWORKS) /* there is no "real" VxWorks define - this has to be set in the mkspec! */
diff --git a/src/corelib/global/qt_windows.h b/src/corelib/global/qt_windows.h
index bc48104edc..67ba27f072 100644
--- a/src/corelib/global/qt_windows.h
+++ b/src/corelib/global/qt_windows.h
@@ -48,10 +48,10 @@
#if defined(Q_CC_MINGW)
// mingw's windows.h does not set _WIN32_WINNT, resulting breaking compilation
# ifndef WINVER
-# define WINVER 0x600
+# define WINVER 0x601
# endif
# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x600
+# define _WIN32_WINNT 0x601
# endif
# ifndef NTDDI_VERSION
# define NTDDI_VERSION 0x06000000
diff --git a/src/corelib/global/qtrace_p.h b/src/corelib/global/qtrace_p.h
new file mode 100644
index 0000000000..ab8fc14af5
--- /dev/null
+++ b/src/corelib/global/qtrace_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTRACE_P_H
+#define QTRACE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+/*
+ * The Qt tracepoints API consists of only three macros:
+ *
+ * - Q_TRACE(tracepoint, args...)
+ * Fires 'tracepoint' if it is enabled.
+ *
+ * - Q_UNCONDITIONAL_TRACE(tracepoint, args...)
+ * Fires 'tracepoint' unconditionally: no check is performed to query
+ * whether 'tracepoint' is enabled.
+ *
+ * - Q_TRACE_ENABLED(tracepoint)
+ * Returns 'true' if 'tracepoint' is enabled; false otherwise.
+ *
+ * When using LTTNG, Q_TRACE, Q_UNCONDITIONAL_TRACE and Q_TRACE_ENABLED map
+ * ultimately to tracepoint(), do_tracepoint() and tracepoint_enabled(),
+ * respectively, described on the lttng-ust manpage (man 3 lttng-ust).
+ *
+ * On ETW, Q_TRACE() and Q_UNCONDITIONAL_TRACE() are equivalent, ultimately
+ * amounting to a call to TraceLoggingWrite(), whereas Q_TRACE_ENABLED()
+ * wraps around TraceLoggingProviderEnabled().
+ *
+ * A tracepoint provider is defined in a separate file, that follows the
+ * following format:
+ *
+ * tracepoint_name(arg_type arg_name, ...)
+ *
+ * For instance:
+ *
+ * qcoreapplication_ctor(int argc, const char * const argv)
+ * qcoreapplication_foo(int argc, const char[10] argv)
+ * qcoreapplication_baz(const char[len] some_string, unsigned int len)
+ * qcoreapplication_qstring(const QString &foo)
+ * qcoreapplication_qrect(const QRect &rect)
+ *
+ * The provider file is then parsed by src/tools/tracegen, which can be
+ * switched to output either ETW or LTTNG tracepoint definitions. The provider
+ * name is deduced to be basename(provider_file).
+ *
+ * To use the above (inside qtcore), you need to include
+ * <providername_tracepoints_p.h>. After that, the following call becomes
+ * possible:
+ *
+ * Q_TRACE(qcoreapplication_qrect, myRect);
+ *
+ * Currently, all C++ primitive non-pointer types are supported for
+ * arguments. Additionally, char * is supported, and is assumed to
+ * be a NULL-terminated string. Finally, the following subset of Qt types also
+ * currently supported:
+ *
+ * - QString
+ * - QByteArray
+ * - QUrl
+ * - QRect
+ *
+ * Dynamic arrays are supported using the syntax illustrated by
+ * qcoreapplication_baz above.
+ */
+
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_TRACEPOINT) && !defined(QT_BOOTSTRAPPED)
+# define Q_TRACE(x, ...) QtPrivate::trace_ ## x(__VA_ARGS__)
+# define Q_UNCONDITIONAL_TRACE(x, ...) QtPrivate::do_trace_ ## x(__VA_ARGS__)
+# define Q_TRACE_ENABLED(x) QtPrivate::trace_ ## x ## _enabled()
+#else
+# define Q_TRACE(x, ...)
+# define Q_UNCONDITIONAL_TRACE(x, ...)
+# define Q_TRACE_ENABLED(x) false
+#endif // defined(Q_TRACEPOINT) && !defined(QT_BOOTSTRAPPED)
+
+QT_END_NAMESPACE
+
+#endif // QTRACE_P_H