// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #pragma once #include #include namespace anki { /// @addtogroup util_other /// @{ enum class AtomicMemoryOrder { RELAXED = std::memory_order_relaxed, CONSUME = std::memory_order_consume, ACQUIRE = std::memory_order_acquire, RELEASE = std::memory_order_release, ACQ_REL = std::memory_order_acq_rel, SEQ_CST = std::memory_order_seq_cst }; /// Atomic template. At the moment it doesn't work well with pointers. template class Atomic { public: using Value = T; static constexpr AtomicMemoryOrder MEMORY_ORDER = tmemOrd; /// It will not set itself to zero. Atomic() { } Atomic(Value a) : m_val(a) { } Atomic(const Atomic&) = delete; // Non-copyable Atomic& operator=(const Atomic&) = delete; // Non-copyable /// Set the value without protection. void setNonAtomically(Value a) { m_val = a; } /// Get the value without protection. Value getNonAtomically() const { return m_val; } /// Get the value of the atomic. Value load(AtomicMemoryOrder memOrd = MEMORY_ORDER) const { return m_att.load(static_cast(memOrd)); } /// Store void store(Value a, AtomicMemoryOrder memOrd = MEMORY_ORDER) { m_att.store(a, static_cast(memOrd)); } /// Fetch and add. template Value fetchAdd(Y a, AtomicMemoryOrder memOrd = MEMORY_ORDER) { return m_att.fetch_add(a, static_cast(memOrd)); } /// Fetch and subtract. template Value fetchSub(Y a, AtomicMemoryOrder memOrd = MEMORY_ORDER) { return m_att.fetch_sub(a, static_cast(memOrd)); } /// Fetch and do bitwise or. template Value fetchOr(Y a, AtomicMemoryOrder memOrd = MEMORY_ORDER) { return m_att.fetch_or(a, static_cast(memOrd)); } /// Fetch and do bitwise and. template Value fetchAnd(Y a, AtomicMemoryOrder memOrd = MEMORY_ORDER) { return m_att.fetch_and(a, static_cast(memOrd)); } /// @code /// if(m_val == expected) { /// m_val = desired; /// return true; /// } else { /// expected = m_val; /// return false; /// } /// @endcode Bool compareExchange(Value& expected, Value desired, AtomicMemoryOrder successMemOrd = MEMORY_ORDER, AtomicMemoryOrder failMemOrd = MEMORY_ORDER) { return m_att.compare_exchange_weak(expected, desired, static_cast(successMemOrd), static_cast(failMemOrd)); } /// Set @a a to the atomic and return the previous value. Value exchange(Value a, AtomicMemoryOrder memOrd = MEMORY_ORDER) { return m_att.exchange(a, static_cast(memOrd)); } /// Store the minimum using compare-and-swap. void min(Value a) { Value prev = load(); while(a < prev && !compareExchange(prev, a)) { } } /// Store the maximum using compare-and-swap. void max(Value a) { Value prev = load(); while(a > prev && !compareExchange(prev, a)) { } } private: union { Value m_val; std::atomic m_att; }; }; /// @} } // end namespace anki