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