/* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include namespace ams::util { namespace impl { template struct AtomicIntegerStorage; template requires (sizeof(T) == sizeof(u8)) struct AtomicIntegerStorage { using Type = u8; }; template requires (sizeof(T) == sizeof(u16)) struct AtomicIntegerStorage { using Type = u16; }; template requires (sizeof(T) == sizeof(u32)) struct AtomicIntegerStorage { using Type = u32; }; template requires (sizeof(T) == sizeof(u64)) struct AtomicIntegerStorage { using Type = u64; }; template concept UsableAtomicType = (sizeof(T) <= sizeof(u64)) && !std::is_const::value && !std::is_volatile::value && (std::is_pointer::value || requires (const T &t) { std::bit_cast::Type, T>(t); }); } template class Atomic { NON_COPYABLE(Atomic); NON_MOVEABLE(Atomic); private: static_assert(std::atomic::is_always_lock_free); private: std::atomic m_v; public: ALWAYS_INLINE explicit Atomic() { /* ... */ } constexpr ALWAYS_INLINE explicit Atomic(T v) : m_v(v) { /* ... */ } ALWAYS_INLINE T operator=(T desired) { return (m_v = desired); } template ALWAYS_INLINE T Load() const { return m_v.load(Order); } template ALWAYS_INLINE void Store(T arg) { return m_v.store(Order); } template ALWAYS_INLINE T Exchange(T arg) { return m_v.exchange(arg, Order); } template ALWAYS_INLINE bool CompareExchangeWeak(T &expected, T desired) { return m_v.compare_exchange_weak(expected, desired, Order); } template ALWAYS_INLINE bool CompareExchangeStrong(T &expected, T desired) { return m_v.compare_exchange_strong(expected, desired, Order); } #define AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(_OPERATION_, _OPERATION_LOWER_) \ ALWAYS_INLINE T Fetch ## _OPERATION_(T arg) { \ return m_v.fetch_##_OPERATION_LOWER_(arg); \ } AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Add, add) AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Sub, sub) AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(And, and) AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Or, or) AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Xor, xor) #undef AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION }; }