PMDK C++ bindings  1.12
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, 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 = reinterpret_cast<uintptr_t>(
226  reinterpret_cast<const_byte_ptr_type>(this) +
227  other_offset + 1);
228  ptr &= mask;
229  return reinterpret_cast<void *>(ptr);
230  }
231 
235  difference_type
237  {
238  /*
239  This version without branches is vectorization-friendly.
240  mask = is_null() should not create a branch in the code.
241  In this line, we just assign 0 or 1 to the mask variable.
242 
243  This code is equal:
244  return ptr.is_null()
245  ? nullptr_offset
246  : ptr.offset + this->distance_between_self(ptr);
247  */
248  uintptr_t mask = ptr.is_null();
249  --mask;
250  difference_type distance_between_self =
251  reinterpret_cast<const_byte_ptr_type>(&ptr) -
252  reinterpret_cast<const_byte_ptr_type>(this);
253  distance_between_self &=
254  reinterpret_cast<difference_type &>(mask);
255  return ptr.offset + distance_between_self;
256  }
257 
261  difference_type
262  pointer_to_offset(void *ptr) const noexcept
263  {
264  /*
265  This version without branches is vectorization-friendly.
266  mask = ptr == nullptr should not create a branch in the code.
267  In this line, we just assign 0 or 1 to the mask variable.
268 
269  This code is equal:
270  if (ptr == nullptr)
271  return nullptr_offset
272  else
273  return ptr - this - 1;
274  */
275  uintptr_t mask = ptr == nullptr;
276  --mask;
277  difference_type new_offset = static_cast<byte_ptr_type>(ptr) -
278  reinterpret_cast<const_byte_ptr_type>(this) - 1;
279  new_offset &= reinterpret_cast<difference_type &>(mask);
280  return new_offset;
281  }
282 
283  /* The offset from self */
284  offset_type offset;
285 
286 private:
287  static constexpr difference_type nullptr_offset = 0;
288 
289  template <typename T>
290  friend class self_relative_accessor;
291 };
292 
296 template <typename T>
298 public:
300  using difference_type = typename access_type::difference_type;
301 
302  template <typename PointerType>
303  static difference_type
304  pointer_to_offset(const access_type &obj, PointerType *ptr)
305  {
306  return obj.pointer_to_offset(static_cast<void *>(ptr));
307  }
308 
309  template <typename PointerType>
310  static PointerType *
311  offset_to_pointer(difference_type offset, const access_type &obj)
312  {
313  auto ptr = obj.offset_to_pointer(offset);
314  return static_cast<PointerType *>(ptr);
315  }
316 
317  static T &
318  get_offset(access_type &ptr)
319  {
320  return ptr.offset;
321  }
322 
323  static const T &
324  get_offset(const access_type &ptr)
325  {
326  return ptr.offset;
327  }
328 };
329 
330 } /* namespace detail */
331 
332 } /* namespace pmem */
333 
334 #endif /* LIBPMEMOBJ_CPP_SELF_RELATIVE_PTR_BASE_IMPL_HPP */
Static class accesssor to self_relative_ptr_base.
Definition: self_relative_ptr_base_impl.hpp:297
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:262
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:236
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.