Skip to content

Commit 97ef34e

Browse files
committed
added px_mem
1 parent 8a0df27 commit 97ef34e

File tree

1 file changed

+302
-0
lines changed

1 file changed

+302
-0
lines changed

px_mem.h

+302
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/* -----------------------------------------------------------------------------
2+
Copyright (c) 2018 Jose L. Hidalgo (PpluX)
3+
4+
px_mem.h - Mem management functions
5+
Single header file to handle Mem references, Buffers, unique_ptr/array
6+
alike objects and so on. It offers safer objects to handle pointers to
7+
memory and a RAII implementation for dynamic allocated memory.
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy of
10+
this software and associated documentation files (the "Software"), to deal in
11+
the Software without restriction, including without limitation the rights to
12+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13+
the Software, and to permit persons to whom the Software is furnished to do so,
14+
subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in all
17+
copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25+
----------------------------------------------------------------------------- */
26+
27+
// USAGE
28+
//
29+
// In *ONE* C++ file you need to declare
30+
// #define PX_MEM_IMPLEMENTATION
31+
// before including the file that contains px_mem.h
32+
33+
34+
#ifndef PX_MEM
35+
#define PX_MEM 1
36+
37+
#include <cstddef>
38+
#include <cstdint>
39+
#include <memory> //> for std::align
40+
41+
#ifndef PX_MEM_ASSERT
42+
#include <cassert>
43+
#define PX_MEM_ASSERT(cnd, msg) assert((cnd) && msg)
44+
#endif
45+
46+
namespace px {
47+
48+
// Set this first, before anything else, the default implementation will
49+
// use a wrapper around malloc and free
50+
void SetMemoryFunctions(
51+
void*(*MemAlloc)(size_t size_bytes, size_t alignment),
52+
void (*MemFree)(void*));
53+
54+
// Function to adquire memory (with proper alignment)
55+
void *MemoryAlloc(size_t amount, size_t alignment);
56+
57+
// Function to release a previously adquired memory
58+
void MemoryFree(void *ptr);
59+
60+
// Class to handle references to array of objects in memory
61+
template<class T>
62+
class ConstMemRef {
63+
public:
64+
ConstMemRef() : ptr_(nullptr), count_(0) {}
65+
ConstMemRef(const T* ptr, size_t num) : ptr_(ptr), count_(num) {}
66+
ConstMemRef(const ConstMemRef &) = default;
67+
ConstMemRef& operator=(const ConstMemRef &) = default;
68+
constexpr ConstMemRef(ConstMemRef &&) = default;
69+
ConstMemRef& operator=(ConstMemRef &&) = default;
70+
71+
const T& operator[](size_t p) const { PX_MEM_ASSERT(p < count_, "Invalid access");return ptr_[p]; }
72+
size_t size() const { return count_; }
73+
size_t sizeInBytes() const { return count_*sizeof(T); }
74+
const T* get() const { return ptr_; }
75+
private:
76+
const T *ptr_;
77+
size_t count_;
78+
};
79+
80+
// Mem<T> similar to unique_ptr but with some restrictions to fully implement RAII and
81+
// avoid any new/delete
82+
template<class T>
83+
class Mem {
84+
public:
85+
Mem() {}
86+
~Mem() { reset(); }
87+
88+
Mem(Mem &&other) {
89+
ptr_ = other.ptr_;
90+
other.ptr_ = nullptr;
91+
}
92+
93+
Mem& operator=(Mem &&other) {
94+
reset();
95+
ptr_ = other.ptr_;
96+
other.ptr_ = nullptr;
97+
return *this;
98+
}
99+
100+
bool valid() const { return ptr_ != nullptr; }
101+
operator bool() const { return valid(); }
102+
103+
// instance an object of type T
104+
T* alloc() { reset(); ptr_ = new (MemoryAlloc(sizeof(T), alignof(T))) T(); return ptr_; }
105+
106+
// alloc for derived classes
107+
template<class D>
108+
D* alloc() {
109+
reset();
110+
D *result = new (MemoryAlloc(sizeof(D), alignof(T))) D();
111+
ptr_ = result;
112+
return result;
113+
}
114+
115+
void reset() {
116+
if (ptr_) {
117+
ptr_->~T();
118+
MemoryFree(ptr_);
119+
ptr_ = nullptr;
120+
}
121+
}
122+
123+
T* get() { return ptr_; }
124+
const T* get() const { return ptr_; }
125+
126+
T* operator->() { return ptr_; }
127+
const T* operator->() const { return ptr_; }
128+
T& operator*() { return *ptr_; }
129+
const T& operator*() const { return *ptr_; }
130+
131+
private:
132+
T *ptr_ = nullptr;
133+
};
134+
135+
136+
137+
template<class T>
138+
class Mem<T[]> {
139+
public:
140+
typedef T* iterator;
141+
typedef const T* const_iterator;
142+
143+
Mem() {}
144+
~Mem() { reset(); }
145+
146+
Mem(Mem &&other) {
147+
ptr_ = other.ptr_;
148+
size_ = other.size_;
149+
other.ptr_ = nullptr;
150+
other.size_ = 0;
151+
}
152+
153+
Mem& operator=(Mem &&other) {
154+
reset();
155+
ptr_ = other.ptr_;
156+
size_ = other.size_;
157+
other.ptr_ = nullptr;
158+
other.size_ = 0;
159+
return *this;
160+
}
161+
162+
bool valid() const { return ptr_ != nullptr; }
163+
operator bool() const { return valid(); }
164+
165+
T* alloc(size_t num) {
166+
reset();
167+
ptr_ = reinterpret_cast<T*>(MemoryAlloc(sizeof(T)*num, alignof(T)));
168+
size_ = num;
169+
for(size_t i = 0; i < size_; ++i) {
170+
new (&ptr_[i]) T();
171+
}
172+
return ptr_;
173+
}
174+
175+
void reset() {
176+
if (ptr_) {
177+
for(size_t i = 0; i < size_; ++i) {
178+
ptr_[i].~T();
179+
}
180+
MemoryFree(ptr_);
181+
ptr_ = nullptr;
182+
size_ = 0;
183+
}
184+
}
185+
186+
void copy(const T* begin, const T* end) {
187+
T *dst = alloc(((size_t)end-(size_t)begin)/sizeof(T));
188+
for(const T *p = begin; p != end; ++p, ++dst) {
189+
*dst = *p;
190+
}
191+
}
192+
193+
void copy(ConstMemRef<T> memref) {
194+
if (memref.size() == 0) {
195+
reset();
196+
} else {
197+
T *dst = alloc(memref.size());
198+
for(size_t i = 0; i < memref.size(); ++i) {
199+
dst[i] = memref[i];
200+
}
201+
}
202+
}
203+
204+
T& operator[](size_t i) {
205+
PX_MEM_ASSERT(i < size_, "Invalid Access");
206+
return ptr_[i];
207+
}
208+
209+
const T& operator[](size_t i) const {
210+
PX_MEM_ASSERT(i < size_, "Invalid Access");
211+
return ptr_[i];
212+
}
213+
214+
iterator begin() const {
215+
return ptr_;
216+
}
217+
iterator end() const {
218+
return ptr_+size_;
219+
}
220+
const_iterator cbegin() const {
221+
return ptr_;
222+
}
223+
const_iterator cend() const {
224+
return ptr_+size_;
225+
}
226+
227+
size_t size() const { return size_; }
228+
size_t sizeInBytes() const { return size_*sizeof(T); }
229+
230+
T* get() { return ptr_; }
231+
const T* get() const { return ptr_; }
232+
233+
operator ConstMemRef<T>() const { return ref(); }
234+
ConstMemRef<T> ref() const { return ConstMemRef<T>(ptr_, size()); }
235+
236+
private:
237+
T *ptr_ = nullptr;
238+
size_t size_ = 0;
239+
};
240+
241+
// minimal standard allocator that uses MemoryAlloc/MemoryFree functions
242+
template <class T>
243+
struct Allocator {
244+
typedef T value_type;
245+
Allocator() {}
246+
template <class U> Allocator(const Allocator<U>& other) {}
247+
T* allocate(std::size_t n) {
248+
return (T*)MemoryAlloc(sizeof(T)*n, alignof(T));
249+
}
250+
void deallocate(T* p, std::size_t n) {
251+
MemoryFree(p);
252+
}
253+
};
254+
template <class T, class U>
255+
bool operator==(const Allocator<T>&, const Allocator<U>&) { return false; }
256+
template <class T, class U>
257+
bool operator!=(const Allocator<T>&, const Allocator<U>&) { return true; }
258+
259+
#ifdef PX_MEM_IMPLEMENTATION
260+
namespace {
261+
void* _DefaultMemoryAlloc(size_t mem_size, size_t align) {
262+
size_t mem_plus_align = mem_size+align;
263+
void *raw_mem = std::malloc(mem_plus_align+sizeof(void*));
264+
void *ptr = ((char*)raw_mem)+sizeof(void*);
265+
void *result = std::align(align, mem_size, ptr , mem_plus_align);
266+
PX_MEM_ASSERT(result != nullptr, "Default Memory Alloc failed");
267+
((void**)result)[-1] = raw_mem;
268+
return result;
269+
}
270+
271+
void _DefaultMemoryFree(void *ptr) {
272+
void *raw_mem = ((void**)ptr)[-1];
273+
std::free(raw_mem);
274+
}
275+
}
276+
277+
static struct {
278+
void *(*alloc)(size_t, size_t ) = _DefaultMemoryAlloc;
279+
void (*free)(void*) = _DefaultMemoryFree;
280+
} GLOBAL_mem;
281+
282+
void *MemoryAlloc(size_t amount, size_t alignment) {
283+
return GLOBAL_mem.alloc(amount, alignment);
284+
}
285+
286+
void MemoryFree(void *ptr) {
287+
return GLOBAL_mem.free(ptr);
288+
}
289+
290+
void SetMemoryFunctions( void*(*MemAlloc)(size_t, size_t), void (*MemFree)(void*)) {
291+
if (!MemAlloc && !MemFree) {
292+
MemAlloc = _DefaultMemoryAlloc;
293+
MemFree = _DefaultMemoryFree;
294+
}
295+
GLOBAL_mem.alloc = MemAlloc;
296+
GLOBAL_mem.free = MemFree;
297+
}
298+
#endif
299+
300+
} // px
301+
302+
#endif

0 commit comments

Comments
 (0)