diff options
Diffstat (limited to 'include/EASTL/internal/atomic/atomic.h')
-rw-r--r-- | include/EASTL/internal/atomic/atomic.h | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/include/EASTL/internal/atomic/atomic.h b/include/EASTL/internal/atomic/atomic.h new file mode 100644 index 0000000..e1c5286 --- /dev/null +++ b/include/EASTL/internal/atomic/atomic.h @@ -0,0 +1,252 @@ +///////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_ATOMIC_INTERNAL_H +#define EASTL_ATOMIC_INTERNAL_H + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once +#endif + + +#include <EASTL/internal/config.h> +#include <EASTL/internal/move_help.h> +#include <EASTL/internal/memory_base.h> +#include <EASTL/type_traits.h> + +#include "atomic_macros.h" +#include "atomic_casts.h" + +#include "atomic_memory_order.h" +#include "atomic_asserts.h" + +#include "atomic_size_aligned.h" +#include "atomic_base_width.h" + +#include "atomic_integral.h" + +#include "atomic_pointer.h" + + +///////////////////////////////////////////////////////////////////////////////// + + +/** + * NOTE: + * + * All of the actual implementation is done via the ATOMIC_MACROS in the compiler or arch sub folders. + * The C++ code is merely boilerplate around these macros that actually implement the atomic operations. + * The C++ boilerplate is also hidden behind macros. + * This may seem more complicated but this is all meant to reduce copy-pasting and to ensure all operations + * all end up going down to one macro that does the actual implementation. + * The reduced code duplication makes it easier to verify the implementation and reason about it. + * Ensures we do not have to re-implement the same code for compilers that do not support generic builtins such as MSVC. + * Ensures for compilers that have separate intrinsics for different widths, that C++ boilerplate isn't copy-pasted leading to programmer errors. + * Ensures if we ever have to implement a new platform, only the low-level leaf macros have to be implemented, everything else will be generated for you. + */ + + +#include "atomic_push_compiler_options.h" + + +namespace eastl +{ + + +namespace internal +{ + + + template <typename T> + struct is_atomic_lockfree_size + { + static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = false || + #if defined(EASTL_ATOMIC_HAS_8BIT) + sizeof(T) == 1 || + #endif + #if defined(EASTL_ATOMIC_HAS_16BIT) + sizeof(T) == 2 || + #endif + #if defined(EASTL_ATOMIC_HAS_32BIT) + sizeof(T) == 4 || + #endif + #if defined(EASTL_ATOMIC_HAS_64BIT) + sizeof(T) == 8 || + #endif + #if defined(EASTL_ATOMIC_HAS_128BIT) + sizeof(T) == 16 || + #endif + false; + }; + + + template <typename T> + struct is_user_type_suitable_for_primary_template + { + static EASTL_CPP17_INLINE_VARIABLE constexpr bool value = eastl::internal::is_atomic_lockfree_size<T>::value; + }; + + + template <typename T> + using select_atomic_inherit_0 = typename eastl::conditional<eastl::is_same_v<bool, T> || eastl::internal::is_user_type_suitable_for_primary_template<T>::value, + eastl::internal::atomic_base_width<T>, /* True */ + eastl::internal::atomic_invalid_type<T> /* False */ + >::type; + + template <typename T> + using select_atomic_inherit = select_atomic_inherit_0<T>; + + +} // namespace internal + + +#define EASTL_ATOMIC_CLASS_IMPL(type, base, valueType, differenceType) \ + private: \ + \ + EASTL_ATOMIC_STATIC_ASSERT_TYPE(type); \ + \ + using Base = base; \ + \ + public: \ + \ + typedef valueType value_type; \ + typedef differenceType difference_type; \ + \ + public: \ + \ + static EASTL_CPP17_INLINE_VARIABLE constexpr bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size<type>::value; \ + \ + public: /* deleted ctors && assignment operators */ \ + \ + atomic(const atomic&) EA_NOEXCEPT = delete; \ + \ + atomic& operator=(const atomic&) EA_NOEXCEPT = delete; \ + atomic& operator=(const atomic&) volatile EA_NOEXCEPT = delete; \ + \ + public: /* ctors */ \ + \ + EA_CONSTEXPR atomic(type desired) EA_NOEXCEPT \ + : Base{ desired } \ + { \ + } \ + \ + EA_CONSTEXPR atomic() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v<type>) = default; \ + \ + public: \ + \ + bool is_lock_free() const EA_NOEXCEPT \ + { \ + return eastl::internal::is_atomic_lockfree_size<type>::value; \ + } \ + \ + bool is_lock_free() const volatile EA_NOEXCEPT \ + { \ + EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(type); \ + return false; \ + } + + +#define EASTL_ATOMIC_USING_ATOMIC_BASE(type) \ + public: \ + \ + using Base::operator=; \ + using Base::store; \ + using Base::load; \ + using Base::exchange; \ + using Base::compare_exchange_weak; \ + using Base::compare_exchange_strong; \ + \ + public: \ + \ + operator type() const volatile EA_NOEXCEPT \ + { \ + EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \ + } \ + \ + operator type() const EA_NOEXCEPT \ + { \ + return load(eastl::memory_order_seq_cst); \ + } + + +#define EASTL_ATOMIC_USING_ATOMIC_INTEGRAL() \ + public: \ + \ + using Base::fetch_add; \ + using Base::add_fetch; \ + \ + using Base::fetch_sub; \ + using Base::sub_fetch; \ + \ + using Base::fetch_and; \ + using Base::and_fetch; \ + \ + using Base::fetch_or; \ + using Base::or_fetch; \ + \ + using Base::fetch_xor; \ + using Base::xor_fetch; \ + \ + using Base::operator++; \ + using Base::operator--; \ + using Base::operator+=; \ + using Base::operator-=; \ + using Base::operator&=; \ + using Base::operator|=; \ + using Base::operator^=; + + +#define EASTL_ATOMIC_USING_ATOMIC_POINTER() \ + public: \ + \ + using Base::fetch_add; \ + using Base::add_fetch; \ + using Base::fetch_sub; \ + using Base::sub_fetch; \ + \ + using Base::operator++; \ + using Base::operator--; \ + using Base::operator+=; \ + using Base::operator-=; + + +template <typename T, typename = void> +struct atomic : protected eastl::internal::select_atomic_inherit<T> +{ + EASTL_ATOMIC_CLASS_IMPL(T, eastl::internal::select_atomic_inherit<T>, T, T) + + EASTL_ATOMIC_USING_ATOMIC_BASE(T) +}; + + +template <typename T> +struct atomic<T, eastl::enable_if_t<eastl::is_integral_v<T> && !eastl::is_same_v<bool, T>>> : protected eastl::internal::atomic_integral_width<T> +{ + EASTL_ATOMIC_CLASS_IMPL(T, eastl::internal::atomic_integral_width<T>, T, T) + + EASTL_ATOMIC_USING_ATOMIC_BASE(T) + + EASTL_ATOMIC_USING_ATOMIC_INTEGRAL() +}; + + +template <typename T> +struct atomic<T*> : protected eastl::internal::atomic_pointer_width<T*> +{ + EASTL_ATOMIC_CLASS_IMPL(T*, eastl::internal::atomic_pointer_width<T*>, T*, ptrdiff_t) + + EASTL_ATOMIC_USING_ATOMIC_BASE(T*) + + EASTL_ATOMIC_USING_ATOMIC_POINTER() +}; + + +} // namespace eastl + + +#include "atomic_pop_compiler_options.h" + + +#endif /* EASTL_ATOMIC_INTERNAL_H */ |