blob: 13a0b20250a027cb06bb1dccfc2258aa1b6cda55 [file] [log] [blame]
#ifndef SUPPORT_TEST_ATOMIC_H
#define SUPPORT_TEST_ATOMIC_H
// If the atomic memory order macros are defined then assume
// the compiler supports the required atomic builtins.
#if !defined(__ATOMIC_SEQ_CST)
#define TEST_HAS_NO_ATOMICS
#endif
template <class ValType>
class Atomic {
ValType value;
Atomic(Atomic const&);
Atomic& operator=(Atomic const&);
Atomic& operator=(Atomic const&) volatile;
private:
enum {
#if !defined(TEST_HAS_NO_ATOMICS)
AO_Relaxed = __ATOMIC_RELAXED,
AO_Seq = __ATOMIC_SEQ_CST
#else
AO_Relaxed,
AO_Seq
#endif
};
template <class Tp, class FromType>
static inline void atomic_store_imp(Tp* dest, FromType from, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
__atomic_store_n(dest, from, order);
#else
*dest = from;
#endif
}
template <class Tp>
static inline Tp atomic_load_imp(Tp* from, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
return __atomic_load_n(from, order);
#else
return *from;
#endif
}
template <class Tp, class AddType>
static inline Tp atomic_add_imp(Tp* val, AddType add, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
return __atomic_add_fetch(val, add, order);
#else
return *val += add;
#endif
}
template <class Tp>
static inline Tp atomic_exchange_imp(Tp* val, Tp other, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
return __atomic_exchange_n(val, other, order);
#else
Tp old = *val;
*val = other;
return old;
#endif
}
public:
Atomic() : value(0) {}
Atomic(ValType x) : value(x) {}
ValType operator=(ValType val) {
atomic_store_imp(&value, val);
return val;
}
ValType operator=(ValType val) volatile {
atomic_store_imp(&value, val);
return val;
}
ValType load() const volatile { return atomic_load_imp(&value); }
void store(ValType val) volatile { atomic_store_imp(&value, val); }
ValType relaxedLoad() const volatile { return atomic_load_imp(&value, AO_Relaxed); }
void relaxedStore(ValType val) volatile { atomic_store_imp(&value, val, AO_Relaxed); }
ValType exchange(ValType other) volatile { return atomic_exchange_imp(&value, other); }
bool testAndSet() volatile { return atomic_exchange_imp(&value, 1); }
void clear() volatile { atomic_store_imp(&value, 0); }
operator ValType() const { return atomic_load_imp(&value); }
operator ValType() const volatile { return atomic_load_imp(&value); }
ValType operator+=(ValType val) { return atomic_add_imp(&value, val); }
ValType operator-=(ValType val) { return atomic_add_imp(&value, -val); }
ValType operator+=(ValType val) volatile { return atomic_add_imp(&value, val); }
ValType operator-=(ValType val) volatile { return atomic_add_imp(&value, -val); }
ValType operator++() { return *this += 1; }
ValType operator++(int) { return (*this += 1) - 1; }
ValType operator++() volatile { return *this += 1; }
ValType operator++(int) volatile { return (*this += 1) - 1; }
ValType operator--() { return *this -= 1; }
ValType operator--(int) { return (*this -= 1) + 1; }
ValType operator--() volatile { return *this -= 1; }
ValType operator--(int) volatile { return (*this -= 1) + 1; }
};
typedef Atomic<int> AtomicInt;
typedef Atomic<bool> AtomicBool;
#endif // SUPPORT_TEST_ATOMIC_H