Revert "Remove CDS_CXX11_ATOMIC_BEGIN_NAMESPACE/CDS_CXX11_ATOMIC_END_NAMESPACE defines"
[libcds.git] / cds / cxx11_atomic.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CXX11_ATOMIC_H
4 #define __CDS_CXX11_ATOMIC_H
5
6 #include <cds/details/defs.h>
7
8 namespace cds {
9
10 /// C++11 Atomic library support
11 /** @ingroup cds_cxx11_stdlib_wrapper
12     <b>libcds</b> has an implementation of C++11 atomic library (header <tt><cds/cxx11_atomic.h></tt>)
13     specified in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf">N3242, p.29</a>.
14
15     This implementation has full support
16     - <tt>atomic<T></tt> class and its specializations for integral types and pointers
17     - <tt>atomic_flag</tt> class
18     - free <tt>atomic_xxx</tt> functions
19
20     Exclusions: the following features specified in C++11 standard are not implemented:
21     - Atomic emulation. The library implements only genuine atomic operations for supported processors
22     - Static initialization macros (like \p ATOMIC_FLAG_INIT and others)
23     - \p atomic_init functions
24
25     Internal atomic implementation is used when the standard library provided by compiler
26     has no C++11 <tt>\<atomic\></tt> header or it is not standard compliant,
27     or when \p CDS_USE_LIBCDS_ATOMIC preprocessor macro is explicitly defined in compiler command line.
28     The library defines \p CDS_ATOMIC macro that specifies atomic library namespace:
29     - \p std for compiler-provided <tt>\<atomic\></tt> library
30     - \p boost if you use <tt>boost.atomic</tt> library (see note below)
31     - \p cds::cxx11_atomic if internal \p libcds atomic implementation used
32
33     The library has internal atomic implementation for the following processor architectures:
34     - Intel and AMD x86 (32bit) and amd64 (64bit)
35     - Intel Itanium IA64 (64bit)
36     - UltraSparc (64bit)
37
38     Using \p CDS_ATOMIC macro you may call <tt>\<atomic\></tt> library functions and classes,
39     for example:
40     \code
41     CDS_ATOMIC::atomic<int> atomInt;
42     CDS_ATOMIC::atomic_store_explicit( &atomInt, 0, CDS_ATOMIC::memory_order_release );
43     \endcode
44
45     \par Microsoft Visual C++
46
47     MS Visual C++ has native <tt>\<atomic\></tt> header beginning from Visual C++ 2012.
48     However, MSVC++ 2012 has a quite inefficient implementation on atomic load/store
49     based on \p compare_exchange, so \p libcds does not use MSVC++ 2012 atomics.
50     The \p libcds library defines \p CDS_ATOMIC as
51     - \p cds::cxx11_atomic (internal implementation) for MS VC++ 2008, 2010, and 2012
52     - \p std for MS VC++ 2013 and above.
53
54     \par GCC
55
56     For GCC compiler the macro \p CDS_ATOMIC is defined as:
57     - \p cds::cxx11_atomic by default
58     - \p std if the compiler version is 4.6 and \p CDS_CXX11_ATOMIC_GCC is defined (see below)
59     - \p std for GCC 4.7 and above
60
61     GCC team implements full support for C++11 memory model in version 4.7
62     (see <a href="http://gcc.gnu.org/wiki/Atomic/GCCMM">http://gcc.gnu.org/wiki/Atomic/GCCMM</a>).
63     \p libcds uses its own implementation of C++11 <tt>\<atomic\></tt> library located in
64     file <tt><cds/cxx11_atomic.h></tt> for GCC version up to 4.6. This implementation almost conforms to C++11 standard draft
65     <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf">N3242</a> (see exclusions above)
66     that is closest to final version.
67     However, GCC 4.6 has the implementation of <tt>\<atomic\></tt> header in its <tt>libstdc++</tt>
68     that is built on <tt>__sync_xxx</tt> (or <tt>__atomic_xxx</tt>) built-in functions. You can use <b>libcds</b> with GCC 4.6
69     <tt>\<atomic\></tt> specifying \p CDS_CXX11_ATOMIC_GCC macro in g++ command line:
70     \code g++ -DCDS_CXX11_ATOMIC_GCC ... \endcode
71     GCC 4.6 atomic implementation does not support <tt>atomic<T></tt> for <b>any</b> type \p T. The linker
72     generates "undefined symbol" error for <tt>atomic<T></tt> if \p T is not an integral type or a pointer. It is
73     not essential for intrusive and non-intrusive containers represented in \p libcds.
74     However, cds::memory::michael memory allocator cannot be linked with GCC 4.6 <tt>\<atomic\></tt> header.
75     This error has been fixed in GCC 4.7.
76
77     \par Clang
78
79     The macro \p CDS_ATOMIC is defined as \p cds::cxx11_atomic.
80     \p libcds does not yet use native clang atomics.
81
82     \par boost::atomic
83
84     Beginning from version 1.54, <a href="http://boost.org">boost</a> library contains an implementation of atomic
85     sufficient for \p libcds.
86     You can compile \p libcds and your projects with <tt>boost.atomic</tt> specifying \p -DCDS_USE_BOOST_ATOMIC
87     in compiler's command line.
88 */
89 namespace cxx11_atomics {
90 }} // namespace cds::cxx11_atomics
91
92 //@cond
93 #if defined(CDS_USE_BOOST_ATOMIC)
94     // boost atomic
95 #   include <boost/version.hpp>
96 #   if BOOST_VERSION >= 105400
97 #       include <boost/atomic.hpp>
98 #       define CDS_ATOMIC boost
99 #       define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
100 #       define CDS_CXX11_ATOMIC_END_NAMESPACE }
101 #   else
102 #       error "Boost version 1.54 or above is needed for boost.atomic"
103 #   endif
104 #elif defined(CDS_USE_LIBCDS_ATOMIC)
105     // libcds atomic
106 #   include <cds/compiler/cxx11_atomic.h>
107 #   define CDS_ATOMIC cds::cxx11_atomics
108 #   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomics {
109 #   define CDS_CXX11_ATOMIC_END_NAMESPACE }}
110 #else
111     // Compiler provided C++11 atomic
112 #   include <atomic>
113 #   define CDS_ATOMIC std
114 #   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
115 #   define CDS_CXX11_ATOMIC_END_NAMESPACE }
116 #endif
117 //@endcond
118
119 namespace cds {
120
121     /// Atomic primitives
122     /**
123         This namespace contains useful primitives derived from <tt>std::atomic</tt>.
124     */
125     namespace atomicity {
126
127         /// Atomic event counter.
128         /**
129             This class is based on <tt>std::atomic_size_t</tt>.
130             It uses relaxed memory ordering \p memory_order_relaxed and may be used as a statistic counter.
131         */
132         class event_counter
133         {
134             //@cond
135             CDS_ATOMIC::atomic_size_t   m_counter;
136             //@endcond
137
138         public:
139             typedef size_t      value_type  ;       ///< Type of counter
140
141         public:
142             // Initializes event counter with zero
143             event_counter() CDS_NOEXCEPT
144                 : m_counter(size_t(0))
145             {}
146
147             /// Assign operator
148             /**
149                 Returns \p n.
150             */
151             value_type operator =(
152                 value_type n    //< new value of the counter
153             ) CDS_NOEXCEPT
154             {
155                 m_counter.exchange( n, CDS_ATOMIC::memory_order_relaxed );
156                 return n;
157             }
158
159             /// Addition
160             /**
161                 Returns new value of the atomic counter.
162             */
163             size_t operator +=(
164                 size_t n    ///< addendum
165             ) CDS_NOEXCEPT
166             {
167                 return m_counter.fetch_add( n, CDS_ATOMIC::memory_order_relaxed ) + n;
168             }
169
170             /// Substraction
171             /**
172                 Returns new value of the atomic counter.
173             */
174             size_t operator -=(
175                 size_t n    ///< subtrahend
176             ) CDS_NOEXCEPT
177             {
178                 return m_counter.fetch_sub( n, CDS_ATOMIC::memory_order_relaxed ) - n;
179             }
180
181             /// Get current value of the counter
182             operator size_t () const CDS_NOEXCEPT
183             {
184                 return m_counter.load( CDS_ATOMIC::memory_order_relaxed );
185             }
186
187             /// Preincrement
188             size_t operator ++() CDS_NOEXCEPT
189             {
190                 return m_counter.fetch_add( 1, CDS_ATOMIC::memory_order_relaxed ) + 1;
191             }
192             /// Postincrement
193             size_t operator ++(int) CDS_NOEXCEPT
194             {
195                 return m_counter.fetch_add( 1, CDS_ATOMIC::memory_order_relaxed );
196             }
197
198             /// Predecrement
199             size_t operator --() CDS_NOEXCEPT
200             {
201                 return m_counter.fetch_sub( 1, CDS_ATOMIC::memory_order_relaxed ) - 1;
202             }
203             /// Postdecrement
204             size_t operator --(int) CDS_NOEXCEPT
205             {
206                 return m_counter.fetch_sub( 1, CDS_ATOMIC::memory_order_relaxed );
207             }
208
209             /// Get current value of the counter
210             size_t get() const CDS_NOEXCEPT
211             {
212                 return m_counter.load( CDS_ATOMIC::memory_order_relaxed );
213             }
214
215             /// Resets the counter to 0
216             void reset() CDS_NOEXCEPT
217             {
218                 m_counter.store( 0, CDS_ATOMIC::memory_order_release );
219             }
220
221         };
222
223         /// Atomic item counter
224         /**
225             This class is simplified interface around <tt>std::atomic_size_t</tt>.
226             The class supports getting of current value of the counter and increment/decrement its value.
227         */
228         class item_counter
229         {
230         public:
231             typedef CDS_ATOMIC::atomic_size_t   atomic_type ;   ///< atomic type used
232             typedef size_t counter_type    ;   ///< Integral item counter type (size_t)
233
234         private:
235             //@cond
236             atomic_type                         m_Counter   ;   ///< Atomic item counter
237             //@endcond
238
239         public:
240             /// Default ctor initializes the counter to zero.
241             item_counter()
242                 : m_Counter(counter_type(0))
243             {}
244
245             /// Returns current value of the counter
246             counter_type    value(CDS_ATOMIC::memory_order order = CDS_ATOMIC::memory_order_relaxed) const
247             {
248                 return m_Counter.load( order );
249             }
250
251             /// Same as \ref value() with relaxed memory ordering
252             operator counter_type() const
253             {
254                 return value();
255             }
256
257             /// Returns underlying atomic interface
258             atomic_type&  getAtomic()
259             {
260                 return m_Counter;
261             }
262
263             /// Returns underlying atomic interface (const)
264             const atomic_type&  getAtomic() const
265             {
266                 return m_Counter;
267             }
268
269             /// Increments the counter. Semantics: postincrement
270             counter_type inc(CDS_ATOMIC::memory_order order = CDS_ATOMIC::memory_order_relaxed )
271             {
272                 return m_Counter.fetch_add( 1, order );
273             }
274
275             /// Decrements the counter. Semantics: postdecrement
276             counter_type dec(CDS_ATOMIC::memory_order order = CDS_ATOMIC::memory_order_relaxed)
277             {
278                 return m_Counter.fetch_sub( 1, order );
279             }
280
281             /// Preincrement
282             counter_type operator ++()
283             {
284                 return inc() + 1;
285             }
286             /// Postincrement
287             counter_type operator ++(int)
288             {
289                 return inc();
290             }
291
292             /// Predecrement
293             counter_type operator --()
294             {
295                 return dec() - 1;
296             }
297             /// Postdecrement
298             counter_type operator --(int)
299             {
300                 return dec();
301             }
302
303             /// Resets count to 0
304             void reset(CDS_ATOMIC::memory_order order = CDS_ATOMIC::memory_order_relaxed)
305             {
306                 m_Counter.store( 0, order );
307             }
308         };
309
310         /// Empty item counter
311         /**
312             This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
313             All methods of the class is empty and returns 0.
314
315             The object of this class should not be used in data structure that behavior significantly depends on item counting
316             (for example, in many hash map implementation).
317         */
318         class empty_item_counter {
319         public:
320             typedef size_t counter_type    ;  ///< Counter type
321         public:
322             /// Returns 0
323             counter_type    value(CDS_ATOMIC::memory_order /*order*/ = CDS_ATOMIC::memory_order_relaxed) const
324             {
325                 return 0;
326             }
327
328             /// Same as \ref value(), always returns 0.
329             operator counter_type() const
330             {
331                 return value();
332             }
333
334             /// Dummy increment. Always returns 0
335             size_t inc(CDS_ATOMIC::memory_order /*order*/ = CDS_ATOMIC::memory_order_relaxed)
336             {
337                 return 0;
338             }
339
340             /// Dummy increment. Always returns 0
341             size_t dec(CDS_ATOMIC::memory_order /*order*/ = CDS_ATOMIC::memory_order_relaxed)
342             {
343                 return 0;
344             }
345
346             /// Dummy pre-increment. Always returns 0
347             size_t operator ++()
348             {
349                 return 0;
350             }
351             /// Dummy post-increment. Always returns 0
352             size_t operator ++(int)
353             {
354                 return 0;
355             }
356
357             /// Dummy pre-decrement. Always returns 0
358             size_t operator --()
359             {
360                 return 0;
361             }
362             /// Dummy post-decrement. Always returns 0
363             size_t operator --(int)
364             {
365                 return 0;
366             }
367
368             /// Dummy function
369             void reset(CDS_ATOMIC::memory_order /*order*/ = CDS_ATOMIC::memory_order_relaxed)
370             {}
371         };
372
373
374     }   // namespace atomicity
375
376 }   // namespace cds
377
378 #endif // #ifndef __CDS_CXX11_ATOMIC_H