Implemented support for ARMv8 (64 bit arm)
[libcds.git] / cds / algo / atomic.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_CXX11_ATOMIC_H
32 #define CDSLIB_CXX11_ATOMIC_H
33
34 #include <cds/details/defs.h>
35
36 namespace cds {
37
38 /// C++11 Atomic library support
39 /** @anchor cds_cxx11_atomic
40     \p libcds can use the following implementations of the atomics:
41     - STL \p &lt;atomic&gt;. This is used by default
42     - \p boost.atomic for boost 1.54 and above. To use it you should define \p CDS_USE_BOOST_ATOMIC for
43       your compiler invocation, for example, for gcc specify \p -DCDS_USE_BOOST_ATOMIC
44       in command line
45     - \p libcds implementation of atomic operation according to C++11 standard as
46       specified in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf">N3242, p.29</a>.
47       \p libcds implementation is not the full standard compliant, it provides only C++ part of standard,
48       for example, \p libcds has no static initialization of the atomic variables and some other C features.
49       However, that imlementation is enough for the library purposes. Supported architecture: x86, amd64,
50       ia64 (Itanium) 64bit, 64bit Sparc. To use \p libcds atomic you should define \p CDS_USE_LIBCDS_ATOMIC
51       in the compiler command line (\p -DCDS_USE_LIBCDS_ATOMIC for gcc/clang).
52
53       @note For Clang compiler \p libcds doesn't use native \p libc++ \p &lt;atomic&gt; due some problems.
54       Instead, \p libcds atomic is used by default, or you can try to use \p boost.atomic.
55
56       The library defines \p atomics alias for atomic namespace:
57       - <tt>namespace atomics = std</tt> for STL
58       - <tt>namespace atomics = boost</tt> for \p boost.atomic
59       - <tt>namespace atomics = cds::cxx11_atomic</tt> for library-provided atomic implementation
60 */
61 namespace cxx11_atomic {
62 }} // namespace cds::cxx11_atomic
63
64 //@cond
65 #if defined(CDS_USE_BOOST_ATOMIC)
66     // boost atomic
67 #   include <boost/version.hpp>
68 #   if BOOST_VERSION >= 105400
69 #       include <boost/atomic.hpp>
70         namespace atomics = boost;
71 #       define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
72 #       define CDS_CXX11_ATOMIC_END_NAMESPACE }
73 #   else
74 #       error "Boost version 1.54 or above is needed for boost.atomic"
75 #   endif
76 #elif defined(CDS_USE_LIBCDS_ATOMIC)
77     // libcds atomic
78 #   include <cds/compiler/cxx11_atomic.h>
79     namespace atomics = cds::cxx11_atomic;
80 #   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomic {
81 #   define CDS_CXX11_ATOMIC_END_NAMESPACE }}
82 #else
83     // Compiler provided C++11 atomic
84 #   include <atomic>
85     namespace atomics = std;
86 #   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
87 #   define CDS_CXX11_ATOMIC_END_NAMESPACE }
88 #endif
89 //@endcond
90
91 namespace cds {
92
93     /// Atomic primitives
94     /**
95         This namespace contains useful primitives derived from <tt>std::atomic</tt>.
96     */
97     namespace atomicity {
98
99         /// Atomic event counter.
100         /**
101             This class is based on <tt>std::atomic_size_t</tt>.
102             It uses relaxed memory ordering \p memory_order_relaxed and may be used as a statistic counter.
103         */
104         class event_counter
105         {
106             //@cond
107             atomics::atomic_size_t   m_counter;
108             //@endcond
109
110         public:
111             typedef size_t      value_type  ;       ///< Type of counter
112
113         public:
114             // Initializes event counter with zero
115             event_counter() CDS_NOEXCEPT
116                 : m_counter(size_t(0))
117             {}
118
119             /// Assign operator
120             /**
121                 Returns \p n.
122             */
123             value_type operator =(
124                 value_type n    //< new value of the counter
125             ) CDS_NOEXCEPT
126             {
127                 m_counter.exchange( n, atomics::memory_order_relaxed );
128                 return n;
129             }
130
131             /// Addition
132             /**
133                 Returns new value of the atomic counter.
134             */
135             size_t operator +=(
136                 size_t n    ///< addendum
137             ) CDS_NOEXCEPT
138             {
139                 return m_counter.fetch_add( n, atomics::memory_order_relaxed ) + n;
140             }
141
142             /// Substraction
143             /**
144                 Returns new value of the atomic counter.
145             */
146             size_t operator -=(
147                 size_t n    ///< subtrahend
148             ) CDS_NOEXCEPT
149             {
150                 return m_counter.fetch_sub( n, atomics::memory_order_relaxed ) - n;
151             }
152
153             /// Get current value of the counter
154             operator size_t () const CDS_NOEXCEPT
155             {
156                 return m_counter.load( atomics::memory_order_relaxed );
157             }
158
159             /// Preincrement
160             size_t operator ++() CDS_NOEXCEPT
161             {
162                 return m_counter.fetch_add( 1, atomics::memory_order_relaxed ) + 1;
163             }
164             /// Postincrement
165             size_t operator ++(int) CDS_NOEXCEPT
166             {
167                 return m_counter.fetch_add( 1, atomics::memory_order_relaxed );
168             }
169
170             /// Predecrement
171             size_t operator --() CDS_NOEXCEPT
172             {
173                 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed ) - 1;
174             }
175             /// Postdecrement
176             size_t operator --(int) CDS_NOEXCEPT
177             {
178                 return m_counter.fetch_sub( 1, atomics::memory_order_relaxed );
179             }
180
181             /// Get current value of the counter
182             size_t get() const CDS_NOEXCEPT
183             {
184                 return m_counter.load( atomics::memory_order_relaxed );
185             }
186
187             /// Resets the counter to 0
188             void reset() CDS_NOEXCEPT
189             {
190                 m_counter.store( 0, atomics::memory_order_release );
191             }
192         };
193
194         /// Atomic item counter
195         /**
196             This class is simplified interface around \p std::atomic_size_t.
197             The class supports getting of current value of the counter and increment/decrement its value.
198         */
199         class item_counter
200         {
201         public:
202             typedef atomics::atomic_size_t   atomic_type ;   ///< atomic type used
203             typedef size_t counter_type    ;   ///< Integral item counter type (size_t)
204
205         private:
206             //@cond
207             atomic_type                         m_Counter   ;   ///< Atomic item counter
208             //@endcond
209
210         public:
211             /// Default ctor initializes the counter to zero.
212             item_counter()
213                 : m_Counter(counter_type(0))
214             {}
215
216             /// Returns current value of the counter
217             counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
218             {
219                 return m_Counter.load( order );
220             }
221
222             /// Same as \ref value() with relaxed memory ordering
223             operator counter_type() const
224             {
225                 return value();
226             }
227
228             /// Returns underlying atomic interface
229             atomic_type& getAtomic()
230             {
231                 return m_Counter;
232             }
233
234             /// Returns underlying atomic interface (const)
235             const atomic_type& getAtomic() const
236             {
237                 return m_Counter;
238             }
239
240             /// Increments the counter. Semantics: postincrement
241             counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
242             {
243                 return m_Counter.fetch_add( 1, order );
244             }
245
246             /// Decrements the counter. Semantics: postdecrement
247             counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
248             {
249                 return m_Counter.fetch_sub( 1, order );
250             }
251
252             /// Preincrement
253             counter_type operator ++()
254             {
255                 return inc() + 1;
256             }
257             /// Postincrement
258             counter_type operator ++(int)
259             {
260                 return inc();
261             }
262
263             /// Predecrement
264             counter_type operator --()
265             {
266                 return dec() - 1;
267             }
268             /// Postdecrement
269             counter_type operator --(int)
270             {
271                 return dec();
272             }
273
274             /// Resets count to 0
275             void reset(atomics::memory_order order = atomics::memory_order_relaxed)
276             {
277                 m_Counter.store( 0, order );
278             }
279         };
280
281         /// Empty item counter
282         /**
283             This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
284             All methods of the class is empty and returns 0.
285
286             The object of this class should not be used in data structure that behavior significantly depends on item counting
287             (for example, in many hash map implementation).
288         */
289         class empty_item_counter {
290         public:
291             typedef size_t counter_type    ;  ///< Counter type
292         public:
293             /// Returns 0
294             static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
295             {
296                 return 0;
297             }
298
299             /// Same as \ref value(), always returns 0.
300             operator counter_type() const
301             {
302                 return value();
303             }
304
305             /// Dummy increment. Always returns 0
306             static size_t inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
307             {
308                 return 0;
309             }
310
311             /// Dummy increment. Always returns 0
312             static size_t dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
313             {
314                 return 0;
315             }
316
317             /// Dummy pre-increment. Always returns 0
318             size_t operator ++() const
319             {
320                 return 0;
321             }
322             /// Dummy post-increment. Always returns 0
323             size_t operator ++(int) const
324             {
325                 return 0;
326             }
327
328             /// Dummy pre-decrement. Always returns 0
329             size_t operator --() const
330             {
331                 return 0;
332             }
333             /// Dummy post-decrement. Always returns 0
334             size_t operator --(int) const
335             {
336                 return 0;
337             }
338
339             /// Dummy function
340             static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
341             {}
342         };
343     }   // namespace atomicity
344 }   // namespace cds
345
346 #endif // #ifndef CDSLIB_CXX11_ATOMIC_H