alignment.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // SPDX-FileCopyrightText: 2014 Jannik Vogel <email@jannikvogel.de>
  2. // SPDX-License-Identifier: CC0-1.0
  3. #pragma once
  4. #include <bit>
  5. #include <cstddef>
  6. #include <new>
  7. #include <type_traits>
  8. namespace Common {
  9. template <typename T>
  10. requires std::is_integral_v<T>
  11. [[nodiscard]] constexpr T AlignUp(T value_, size_t size) {
  12. using U = typename std::make_unsigned_t<T>;
  13. auto value{static_cast<U>(value_)};
  14. auto mod{static_cast<T>(value % size)};
  15. value -= mod;
  16. return static_cast<T>(mod == T{0} ? value : value + size);
  17. }
  18. template <typename T>
  19. requires std::is_unsigned_v<T>
  20. [[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
  21. return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
  22. }
  23. template <typename T>
  24. requires std::is_integral_v<T>
  25. [[nodiscard]] constexpr T AlignDown(T value_, size_t size) {
  26. using U = typename std::make_unsigned_t<T>;
  27. const auto value{static_cast<U>(value_)};
  28. return static_cast<T>(value - value % size);
  29. }
  30. template <typename T>
  31. requires std::is_unsigned_v<T>
  32. [[nodiscard]] constexpr bool Is4KBAligned(T value) {
  33. return (value & 0xFFF) == 0;
  34. }
  35. template <typename T>
  36. requires std::is_unsigned_v<T>
  37. [[nodiscard]] constexpr bool IsWordAligned(T value) {
  38. return (value & 0b11) == 0;
  39. }
  40. template <typename T>
  41. requires std::is_integral_v<T>
  42. [[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
  43. using U = typename std::make_unsigned_t<T>;
  44. const U mask = static_cast<U>(alignment - 1);
  45. return (value & mask) == 0;
  46. }
  47. template <typename T, typename U>
  48. requires std::is_integral_v<T>
  49. [[nodiscard]] constexpr T DivideUp(T x, U y) {
  50. return (x + (y - 1)) / y;
  51. }
  52. template <typename T>
  53. requires std::is_integral_v<T>
  54. [[nodiscard]] constexpr T LeastSignificantOneBit(T x) {
  55. return x & ~(x - 1);
  56. }
  57. template <typename T>
  58. requires std::is_integral_v<T>
  59. [[nodiscard]] constexpr T ResetLeastSignificantOneBit(T x) {
  60. return x & (x - 1);
  61. }
  62. template <typename T>
  63. requires std::is_integral_v<T>
  64. [[nodiscard]] constexpr bool IsPowerOfTwo(T x) {
  65. return x > 0 && ResetLeastSignificantOneBit(x) == 0;
  66. }
  67. template <typename T>
  68. requires std::is_integral_v<T>
  69. [[nodiscard]] constexpr T FloorPowerOfTwo(T x) {
  70. return T{1} << (sizeof(T) * 8 - std::countl_zero(x) - 1);
  71. }
  72. template <typename T, size_t Align = 16>
  73. class AlignmentAllocator {
  74. public:
  75. using value_type = T;
  76. using size_type = size_t;
  77. using difference_type = ptrdiff_t;
  78. using propagate_on_container_copy_assignment = std::true_type;
  79. using propagate_on_container_move_assignment = std::true_type;
  80. using propagate_on_container_swap = std::true_type;
  81. using is_always_equal = std::false_type;
  82. constexpr AlignmentAllocator() noexcept = default;
  83. template <typename T2>
  84. constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
  85. [[nodiscard]] T* allocate(size_type n) {
  86. return static_cast<T*>(::operator new(n * sizeof(T), std::align_val_t{Align}));
  87. }
  88. void deallocate(T* p, size_type n) {
  89. ::operator delete(p, n * sizeof(T), std::align_val_t{Align});
  90. }
  91. template <typename T2>
  92. struct rebind {
  93. using other = AlignmentAllocator<T2, Align>;
  94. };
  95. template <typename T2, size_t Align2>
  96. constexpr bool operator==(const AlignmentAllocator<T2, Align2>&) const noexcept {
  97. return std::is_same_v<T, T2> && Align == Align2;
  98. }
  99. };
  100. } // namespace Common