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");