density
C++11 library for paged memory management, function queues, heterogeneous queues and lifo memory management
density_common.h
Go to the documentation of this file.
1 
2 // Copyright Giuseppe Campana (giu.campana@gmail.com) 2016-2018.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #pragma once
8 #include <atomic> // for std::memory_order
9 #include <cstddef>
10 #include <limits>
11 #include <new>
12 #include <type_traits>
13 #include <utility>
14 
15 #include <density/density_config.h>
16 
20 #define DENSITY_VERSION 0x00020000
21 
22 // detect 'Relaxed constraints on constexpr functions / constexpr member functions and implicit const'
23 // see http://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros#C.2B.2B14
24 #if __cpp_constexpr >= 201304
25 #define DENSITY_CPP14_CONSTEXPR constexpr
26 #else
27 #define DENSITY_CPP14_CONSTEXPR
28 #endif
29 
30 #if __cpp_noexcept_function_type >= 201510
31 #define DENSITY_CPP17_NOEXCEPT noexcept
32 #else
33 #define DENSITY_CPP17_NOEXCEPT
34 #endif
35 
36 // DENSITY_NODISCARD
37 #if defined(__has_cpp_attribute)
38 #if __has_cpp_attribute(nodiscard) >= 201603
39 // clang-format off
40 #define DENSITY_NODISCARD [[nodiscard]]
41 // clang-format on
42 #endif
43 #endif
44 #ifndef DENSITY_NODISCARD
45 #define DENSITY_NODISCARD
46 #endif
47 
49 namespace density
50 {
53  constexpr char version[] = "2.0.0";
54 
57  {
62  };
63 
66  {
73  };
74 
85  {
94  };
95 
98  {
103  };
104 
105  // address functions
106 
109  constexpr bool is_power_of_2(size_t i_number) noexcept
110  {
111  //DENSITY_ASSERT(i_number > 0);
112  return (i_number & (i_number - 1)) == 0;
113  }
114 
118  inline bool address_is_aligned(const void * i_address, size_t i_alignment) noexcept
119  {
120  DENSITY_ASSERT(is_power_of_2(i_alignment));
121  DENSITY_ASSUME(i_alignment > 0);
122  return (reinterpret_cast<uintptr_t>(i_address) & (i_alignment - 1)) == 0;
123  }
124 
128  template <typename UINT> inline bool uint_is_aligned(UINT i_uint, UINT i_alignment) noexcept
129  {
130  static_assert(
131  std::numeric_limits<UINT>::is_integer && !std::numeric_limits<UINT>::is_signed,
132  "UINT mus be an unsigned integer");
133  DENSITY_ASSERT(is_power_of_2(i_alignment));
134  DENSITY_ASSUME(i_alignment > 0);
135  return (i_uint & (i_alignment - 1)) == 0;
136  }
137 
142  inline void * address_add(void * i_address, size_t i_offset) noexcept
143  {
144  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
145  return reinterpret_cast<void *>(uint_pointer + i_offset);
146  }
147 
152  inline const void * address_add(const void * i_address, size_t i_offset) noexcept
153  {
154  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
155  return reinterpret_cast<const void *>(uint_pointer + i_offset);
156  }
157 
162  inline void * address_sub(void * i_address, size_t i_offset) noexcept
163  {
164  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
165  DENSITY_ASSUME(uint_pointer >= i_offset);
166  return reinterpret_cast<void *>(uint_pointer - i_offset);
167  }
168 
173  inline const void * address_sub(const void * i_address, size_t i_offset) noexcept
174  {
175  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
176  DENSITY_ASSUME(uint_pointer >= i_offset);
177  return reinterpret_cast<const void *>(uint_pointer - i_offset);
178  }
179 
184  inline uintptr_t address_diff(const void * i_end_address, const void * i_start_address) noexcept
185  {
186  DENSITY_ASSUME(i_end_address >= i_start_address);
187 
188  const uintptr_t end_uint_pointer = reinterpret_cast<uintptr_t>(i_end_address);
189  const uintptr_t start_uint_pointer = reinterpret_cast<uintptr_t>(i_start_address);
190 
191  return end_uint_pointer - start_uint_pointer;
192  }
193 
198  inline void * address_lower_align(void * i_address, size_t i_alignment) noexcept
199  {
200  DENSITY_ASSERT(is_power_of_2(i_alignment));
201  DENSITY_ASSUME(i_alignment > 0);
202 
203  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
204 
205  const size_t mask = i_alignment - 1;
206 
207  return reinterpret_cast<void *>(uint_pointer & ~mask);
208  }
209 
214  inline const void * address_lower_align(const void * i_address, size_t i_alignment) noexcept
215  {
216  DENSITY_ASSERT(is_power_of_2(i_alignment));
217  DENSITY_ASSUME(i_alignment > 0);
218 
219  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
220 
221  const size_t mask = i_alignment - 1;
222 
223  return reinterpret_cast<void *>(uint_pointer & ~mask);
224  }
225 
231  inline void *
232  address_lower_align(void * i_address, size_t i_alignment, size_t i_alignment_offset) noexcept
233  {
234  void * address = address_add(i_address, i_alignment_offset);
235 
236  address = address_lower_align(address, i_alignment);
237 
238  address = address_sub(address, i_alignment_offset);
239 
240  return address;
241  }
242 
248  inline const void * address_lower_align(
249  const void * i_address, size_t i_alignment, size_t i_alignment_offset) noexcept
250  {
251  const void * address = address_add(i_address, i_alignment_offset);
252 
253  address = address_lower_align(address, i_alignment);
254 
255  address = address_sub(address, i_alignment_offset);
256 
257  return address;
258  }
259 
264  inline void * address_upper_align(void * i_address, size_t i_alignment) noexcept
265  {
266  DENSITY_ASSERT(is_power_of_2(i_alignment));
267  DENSITY_ASSUME(i_alignment > 0);
268 
269  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
270 
271  const size_t mask = i_alignment - 1;
272 
273  return reinterpret_cast<void *>((uint_pointer + mask) & ~mask);
274  }
275 
280  inline const void * address_upper_align(const void * i_address, size_t i_alignment) noexcept
281  {
282  DENSITY_ASSERT(is_power_of_2(i_alignment));
283  DENSITY_ASSUME(i_alignment > 0);
284 
285  const uintptr_t uint_pointer = reinterpret_cast<uintptr_t>(i_address);
286 
287  const size_t mask = i_alignment - 1;
288 
289  return reinterpret_cast<void *>((uint_pointer + mask) & ~mask);
290  }
291 
296  template <typename UINT>
297  constexpr UINT uint_upper_align(UINT i_uint, size_t i_alignment) noexcept
298  {
299  static_assert(
300  std::numeric_limits<UINT>::is_integer && !std::numeric_limits<UINT>::is_signed,
301  "UINT must be an unsigned integer");
302  return (i_uint + (i_alignment - 1)) & ~(i_alignment - 1);
303  }
304 
305 
310  template <typename UINT>
311  constexpr UINT uint_lower_align(UINT i_uint, size_t i_alignment) noexcept
312  {
313  static_assert(
314  std::numeric_limits<UINT>::is_integer && !std::numeric_limits<UINT>::is_signed,
315  "UINT must be an unsigned integer");
316  return i_uint & ~(i_alignment - 1);
317  }
318 
324  inline void *
325  address_upper_align(void * i_address, size_t i_alignment, size_t i_alignment_offset) noexcept
326  {
327  void * address = address_add(i_address, i_alignment_offset);
328 
329  address = address_upper_align(address, i_alignment);
330 
331  address = address_sub(address, i_alignment_offset);
332 
333  return address;
334  }
335 
341  inline const void * address_upper_align(
342  const void * i_address, size_t i_alignment, size_t i_alignment_offset) noexcept
343  {
344  const void * address = address_add(i_address, i_alignment_offset);
345 
346  address = address_upper_align(address, i_alignment);
347 
348  address = address_sub(address, i_alignment_offset);
349 
350  return address;
351  }
352 
355  namespace detail
356  {
357  // size_min: avoid including <algorithm> just to use std::min<size_t>
358  constexpr inline size_t size_min(size_t i_first, size_t i_second) noexcept
359  {
360  return i_first < i_second ? i_first : i_second;
361  }
362 
363  // size_max: avoid including <algorithm> just to use std::max<size_t>
364  constexpr inline size_t size_max(size_t i_first, size_t i_second) noexcept
365  {
366  return i_first > i_second ? i_first : i_second;
367  }
368  constexpr inline size_t size_max(size_t i_first, size_t i_second, size_t i_third) noexcept
369  {
370  return size_max(size_max(i_first, i_second), i_third);
371  }
372  constexpr inline size_t
373  size_max(size_t i_first, size_t i_second, size_t i_third, size_t i_fourth) noexcept
374  {
375  return size_max(size_max(i_first, i_second), size_max(i_third, i_fourth));
376  }
377 
378  struct AlignmentHeader
379  {
380  void * m_block;
381  };
382 
383  constexpr auto mem_relaxed =
384  !enable_relaxed_atomics ? std::memory_order_seq_cst : std::memory_order_relaxed;
385  constexpr auto mem_acquire =
386  !enable_relaxed_atomics ? std::memory_order_seq_cst : std::memory_order_acquire;
387  constexpr auto mem_release =
388  !enable_relaxed_atomics ? std::memory_order_seq_cst : std::memory_order_release;
389  constexpr auto mem_acq_rel =
390  !enable_relaxed_atomics ? std::memory_order_seq_cst : std::memory_order_acq_rel;
391  constexpr auto mem_seq_cst =
392  !enable_relaxed_atomics ? std::memory_order_seq_cst : std::memory_order_seq_cst;
393 
396  constexpr size_t size_log2(size_t i_size) noexcept
397  {
398  return i_size <= 1 ? 0 : size_log2(i_size / 2) + 1;
399  }
400 
403  inline bool ConstConditional(bool i_value) noexcept { return i_value; }
404 
405  struct ExternalBlock
406  {
407  void * m_block;
408  size_t m_size, m_alignment;
409  };
410 
412  template <typename TYPE> struct size_of
413  {
414  static constexpr size_t value = std::is_empty<TYPE>::value ? 0 : sizeof(TYPE);
415  };
416 
417  // old versions of libstdc++ define max_align_t only outside std::
418 #if defined(__GLIBCXX__)
419  constexpr size_t MaxAlignment = alignof(max_align_t);
420 #else
421  constexpr size_t MaxAlignment = alignof(std::max_align_t);
422 #endif
423 
426 #ifdef _MSC_VER
427 #define DENSITY_INTERNAL_RETHROW_FROM_NOEXCEPT \
428  __pragma(warning(push)) __pragma(warning(disable : 4297)) throw; \
429  __pragma(warning(pop))
430 #elif defined(__GNUG__) && __GNUG__ >= 6 && !defined(__clang__)
431 #define DENSITY_INTERNAL_RETHROW_FROM_NOEXCEPT \
432  _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wterminate\"") throw; \
433  _Pragma("GCC diagnostic pop")
434 #else
435 #define DENSITY_INTERNAL_RETHROW_FROM_NOEXCEPT throw;
436 #endif
437  } // namespace detail
438 
460  inline void * aligned_allocate(size_t i_size, size_t i_alignment, size_t i_alignment_offset = 0)
461  {
462  DENSITY_ASSERT(is_power_of_2(i_alignment));
463  DENSITY_ASSUME(i_alignment > 0);
464  DENSITY_ASSUME(i_alignment_offset <= i_size);
465 
466  void * user_block;
467  if (i_alignment <= detail::MaxAlignment && i_alignment_offset == 0)
468  {
469  user_block = operator new(i_size);
470  }
471  else
472  {
473  // reserve an additional space in the block equal to the max(i_alignment, sizeof(AlignmentHeader) - sizeof(void*) )
474  size_t const extra_size =
475  detail::size_max(i_alignment, sizeof(detail::AlignmentHeader));
476  size_t const actual_size = i_size + extra_size;
477  auto const complete_block = operator new(actual_size);
478  user_block = address_lower_align(
479  address_add(complete_block, extra_size), i_alignment, i_alignment_offset);
480  detail::AlignmentHeader & header =
481  *(static_cast<detail::AlignmentHeader *>(user_block) - 1);
482  header.m_block = complete_block;
484  user_block >= complete_block &&
485  address_add(user_block, i_size) <= address_add(complete_block, actual_size));
486  }
487  return user_block;
488  }
489 
510  inline void * try_aligned_allocate(
511  size_t i_size, size_t i_alignment, size_t i_alignment_offset = 0) noexcept
512  {
513  DENSITY_ASSERT(is_power_of_2(i_alignment));
514  DENSITY_ASSUME(i_alignment > 0);
515  DENSITY_ASSUME(i_alignment_offset <= i_size);
516 
517  void * user_block;
518  if (i_alignment <= detail::MaxAlignment && i_alignment_offset == 0)
519  {
520  user_block = operator new(i_size, std::nothrow);
521  }
522  else
523  {
524  // reserve an additional space in the block equal to the max(i_alignment, sizeof(AlignmentHeader) - sizeof(void*) )
525  size_t const extra_size =
526  detail::size_max(i_alignment, sizeof(detail::AlignmentHeader));
527  size_t const actual_size = i_size + extra_size;
528  auto const complete_block = operator new(actual_size, std::nothrow);
529  if (complete_block != nullptr)
530  {
531  user_block = address_lower_align(
532  address_add(complete_block, extra_size), i_alignment, i_alignment_offset);
533  detail::AlignmentHeader & header =
534  *(static_cast<detail::AlignmentHeader *>(user_block) - 1);
535  header.m_block = complete_block;
537  user_block >= complete_block &&
538  address_add(user_block, i_size) <= address_add(complete_block, actual_size));
539  }
540  else
541  {
542  user_block = nullptr;
543  }
544  }
545  return user_block;
546  }
547 
564  inline void aligned_deallocate(
565  void * i_block, size_t i_size, size_t i_alignment, size_t i_alignment_offset = 0) noexcept
566  {
567  DENSITY_ASSERT(is_power_of_2(i_alignment));
568  DENSITY_ASSUME(i_alignment > 0);
569 
570  if (i_alignment <= detail::MaxAlignment && i_alignment_offset == 0)
571  {
572 #if __cpp_sized_deallocation >= 201309
573  operator delete(i_block, i_size); // since C++14
574 #else
575  (void)i_size;
576  operator delete(i_block);
577 #endif
578  }
579  else
580  {
581  if (i_block != nullptr)
582  {
583  const auto & header = *(static_cast<detail::AlignmentHeader *>(i_block) - 1);
584 #if __cpp_sized_deallocation >= 201309 // since C++14
585  size_t const extra_size =
586  detail::size_max(i_alignment, sizeof(detail::AlignmentHeader));
587  size_t const actual_size = i_size + extra_size;
588  operator delete(header.m_block, actual_size);
589 #else
590  (void)i_size;
591  operator delete(header.m_block);
592 #endif
593  }
594  }
595  }
596 
597  // clang-format off
922  // clang-format on
923 } // namespace density
void * address_add(void *i_address, size_t i_offset) noexcept
Definition: density_common.h:142
Definition: density_common.h:70
bool address_is_aligned(const void *i_address, size_t i_alignment) noexcept
Definition: density_common.h:118
constexpr char version[]
Definition: density_common.h:53
concurrency_cardinality
Definition: density_common.h:56
constexpr bool enable_relaxed_atomics
Definition: density_config.h:118
Definition: conc_function_queue.h:11
Definition: density_common.h:67
Definition: density_common.h:60
Definition: density_common.h:86
Definition: density_common.h:90
Definition: density_common.h:58
uintptr_t address_diff(const void *i_end_address, const void *i_start_address) noexcept
Definition: density_common.h:184
#define DENSITY_ASSERT(...)
Definition: density_config.h:19
constexpr UINT uint_lower_align(UINT i_uint, size_t i_alignment) noexcept
Definition: density_common.h:311
Definition: density_common.h:99
void * address_sub(void *i_address, size_t i_offset) noexcept
Definition: density_common.h:162
Definition: density_common.h:88
progress_guarantee
Definition: density_common.h:84
Definition: density_common.h:101
constexpr bool is_power_of_2(size_t i_number) noexcept
Definition: density_common.h:109
void * aligned_allocate(size_t i_size, size_t i_alignment, size_t i_alignment_offset=0)
Definition: density_common.h:460
void * address_upper_align(void *i_address, size_t i_alignment) noexcept
Definition: density_common.h:264
#define DENSITY_ASSERT_INTERNAL(...)
Definition: density_config.h:28
void * address_lower_align(void *i_address, size_t i_alignment) noexcept
Definition: density_common.h:198
void * try_aligned_allocate(size_t i_size, size_t i_alignment, size_t i_alignment_offset=0) noexcept
Definition: density_common.h:510
Definition: density_common.h:92
constexpr UINT uint_upper_align(UINT i_uint, size_t i_alignment) noexcept
Definition: density_common.h:297
void aligned_deallocate(void *i_block, size_t i_size, size_t i_alignment, size_t i_alignment_offset=0) noexcept
Definition: density_common.h:564
function_type_erasure
Definition: density_common.h:97
consistency_model
Definition: density_common.h:65
#define DENSITY_ASSUME(bool_expr,...)
Definition: density_config.h:46
bool uint_is_aligned(UINT i_uint, UINT i_alignment) noexcept
Definition: density_common.h:128