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