openMSX
AlignedBuffer.hh
Go to the documentation of this file.
1#ifndef ALIGNEDBUFFER_HH
2#define ALIGNEDBUFFER_HH
3
4#include <array>
5#include <bit>
6#include <cassert>
7#include <concepts>
8#include <cstdint>
9#include <cstddef>
10#include <type_traits>
11
12namespace openmsx {
13
14// Interface for an aligned buffer.
15// This type doesn't itself provide any storage, it only 'refers' to some
16// storage. In that sense it is very similar in usage to a 'uint8_t*'.
17//
18// For example:
19// void f1(uint8_t* buf) {
20// ... uint8_t x = buf[7];
21// ... buf[4] = 10;
22// ... uint8_t* begin = buf;
23// ... uint8_t* end = buf + 12;
24// }
25// void f2(AlignedBuffer& buf) {
26// // The exact same syntax as above, the only difference is that here
27// // the compiler knows at compile-time the alignment of 'buf', while
28// // above the compiler must assume worst case alignment.
29// }
30class alignas(std::max_align_t) AlignedBuffer
31{
32private:
33 [[nodiscard]] auto* p() { return std::bit_cast< uint8_t*>(this); }
34 [[nodiscard]] auto* p() const { return std::bit_cast<const uint8_t*>(this); }
35
36public:
37 static constexpr auto ALIGNMENT = alignof(std::max_align_t);
38
39 [[nodiscard]] operator uint8_t*() { return p(); }
40 [[nodiscard]] operator const uint8_t*() const { return p(); }
41 [[nodiscard]] auto* data() { return p(); }
42 [[nodiscard]] const auto* data() const { return p(); }
43
44 template<std::integral I>
45 [[nodiscard]] auto* operator+(I i) { return p() + i; }
46 template<std::integral I>
47 [[nodiscard]] const auto* operator+(I i) const { return p() + i; }
48
49 template<std::integral I>
50 [[nodiscard]] auto& operator[](I i) { return *(p() + i); }
51 template<std::integral I>
52 [[nodiscard]] const auto& operator[](I i) const { return *(p() + i); }
53};
54static_assert(alignof(AlignedBuffer) == AlignedBuffer::ALIGNMENT, "must be aligned");
55
56
57// Provide actual storage for the AlignedBuffer
58// A possible alternative is to use a union.
59template<size_t N> class AlignedByteArray : public AlignedBuffer
60{
61public:
62 [[nodiscard]] auto size() const { return dat.size(); }
63 [[nodiscard]] auto* data() { return dat.data(); }
64 [[nodiscard]] auto* data() const { return dat.data(); }
65 [[nodiscard]] auto begin() { return dat.begin(); }
66 [[nodiscard]] auto begin() const { return dat.begin(); }
67 [[nodiscard]] auto end() { return dat.end(); }
68 [[nodiscard]] auto end() const { return dat.end(); }
69
70private:
71 std::array<uint8_t, N> dat;
72
73};
74static_assert(alignof(AlignedByteArray<13>) == AlignedBuffer::ALIGNMENT,
75 "must be aligned");
76static_assert(sizeof(AlignedByteArray<32>) == 32,
77 "we rely on the empty-base optimization");
78
79
84template<typename T> [[nodiscard]] static inline T aligned_cast(void* p)
85{
86 static_assert(std::is_pointer_v<T>,
87 "can only perform aligned_cast on pointers");
88 assert((std::bit_cast<uintptr_t>(p) %
89 alignof(std::remove_pointer_t<T>)) == 0);
90 return std::bit_cast<T>(p);
91}
92
93} //namespace openmsx
94
95#endif
const auto & operator[](I i) const
static constexpr auto ALIGNMENT
const auto * operator+(I i) const
const auto * data() const
This file implemented 3 utility functions:
Definition Autofire.cc:11