@@ -24,19 +24,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
24
24
#if __cplusplus >= 201103L
25
25
#include < atomic>
26
26
template <typename T> using Atomic = std::atomic<T>;
27
+ template <typename T> using GenericAtomic = std::atomic<T>;
27
28
#else
28
29
29
30
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
30
31
#define CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
31
32
#if GCC_VERSION >= 407 || CLANG_VERSION >= 302
33
+ #define ATOMIC_LOAD_GENERIC (T, v ) do { \
34
+ T _val; \
35
+ __atomic_load (&(v), &(_val), __ATOMIC_SEQ_CST); \
36
+ return _val; \
37
+ } while (0 )
32
38
#define ATOMIC_LOAD (T, v ) return __atomic_load_n (&(v), __ATOMIC_SEQ_CST)
33
39
#define ATOMIC_STORE (T, v, x ) __atomic_store (&(v), &(x), __ATOMIC_SEQ_CST); return x
34
- #define ATOMIC_EXCHANGE (T, v, x ) return __atomic_exchange_n (&(v), (x), __ATOMIC_SEQ_CST)
40
+ #define ATOMIC_EXCHANGE (T, v, x ) return __atomic_exchange (&(v), & (x), __ATOMIC_SEQ_CST)
35
41
#define ATOMIC_ADD_EQ (T, v, x ) return __atomic_add_fetch (&(v), (x), __ATOMIC_SEQ_CST)
36
42
#define ATOMIC_SUB_EQ (T, v, x ) return __atomic_sub_fetch (&(v), (x), __ATOMIC_SEQ_CST)
37
43
#define ATOMIC_POST_INC (T, v ) return __atomic_fetch_add (&(v), 1 , __ATOMIC_SEQ_CST)
38
44
#define ATOMIC_POST_DEC (T, v ) return __atomic_fetch_sub (&(v), 1 , __ATOMIC_SEQ_CST)
39
- #define ATOMIC_CAS (T, v, e, d ) return __atomic_compare_exchange_n (&(v), &(e), (d), \
45
+ #define ATOMIC_CAS (T, v, e, d ) return __atomic_compare_exchange (&(v), &(e), & (d), \
40
46
false , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
41
47
#else
42
48
#define ATOMIC_USE_LOCK
@@ -56,12 +62,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
56
62
m_mutex.unlock (); \
57
63
return _eq; \
58
64
} while (0 )
59
- #define ATOMIC_LOAD (T, v ) \
60
- if (sizeof (T) <= sizeof (void *)) return v; \
61
- else ATOMIC_LOCK_OP(T, v);
62
- #define ATOMIC_STORE (T, v, x ) \
63
- if (sizeof (T) <= sizeof (void *)) return v = x; \
64
- else ATOMIC_LOCK_OP(T, v = x);
65
+ #define ATOMIC_LOAD (T, v ) ATOMIC_LOCK_OP(T, v)
66
+ #define ATOMIC_LOAD_GENERIC (T, v ) ATOMIC_LOAD(T, v)
67
+ #define ATOMIC_STORE (T, v, x ) ATOMIC_LOCK_OP(T, v = x)
65
68
#define ATOMIC_EXCHANGE (T, v, x ) do { \
66
69
m_mutex.lock (); \
67
70
T _val = v; \
@@ -84,32 +87,53 @@ with this program; if not, write to the Free Software Foundation, Inc.,
84
87
#endif
85
88
#endif
86
89
87
-
90
+ // For usage with integral types.
88
91
template <typename T>
89
92
class Atomic {
90
93
public:
91
- Atomic (const T &v = 0 ) : val (v) {}
94
+ Atomic (const T &v = 0 ) : m_val (v) {}
92
95
93
- operator T () { ATOMIC_LOAD (T, val ); }
96
+ operator T () { ATOMIC_LOAD (T, m_val ); }
94
97
95
- T exchange (T x) { ATOMIC_EXCHANGE (T, val , x); }
96
- bool compare_exchange_strong (T &expected, T desired) { ATOMIC_CAS (T, val , expected, desired); }
98
+ T exchange (T x) { ATOMIC_EXCHANGE (T, m_val , x); }
99
+ bool compare_exchange_strong (T &expected, T desired) { ATOMIC_CAS (T, m_val , expected, desired); }
97
100
98
- T operator = (T x) { ATOMIC_STORE (T, val , x); }
99
- T operator += (T x) { ATOMIC_ADD_EQ (T, val , x); }
100
- T operator -= (T x) { ATOMIC_SUB_EQ (T, val , x); }
101
+ T operator = (T x) { ATOMIC_STORE (T, m_val , x); }
102
+ T operator += (T x) { ATOMIC_ADD_EQ (T, m_val , x); }
103
+ T operator -= (T x) { ATOMIC_SUB_EQ (T, m_val , x); }
101
104
T operator ++ () { return *this += 1 ; }
102
105
T operator -- () { return *this -= 1 ; }
103
- T operator ++ (int ) { ATOMIC_POST_INC (T, val ); }
104
- T operator -- (int ) { ATOMIC_POST_DEC (T, val ); }
106
+ T operator ++ (int ) { ATOMIC_POST_INC (T, m_val ); }
107
+ T operator -- (int ) { ATOMIC_POST_DEC (T, m_val ); }
105
108
private:
106
- T val ;
109
+ T m_val ;
107
110
#ifdef ATOMIC_USE_LOCK
108
111
Mutex m_mutex;
109
112
#endif
110
113
};
111
114
112
- #endif // C++11
115
+ // For usage with non-integral types like float for example.
116
+ // Needed because the other operations aren't provided by gcc
117
+ // for non-integral types:
118
+ // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/_005f_005fatomic-Builtins.html
119
+ template <typename T>
120
+ class GenericAtomic {
121
+ public:
122
+ GenericAtomic (const T &v = 0 ) : m_val(v) {}
113
123
124
+ operator T () { ATOMIC_LOAD_GENERIC (T, m_val); }
125
+
126
+ T exchange (T x) { ATOMIC_EXCHANGE (T, m_val, x); }
127
+ bool compare_exchange_strong (T &expected, T desired) { ATOMIC_CAS (T, m_val, expected, desired); }
128
+
129
+ T operator = (T x) { ATOMIC_STORE (T, m_val, x); }
130
+ private:
131
+ T m_val;
132
+ #ifdef ATOMIC_USE_LOCK
133
+ Mutex m_mutex;
114
134
#endif
135
+ };
115
136
137
+ #endif // C++11
138
+
139
+ #endif
2 commit comments
ShadowNinja commentedon Nov 12, 2015
Instead of adding a
GenericAtomic
class you should just add locks for the unsuported operation/type combinations.est31 commentedon Nov 12, 2015
That's bad IMO because then people will use these operations, assuming they were fast. Atomic should stay as close to hardware as possible, that's the whole point why it exists the first place.