PMDK C++ bindings 1.13.0
This is the C++ bindings documentation for PMDK's libpmemobj.
Loading...
Searching...
No Matches
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
18namespace pmem
19{
20
21namespace detail
22{
23
38template <typename OffsetType>
40public:
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
194protected:
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
285private:
286 static constexpr difference_type nullptr_offset = 0;
287
288 template <typename T>
289 friend class self_relative_accessor;
290};
291
295template <typename T>
297public:
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
void * offset_to_pointer(difference_type other_offset) const noexcept
Conversion to void* use other offset.
Definition: self_relative_ptr_base_impl.hpp:209
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
self_relative_ptr_base_impl & operator=(std::nullptr_t &&)
Nullptr move assignment operator.
Definition: self_relative_ptr_base_impl.hpp:116
difference_type pointer_to_offset(void *ptr) const noexcept
Conversion pointer to offset.
Definition: self_relative_ptr_base_impl.hpp:261
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
self_relative_ptr_base_impl & operator=(self_relative_ptr_base_impl const &r)
Assignment operator.
Definition: self_relative_ptr_base_impl.hpp:100
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
void * to_void_pointer() const noexcept
Conversion to void*.
Definition: self_relative_ptr_base_impl.hpp:154
self_relative_ptr_base_impl(void *ptr) noexcept
Volatile pointer constructor.
Definition: self_relative_ptr_base_impl.hpp:73
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
Commonly used functionality.
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Helper template for persistent ptr specialization.