katie/src/core/thread/qatomic.h
Ivailo Monev 434192716e export QAtomicInt and QAtomicPointer
Signed-off-by: Ivailo Monev <xakepa10@laimg.moc>
2016-10-04 16:57:16 +00:00

361 lines
9.4 KiB
C++

/***********************************************************************
*
* Copyright (c) 2012-2016 Barbara Geller
* Copyright (c) 2012-2016 Ansel Sermersheim
* Copyright (c) 2012-2014 Digia Plc and/or its subsidiary(-ies).
* Copyright (c) 2008-2012 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* This file is part of CopperSpice.
*
* CopperSpice is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* CopperSpice is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with CopperSpice. If not, see
* <http://www.gnu.org/licenses/>.
*
***********************************************************************/
#ifndef QATOMIC_H
#define QATOMIC_H
#include "QtCore/qglobal.h"
#include <atomic>
#include <cstddef>
#ifndef ATOMIC_INT_LOCK_FREE
#define ATOMIC_INT_LOCK_FREE 0
#endif
#ifndef ATOMIC_POINTER_LOCK_FREE
#define ATOMIC_POINTER_LOCK_FREE 0
#endif
QT_BEGIN_NAMESPACE
QT_BEGIN_HEADER
class Q_CORE_EXPORT QAtomicInt
{
public:
inline QAtomicInt() : m_data(0) {
}
inline QAtomicInt(int value) : m_data(value) {
}
inline QAtomicInt(const QAtomicInt &other) {
int data = other.load();
store(data);
}
inline QAtomicInt &operator=(const QAtomicInt &other) {
int data = other.load();
store(data);
return *this;
}
inline QAtomicInt &operator=(int data) {
store(data);
return *this;
}
int load() const {
return m_data.load();
}
int loadAcquire() {
return m_data.load(std::memory_order_acquire);
}
void store(int newValue) {
m_data.store(newValue);
}
void storeRelease(int newValue) {
m_data.store(newValue, std::memory_order_release);
}
//
static bool isReferenceCountingNative() {
return ATOMIC_INT_LOCK_FREE == 2;
}
static bool isReferenceCountingWaitFree() {
return ATOMIC_INT_LOCK_FREE == 2;
}
bool ref() {
int newValue = ++m_data;
return newValue != 0;
}
bool deref() {
int newValue = --m_data;
return newValue != 0;
}
//
static bool isTestAndSetNative() {
return ATOMIC_INT_LOCK_FREE == 2;
}
static bool isTestAndSetWaitFree() {
return ATOMIC_INT_LOCK_FREE == 2;
}
bool testAndSetRelaxed(int expectedValue, int newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_relaxed);
}
bool testAndSetAcquire(int expectedValue, int newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_acquire);
}
bool testAndSetRelease(int expectedValue, int newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_release);
}
bool testAndSetOrdered(int expectedValue, int newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_seq_cst);
}
//
static bool isFetchAndStoreNative() {
return ATOMIC_INT_LOCK_FREE == 2;
}
static bool isFetchAndStoreWaitFree() {
return ATOMIC_INT_LOCK_FREE == 2;
}
int fetchAndStoreRelaxed(int newValue) {
return m_data.exchange(newValue, std::memory_order_relaxed);
}
int fetchAndStoreAcquire(int newValue) {
return m_data.exchange(newValue, std::memory_order_acquire);
}
int fetchAndStoreRelease(int newValue) {
return m_data.exchange(newValue, std::memory_order_release);
}
int fetchAndStoreOrdered(int newValue) {
return m_data.exchange(newValue, std::memory_order_seq_cst);
}
//
static bool isFetchAndAddNative() {
return ATOMIC_INT_LOCK_FREE == 2;
}
static bool isFetchAndAddWaitFree() {
return ATOMIC_INT_LOCK_FREE == 2;
}
int fetchAndAddRelaxed(int valueToAdd) {
return m_data.fetch_add(valueToAdd, std::memory_order_relaxed);
}
int fetchAndAddAcquire(int valueToAdd) {
return m_data.fetch_add(valueToAdd, std::memory_order_acquire);
}
int fetchAndAddRelease(int valueToAdd) {
return m_data.fetch_add(valueToAdd, std::memory_order_release);
}
int fetchAndAddOrdered(int valueToAdd) {
return m_data.fetch_add(valueToAdd, std::memory_order_seq_cst);
}
inline operator int() const
{ return load(); }
private:
std::atomic<int> m_data;
};
template <typename T>
class Q_CORE_EXPORT QAtomicPointer
{
public:
QAtomicPointer(T *value = 0) : m_data(value) {
}
QAtomicPointer(const QAtomicPointer<T> &other) {
T *data = other.load();
store(data);
}
QAtomicPointer<T> &operator=(const QAtomicPointer<T> &other) {
T *data = other.load();
store(data);
return *this;
}
QAtomicPointer<T> &operator=(T *data) {
store(data);
return *this;
}
T *load() const {
return m_data.load();
}
T *loadAcquire() {
return m_data.load(std::memory_order_acquire);
}
void store(T *newValue) {
m_data.store(newValue);
}
void storeRelease(T *newValue) {
m_data.store(newValue, std::memory_order_release);
}
//
static bool isTestAndSetNative() {
return ATOMIC_POINTER_LOCK_FREE == 2;
}
static bool isTestAndSetWaitFree() {
return ATOMIC_POINTER_LOCK_FREE == 2;
}
bool testAndSetRelaxed(T *expectedValue, T *newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_relaxed);
}
bool testAndSetAcquire(T *expectedValue, T *newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_acquire);
}
bool testAndSetRelease(T *expectedValue, T *newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_release);
}
bool testAndSetOrdered(T *expectedValue, T *newValue) {
return m_data.compare_exchange_strong(expectedValue, newValue, std::memory_order_seq_cst);
}
//
static bool isFetchAndStoreNative() {
return ATOMIC_POINTER_LOCK_FREE == 2;
}
static bool isFetchAndStoreWaitFree() {
return ATOMIC_POINTER_LOCK_FREE == 2;
}
T *fetchAndStoreRelaxed(T *newValue) {
return m_data.exchange(newValue, std::memory_order_relaxed);
}
T *fetchAndStoreAcquire(T *newValue) {
return m_data.exchange(newValue, std::memory_order_acquire);
}
T *fetchAndStoreRelease(T *newValue) {
return m_data.exchange(newValue, std::memory_order_release);
}
T *fetchAndStoreOrdered(T *newValue) {
return m_data.exchange(newValue, std::memory_order_seq_cst);
}
//
static bool isFetchAndAddNative() {
return ATOMIC_POINTER_LOCK_FREE == 2;
}
static bool isFetchAndAddWaitFree() {
return ATOMIC_POINTER_LOCK_FREE == 2;
}
T *fetchAndAddRelaxed(std::ptrdiff_t valueToAdd) {
return m_data.fetch_add(valueToAdd, std::memory_order_relaxed);
}
T *fetchAndAddAcquire(std::ptrdiff_t valueToAdd) {
return m_data.fetch_add(valueToAdd, std::memory_order_acquire);
}
T *fetchAndAddRelease(std::ptrdiff_t valueToAdd){
return m_data.fetch_add(valueToAdd, std::memory_order_release);
}
T *fetchAndAddOrdered(std::ptrdiff_t valueToAdd){
return m_data.fetch_add(valueToAdd, std::memory_order_seq_cst);
}
inline operator T *() const
{ return load(); }
inline T *operator->() const
{ return load(); }
private:
std::atomic<T *> m_data;
};
/*!
This is a helper for the assignment operators of implicitly
shared classes. Your assignment operator should look like this:
\snippet doc/src/snippets/code/src.corelib.thread.qatomic.h 0
*/
template <typename T>
inline void qAtomicAssign(T *&d, T *x)
{
if (d == x) {
return;
}
x->ref.ref();
if (! d->ref.deref()) {
delete d;
}
d = x;
}
/*!
This is a helper for the detach method of implicitly shared
classes. Your private class needs a copy constructor which copies
the members and sets the refcount to 1. After that, your detach
function should look like this:
\snippet doc/src/snippets/code/src.corelib.thread.qatomic.h 1
*/
template <typename T>
inline void qAtomicDetach(T *&d)
{
if (d->ref.load() == 1) {
return;
}
T *x = d;
d = new T(*d);
if (! x->ref.deref()) {
delete x;
}
}
QT_END_NAMESPACE
QT_END_HEADER
#endif // QATOMIC_H