PMDK C++ bindings  1.13.0-git107.g7e59f08f
This is the C++ bindings documentation for PMDK's libpmemobj.
common.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2016-2021, Intel Corporation */
3 
9 #ifndef LIBPMEMOBJ_CPP_COMMON_HPP
10 #define LIBPMEMOBJ_CPP_COMMON_HPP
11 
13 #include <libpmemobj/tx_base.h>
14 #include <string>
15 #include <typeinfo>
16 
17 #if _MSC_VER
18 #include <intrin.h>
19 #include <windows.h>
20 #endif
21 
22 #if defined(__GNUC__) || defined(__clang__)
23 #define POBJ_CPP_DEPRECATED __attribute__((deprecated))
24 #elif defined(_MSC_VER)
25 #define POBJ_CPP_DEPRECATED __declspec(deprecated)
26 #else
27 #define POBJ_CPP_DEPRECATED
28 #endif
29 
30 #if LIBPMEMOBJ_CPP_VG_ENABLED
31 #undef LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
32 #undef LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED
33 #undef LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
34 #undef LIBPMEMOBJ_CPP_VG_DRD_ENABLED
35 
36 #define LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED 1
37 #define LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED 1
38 #define LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED 1
39 #define LIBPMEMOBJ_CPP_VG_DRD_ENABLED 1
40 #endif
41 
42 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED || \
43  LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED || \
44  LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED || LIBPMEMOBJ_CPP_VG_DRD_ENABLED
45 #define LIBPMEMOBJ_CPP_ANY_VG_TOOL_ENABLED 1
46 #endif
47 
48 #if LIBPMEMOBJ_CPP_ANY_VG_TOOL_ENABLED
49 #include <valgrind.h>
50 #endif
51 
52 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
53 #include <pmemcheck.h>
54 #endif
55 
56 #if LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED
57 #include <memcheck.h>
58 #endif
59 
60 #if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
61 #include <helgrind.h>
62 #endif
63 
64 #if LIBPMEMOBJ_CPP_VG_DRD_ENABLED
65 #include <drd.h>
66 #endif
67 
68 #if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
69 
70 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, ptr) \
71  if (order == std::memory_order_release || \
72  order == std::memory_order_acq_rel || \
73  order == std::memory_order_seq_cst) { \
74  ANNOTATE_HAPPENS_BEFORE(ptr); \
75  }
76 
77 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, ptr) \
78  if (order == std::memory_order_consume || \
79  order == std::memory_order_acquire || \
80  order == std::memory_order_acq_rel || \
81  order == std::memory_order_seq_cst) { \
82  ANNOTATE_HAPPENS_AFTER(ptr); \
83  }
84 #else
85 
86 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, ptr)
87 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, ptr)
88 
89 #endif
90 
91 /*
92  * Workaround for missing "is_trivially_copyable" in gcc < 5.0.
93  * Be aware of a difference between __has_trivial_copy and is_trivially_copyable
94  * e.g. for deleted copy constructors __has_trivial_copy(A) returns 1 in clang
95  * and 0 in gcc. It means that for gcc < 5 LIBPMEMOBJ_CPP_IS_TRIVIALLY_COPYABLE
96  * is more restrictive than is_trivially_copyable.
97  */
98 #if !defined(LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY)
99 #if !defined(__clang__) && defined(__GNUG__) && __GNUC__ < 5
100 #define LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY 1
101 #else
102 #define LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY 0
103 #endif
104 #endif
105 
106 #if LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY
107 #define LIBPMEMOBJ_CPP_IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T)
108 #else
109 #define LIBPMEMOBJ_CPP_IS_TRIVIALLY_COPYABLE(T) \
110  std::is_trivially_copyable<T>::value
111 #endif
112 
119 namespace pmem
120 {
127 namespace obj
128 {
129 template <typename T>
130 class persistent_ptr;
131 
139 namespace experimental
140 {
141 }
142 }
143 
150 namespace detail
151 {
152 
153 #if defined(__x86_64) || defined(_M_X64) || defined(__aarch64__) || \
154  defined(__riscv)
155 static constexpr size_t CACHELINE_SIZE = 64ULL;
156 #elif defined(__PPC64__)
157 static constexpr size_t CACHELINE_SIZE = 128ULL;
158 #else
159 #error unable to recognize architecture at compile time
160 #endif
161 
174 template <typename T>
175 inline void
176 conditional_add_to_tx(const T *that, std::size_t count = 1, uint64_t flags = 0)
177 {
178  if (count == 0)
179  return;
180 
181  if (pmemobj_tx_stage() != TX_STAGE_WORK)
182  return;
183 
184  /* 'that' is not in any open pool */
185  if (!pmemobj_pool_by_ptr(that))
186  return;
187 
188  if (pmemobj_tx_xadd_range_direct(that, sizeof(*that) * count, flags)) {
189  const char *msg = "Could not add object(s) to the transaction.";
190  if (errno == ENOMEM)
193  else
194  throw exception_with_errormsg<pmem::transaction_error>(
195  msg);
196  }
197 }
198 
202 template <typename T>
203 uint64_t
205 {
206  return typeid(T).hash_code();
207 }
208 
212 inline uint64_t
213 next_pow_2(uint64_t v)
214 {
215  v--;
216  v |= v >> 1;
217  v |= v >> 2;
218  v |= v >> 4;
219  v |= v >> 8;
220  v |= v >> 16;
221  v |= v >> 32;
222  ++v;
223  return v + (v == 0);
224 }
225 
229 inline uint64_t
230 next_pow_2(uint32_t v)
231 {
232  v--;
233  v |= v >> 1;
234  v |= v >> 2;
235  v |= v >> 4;
236  v |= v >> 8;
237  v |= v >> 16;
238  ++v;
239  return v + (v == 0);
240 }
241 
242 #if _MSC_VER
243 static inline int
244 Log2(uint64_t x)
245 {
246  unsigned long j;
247  _BitScanReverse64(&j, x);
248  return static_cast<int>(j);
249 }
250 #elif __GNUC__ || __clang__
251 static inline int
252 Log2(uint64_t x)
253 {
254  // __builtin_clz builtin count _number_ of leading zeroes
255  return 8 * int(sizeof(x)) - __builtin_clzll(x) - 1;
256 }
257 #else
258 static inline int
259 Log2(uint64_t x)
260 {
261  x |= (x >> 1);
262  x |= (x >> 2);
263  x |= (x >> 4);
264  x |= (x >> 8);
265  x |= (x >> 16);
266  x |= (x >> 32);
267 
268  static const int table[64] = {
269  0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61,
270  51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62,
271  57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56,
272  45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63};
273 
274  return table[(x * 0x03f6eaf2cd271461) >> 58];
275 }
276 #endif
277 
278 #ifndef _MSC_VER
279 
281 static inline uint8_t
282 mssb_index64(unsigned long long value)
283 {
284  return ((uint8_t)(63 - __builtin_clzll(value)));
285 }
286 
288 static inline uint8_t
289 mssb_index(unsigned int value)
290 {
291  return ((uint8_t)(31 - __builtin_clz(value)));
292 }
293 
294 #else
295 
296 static __inline uint8_t
297 mssb_index(unsigned long value)
298 {
299  unsigned long ret;
300  _BitScanReverse(&ret, value);
301  return (uint8_t)ret;
302 }
303 
304 static __inline uint8_t
305 mssb_index64(uint64_t value)
306 {
307  unsigned long ret;
308  _BitScanReverse64(&ret, value);
309  return (uint8_t)ret;
310 }
311 
312 #endif
313 
314 static constexpr size_t
315 align_up(size_t size, size_t align)
316 {
317  return ((size) + (align)-1) & ~((align)-1);
318 }
319 
320 static constexpr size_t
321 align_down(size_t size, size_t align)
322 {
323  return (size) & ~((align)-1);
324 }
325 
326 } /* namespace detail */
327 
328 } /* namespace pmem */
329 
330 #endif /* LIBPMEMOBJ_CPP_COMMON_HPP */
Custom out of memory error class.
Definition: pexceptions.hpp:144
void conditional_add_to_tx(const T *that, std::size_t count=1, uint64_t flags=0)
Conditionally add 'count' objects to a transaction.
Definition: common.hpp:176
static uint8_t mssb_index(unsigned int value)
Returns index of most significant set bit.
Definition: common.hpp:289
ExcT exception_with_errormsg(Args &&... args)
Generic error message decorator for pmemobj-based exceptions.
Definition: pexceptions.hpp:69
uint64_t next_pow_2(uint64_t v)
Round up to the next lowest power of 2.
Definition: common.hpp:213
uint64_t type_num()
Return type number for given type.
Definition: common.hpp:204
static uint8_t mssb_index64(unsigned long long value)
Returns index of most significant set bit.
Definition: common.hpp:282
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Custom pmem exceptions.