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