diff options
author | Marc Mutz <marc.mutz@qt.io> | 2022-05-30 13:48:52 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2022-05-31 19:25:52 +0200 |
commit | 5e48a51608485cbc87b68498fd54ab36f001d584 (patch) | |
tree | 83a088b06111b0a58ee9dd6c19db03c0adb01537 /src/corelib/tools/qatomicscopedvaluerollback_p.h | |
parent | 4fc66d760376d736a3f85c945bdaed83ccdfcfe3 (diff) |
Long live QAtomicScopedValueRollback (private API)!
QScopedValueRollback has a few users that apply it on QAtomicInt,
which happens to work as QAtomicInt is copy-constructible and its
ctors are implicit.
But that's of course nonsense. We don't need to store the oldValue in
an atomic, nor do we need to pass the new value into the ctor as an
atomic.
So, add a QAtomicScopedValueRollback which works on std::atomic as
well as the Qt atomics, but distinguishes between the reference (which
is atomic) and the value (which isn't), and use it in one of the
users, tst_QList.
Keep it private until we know whether there's an actual need for this.
The test is a copy of tst_qscopedvaluefallback, so the occasional
oddity (like atomic op*=) should be ignored.
Task-number: QTBUG-103835
Change-Id: I3c05b3e51f465698657a02ca5521ed465386e9a6
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib/tools/qatomicscopedvaluerollback_p.h')
-rw-r--r-- | src/corelib/tools/qatomicscopedvaluerollback_p.h | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/corelib/tools/qatomicscopedvaluerollback_p.h b/src/corelib/tools/qatomicscopedvaluerollback_p.h new file mode 100644 index 0000000000..c802244d2e --- /dev/null +++ b/src/corelib/tools/qatomicscopedvaluerollback_p.h @@ -0,0 +1,95 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QATOMICSCOPEDVALUEROLLBACK_P_H +#define QATOMICSCOPEDVALUEROLLBACK_P_H + +#include <QtCore/qglobal.h> +#include <QtCore/qatomic.h> + +#include <atomic> + +QT_BEGIN_NAMESPACE + +template <typename T> +class [[nodiscard]] QAtomicScopedValueRollback +{ + std::atomic<T> &m_atomic; + T m_value; + std::memory_order m_mo; + + Q_DISABLE_COPY_MOVE(QAtomicScopedValueRollback) + + constexpr std::memory_order store_part(std::memory_order mo) noexcept + { + switch (mo) { + case std::memory_order_relaxed: + case std::memory_order_consume: + case std::memory_order_acquire: return std::memory_order_relaxed; + case std::memory_order_release: + case std::memory_order_acq_rel: return std::memory_order_release; + case std::memory_order_seq_cst: return std::memory_order_seq_cst; + } + // GCC 8.x does not tread __builtin_unreachable() as constexpr +#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900) + Q_UNREACHABLE(); +#endif + return std::memory_order_seq_cst; + } +public: + // + // std::atomic: + // + explicit constexpr + QAtomicScopedValueRollback(std::atomic<T> &var, + std::memory_order mo = std::memory_order_seq_cst) + : m_atomic(var), m_value(var.load(mo)), m_mo(mo) {} + + explicit constexpr + QAtomicScopedValueRollback(std::atomic<T> &var, T value, + std::memory_order mo = std::memory_order_seq_cst) + : m_atomic(var), m_value(var.exchange(value, mo)), m_mo(mo) {} + + // + // Q(Basic)AtomicInteger: + // + explicit constexpr + QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, + std::memory_order mo = std::memory_order_seq_cst) + : QAtomicScopedValueRollback(var._q_value, mo) {} + + explicit constexpr + QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, T value, + std::memory_order mo = std::memory_order_seq_cst) + : QAtomicScopedValueRollback(var._q_value, value, mo) {} + + // + // Q(Basic)AtomicPointer: + // + explicit constexpr + QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, + std::memory_order mo = std::memory_order_seq_cst) + : QAtomicScopedValueRollback(var._q_value, mo) {} + + explicit constexpr + QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, T value, + std::memory_order mo = std::memory_order_seq_cst) + : QAtomicScopedValueRollback(var._q_value, value, mo) {} + +#if __cpp_constexpr >= 201907L + constexpr +#endif + ~QAtomicScopedValueRollback() + { + m_atomic.store(m_value, store_part(m_mo)); + } + + constexpr void commit() + { + m_value = m_atomic.load(m_mo); + } +}; + +QT_END_NAMESPACE + +#endif // QATOMICASCOPEDVALUEROLLBACK_P_H |