PMDK C++ bindings 1.13.0
This is the C++ bindings documentation for PMDK's libpmemobj.
tagged_ptr.hpp
1// SPDX-License-Identifier: BSD-3-Clause
2/* Copyright 2021, Intel Corporation */
3
4#ifndef LIBPMEMOBJ_CPP_TAGGED_PTR
5#define LIBPMEMOBJ_CPP_TAGGED_PTR
6
7#include <cassert>
8
10#include <libpmemobj++/experimental/atomic_self_relative_ptr.hpp>
13
14namespace pmem
15{
16namespace detail
17{
18
19template <typename P1, typename P2, typename PointerType>
20struct tagged_ptr_impl {
21 tagged_ptr_impl() = default;
22 tagged_ptr_impl(const tagged_ptr_impl &rhs) = default;
23
24 tagged_ptr_impl(std::nullptr_t) : ptr(nullptr)
25 {
26 assert(!(bool)*this);
27 }
28
29 tagged_ptr_impl(const PointerType &ptr) : ptr(ptr)
30 {
31 }
32
33 tagged_ptr_impl(const obj::persistent_ptr<P1> &ptr)
34 : ptr(add_tag(ptr.get()))
35 {
36 assert(get<P1>() == ptr.get());
37 }
38
39 tagged_ptr_impl(const obj::persistent_ptr<P2> &ptr) : ptr(ptr.get())
40 {
41 assert(get<P2>() == ptr.get());
42 }
43
44 tagged_ptr_impl &operator=(const tagged_ptr_impl &rhs) = default;
45
46 tagged_ptr_impl &operator=(std::nullptr_t)
47 {
48 ptr = nullptr;
49 assert(!(bool)*this);
50
51 return *this;
52 }
53 tagged_ptr_impl &
54 operator=(const obj::persistent_ptr<P1> &rhs)
55 {
56 ptr = add_tag(rhs.get());
57 assert(get<P1>() == rhs.get());
58
59 return *this;
60 }
61 tagged_ptr_impl &
62 operator=(const obj::persistent_ptr<P2> &rhs)
63 {
64 ptr = rhs.get();
65 assert(get<P2>() == rhs.get());
66
67 return *this;
68 }
69
70 bool
71 operator==(const tagged_ptr_impl &rhs) const
72 {
73 return ptr.to_byte_pointer() == rhs.ptr.to_byte_pointer();
74 }
75 bool
76 operator!=(const tagged_ptr_impl &rhs) const
77 {
78 return !(*this == rhs);
79 }
80
81 bool
82 operator==(const P1 *rhs) const
83 {
84 return is_tagged() && get<P1>() == rhs;
85 }
86
87 bool
88 operator!=(const P2 *rhs) const
89 {
90 return !(*this == rhs);
91 }
92
93 void
94 swap(tagged_ptr_impl &rhs)
95 {
96 ptr.swap(rhs.ptr);
97 }
98
99 template <typename T>
100 typename std::enable_if<std::is_same<T, P1>::value, bool>::type
101 is() const
102 {
103 return is_tagged();
104 }
105
106 template <typename T>
107 typename std::enable_if<!std::is_same<T, P1>::value, bool>::type
108 is() const
109 {
110 return !is_tagged();
111 }
112
113 template <typename T>
114 typename std::enable_if<std::is_same<T, P1>::value, T *>::type
115 get() const
116 {
117 assert(is_tagged());
118 return static_cast<P1 *>(remove_tag(ptr.to_void_pointer()));
119 }
120
121 template <typename T>
122 typename std::enable_if<!std::is_same<T, P1>::value, T *>::type
123 get() const
124 {
125 assert(!is_tagged());
126 return static_cast<P2 *>(ptr.to_void_pointer());
127 }
128
129 P2 *operator->() const
130 {
131 return get<P2>();
132 }
133
134 explicit operator bool() const noexcept
135 {
136 return remove_tag(ptr.to_void_pointer()) != nullptr;
137 }
138
139private:
140 static constexpr uintptr_t IS_TAGGED = 1;
141 void *
142 add_tag(P1 *ptr) const
143 {
144 auto tagged =
145 reinterpret_cast<uintptr_t>(ptr) | uintptr_t(IS_TAGGED);
146 return reinterpret_cast<P1 *>(tagged);
147 }
148
149 void *
150 remove_tag(void *ptr) const
151 {
152 auto untagged = reinterpret_cast<uintptr_t>(ptr) &
153 ~uintptr_t(IS_TAGGED);
154 return reinterpret_cast<void *>(untagged);
155 }
156
157 bool
158 is_tagged() const
159 {
160 auto value = reinterpret_cast<uintptr_t>(ptr.to_void_pointer());
161 return value & uintptr_t(IS_TAGGED);
162 }
163
164 PointerType ptr;
165
166#ifndef DOXYGEN_SHOULD_SKIP_THIS
167 friend std::atomic<tagged_ptr_impl<
168 P1, P2, obj::experimental::self_relative_ptr<void>>>;
169#endif /* DOXYGEN_SHOULD_SKIP_THIS */
170};
171
172template <typename P1, typename P2>
173using tagged_ptr =
174 tagged_ptr_impl<P1, P2, obj::experimental::self_relative_ptr<void>>;
175
176} /* namespace detail */
177} /* namespace pmem */
178
179namespace std
180{
181
182template <typename P1, typename P2>
183struct atomic<pmem::detail::tagged_ptr<P1, P2>> {
184private:
185 using ptr_type = pmem::detail::tagged_ptr_impl<
186 P1, P2,
187 atomic<pmem::obj::experimental::self_relative_ptr<void>>>;
188 using value_type = pmem::detail::tagged_ptr<P1, P2>;
189
190public:
191 /*
192 * Constructors
193 */
194 constexpr atomic() noexcept = default;
195
196 atomic(value_type value) : ptr()
197 {
198 store(value);
199 }
200
201 atomic(const atomic &) = delete;
202
203 void
204 store(value_type desired,
205 std::memory_order order = std::memory_order_seq_cst) noexcept
206 {
207 LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, &ptr.ptr);
208 ptr.ptr.store(desired.ptr, order);
209 }
210
211 void
212 store_with_snapshot(value_type desired,
213 std::memory_order order = std::memory_order_seq_cst)
214 {
215 LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, &ptr.ptr);
217 ptr.ptr.store(desired.ptr, order);
218 }
219
220 void
221 store_with_snapshot_release(value_type desired)
222 {
223 store_with_snapshot(desired, std::memory_order_release);
224 }
225
226 value_type
227 load(std::memory_order order = std::memory_order_seq_cst) const noexcept
228 {
229#if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
230 VALGRIND_HG_DISABLE_CHECKING(&ptr.ptr, sizeof(ptr.ptr));
231#endif
232 auto ret = this->ptr.ptr.load(order);
233 LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, &ptr.ptr);
234 return value_type(ret);
235 }
236
237 value_type
238 load_acquire() const noexcept
239 {
240 return load(std::memory_order_acquire);
241 }
242
243 void
244 swap(atomic<pmem::detail::tagged_ptr<P1, P2>> &rhs)
245 {
246 auto tmp = rhs.load();
247 rhs.store_with_snapshot(this->load());
248 this->store_with_snapshot(tmp);
249 }
250
251 atomic<pmem::detail::tagged_ptr<P1, P2>> &
252 operator=(atomic<pmem::detail::tagged_ptr<P1, P2>> &) = delete;
253
254private:
255 ptr_type ptr;
256};
257
258} /* namespace std */
259
260#endif /* LIBPMEMOBJ_CPP_TAGGED_PTR */
static void snapshot(const T *addr, size_t num=1)
Takes a “snapshot” of given elements of type T number (1 by default), located at the given address pt...
Definition: transaction.hpp:428
Commonly used functionality.
T & get(pmem::obj::array< T, N > &a)
Non-member get function.
Definition: array.hpp:919
bool operator!=(const allocator< T, P, Tr > &lhs, const OtherAllocator &rhs)
Determines if memory from another allocator can be deallocated from this one.
Definition: allocator.hpp:536
bool operator==(standard_alloc_policy< T > const &, standard_alloc_policy< T2 > const &)
Determines if memory from another allocator can be deallocated from this one.
Definition: allocator.hpp:420
void swap(pmem::obj::array< T, N > &lhs, pmem::obj::array< T, N > &rhs)
Non-member swap function.
Definition: array.hpp:909
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Persistent smart pointer.
Persistent self-relative smart pointer.