openMSX
MemBuffer.hh
Go to the documentation of this file.
1 #ifndef MEMBUFFER_HH
2 #define MEMBUFFER_HH
3 
4 #include "MemoryOps.hh"
5 #include "alignof.hh"
6 #include <algorithm>
7 #include <new> // for bad_alloc
8 #include <cstdlib>
9 #include <cassert>
10 
11 namespace openmsx {
12 
13 // When SSE2 is enabled (some) buffers need to be 16-bytes aligned. If not
14 // then don't enforce stricter than default alignment.
15 #ifdef __SSE2__
16 static const size_t SSE2_ALIGNMENT = 16;
17 #else
18 static const size_t SSE2_ALIGNMENT = 0;
19 #endif
20 
21 
37 template<typename T, size_t ALIGNMENT = 0> class MemBuffer
38 {
39 public:
43  : dat(nullptr)
44 #ifdef DEBUG
45  , sz(0)
46 #endif
47  {
48  }
49 
52  explicit MemBuffer(size_t size)
53  : dat(static_cast<T*>(my_malloc(size * sizeof(T))))
54 #ifdef DEBUG
55  , sz(size)
56 #endif
57  {
58  }
59 
61  MemBuffer(MemBuffer&& other) noexcept
62  : dat(other.dat)
63 #ifdef DEBUG
64  , sz(other.sz)
65 #endif
66  {
67  other.dat = nullptr;
68  }
69 
71  MemBuffer& operator=(MemBuffer&& other) noexcept
72  {
73  std::swap(dat, other.dat);
74 #ifdef DEBUG
75  std::swap(sz , other.sz);
76 #endif
77  return *this;
78  }
79 
83  {
84  my_free(dat);
85  }
86 
90  const T* data() const { return dat; }
91  T* data() { return dat; }
92 
95  const T& operator[](size_t i) const
96  {
97 #ifdef DEBUG
98  assert(i < sz);
99 #endif
100  return dat[i];
101  }
102  T& operator[](size_t i)
103  {
104 #ifdef DEBUG
105  assert(i < sz);
106 #endif
107  return dat[i];
108  }
109 
112  bool empty() const { return !dat; }
113 
120  void resize(size_t size)
121  {
122  if (size) {
123  dat = static_cast<T*>(my_realloc(dat, size * sizeof(T)));
124 #ifdef DEBUG
125  sz = size;
126 #endif
127  } else {
128  clear();
129  }
130  }
131 
134  void clear()
135  {
136  my_free(dat);
137  dat = nullptr;
138 #ifdef DEBUG
139  sz = 0;
140 #endif
141  }
142 
145  void swap(MemBuffer& other) noexcept
146  {
147  std::swap(dat, other.dat);
148 #ifdef DEBUG
149  std::swap(sz , other.sz );
150 #endif
151  }
152 
153 private:
154  // If the requested alignment is less or equally strict than the
155  // guaranteed alignment by the standard malloc()-like functions
156  // we use those. Otherwise we use platform specific functions to
157  // request aligned memory.
158  // A valid alternative would be to always use the platform specific
159  // functions. The only disadvantage is that we cannot use realloc()
160  // in that case (there are no, not even platform specific, functions
161  // to realloc memory with bigger than default alignment).
162  static const bool SIMPLE_MALLOC = ALIGNMENT <= ALIGNOF(MAX_ALIGN_T);
163 
164  void* my_malloc(size_t bytes)
165  {
166  void* result;
167  if (SIMPLE_MALLOC) {
168  result = malloc(bytes);
169  if (!result && bytes) throw std::bad_alloc();
170  } else {
171  // already throws bad_alloc in case of error
172  result = MemoryOps::mallocAligned(ALIGNMENT, bytes);
173  }
174  return result;
175  }
176 
177  void my_free(void* p)
178  {
179  if (SIMPLE_MALLOC) {
180  free(p);
181  } else {
183  }
184  }
185 
186  void* my_realloc(void* old, size_t bytes)
187  {
188  void* result;
189  if (SIMPLE_MALLOC) {
190  result = realloc(old, bytes);
191  if (!result && bytes) throw std::bad_alloc();
192  } else {
193  result = MemoryOps::mallocAligned(ALIGNMENT, bytes);
194  if (!result && bytes) throw std::bad_alloc();
196  }
197  return result;
198  }
199 
200 private:
201  T* dat;
202 #ifdef DEBUG
203  size_t sz;
204 #endif
205 };
206 
207 } // namespace openmsx
208 
209 namespace std {
210  template<typename T>
212  {
213  l.swap(r);
214  }
215 }
216 
217 #endif
T & operator[](size_t i)
Definition: MemBuffer.hh:102
void freeAligned(void *)
Definition: MemoryOps.cc:323
STL namespace.
void swap(MemBuffer &other) noexcept
Swap the managed memory block of two MemBuffers.
Definition: MemBuffer.hh:145
MemBuffer()
Construct an empty MemBuffer, no memory is allocated.
Definition: MemBuffer.hh:42
void resize(size_t size)
Grow or shrink the memory block.
Definition: MemBuffer.hh:120
void clear()
Free the allocated memory block and set the current size to 0.
Definition: MemBuffer.hh:134
void * mallocAligned(size_t alignment, size_t size)
Definition: MemoryOps.cc:293
const T * data() const
Returns pointer to the start of the memory buffer.
Definition: MemBuffer.hh:90
MemBuffer(size_t size)
Construct a (uninitialized) memory buffer of given size.
Definition: MemBuffer.hh:52
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
MemBuffer(MemBuffer &&other) noexcept
Move constructor.
Definition: MemBuffer.hh:61
size_t size() const
MemBuffer & operator=(MemBuffer &&other) noexcept
Move assignment.
Definition: MemBuffer.hh:71
~MemBuffer()
Free the memory buffer.
Definition: MemBuffer.hh:82
const T & operator[](size_t i) const
Access elements in the memory buffer.
Definition: MemBuffer.hh:95
This class manages the lifetime of a block of memory.
Definition: MemBuffer.hh:37
bool empty() const
No memory allocated?
Definition: MemBuffer.hh:112
#define ALIGNOF(T)
Definition: alignof.hh:25