openMSX
MemBuffer.hh
Go to the documentation of this file.
1#ifndef MEMBUFFER_HH
2#define MEMBUFFER_HH
3
4#include "MemoryOps.hh"
5
6#include <algorithm>
7#include <cstddef>
8#include <cstdlib>
9#include <cassert>
10#include <new> // for bad_alloc
11#include <span>
12#include <type_traits>
13
14namespace openmsx {
15
31template<typename T, size_t ALIGNMENT = 0> class MemBuffer
32{
33 static_assert(std::is_trivially_copyable_v<T>);
34 static_assert(std::is_trivially_destructible_v<T>);
35public:
39 : dat(nullptr)
40 , sz(0)
41 {
42 }
43
46 explicit MemBuffer(size_t size)
47 : dat(static_cast<T*>(my_malloc(size * sizeof(T))))
48 , sz(size)
49 {
50 }
51
53 MemBuffer(MemBuffer&& other) noexcept
54 : dat(other.dat)
55 , sz(other.sz)
56 {
57 other.dat = nullptr;
58 other.sz = 0;
59 }
60
62 MemBuffer& operator=(MemBuffer&& other) noexcept
63 {
64 std::swap(dat, other.dat);
65 std::swap(sz , other.sz);
66 return *this;
67 }
68
72 {
73 my_free(dat);
74 }
75
79 [[nodiscard]] const T* data() const { return dat; }
80 [[nodiscard]] T* data() { return dat; }
81
82 [[nodiscard]] T* begin() { return data(); }
83 [[nodiscard]] const T* begin() const { return data(); }
84 [[nodiscard]] T* end() { return data() + size(); }
85 [[nodiscard]] const T* end() const { return data() + size(); }
86
89 [[nodiscard]] const T& operator[](size_t i) const
90 {
91 assert(i < sz);
92 return dat[i];
93 }
94 [[nodiscard]] T& operator[](size_t i)
95 {
96 assert(i < sz);
97 return dat[i];
98 }
99
100 [[nodiscard]] bool empty() const { return sz == 0; }
101 [[nodiscard]] size_t size() const { return sz; }
102
103 [[nodiscard]] T& front()
104 {
105 assert(!empty());
106 return dat[0];
107 }
108 [[nodiscard]] const T& front() const
109 {
110 assert(!empty());
111 return dat[0];
112 }
113 [[nodiscard]] T& back()
114 {
115 assert(!empty());
116 return dat[sz - 1];
117 }
118 [[nodiscard]] const T& back() const
119 {
120 assert(!empty());
121 return dat[sz - 1];
122 }
123
124 [[nodiscard]] operator std::span< T>() { return {data(), size()}; }
125 [[nodiscard]] operator std::span<const T>() const { return {data(), size()}; }
126
127 [[nodiscard]] std::span<const T> first(size_t n) const
128 {
129 assert(n <= sz);
130 return std::span{*this}.first(n);
131 }
132 [[nodiscard]] std::span<T> first(size_t n)
133 {
134 assert(n <= sz);
135 return std::span{*this}.first(n);
136 }
137 [[nodiscard]] std::span<const T> subspan(size_t offset, size_t n = std::dynamic_extent) const
138 {
139 assert(offset <= sz);
140 assert(n == std::dynamic_extent || (offset + n <= sz));
141 return std::span{*this}.subspan(offset, n);
142 }
143 [[nodiscard]] std::span<T> subspan(size_t offset, size_t n = std::dynamic_extent)
144 {
145 assert(offset <= sz);
146 assert(n == std::dynamic_extent || (offset + n <= sz));
147 return std::span{*this}.subspan(offset, n);
148 }
149
156 void resize(size_t size)
157 {
158 if (size) {
159 dat = static_cast<T*>(my_realloc(dat, size * sizeof(T)));
160 sz = size;
161 } else {
162 clear();
163 }
164 }
165
168 void clear()
169 {
170 my_free(dat);
171 dat = nullptr;
172 sz = 0;
173 }
174
175private:
176 // If the requested alignment is less or equally strict than the
177 // guaranteed alignment by the standard malloc()-like functions
178 // we use those. Otherwise we use platform specific functions to
179 // request aligned memory.
180 // A valid alternative would be to always use the platform specific
181 // functions. The only disadvantage is that we cannot use realloc()
182 // in that case (there are no, not even platform specific, functions
183 // to realloc memory with bigger than default alignment).
184 static constexpr bool SIMPLE_MALLOC = ALIGNMENT <= alignof(std::max_align_t);
185
186 [[nodiscard]] static void* my_malloc(size_t bytes)
187 {
188 if constexpr (SIMPLE_MALLOC) {
189 void* result = malloc(bytes);
190 if (!result && bytes) throw std::bad_alloc();
191 return result;
192 } else {
193 // already throws bad_alloc in case of error
194 return MemoryOps::mallocAligned(ALIGNMENT, bytes);
195 }
196 }
197
198 static void my_free(void* p)
199 {
200 if constexpr (SIMPLE_MALLOC) {
201 free(p);
202 } else {
204 }
205 }
206
207 [[nodiscard]] void* my_realloc(void* old, size_t bytes)
208 {
209 if constexpr (SIMPLE_MALLOC) {
210 void* result = realloc(old, bytes);
211 if (!result && bytes) throw std::bad_alloc();
212 return result;
213 } else {
214 void* result = MemoryOps::mallocAligned(ALIGNMENT, bytes);
215 if (!result && bytes) throw std::bad_alloc();
217 return result;
218 }
219 }
220
221private:
222 T* dat;
223 size_t sz;
224};
225
226} // namespace openmsx
227
228#endif
This class manages the lifetime of a block of memory.
Definition MemBuffer.hh:32
~MemBuffer()
Free the memory buffer.
Definition MemBuffer.hh:71
MemBuffer()
Construct an empty MemBuffer, no memory is allocated.
Definition MemBuffer.hh:38
std::span< const T > first(size_t n) const
Definition MemBuffer.hh:127
std::span< const T > subspan(size_t offset, size_t n=std::dynamic_extent) const
Definition MemBuffer.hh:137
const T & front() const
Definition MemBuffer.hh:108
const T * begin() const
Definition MemBuffer.hh:83
void resize(size_t size)
Grow or shrink the memory block.
Definition MemBuffer.hh:156
MemBuffer(size_t size)
Construct a (uninitialized) memory buffer of given size.
Definition MemBuffer.hh:46
const T * end() const
Definition MemBuffer.hh:85
bool empty() const
Definition MemBuffer.hh:100
size_t size() const
Definition MemBuffer.hh:101
MemBuffer(MemBuffer &&other) noexcept
Move constructor.
Definition MemBuffer.hh:53
std::span< T > subspan(size_t offset, size_t n=std::dynamic_extent)
Definition MemBuffer.hh:143
std::span< T > first(size_t n)
Definition MemBuffer.hh:132
MemBuffer & operator=(MemBuffer &&other) noexcept
Move assignment.
Definition MemBuffer.hh:62
const T * data() const
Returns pointer to the start of the memory buffer.
Definition MemBuffer.hh:79
const T & operator[](size_t i) const
Access elements in the memory buffer.
Definition MemBuffer.hh:89
const T & back() const
Definition MemBuffer.hh:118
T & operator[](size_t i)
Definition MemBuffer.hh:94
void clear()
Free the allocated memory block and set the current size to 0.
Definition MemBuffer.hh:168
void * mallocAligned(size_t alignment, size_t size)
Definition MemoryOps.cc:86
void freeAligned(void *)
Definition MemoryOps.cc:116
This file implemented 3 utility functions:
Definition Autofire.cc:11