aboutsummaryrefslogtreecommitdiff
path: root/include/EASTL/internal/atomic/atomic.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/EASTL/internal/atomic/atomic.h')
-rw-r--r--include/EASTL/internal/atomic/atomic.h252
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 */