PMDK C++ bindings  1.13.0-git23.gf49772ac
This is the C++ bindings documentation for PMDK's libpmemobj.
self_relative_ptr_base_impl.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2020-2021, Intel Corporation */
3 
9 #ifndef LIBPMEMOBJ_CPP_SELF_RELATIVE_PTR_BASE_IMPL_HPP
10 #define LIBPMEMOBJ_CPP_SELF_RELATIVE_PTR_BASE_IMPL_HPP
11 
12 #include <cstdint>
13 #include <type_traits>
14 
17 
18 namespace pmem
19 {
20 
21 namespace detail
22 {
23 
38 template <typename OffsetType>
40 public:
42  using difference_type = std::ptrdiff_t;
43  using offset_type = OffsetType;
44  using byte_type = uint8_t;
45  using byte_ptr_type = byte_type *;
46  using const_byte_ptr_type = const byte_type *;
47 
48  /*
49  * Constructors
50  */
51 
55  constexpr self_relative_ptr_base_impl() noexcept
56  : offset(nullptr_offset)
57  {
58  }
59 
63  constexpr self_relative_ptr_base_impl(std::nullptr_t) noexcept
64  : offset(nullptr_offset)
65  {
66  }
67 
73  self_relative_ptr_base_impl(void *ptr) noexcept
74  : offset(pointer_to_offset(ptr))
75  {
76  }
77 
84  self_relative_ptr_base_impl const &r) noexcept
85  : offset(pointer_to_offset(r))
86  {
87  }
88 
101  {
102  if (this == &r)
103  return *this;
104  detail::conditional_add_to_tx(this);
105  offset = pointer_to_offset(r);
106  return *this;
107  }
108 
116  operator=(std::nullptr_t &&)
117  {
118  detail::conditional_add_to_tx(this);
119  offset = pointer_to_offset(nullptr);
120  return *this;
121  }
122 
128  void
130  {
131  if (this == &other)
132  return;
133  detail::conditional_add_to_tx(this);
134  detail::conditional_add_to_tx(&other);
135  auto first = this->to_byte_pointer();
136  auto second = other.to_byte_pointer();
137  this->offset = pointer_to_offset(second);
138  other.offset = other.pointer_to_offset(first);
139  }
140 
144  byte_ptr_type
145  to_byte_pointer() const noexcept
146  {
147  return static_cast<byte_ptr_type>(this->to_void_pointer());
148  }
149 
153  void *
154  to_void_pointer() const noexcept
155  {
156  return offset_to_pointer(this->offset);
157  }
158 
162  explicit operator void *() const noexcept
163  {
164  return to_void_pointer();
165  }
166 
170  explicit operator byte_ptr_type() const noexcept
171  {
172  return to_byte_pointer();
173  }
174 
178  static difference_type
180  const self_relative_ptr_base_impl &second)
181  {
182  return second.to_byte_pointer() - first.to_byte_pointer();
183  }
184 
188  inline bool
189  is_null() const noexcept
190  {
191  return offset == nullptr_offset;
192  }
193 
194 protected:
200  self_relative_ptr_base_impl(difference_type offset) noexcept
201  : offset(offset)
202  {
203  }
204 
208  void *
209  offset_to_pointer(difference_type other_offset) const noexcept
210  {
211  /*
212  This version without branches is vectorization-friendly.
213  mask = is_null() should not create a branch in the code.
214  In this line, we just assign 0 or 1 to the mask variable.
215 
216  This code is equal:
217  if (is_null())
218  return nullptr;
219  return reinterpret_cast<byte_ptr_type>(
220  const_cast<this_type *>(this)) +
221  offset + 1;
222  */
223  uintptr_t mask = other_offset == nullptr_offset;
224  --mask;
225  uintptr_t ptr = static_cast<uintptr_t>(
226  reinterpret_cast<intptr_t>(this) + other_offset + 1);
227  ptr &= mask;
228  return reinterpret_cast<void *>(ptr);
229  }
230 
234  difference_type
236  {
237  /*
238  This version without branches is vectorization-friendly.
239  mask = is_null() should not create a branch in the code.
240  In this line, we just assign 0 or 1 to the mask variable.
241 
242  This code is equal:
243  return ptr.is_null()
244  ? nullptr_offset
245  : ptr.offset + this->distance_between_self(ptr);
246  */
247  uintptr_t mask = ptr.is_null();
248  --mask;
249  difference_type distance_between_self =
250  reinterpret_cast<const_byte_ptr_type>(&ptr) -
251  reinterpret_cast<const_byte_ptr_type>(this);
252  distance_between_self &=
253  reinterpret_cast<difference_type &>(mask);
254  return ptr.offset + distance_between_self;
255  }
256 
260  difference_type
261  pointer_to_offset(void *ptr) const noexcept
262  {
263  /*
264  This version without branches is vectorization-friendly.
265  mask = ptr == nullptr should not create a branch in the code.
266  In this line, we just assign 0 or 1 to the mask variable.
267 
268  This code is equal:
269  if (ptr == nullptr)
270  return nullptr_offset
271  else
272  return ptr - this - 1;
273  */
274  uintptr_t mask = ptr == nullptr;
275  --mask;
276  difference_type new_offset = static_cast<byte_ptr_type>(ptr) -
277  reinterpret_cast<const_byte_ptr_type>(this) - 1;
278  new_offset &= reinterpret_cast<difference_type &>(mask);
279  return new_offset;
280  }
281 
282  /* The offset from self */
283  offset_type offset;
284 
285 private:
286  static constexpr difference_type nullptr_offset = 0;
287 
288  template <typename T>
289  friend class self_relative_accessor;
290 };
291 
295 template <typename T>
297 public:
299  using difference_type = typename access_type::difference_type;
300 
301  template <typename PointerType>
302  static difference_type
303  pointer_to_offset(const access_type &obj, PointerType *ptr)
304  {
305  return obj.pointer_to_offset(static_cast<void *>(ptr));
306  }
307 
308  template <typename PointerType>
309  static PointerType *
310  offset_to_pointer(difference_type offset, const access_type &obj)
311  {
312  auto ptr = obj.offset_to_pointer(offset);
313  return static_cast<PointerType *>(ptr);
314  }
315 
316  static T &
317  get_offset(access_type &ptr)
318  {
319  return ptr.offset;
320  }
321 
322  static const T &
323  get_offset(const access_type &ptr)
324  {
325  return ptr.offset;
326  }
327 };
328 
329 } /* namespace detail */
330 
331 } /* namespace pmem */
332 
333 #endif /* LIBPMEMOBJ_CPP_SELF_RELATIVE_PTR_BASE_IMPL_HPP */
Static class accessor to self_relative_ptr_base.
Definition: self_relative_ptr_base_impl.hpp:296
self_relative_ptr base template class
Definition: self_relative_ptr_base_impl.hpp:39
static difference_type distance_between(const self_relative_ptr_base_impl &first, const self_relative_ptr_base_impl &second)
Byte distance between two relative pointers.
Definition: self_relative_ptr_base_impl.hpp:179
self_relative_ptr_base_impl(self_relative_ptr_base_impl const &r) noexcept
Copy constructor.
Definition: self_relative_ptr_base_impl.hpp:83
constexpr self_relative_ptr_base_impl(std::nullptr_t) noexcept
Nullptr constructor.
Definition: self_relative_ptr_base_impl.hpp:63
void * to_void_pointer() const noexcept
Conversion to void*.
Definition: self_relative_ptr_base_impl.hpp:154
difference_type pointer_to_offset(void *ptr) const noexcept
Conversion pointer to offset.
Definition: self_relative_ptr_base_impl.hpp:261
void * offset_to_pointer(difference_type other_offset) const noexcept
Conversion to void* use other offset.
Definition: self_relative_ptr_base_impl.hpp:209
byte_ptr_type to_byte_pointer() const noexcept
Conversion to byte pointer.
Definition: self_relative_ptr_base_impl.hpp:145
bool is_null() const noexcept
Fast null checking without conversion to void*.
Definition: self_relative_ptr_base_impl.hpp:189
void swap(self_relative_ptr_base_impl &other)
Swaps two self_relative_ptr_base objects of the same type.
Definition: self_relative_ptr_base_impl.hpp:129
constexpr self_relative_ptr_base_impl() noexcept
Default constructor, equal the nullptr.
Definition: self_relative_ptr_base_impl.hpp:55
self_relative_ptr_base_impl(void *ptr) noexcept
Volatile pointer constructor.
Definition: self_relative_ptr_base_impl.hpp:73
self_relative_ptr_base_impl & operator=(self_relative_ptr_base_impl const &r)
Assignment operator.
Definition: self_relative_ptr_base_impl.hpp:100
self_relative_ptr_base_impl(difference_type offset) noexcept
Offset constructor.
Definition: self_relative_ptr_base_impl.hpp:200
difference_type pointer_to_offset(const self_relative_ptr_base_impl &ptr) const noexcept
Conversion self_relative_ptr_base to offset from itself.
Definition: self_relative_ptr_base_impl.hpp:235
self_relative_ptr_base_impl & operator=(std::nullptr_t &&)
Nullptr move assignment operator.
Definition: self_relative_ptr_base_impl.hpp:116
Commonly used functionality.
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Helper template for persistent ptr specialization.