Turi Create  4.0
atomic.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_ATOMIC_HPP
7 #define TURI_ATOMIC_HPP
8 
9 #include <stdint.h>
10 #include <type_traits>
11 
12 #include <core/storage/serialization/serialization_includes.hpp>
13 #include <core/parallel/atomic_ops.hpp>
14 
15 namespace turi {
16 namespace turi_impl {
17  template<typename T, bool IsIntegral>
18  class atomic_impl {};
19  /**
20  * \internal
21  * \brief atomic object
22  * A templated class for creating atomic numbers.
23  */
24  template<typename T>
25  class atomic_impl <T, true>: public IS_POD_TYPE {
26  public:
27  //! The current value of the atomic number
28  volatile T value;
29 
30  //! Creates an atomic number with value "value"
31  atomic_impl(const T& value = T()) : value(value) { }
32 
33  //! Performs an atomic increment by 1, returning the new value
34  T inc() { return __sync_add_and_fetch(&value, 1); }
35 
36  //! Performs an atomic decrement by 1, returning the new value
37  T dec() { return __sync_sub_and_fetch(&value, 1); }
38 
39  //! Lvalue implicit cast
40  operator T() const { return value; }
41 
42  //! Performs an atomic increment by 1, returning the new value
43  T operator++() { return inc(); }
44 
45  //! Performs an atomic decrement by 1, returning the new value
46  T operator--() { return dec(); }
47 
48  //! Performs an atomic increment by 'val', returning the new value
49  T inc(const T val) { return __sync_add_and_fetch(&value, val); }
50 
51  //! Performs an atomic decrement by 'val', returning the new value
52  T dec(const T val) { return __sync_sub_and_fetch(&value, val); }
53 
54  //! Performs an atomic increment by 'val', returning the new value
55  T operator+=(const T val) { return inc(val); }
56 
57  //! Performs an atomic decrement by 'val', returning the new value
58  T operator-=(const T val) { return dec(val); }
59 
60  //! Performs an atomic increment by 1, returning the old value
61  T inc_ret_last() { return __sync_fetch_and_add(&value, 1); }
62 
63  //! Performs an atomic decrement by 1, returning the old value
64  T dec_ret_last() { return __sync_fetch_and_sub(&value, 1); }
65 
66  //! Performs an atomic increment by 1, returning the old value
67  T operator++(int) { return inc_ret_last(); }
68 
69  //! Performs an atomic decrement by 1, returning the old value
70  T operator--(int) { return dec_ret_last(); }
71 
72  //! Performs an atomic increment by 'val', returning the old value
73  T inc_ret_last(const T val) { return __sync_fetch_and_add(&value, val); }
74 
75  //! Performs an atomic decrement by 'val', returning the new value
76  T dec_ret_last(const T val) { return __sync_fetch_and_sub(&value, val); }
77 
78  //! Performs an atomic exchange with 'val', returning the previous value
79  T exchange(const T val) { return __sync_lock_test_and_set(&value, val); }
80  };
81 
82  // specialization for floats and doubles
83  template<typename T>
84  class atomic_impl <T, false>: public IS_POD_TYPE {
85  public:
86  //! The current value of the atomic number
87  volatile T value;
88 
89  //! Creates an atomic number with value "value"
90  atomic_impl(const T& value = T()) : value(value) { }
91 
92  //! Performs an atomic increment by 1, returning the new value
93  T inc() { return inc(1); }
94 
95  //! Performs an atomic decrement by 1, returning the new value
96  T dec() { return dec(1); }
97 
98  //! Lvalue implicit cast
99  operator T() const { return value; }
100 
101  //! Performs an atomic increment by 1, returning the new value
102  T operator++() { return inc(); }
103 
104  //! Performs an atomic decrement by 1, returning the new value
105  T operator--() { return dec(); }
106 
107  //! Performs an atomic increment by 'val', returning the new value
108  T inc(const T val) {
109  T prev_value;
110  T new_value;
111  do {
112  prev_value = value;
113  new_value = prev_value + val;
114  } while(!atomic_compare_and_swap(value, prev_value, new_value));
115  return new_value;
116  }
117 
118  //! Performs an atomic decrement by 'val', returning the new value
119  T dec(const T val) {
120  T prev_value;
121  T new_value;
122  do {
123  prev_value = value;
124  new_value = prev_value - val;
125  } while(!atomic_compare_and_swap(value, prev_value, new_value));
126  return new_value;
127  }
128 
129  //! Performs an atomic increment by 'val', returning the new value
130  T operator+=(const T val) { return inc(val); }
131 
132  //! Performs an atomic decrement by 'val', returning the new value
133  T operator-=(const T val) { return dec(val); }
134 
135  //! Performs an atomic increment by 1, returning the old value
136  T inc_ret_last() { return inc_ret_last(1); }
137 
138  //! Performs an atomic decrement by 1, returning the old value
139  T dec_ret_last() { return dec_ret_last(1); }
140 
141  //! Performs an atomic increment by 1, returning the old value
142  T operator++(int) { return inc_ret_last(); }
143 
144  //! Performs an atomic decrement by 1, returning the old value
145  T operator--(int) { return dec_ret_last(); }
146 
147  //! Performs an atomic increment by 'val', returning the old value
148  T inc_ret_last(const T val) {
149  T prev_value;
150  T new_value;
151  do {
152  prev_value = value;
153  new_value = prev_value + val;
154  } while(!atomic_compare_and_swap(value, prev_value, new_value));
155  return prev_value;
156  }
157 
158  //! Performs an atomic decrement by 'val', returning the new value
159  T dec_ret_last(const T val) {
160  T prev_value;
161  T new_value;
162  do {
163  prev_value = value;
164  new_value = prev_value - val;
165  } while(!atomic_compare_and_swap(value, prev_value, new_value));
166  return prev_value;
167  }
168 
169  //! Performs an atomic exchange with 'val', returning the previous value
170  T exchange(const T val) { return __sync_lock_test_and_set(&value, val); }
171  };
172 } // namespace turi_impl
173 
174 template <typename T>
175 class atomic: public turi_impl::atomic_impl<T, std::is_integral<T>::value> {
176  public:
177  //! Creates an atomic number with value "value"
178  atomic(const T& value = T()):
179  turi_impl::atomic_impl<T, std::is_integral<T>::value>(value) { }
180 
181 };
182 
183 } // namespace turi
184 #endif
T exchange(const T val)
Performs an atomic exchange with &#39;val&#39;, returning the previous value.
Definition: atomic.hpp:79
atomic_impl(const T &value=T())
Creates an atomic number with value "value".
Definition: atomic.hpp:31
volatile T value
The current value of the atomic number.
Definition: atomic.hpp:28
T operator++()
Performs an atomic increment by 1, returning the new value.
Definition: atomic.hpp:43
T operator++(int)
Performs an atomic increment by 1, returning the old value.
Definition: atomic.hpp:67
T operator--(int)
Performs an atomic decrement by 1, returning the old value.
Definition: atomic.hpp:70
T operator+=(const T val)
Performs an atomic increment by &#39;val&#39;, returning the new value.
Definition: atomic.hpp:55
T dec()
Performs an atomic decrement by 1, returning the new value.
Definition: atomic.hpp:37
Inheriting from this type will force the serializer to treat the derived type as a POD type...
Definition: is_pod.hpp:16
bool atomic_compare_and_swap(T &a, T oldval, T newval)
Definition: atomic_ops.hpp:27
T inc()
Performs an atomic increment by 1, returning the new value.
Definition: atomic.hpp:34
T inc(const T val)
Performs an atomic increment by &#39;val&#39;, returning the new value.
Definition: atomic.hpp:49
T dec_ret_last()
Performs an atomic decrement by 1, returning the old value.
Definition: atomic.hpp:64
T dec(const T val)
Performs an atomic decrement by &#39;val&#39;, returning the new value.
Definition: atomic.hpp:52
T inc_ret_last(const T val)
Performs an atomic increment by &#39;val&#39;, returning the old value.
Definition: atomic.hpp:73
T operator--()
Performs an atomic decrement by 1, returning the new value.
Definition: atomic.hpp:46
T operator-=(const T val)
Performs an atomic decrement by &#39;val&#39;, returning the new value.
Definition: atomic.hpp:58
T dec_ret_last(const T val)
Performs an atomic decrement by &#39;val&#39;, returning the new value.
Definition: atomic.hpp:76
T inc_ret_last()
Performs an atomic increment by 1, returning the old value.
Definition: atomic.hpp:61