PMDK C++ bindings  1.13.0-git23.gf49772ac
This is the C++ bindings documentation for PMDK's libpmemobj.
atomic_self_relative_ptr.hpp
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2020-2021, Intel Corporation */
3 
4 #ifndef LIBPMEMOBJ_CPP_ATOMIC_SELF_RELATIVE_PTR_HPP
5 #define LIBPMEMOBJ_CPP_ATOMIC_SELF_RELATIVE_PTR_HPP
6 
11 
12 #include <atomic>
13 
14 namespace std
15 {
22 template <typename T>
23 struct atomic<pmem::obj::experimental::self_relative_ptr<T>> {
24 private:
26  std::atomic<std::ptrdiff_t>>;
28  std::atomic<std::ptrdiff_t>>;
29 
30 public:
31  using this_type = atomic;
33  using difference_type = typename value_type::difference_type;
34 
35  /*
36  * Constructors
37  */
38 
39  constexpr atomic() noexcept = default;
40  atomic(value_type value) : ptr()
41  {
42  store(value);
43  }
44  atomic(const atomic &) = delete;
45 
46  void
47  store(value_type desired,
48  std::memory_order order = std::memory_order_seq_cst) noexcept
49  {
50  auto offset = accessor::pointer_to_offset(ptr, desired.get());
51  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, &ptr);
52  accessor::get_offset(ptr).store(offset, order);
53  }
54 
56  load(std::memory_order order = std::memory_order_seq_cst) const noexcept
57  {
58  auto offset = accessor::get_offset(ptr).load(order);
59  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, &ptr);
60  auto pointer = accessor::offset_to_pointer<T>(offset, ptr);
61  return value_type{pointer};
62  }
63 
65  exchange(value_type desired,
66  std::memory_order order = std::memory_order_seq_cst) noexcept
67  {
68  auto new_offset =
69  accessor::pointer_to_offset(ptr, desired.get());
70  auto old_offset =
71  accessor::get_offset(ptr).exchange(new_offset, order);
72  return value_type{
73  accessor::offset_to_pointer<T>(old_offset, ptr)};
74  }
75 
76  bool
77  compare_exchange_weak(value_type &expected, value_type desired,
78  std::memory_order success,
79  std::memory_order failure) noexcept
80  {
81  auto expected_offset =
82  accessor::pointer_to_offset(ptr, expected.get());
83  auto desired_offset =
84  accessor::pointer_to_offset(ptr, desired.get());
85 
86  bool result = accessor::get_offset(ptr).compare_exchange_weak(
87  expected_offset, desired_offset, success, failure);
88  if (!result) {
89  try {
90  expected = accessor::offset_to_pointer<T>(
91  expected_offset, ptr);
92  } catch (...) {
93  std::terminate();
94  }
95  }
96  return result;
97  }
98 
99  bool
100  compare_exchange_weak(
101  value_type &expected, value_type desired,
102  std::memory_order order = std::memory_order_seq_cst) noexcept
103  {
104  auto expected_offset =
105  accessor::pointer_to_offset(ptr, expected.get());
106  auto desired_offset =
107  accessor::pointer_to_offset(ptr, desired.get());
108 
109  bool result = accessor::get_offset(ptr).compare_exchange_weak(
110  expected_offset, desired_offset, order);
111  if (!result) {
112  try {
113  expected = accessor::offset_to_pointer<T>(
114  expected_offset, ptr);
115  } catch (...) {
116  std::terminate();
117  }
118  }
119  return result;
120  }
121 
122  bool
123  compare_exchange_strong(value_type &expected, value_type desired,
124  std::memory_order success,
125  std::memory_order failure) noexcept
126  {
127  auto expected_offset =
128  accessor::pointer_to_offset(ptr, expected.get());
129  auto desired_offset =
130  accessor::pointer_to_offset(ptr, desired.get());
131 
132  bool result = accessor::get_offset(ptr).compare_exchange_strong(
133  expected_offset, desired_offset, success, failure);
134  if (!result) {
135  try {
136  expected = accessor::offset_to_pointer<T>(
137  expected_offset, ptr);
138  } catch (...) {
139  std::terminate();
140  }
141  }
142  return result;
143  }
144 
145  bool
146  compare_exchange_strong(
147  value_type &expected, value_type desired,
148  std::memory_order order = std::memory_order_seq_cst) noexcept
149  {
150  auto expected_offset =
151  accessor::pointer_to_offset(ptr, expected.get());
152  auto desired_offset =
153  accessor::pointer_to_offset(ptr, desired.get());
154 
155  bool result = accessor::get_offset(ptr).compare_exchange_strong(
156  expected_offset, desired_offset, order);
157  if (!result) {
158  try {
159  expected = accessor::offset_to_pointer<T>(
160  expected_offset, ptr);
161  } catch (...) {
162  std::terminate();
163  }
164  }
165  return result;
166  }
167 
168  value_type
169  fetch_add(difference_type val,
170  std::memory_order order = std::memory_order_seq_cst) noexcept
171  {
172  auto offset = accessor::get_offset(ptr).fetch_add(
173  val * static_cast<difference_type>(sizeof(T)), order);
174  return value_type{accessor::offset_to_pointer<T>(offset, ptr)};
175  }
176 
177  value_type
178  fetch_sub(difference_type val,
179  std::memory_order order = std::memory_order_seq_cst) noexcept
180  {
181  auto offset = accessor::get_offset(ptr).fetch_sub(
182  val * static_cast<difference_type>(sizeof(T)), order);
183  return value_type{accessor::offset_to_pointer<T>(offset, ptr)};
184  }
185 
186  bool
187  is_lock_free() const noexcept
188  {
189  return accessor::get_offset(ptr).is_lock_free();
190  }
191 
192  /*
193  * Operators
194  */
195 
196  operator value_type() const noexcept
197  {
198  return load();
199  }
200 
201  atomic &operator=(const atomic &) = delete;
202  atomic &operator=(const atomic &) volatile = delete;
203 
204  value_type
205  operator=(value_type desired) noexcept
206  {
207  store(desired);
208  return desired;
209  }
210 
211  value_type
212  operator++() noexcept
213  {
214  try {
215  return this->fetch_add(1) + 1;
216  } catch (...) {
217  /* This should never happen during normal program
218  * execution */
219  std::terminate();
220  }
221  }
222 
223  value_type
224  operator++(int) noexcept
225  {
226  return this->fetch_add(1);
227  }
228 
229  value_type
230  operator--() noexcept
231  {
232  try {
233  return this->fetch_sub(1) - 1;
234  } catch (...) {
235  /* This should never happen during normal program
236  * execution */
237  std::terminate();
238  }
239  }
240 
241  value_type
242  operator--(int) noexcept
243  {
244  return this->fetch_sub(1);
245  }
246 
247  value_type
248  operator+=(difference_type diff) noexcept
249  {
250  try {
251  return this->fetch_add(diff) + diff;
252  } catch (...) {
253  /* This should never happen during normal program
254  * execution */
255  std::terminate();
256  }
257  }
258 
259  value_type
260  operator-=(difference_type diff) noexcept
261  {
262  try {
263  return this->fetch_sub(diff) - diff;
264  } catch (...) {
265  /* This should never happen during normal program
266  * execution */
267  std::terminate();
268  }
269  }
270 
271 private:
272  ptr_type ptr;
273 };
274 
275 } /* namespace std */
276 
277 namespace pmem
278 {
279 
280 namespace detail
281 {
282 
288 template <typename T>
289 struct can_do_snapshot<std::atomic<obj::experimental::self_relative_ptr<T>>> {
291  static constexpr bool value = sizeof(std::atomic<snapshot_type>) ==
292  sizeof(typename snapshot_type::offset_type);
293  static_assert(value,
294  "std::atomic<self_relative_ptr> should be the same size");
295 };
296 
297 } /* namespace detail */
298 
299 } /* namespace pmem */
300 
301 #endif
Static class accessor to self_relative_ptr_base.
Definition: self_relative_ptr_base_impl.hpp:296
Persistent self-relative pointer class.
Definition: self_relative_ptr.hpp:81
element_type * get() const noexcept
Get the direct pointer.
Definition: self_relative_ptr.hpp:196
typename base_type::difference_type difference_type
The self_relative_ptr difference type.
Definition: self_relative_ptr.hpp:99
Commonly used functionality.
p< T > & operator+=(p< T > &lhs, const p< Y > &rhs)
Addition assignment operator overload.
Definition: pext.hpp:94
p< T > & operator++(p< T > &pp)
Prefix increment operator overload.
Definition: pext.hpp:48
p< T > & operator--(p< T > &pp)
Prefix decrement operator overload.
Definition: pext.hpp:59
p< T > & operator-=(p< T > &lhs, const p< Y > &rhs)
Subtraction assignment operator overload.
Definition: pext.hpp:116
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Persistent self-relative smart pointer.
Base class for self_relative_ptr.
A structure that checks if it is possible to snapshot the specified memory.
Definition: transaction.hpp:36
C++ pmemobj transactions.