4 #ifndef LIBPMEMOBJ_CPP_ATOMIC_SELF_RELATIVE_PTR_HPP
5 #define LIBPMEMOBJ_CPP_ATOMIC_SELF_RELATIVE_PTR_HPP
13 #if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
15 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, ptr) \
16 if (order == std::memory_order_release || \
17 order == std::memory_order_acq_rel || \
18 order == std::memory_order_seq_cst) { \
19 ANNOTATE_HAPPENS_BEFORE(ptr); \
22 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, ptr) \
23 if (order == std::memory_order_consume || \
24 order == std::memory_order_acquire || \
25 order == std::memory_order_acq_rel || \
26 order == std::memory_order_seq_cst) { \
27 ANNOTATE_HAPPENS_AFTER(ptr); \
31 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, ptr)
32 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, ptr)
45 struct atomic<
pmem::obj::experimental::self_relative_ptr<T>> {
48 std::atomic<std::ptrdiff_t>>;
50 std::atomic<std::ptrdiff_t>>;
53 using this_type = atomic;
61 constexpr atomic() noexcept =
default;
66 atomic(
const atomic &) =
delete;
70 std::memory_order order = std::memory_order_seq_cst) noexcept
72 auto offset = accessor::pointer_to_offset(ptr, desired.
get());
73 LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, &ptr);
74 accessor::get_offset(ptr).store(offset, order);
78 load(std::memory_order order = std::memory_order_seq_cst)
const noexcept
80 auto offset = accessor::get_offset(ptr).load(order);
81 LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, &ptr);
82 auto pointer = accessor::offset_to_pointer<T>(offset, ptr);
88 std::memory_order order = std::memory_order_seq_cst) noexcept
91 accessor::pointer_to_offset(ptr, desired.
get());
93 accessor::get_offset(ptr).exchange(new_offset, order);
95 accessor::offset_to_pointer<T>(old_offset, ptr)};
100 std::memory_order success,
101 std::memory_order failure) noexcept
103 auto expected_offset =
104 accessor::pointer_to_offset(ptr, expected.
get());
105 auto desired_offset =
106 accessor::pointer_to_offset(ptr, desired.
get());
108 bool result = accessor::get_offset(ptr).compare_exchange_weak(
109 expected_offset, desired_offset, success, failure);
111 expected = accessor::offset_to_pointer<T>(
112 expected_offset, ptr);
117 compare_exchange_weak(
119 std::memory_order order = std::memory_order_seq_cst) noexcept
121 auto expected_offset =
122 accessor::pointer_to_offset(ptr, expected.
get());
123 auto desired_offset =
124 accessor::pointer_to_offset(ptr, desired.
get());
126 bool result = accessor::get_offset(ptr).compare_exchange_weak(
127 expected_offset, desired_offset, order);
129 expected = accessor::offset_to_pointer<T>(
130 expected_offset, ptr);
136 std::memory_order success,
137 std::memory_order failure) noexcept
139 auto expected_offset =
140 accessor::pointer_to_offset(ptr, expected.
get());
141 auto desired_offset =
142 accessor::pointer_to_offset(ptr, desired.
get());
144 bool result = accessor::get_offset(ptr).compare_exchange_strong(
145 expected_offset, desired_offset, success, failure);
147 expected = accessor::offset_to_pointer<T>(
148 expected_offset, ptr);
153 compare_exchange_strong(
155 std::memory_order order = std::memory_order_seq_cst) noexcept
157 auto expected_offset =
158 accessor::pointer_to_offset(ptr, expected.
get());
159 auto desired_offset =
160 accessor::pointer_to_offset(ptr, desired.
get());
162 bool result = accessor::get_offset(ptr).compare_exchange_strong(
163 expected_offset, desired_offset, order);
165 expected = accessor::offset_to_pointer<T>(
166 expected_offset, ptr);
171 fetch_add(difference_type val,
172 std::memory_order order = std::memory_order_seq_cst) noexcept
174 auto offset = accessor::get_offset(ptr).fetch_add(
175 val *
static_cast<difference_type
>(
sizeof(T)), order);
176 return value_type{accessor::offset_to_pointer<T>(offset, ptr)};
180 fetch_sub(difference_type val,
181 std::memory_order order = std::memory_order_seq_cst) noexcept
183 auto offset = accessor::get_offset(ptr).fetch_sub(
184 val *
static_cast<difference_type
>(
sizeof(T)), order);
185 return value_type{accessor::offset_to_pointer<T>(offset, ptr)};
189 is_lock_free()
const noexcept
191 return accessor::get_offset(ptr).is_lock_free();
203 atomic &operator=(
const atomic &) =
delete;
204 atomic &operator=(
const atomic &)
volatile =
delete;
216 return this->fetch_add(1) + 1;
222 return this->fetch_add(1);
228 return this->fetch_sub(1) - 1;
234 return this->fetch_sub(1);
240 return this->fetch_add(diff) + diff;
246 return this->fetch_sub(diff) - diff;
255 #undef LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE
256 #undef LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER
269 template <
typename T>
272 static constexpr
bool value =
sizeof(std::atomic<snapshot_type>) ==
273 sizeof(
typename snapshot_type::offset_type);
275 "std::atomic<self_relative_ptr> should be the same size");
Static class accesssor to self_relative_ptr_base.
Definition: self_relative_ptr_base_impl.hpp:297
Persistent self-relative pointer class.
Definition: self_relative_ptr.hpp:44
element_type * get() const noexcept
Get the direct pointer.
Definition: self_relative_ptr.hpp:159
typename base_type::difference_type difference_type
The self_relative_ptr difference type.
Definition: self_relative_ptr.hpp:62
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.