PLaSK library

Loading...
Searching...
No Matches
memalloc.hpp
Go to the documentation of this file.
1/*
2 * This file is part of PLaSK (https://plask.app) by Photonics Group at TUL
3 * Copyright (c) 2022 Lodz University of Technology
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#ifndef PLASK__MEMALLOC_H
15#define PLASK__MEMALLOC_H
16
17#include <cstdlib>
18#include <memory>
19
20#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
21#include <malloc.h>
22#endif
23
24#include <utility>
25#include <limits>
26#include <new>
27
28 namespace plask {
29
30#if (defined(__GLIBC__) && ((__GLIBC__>=2 && __GLIBC_MINOR__ >= 8) || __GLIBC__>2) && defined(__LP64__)) || \
31 defined(__APPLE__) || defined(_WIN64) || (defined(__FreeBSD__) && !defined(__arm__) && !defined(__mips__))
32# define PLASK_MALLOC_ALIGNED 1
33#else
34# define PLASK_MALLOC_ALIGNED 0
35#endif
36
37
38#if !PLASK_MALLOC_ALIGNED && !defined(_MSC_VER)
39 namespace detail {
40
44 inline void* custom_aligned_malloc(std::size_t size)
45 {
46 void *original = std::malloc(size+16);
47 if (original == 0) return 0;
48 void *aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(original) & ~(size_t(15))) + 16);
49 *(reinterpret_cast<void**>(aligned) - 1) = original;
50 return aligned;
51 }
52
56 inline void custom_aligned_free(void *ptr)
57 {
58 if (ptr) std::free(*(reinterpret_cast<void**>(ptr) - 1));
59 }
60
64 inline void* custom_aligned_realloc(void* ptr, std::size_t size, std::size_t=0)
65 {
66 if (ptr == 0) return custom_aligned_malloc(size);
67 void *original = *(reinterpret_cast<void**>(ptr) - 1);
68 original = std::realloc(original,size+16);
69 if (original == 0) return 0;
70 void *aligned = reinterpret_cast<void*>((reinterpret_cast<size_t>(original) & ~(size_t(15))) + 16);
71 *(reinterpret_cast<void**>(aligned) - 1) = original;
72 return aligned;
73 }
74
75}
76#endif
77
83 inline void* aligned_malloc(std::size_t size)
84{
85 void *result;
86#if PLASK_MALLOC_ALIGNED
87 result = std::malloc(size);
88#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
89 result = _aligned_malloc(size, 16);
90#else
91 result = detail::custom_aligned_malloc(size);
92#endif
93 if(!result && size) throw std::bad_alloc();
94 return result;
95}
96
101 inline void aligned_free(void *ptr)
102{
103 if (!ptr) return;
104#if PLASK_MALLOC_ALIGNED
105 std::free(ptr);
106#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
107 _aligned_free(ptr);
108#else
109 detail::custom_aligned_free(ptr);
110#endif
111}
112
120 inline void* aligned_realloc(void *ptr, std::size_t new_size, std::size_t old_size=0)
121{
122 (void) old_size; // don't warn about unused old_size
123 void *result;
124#if PLASK_MALLOC_ALIGNED
125 result = std::realloc(ptr,new_size);
126#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
127 result = _aligned_realloc(ptr,new_size,16);
128#else
129 result = detail::custom_aligned_realloc(ptr,new_size,old_size);
130#endif
131 if (!result && new_size) throw std::bad_alloc();
132 return result;
133}
134
141 template <typename T>
142 inline T* aligned_malloc(std::size_t num=1) {
143 T* mem = reinterpret_cast<T*>(aligned_malloc(num * sizeof(T)));
144 return mem;
145}
146
152 template <typename T>
153 inline void aligned_free(T* ptr) {
154 aligned_free(reinterpret_cast<void*>(const_cast<typename std::remove_const<T>::type*>(ptr)));
155}
156
160 template <typename T>
161 struct aligned_deleter {
162 constexpr aligned_deleter() noexcept = default;
163 template<typename U, typename=typename std::enable_if<std::is_convertible<U*,T*>::value>::type>
164 aligned_deleter(const aligned_deleter<U>&) noexcept {}
165
166 void operator()(T* ptr) const {
167 aligned_free<T>(ptr);
168 }
169};
170
171 template< class T > struct aligned_deleter<T[]> {
172 void operator()(T* ptr) const {
173 aligned_free<T>(ptr);
174 }
175};
176
177 template <typename T>
178 using aligned_unique_ptr = std::unique_ptr<T, aligned_deleter<T>>;
179
186 template <typename T, typename... Args>
187 inline T* aligned_new(Args&&... args) {
188 T* mem = reinterpret_cast<T*>(aligned_malloc(sizeof(T)));
189 new(mem) T(std::forward<Args>(args)...);
190 return mem;
191}
192
198 template <typename T>
199 inline void aligned_delete(T* ptr) {
200 ptr->~T();
201 aligned_free(ptr);
202}
203
210 template <typename T, typename... Args>
211 inline T* aligned_new_array(std::size_t num, Args&&... args) {
212 T* mem = reinterpret_cast<T*>(aligned_malloc(num * sizeof(T)));
213 for (size_t i = 0; i != num; ++i) new(mem+i) T(std::forward<Args>(args)...);
214 return mem;
215}
216
223 template <typename T>
224 inline void aligned_delete_array(std::size_t num, T* ptr) {
225 while (num)
226 ptr[--num].~T();
227 aligned_free(ptr);
228}
229
233 template<class T>
234 struct aligned_allocator {
235
236 typedef std::size_t size_type;
237 typedef std::ptrdiff_t difference_type;
238 typedef T* pointer;
239 typedef const T* const_pointer;
240 typedef T& reference;
241 typedef const T& const_reference;
242 typedef T value_type;
243
244 template<class U>
245 struct rebind { typedef aligned_allocator<U> other; };
246
247 pointer address(reference value) const { return &value; }
248
249 const_pointer address(const_reference value) const { return &value; }
250
251 aligned_allocator() {}
252
253 aligned_allocator(const aligned_allocator&) {}
254
255 template<class U>
256 aligned_allocator(const aligned_allocator<U>&) {}
257
258 ~aligned_allocator(){}
259
260 size_type max_size() const { return (std::numeric_limits<size_type>::max)(); }
261
262 pointer allocate(size_type num) { return aligned_malloc<T>(num); }
263
264 void construct(pointer p, const T& value) { new(p) T(value); }
265
266 template<typename... Args>
267 void construct(pointer p, Args&&... args) { new(p) T(std::forward<Args>(args)...); }
268
269 void destroy(pointer p) { p->~T(); }
270
271 void deallocate(pointer p, size_type) { aligned_free(p); }
272
273 bool operator!=(const aligned_allocator<T>&) const { return false; }
274
275 bool operator==(const aligned_allocator<T>&) const { return true; }
276};
277
278
279
280} // namespace plask
281
282
283#endif // PLASK__MEMALLOC_H