diff options
Diffstat (limited to 'src/corelib/global/qglobal.cpp')
-rw-r--r-- | src/corelib/global/qglobal.cpp | 197 |
1 files changed, 162 insertions, 35 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 78ad2a5421..4ab5bd2edb 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -47,11 +47,15 @@ #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 "qoperatingsystemversion_win_p.h" +# ifndef Q_OS_WINRT +# include "private/qwinregistry_p.h" +# endif +#endif // Q_OS_WIN || Q_OS_CYGWIN #include <private/qlocale_tools_p.h> #include <qmutex.h> +#include <QtCore/private/qlocking_p.h> #include <stdlib.h> #include <limits.h> @@ -1152,12 +1156,12 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value)); \sa QT_VERSION_STR, QLibraryInfo::version() */ -const char *qVersion() Q_DECL_NOTHROW +const char *qVersion() noexcept { return QT_VERSION_STR; } -bool qSharedBuild() Q_DECL_NOTHROW +bool qSharedBuild() noexcept { #ifdef QT_SHARED return true; @@ -1903,6 +1907,42 @@ bool qSharedBuild() Q_DECL_NOTHROW */ /*! + \macro Q_PROCESSOR_RISCV + \relates <QtGlobal> + \since 5.13 + + Defined if the application is compiled for RISC-V processors. Qt currently + supports two RISC-V variants: \l Q_PROCESSOR_RISCV_32 and \l + Q_PROCESSOR_RISCV_64. + + \sa QSysInfo::buildCpuArchitecture() +*/ + +/*! + \macro Q_PROCESSOR_RISCV_32 + \relates <QtGlobal> + \since 5.13 + + Defined if the application is compiled for 32-bit RISC-V processors. The \l + Q_PROCESSOR_RISCV macro is also defined when Q_PROCESSOR_RISCV_32 is + defined. + + \sa QSysInfo::buildCpuArchitecture() +*/ + +/*! + \macro Q_PROCESSOR_RISCV_64 + \relates <QtGlobal> + \since 5.13 + + Defined if the application is compiled for 64-bit RISC-V processors. The \l + Q_PROCESSOR_RISCV macro is also defined when Q_PROCESSOR_RISCV_64 is + defined. + + \sa QSysInfo::buildCpuArchitecture() +*/ + +/*! \macro Q_PROCESSOR_S390 \relates <QtGlobal> @@ -2149,12 +2189,33 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion() QT_WARNING_POP #endif +static QString readVersionRegistryString(const wchar_t *subKey) +{ +#if !defined(QT_BUILD_QMAKE) && !defined(Q_OS_WINRT) + return QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)") + .stringValue(subKey); +#else + Q_UNUSED(subKey); + return QString(); +#endif +} + +static inline QString windows10ReleaseId() +{ + return readVersionRegistryString(L"ReleaseId"); +} + +static inline QString windows7Build() +{ + return readVersionRegistryString(L"CurrentBuild"); +} + static QString winSp_helper() { const auto osv = qWindowsVersionInfo(); const qint16 major = osv.wServicePackMajor; if (major) { - QString sp = QStringLiteral(" SP ") + QString::number(major); + QString sp = QStringLiteral("SP ") + QString::number(major); const qint16 minor = osv.wServicePackMinor; if (minor) sp += QLatin1Char('.') + QString::number(minor); @@ -2867,19 +2928,34 @@ QString QSysInfo::prettyProductName() { #if (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN) const auto version = QOperatingSystemVersion::current(); + const int majorVersion = version.majorVersion(); + const QString versionString = QString::number(majorVersion) + QLatin1Char('.') + + QString::number(version.minorVersion()); + QString result = version.name() + QLatin1Char(' '); const char *name = osVer_helper(version); - if (name) - return version.name() + QLatin1Char(' ') + QLatin1String(name) -# if defined(Q_OS_WIN) - + winSp_helper() -# endif - + QLatin1String(" (") + QString::number(version.majorVersion()) - + QLatin1Char('.') + QString::number(version.minorVersion()) - + QLatin1Char(')'); - else - return version.name() + QLatin1Char(' ') - + QString::number(version.majorVersion()) + QLatin1Char('.') - + QString::number(version.minorVersion()); + if (!name) + return result + versionString; + result += QLatin1String(name); +# if !defined(Q_OS_WIN) || defined(Q_OS_WINRT) + return result + QLatin1String(" (") + versionString + QLatin1Char(')'); +# else + // (resembling winver.exe): Windows 10 "Windows 10 Version 1809" + if (majorVersion >= 10) { + const auto releaseId = windows10ReleaseId(); + if (!releaseId.isEmpty()) + result += QLatin1String(" Version ") + releaseId; + return result; + } + // Windows 7: "Windows 7 Version 6.1 (Build 7601: Service Pack 1)" + result += QLatin1String(" Version ") + versionString + QLatin1String(" ("); + const auto build = windows7Build(); + if (!build.isEmpty()) + result += QLatin1String("Build ") + build; + const auto servicePack = winSp_helper(); + if (!servicePack.isEmpty()) + result += QLatin1String(": ") + servicePack; + return result + QLatin1Char(')'); +# endif // Windows #elif defined(Q_OS_HAIKU) return QLatin1String("Haiku ") + productVersion(); #elif defined(Q_OS_UNIX) @@ -2921,6 +2997,7 @@ QString QSysInfo::machineHostName() struct utsname u; if (uname(&u) == 0) return QString::fromLocal8Bit(u.nodename); + return QString(); #else # ifdef Q_OS_WIN // Important: QtNetwork depends on machineHostName() initializing ws2_32.dll @@ -2933,7 +3010,6 @@ QString QSysInfo::machineHostName() hostName[sizeof(hostName) - 1] = '\0'; return QString::fromLocal8Bit(hostName); #endif - return QString(); } #endif // QT_BOOTSTRAPPED @@ -2998,6 +3074,7 @@ QByteArray QSysInfo::machineUniqueId() } #elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT) // Let's poke at the registry + // ### Qt 6: Use new helpers from qwinregistry.cpp (once bootstrap builds are obsolete) HKEY key = NULL; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ | KEY_WOW64_64KEY, &key) == ERROR_SUCCESS) { @@ -3224,7 +3301,7 @@ QByteArray QSysInfo::bootUniqueId() The Q_CHECK_PTR macro calls this function if an allocation check fails. */ -void qt_check_pointer(const char *n, int l) Q_DECL_NOTHROW +void qt_check_pointer(const char *n, int l) noexcept { // make separate printing calls so that the first one may flush; // the second one could want to allocate memory (fputs prints a @@ -3251,7 +3328,7 @@ void qBadAlloc() Allows you to call std::terminate() without including <exception>. Called internally from QT_TERMINATE_ON_EXCEPTION */ -Q_NORETURN void qTerminate() Q_DECL_NOTHROW +Q_NORETURN void qTerminate() noexcept { std::terminate(); } @@ -3260,7 +3337,7 @@ Q_NORETURN void qTerminate() Q_DECL_NOTHROW /* The Q_ASSERT macro calls this function when the test fails. */ -void qt_assert(const char *assertion, const char *file, int line) Q_DECL_NOTHROW +void qt_assert(const char *assertion, const char *file, int line) noexcept { QMessageLogger(file, line, nullptr).fatal("ASSERT: \"%s\" in file %s, line %d", assertion, file, line); } @@ -3268,7 +3345,7 @@ void qt_assert(const char *assertion, const char *file, int line) Q_DECL_NOTHROW /* The Q_ASSERT_X macro calls this function when the test fails. */ -void qt_assert_x(const char *where, const char *what, const char *file, int line) Q_DECL_NOTHROW +void qt_assert_x(const char *where, const char *what, const char *file, int line) noexcept { QMessageLogger(file, line, nullptr).fatal("ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line); } @@ -3315,7 +3392,7 @@ static QBasicMutex environmentMutex; */ void qTzSet() { - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); #if defined(Q_OS_WIN) _tzset(); #else @@ -3329,7 +3406,7 @@ void qTzSet() */ time_t qMkTime(struct tm *when) { - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); return mktime(when); } @@ -3361,7 +3438,7 @@ time_t qMkTime(struct tm *when) */ QByteArray qgetenv(const char *varName) { - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); #ifdef Q_CC_MSVC size_t requiredSize = 0; QByteArray buffer; @@ -3429,7 +3506,7 @@ QByteArray qgetenv(const char *varName) QString qEnvironmentVariable(const char *varName, const QString &defaultValue) { #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); QVarLengthArray<wchar_t, 32> wname(int(strlen(varName)) + 1); for (int i = 0; i < wname.size(); ++i) // wname.size() is correct: will copy terminating null wname[i] = uchar(varName[i]); @@ -3475,9 +3552,9 @@ QString qEnvironmentVariable(const char *varName) \sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet() */ -bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT +bool qEnvironmentVariableIsEmpty(const char *varName) noexcept { - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); #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 @@ -3510,13 +3587,13 @@ bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT \sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet() */ -int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT +int qEnvironmentVariableIntValue(const char *varName, bool *ok) noexcept { static const int NumBinaryDigitsPerOctalDigit = 3; static const int MaxDigitsForOctalInt = (std::numeric_limits<uint>::digits + NumBinaryDigitsPerOctalDigit - 1) / NumBinaryDigitsPerOctalDigit; - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); #ifdef Q_CC_MSVC // we provide a buffer that can hold any int value: char buffer[MaxDigitsForOctalInt + 2]; // +1 for NUL +1 for optional '-' @@ -3579,15 +3656,15 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT \sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsEmpty() */ -bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT +bool qEnvironmentVariableIsSet(const char *varName) noexcept { - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); #ifdef Q_CC_MSVC size_t requiredSize = 0; (void)getenv_s(&requiredSize, 0, 0, varName); return requiredSize != 0; #else - return ::getenv(varName) != 0; + return ::getenv(varName) != nullptr; #endif } @@ -3611,7 +3688,7 @@ bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT */ bool qputenv(const char *varName, const QByteArray& value) { - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); #if defined(Q_CC_MSVC) return _putenv_s(varName, value.constData()) == 0; #elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_HAIKU) @@ -3642,7 +3719,7 @@ bool qputenv(const char *varName, const QByteArray& value) */ bool qunsetenv(const char *varName) { - QMutexLocker locker(&environmentMutex); + const auto locker = qt_scoped_lock(environmentMutex); #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) @@ -3781,6 +3858,56 @@ bool qunsetenv(const char *varName) */ /*! + \fn template <typename T, typename U = T> T qExchange(T &obj, U &&newValue) + \relates <QtGlobal> + \since 5.14 + + Replaces the value of \a obj with \a newValue and returns the old value of \a obj. + + This is Qt's implementation of std::exchange(). It differs from std::exchange() + only in that it is \c constexpr already in C++14, and available on all supported + compilers. + + Here is how to use qExchange() to implement move constructors: + \code + MyClass(MyClass &&other) + : m_pointer{qExchange(other.m_pointer, nullptr)}, + m_int{qExchange(other.m_int, 0)}, + m_vector{std::move(other.m_vector)}, + ... + \endcode + + For members of class type, we can use std::move(), as their move-constructor will + do the right thing. But for scalar types such as raw pointers or integer type, move + is the same as copy, which, particularly for pointers, is not what we expect. So, we + cannot use std::move() for such types, but we can use std::exchange()/qExchange() to + make sure the source object's member is already reset by the time we get to the + initialization of our next data member, which might come in handy if the constructor + exits with an exception. + + Here is how to use qExchange() to write a loop that consumes the collection it + iterates over: + \code + for (auto &e : qExchange(collection, {}) + doSomethingWith(e); + \endcode + + Which is equivalent to the following, much more verbose code: + \code + { + auto tmp = std::move(collection); + collection = {}; // or collection.clear() + for (auto &e : tmp) + doSomethingWith(e); + } // destroys 'tmp' + \endcode + + This is perfectly safe, as the for-loop keeps the result of qExchange() alive for as + long as the loop runs, saving the declaration of a temporary variable. Be aware, though, + that qExchange() returns a non-const object, so Qt containers may detach. +*/ + +/*! \macro QT_TR_NOOP(sourceText) \relates <QtGlobal> |