Long live qEnvironmentVariableIntegerValue() returning std::optional

That way, we won't need to pass a bool pointer to distinguish an
environment variable containing zero from one that failed to parse.

[ChangeLog][QtCore][QtEnvironment] Added qEnvironmentVariableIntegerValue(),
which returns std::optional<int>.

Fixes: QTBUG-133654
Change-Id: If0d6c3a6f7a080588fa5fffd87b9365f0f8e1089
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Thiago Macieira 2025-02-10 16:00:49 -08:00
parent b888bc09ce
commit fd3c05cd07
5 changed files with 74 additions and 24 deletions

View File

@ -653,6 +653,14 @@ bool readConfiguration(const QFile &file)
qgetenv(varName).toInt(ok, 0)
//! [to-int]
//! [int-value_or]
qEnvironmentVariableIntegerValue(varName).value_or(0)
//! [int-value_or]
//! [int-eq0]
qEnvironmentVariableIntegerValue(varName) == 0
//! [int-eq0]
//! [is-null]
!qgetenv(varName).isNull()
//! [is-null]

View File

@ -38,7 +38,7 @@ Q_CONSTINIT static QBasicMutex environmentMutex;
On Unix systems, this function is lossless.
\sa qputenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet(),
qEnvironmentVariableIsEmpty()
qEnvironmentVariableIsEmpty(), qEnvironmentVariableIntegerValue()
*/
QByteArray qgetenv(const char *varName)
{
@ -104,7 +104,8 @@ QByteArray qgetenv(const char *varName)
\note the variable name \a varName must contain only US-ASCII characters.
\sa qputenv(), qgetenv(), qEnvironmentVariableIsSet(), qEnvironmentVariableIsEmpty()
\sa qputenv(), qgetenv(), qEnvironmentVariableIsSet(), qEnvironmentVariableIsEmpty(),
qEnvironmentVariableIntegerValue()
*/
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
{
@ -192,6 +193,45 @@ bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
\sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet()
*/
int qEnvironmentVariableIntValue(const char *varName, bool *ok) noexcept
{
std::optional<int> value = qEnvironmentVariableIntegerValue(varName);
if (ok)
*ok = bool(value);
return value.value_or(0);
}
/*!
\relates <QtEnvironmentVariables>
\since 6.10
Returns the numerical value of the environment variable \a varName. If the
variable is not set or could not be parsed as an integer, it returns
\c{std::nullopt}.
Similar to
\snippet code/src_corelib_global_qglobal.cpp to-int
except that it's much faster, and can't throw exceptions.
If a value of zero is semantically the same as an empty or unset variable,
applications can use
\snippet code/src_corelib_global_qglobal.cpp int-value_or
Do note in this case that failures to parse a value will also produce a
zero.
But if a value of zero can be used to disable some functionality,
applications can compare the returned \c{std::optional} to zero, which will
only be true if the variable was set and contained a number that parsed as
zero, as in:
\snippet code/src_corelib_global_qglobal.cpp int-eq0
\note there's a limit on the length of the value, which is sufficient for
all valid values of int, not counting leading zeroes or spaces. Values that
are too long will either be truncated or this function will return
\c{std::nullopt}.
\sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet()
*/
std::optional<int> qEnvironmentVariableIntegerValue(const char *varName) noexcept
{
static const int NumBinaryDigitsPerOctalDigit = 3;
static const int MaxDigitsForOctalInt =
@ -205,21 +245,19 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) noexcept
// we provide a buffer that can hold any int value:
char buffer[MaxDigitsForOctalInt + 1]; // +1 for the terminating null
size_t dummy;
if (getenv_s(&dummy, buffer, sizeof buffer, varName) != 0) {
if (ok)
*ok = false;
return 0;
}
if (getenv_s(&dummy, buffer, sizeof buffer, varName) != 0)
return std::nullopt;
size = strlen(buffer);
#else
const char * const buffer = ::getenv(varName);
if (!buffer || (size = strlen(buffer)) > MaxDigitsForOctalInt) {
if (ok)
*ok = false;
return 0;
}
if (!buffer || (size = strlen(buffer)) > MaxDigitsForOctalInt)
return std::nullopt;
#endif
return QByteArrayView(buffer, size).toInt(ok, 0);
bool ok;
int value = QByteArrayView(buffer, size).toInt(&ok, 0);
if (!ok)
return std::nullopt;
return value;
}
/*!
@ -232,7 +270,8 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) noexcept
\snippet code/src_corelib_global_qglobal.cpp is-null
except that it's potentially much faster, and can't throw exceptions.
\sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsEmpty()
\sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsEmpty(),
qEnvironmentVariableIntegerValue()
*/
bool qEnvironmentVariableIsSet(const char *varName) noexcept
{

View File

@ -8,6 +8,8 @@
#include <QtCore/qtcoreexports.h>
#include <QtCore/qtdeprecationmarkers.h>
#include <optional>
#if 0
#pragma qt_class(QtEnvironmentVariables)
#pragma qt_sync_stop_processing
@ -32,6 +34,7 @@ Q_CORE_EXPORT bool qunsetenv(const char *varName);
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept;
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept;
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept;
Q_CORE_EXPORT std::optional<int> qEnvironmentVariableIntegerValue(const char *varName) noexcept;
QT_END_NAMESPACE

View File

@ -40,14 +40,6 @@ static std::optional<QByteArray> qEnvironmentVariableOptionalByteArray(const cha
return value.isNull() ? std::nullopt : std::optional(std::move(value));
}
static std::optional<int> qEnvironmentVariableOptionalInt(const char *name)
{
bool ok = false;
const int value = qEnvironmentVariableIntValue(name, &ok);
auto opt = ok ? std::optional(value) : std::nullopt;
return opt;
}
static std::optional<qreal> qEnvironmentVariableOptionalReal(const char *name)
{
const QByteArray val = qgetenv(name);
@ -402,7 +394,7 @@ void QHighDpiScaling::initHighDpiScaling()
// Read environment variables
static const char* envDebugStr = "environment variable set:";
std::optional<int> envEnableHighDpiScaling = qEnvironmentVariableOptionalInt(enableHighDpiScalingEnvVar);
std::optional<int> envEnableHighDpiScaling = qEnvironmentVariableIntegerValue(enableHighDpiScalingEnvVar);
if (envEnableHighDpiScaling.has_value())
qCDebug(lcHighDpi) << envDebugStr << enableHighDpiScalingEnvVar << envEnableHighDpiScaling.value();
@ -414,7 +406,7 @@ void QHighDpiScaling::initHighDpiScaling()
if (envScreenFactors.has_value())
qCDebug(lcHighDpi) << envDebugStr << screenFactorsEnvVar << envScreenFactors.value();
std::optional<int> envUsePhysicalDpi = qEnvironmentVariableOptionalInt(usePhysicalDpiEnvVar);
std::optional<int> envUsePhysicalDpi = qEnvironmentVariableIntegerValue(usePhysicalDpiEnvVar);
if (envUsePhysicalDpi.has_value())
qCDebug(lcHighDpi) << envDebugStr << usePhysicalDpiEnvVar << envUsePhysicalDpi.value();

View File

@ -28,6 +28,7 @@ void tst_QGetPutEnv::getSetCheck()
QVERIFY(!qEnvironmentVariableIsSet(varName));
QVERIFY(qEnvironmentVariableIsEmpty(varName));
QCOMPARE(qEnvironmentVariableIntegerValue(varName), std::nullopt);
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
@ -44,6 +45,7 @@ void tst_QGetPutEnv::getSetCheck()
QVERIFY(qEnvironmentVariableIsSet(varName));
QVERIFY(qEnvironmentVariableIsEmpty(varName));
QCOMPARE(qEnvironmentVariableIntegerValue(varName), std::nullopt);
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
@ -68,6 +70,7 @@ void tst_QGetPutEnv::getSetCheck()
QVERIFY(qEnvironmentVariableIsSet(varName));
QVERIFY(!qEnvironmentVariableIsEmpty(varName));
QCOMPARE(qEnvironmentVariableIntegerValue(varName), std::nullopt);
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
@ -85,6 +88,7 @@ void tst_QGetPutEnv::getSetCheck()
QVERIFY(qunsetenv(varName));
QVERIFY(!qEnvironmentVariableIsSet(varName)); // note: might fail on some systems!
QVERIFY(qEnvironmentVariableIsEmpty(varName));
QCOMPARE(qEnvironmentVariableIntegerValue(varName), std::nullopt);
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
@ -210,6 +214,10 @@ void tst_QGetPutEnv::intValue()
QCOMPARE(qEnvironmentVariableIntValue(varName), expected);
QCOMPARE(qEnvironmentVariableIntValue(varName, &actualOk), expected);
QCOMPARE(actualOk, ok);
if (actualOk)
QCOMPARE(qEnvironmentVariableIntegerValue(varName), expected);
else
QCOMPARE(qEnvironmentVariableIntegerValue(varName), std::nullopt);
}
QTEST_MAIN(tst_QGetPutEnv)