summaryrefslogtreecommitdiff
path: root/src/common/alignment.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/alignment.h')
-rw-r--r--src/common/alignment.h69
1 files changed, 20 insertions, 49 deletions
diff --git a/src/common/alignment.h b/src/common/alignment.h
index cdd4833f8..5040043de 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -3,41 +3,50 @@
3#pragma once 3#pragma once
4 4
5#include <cstddef> 5#include <cstddef>
6#include <memory> 6#include <new>
7#include <type_traits> 7#include <type_traits>
8 8
9namespace Common { 9namespace Common {
10 10
11template <typename T> 11template <typename T>
12constexpr T AlignUp(T value, std::size_t size) { 12[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
14 return static_cast<T>(value + (size - value % size) % size); 14 auto mod{static_cast<T>(value % size)};
15 value -= mod;
16 return static_cast<T>(mod == T{0} ? value : value + size);
15} 17}
16 18
17template <typename T> 19template <typename T>
18constexpr T AlignDown(T value, std::size_t size) { 20[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
19 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 21 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
20 return static_cast<T>(value - value % size); 22 return static_cast<T>(value - value % size);
21} 23}
22 24
23template <typename T> 25template <typename T>
24constexpr T AlignBits(T value, std::size_t align) { 26[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) {
25 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 27 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
26 return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align); 28 return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
27} 29}
28 30
29template <typename T> 31template <typename T>
30constexpr bool Is4KBAligned(T value) { 32[[nodiscard]] constexpr bool Is4KBAligned(T value) {
31 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 33 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
32 return (value & 0xFFF) == 0; 34 return (value & 0xFFF) == 0;
33} 35}
34 36
35template <typename T> 37template <typename T>
36constexpr bool IsWordAligned(T value) { 38[[nodiscard]] constexpr bool IsWordAligned(T value) {
37 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 39 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
38 return (value & 0b11) == 0; 40 return (value & 0b11) == 0;
39} 41}
40 42
43template <typename T>
44[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
45 using U = typename std::make_unsigned<T>::type;
46 const U mask = static_cast<U>(alignment - 1);
47 return (value & mask) == 0;
48}
49
41template <typename T, std::size_t Align = 16> 50template <typename T, std::size_t Align = 16>
42class AlignmentAllocator { 51class AlignmentAllocator {
43public: 52public:
@@ -45,66 +54,28 @@ public:
45 using size_type = std::size_t; 54 using size_type = std::size_t;
46 using difference_type = std::ptrdiff_t; 55 using difference_type = std::ptrdiff_t;
47 56
48 using pointer = T*;
49 using const_pointer = const T*;
50
51 using reference = T&;
52 using const_reference = const T&;
53
54 using propagate_on_container_copy_assignment = std::true_type; 57 using propagate_on_container_copy_assignment = std::true_type;
55 using propagate_on_container_move_assignment = std::true_type; 58 using propagate_on_container_move_assignment = std::true_type;
56 using propagate_on_container_swap = std::true_type; 59 using propagate_on_container_swap = std::true_type;
57 using is_always_equal = std::true_type; 60 using is_always_equal = std::true_type;
58 61
59public:
60 constexpr AlignmentAllocator() noexcept = default; 62 constexpr AlignmentAllocator() noexcept = default;
61 63
62 template <typename T2> 64 template <typename T2>
63 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {} 65 constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
64 66
65 pointer address(reference r) noexcept { 67 [[nodiscard]] T* allocate(size_type n) {
66 return std::addressof(r); 68 return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
67 }
68
69 const_pointer address(const_reference r) const noexcept {
70 return std::addressof(r);
71 }
72
73 pointer allocate(size_type n) {
74 return static_cast<pointer>(::operator new (n, std::align_val_t{Align}));
75 } 69 }
76 70
77 void deallocate(pointer p, size_type) { 71 void deallocate(T* p, size_type n) {
78 ::operator delete (p, std::align_val_t{Align}); 72 ::operator delete (p, n * sizeof(T), std::align_val_t{Align});
79 }
80
81 void construct(pointer p, const value_type& wert) {
82 new (p) value_type(wert);
83 }
84
85 void destroy(pointer p) {
86 p->~value_type();
87 }
88
89 size_type max_size() const noexcept {
90 return size_type(-1) / sizeof(value_type);
91 } 73 }
92 74
93 template <typename T2> 75 template <typename T2>
94 struct rebind { 76 struct rebind {
95 using other = AlignmentAllocator<T2, Align>; 77 using other = AlignmentAllocator<T2, Align>;
96 }; 78 };
97
98 bool operator!=(const AlignmentAllocator<T, Align>& other) const noexcept {
99 return !(*this == other);
100 }
101
102 // Returns true if and only if storage allocated from *this
103 // can be deallocated from other, and vice versa.
104 // Always returns true for stateless allocators.
105 bool operator==(const AlignmentAllocator<T, Align>& other) const noexcept {
106 return true;
107 }
108}; 79};
109 80
110} // namespace Common 81} // namespace Common