diff options
author | Morten Johan Sørvig <morten.sorvig@qt.io> | 2018-03-08 17:05:14 +0100 |
---|---|---|
committer | Morten Johan Sørvig <morten.sorvig@qt.io> | 2018-03-08 18:14:46 +0100 |
commit | 5a7c33dece358090bc8fd3b84567d8bcb0e3b630 (patch) | |
tree | f73931fd2416debfecced1676761aabe48d2f319 /src/corelib/global | |
parent | c9908423d33828b15e5ea97bb1ee8deb08f15673 (diff) | |
parent | e5a6e9bb80fb2427228f70488b8839b4aa0b4261 (diff) |
Merge remote-tracking branch 'gerrit/5.11' into HEAD
Change-Id: Id3a0e9482b35b5e4c79018e0c547d3c4ff48d9a5
Diffstat (limited to 'src/corelib/global')
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 |