Make sure FX slots that aren't made active are disabled
[openal-soft.git] / common / almalloc.h
blob70a400c4fb7ed9bfe69f70b1cf922b879b86b23e
1 #ifndef AL_MALLOC_H
2 #define AL_MALLOC_H
4 #include <algorithm>
5 #include <cstddef>
6 #include <iterator>
7 #include <limits>
8 #include <memory>
9 #include <new>
10 #include <type_traits>
11 #include <utility>
13 #include "pragmadefs.h"
16 void al_free(void *ptr) noexcept;
17 [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
18 void *al_malloc(size_t alignment, size_t size);
19 [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
20 void *al_calloc(size_t alignment, size_t size);
23 #define DISABLE_ALLOC() \
24 void *operator new(size_t) = delete; \
25 void *operator new[](size_t) = delete; \
26 void operator delete(void*) noexcept = delete; \
27 void operator delete[](void*) noexcept = delete;
29 #define DEF_NEWDEL(T) \
30 void *operator new(size_t size) \
31 { \
32 void *ret = al_malloc(alignof(T), size); \
33 if(!ret) throw std::bad_alloc(); \
34 return ret; \
35 } \
36 void *operator new[](size_t size) { return operator new(size); } \
37 void operator delete(void *block) noexcept { al_free(block); } \
38 void operator delete[](void *block) noexcept { operator delete(block); }
40 #define DEF_PLACE_NEWDEL() \
41 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
42 void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
43 void operator delete(void *block, void*) noexcept { al_free(block); } \
44 void operator delete(void *block) noexcept { al_free(block); } \
45 void operator delete[](void *block, void*) noexcept { al_free(block); } \
46 void operator delete[](void *block) noexcept { al_free(block); }
48 enum FamCount : size_t { };
50 #define DEF_FAM_NEWDEL(T, FamMem) \
51 static constexpr size_t Sizeof(size_t count) noexcept \
52 { \
53 return std::max<size_t>(sizeof(T), \
54 decltype(FamMem)::Sizeof(count, offsetof(T, FamMem))); \
55 } \
57 void *operator new(size_t /*size*/, FamCount count) \
58 { \
59 if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
60 return ret; \
61 throw std::bad_alloc(); \
62 } \
63 void *operator new[](size_t /*size*/) = delete; \
64 void operator delete(void *block, FamCount) { al_free(block); } \
65 void operator delete(void *block) noexcept { al_free(block); } \
66 void operator delete[](void* /*block*/) = delete;
69 namespace al {
71 template<typename T, std::size_t alignment=alignof(T)>
72 struct allocator {
73 using value_type = T;
74 using reference = T&;
75 using const_reference = const T&;
76 using pointer = T*;
77 using const_pointer = const T*;
78 using size_type = std::size_t;
79 using difference_type = std::ptrdiff_t;
80 using is_always_equal = std::true_type;
82 template<typename U>
83 struct rebind {
84 using other = allocator<U, (alignment<alignof(U))?alignof(U):alignment>;
87 constexpr explicit allocator() noexcept = default;
88 template<typename U, std::size_t N>
89 constexpr explicit allocator(const allocator<U,N>&) noexcept { }
91 T *allocate(std::size_t n)
93 if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
94 if(auto p = al_malloc(alignment, n*sizeof(T))) return static_cast<T*>(p);
95 throw std::bad_alloc();
97 void deallocate(T *p, std::size_t) noexcept { al_free(p); }
99 template<typename T, std::size_t N, typename U, std::size_t M>
100 constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
101 template<typename T, std::size_t N, typename U, std::size_t M>
102 constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
104 template<size_t alignment, typename T>
105 [[gnu::assume_aligned(alignment)]] constexpr T* assume_aligned(T *ptr) noexcept { return ptr; }
108 template<typename T, typename ...Args>
109 constexpr T* construct_at(T *ptr, Args&& ...args)
110 noexcept(std::is_nothrow_constructible<T, Args...>::value)
111 { return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...}; }
113 /* At least VS 2015 complains that 'ptr' is unused when the given type's
114 * destructor is trivial (a no-op). So disable that warning for this call.
116 DIAGNOSTIC_PUSH
117 msc_pragma(warning(disable : 4100))
118 template<typename T>
119 constexpr std::enable_if_t<!std::is_array<T>::value>
120 destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
121 { ptr->~T(); }
122 DIAGNOSTIC_POP
123 template<typename T>
124 constexpr std::enable_if_t<std::is_array<T>::value>
125 destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<std::remove_all_extents_t<T>>::value)
127 for(auto &elem : *ptr)
128 al::destroy_at(std::addressof(elem));
131 template<typename T>
132 constexpr void destroy(T first, T end) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
134 while(first != end)
136 al::destroy_at(std::addressof(*first));
137 ++first;
141 template<typename T, typename N>
142 constexpr std::enable_if_t<std::is_integral<N>::value,T>
143 destroy_n(T first, N count) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
145 if(count != 0)
147 do {
148 al::destroy_at(std::addressof(*first));
149 ++first;
150 } while(--count);
152 return first;
156 template<typename T, typename N>
157 inline std::enable_if_t<std::is_integral<N>::value,
158 T> uninitialized_default_construct_n(T first, N count)
160 using ValueT = typename std::iterator_traits<T>::value_type;
161 T current{first};
162 if(count != 0)
164 try {
165 do {
166 ::new(static_cast<void*>(std::addressof(*current))) ValueT;
167 ++current;
168 } while(--count);
170 catch(...) {
171 al::destroy(first, current);
172 throw;
175 return current;
179 /* Storage for flexible array data. This is trivially destructible if type T is
180 * trivially destructible.
182 template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
183 struct FlexArrayStorage {
184 const size_t mSize;
185 union {
186 char mDummy;
187 alignas(alignment) T mArray[1];
190 static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
192 return std::max<size_t>(offsetof(FlexArrayStorage, mArray) + sizeof(T)*count,
193 sizeof(FlexArrayStorage)) + base;
196 FlexArrayStorage(size_t size) : mSize{size}
197 { al::uninitialized_default_construct_n(mArray, mSize); }
198 ~FlexArrayStorage() = default;
200 FlexArrayStorage(const FlexArrayStorage&) = delete;
201 FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
204 template<typename T, size_t alignment>
205 struct FlexArrayStorage<T,alignment,false> {
206 const size_t mSize;
207 union {
208 char mDummy;
209 alignas(alignment) T mArray[1];
212 static constexpr size_t Sizeof(size_t count, size_t base) noexcept
214 return std::max<size_t>(offsetof(FlexArrayStorage, mArray) + sizeof(T)*count,
215 sizeof(FlexArrayStorage)) + base;
218 FlexArrayStorage(size_t size) : mSize{size}
219 { al::uninitialized_default_construct_n(mArray, mSize); }
220 ~FlexArrayStorage() { al::destroy_n(mArray, mSize); }
222 FlexArrayStorage(const FlexArrayStorage&) = delete;
223 FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
226 /* A flexible array type. Used either standalone or at the end of a parent
227 * struct, with placement new, to have a run-time-sized array that's embedded
228 * with its size.
230 template<typename T, size_t alignment=alignof(T)>
231 struct FlexArray {
232 using element_type = T;
233 using value_type = std::remove_cv_t<T>;
234 using index_type = size_t;
235 using difference_type = ptrdiff_t;
237 using pointer = T*;
238 using const_pointer = const T*;
239 using reference = T&;
240 using const_reference = const T&;
242 using iterator = pointer;
243 using const_iterator = const_pointer;
244 using reverse_iterator = std::reverse_iterator<iterator>;
245 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
247 using Storage_t_ = FlexArrayStorage<element_type,alignment>;
249 Storage_t_ mStore;
251 static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
252 { return Storage_t_::Sizeof(count, base); }
253 static std::unique_ptr<FlexArray> Create(index_type count)
255 void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
256 return std::unique_ptr<FlexArray>{al::construct_at(static_cast<FlexArray*>(ptr), count)};
259 FlexArray(index_type size) : mStore{size} { }
260 ~FlexArray() = default;
262 index_type size() const noexcept { return mStore.mSize; }
263 bool empty() const noexcept { return mStore.mSize == 0; }
265 pointer data() noexcept { return mStore.mArray; }
266 const_pointer data() const noexcept { return mStore.mArray; }
268 reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
269 const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
271 reference front() noexcept { return mStore.mArray[0]; }
272 const_reference front() const noexcept { return mStore.mArray[0]; }
274 reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
275 const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
277 iterator begin() noexcept { return mStore.mArray; }
278 const_iterator begin() const noexcept { return mStore.mArray; }
279 const_iterator cbegin() const noexcept { return mStore.mArray; }
280 iterator end() noexcept { return mStore.mArray + mStore.mSize; }
281 const_iterator end() const noexcept { return mStore.mArray + mStore.mSize; }
282 const_iterator cend() const noexcept { return mStore.mArray + mStore.mSize; }
284 reverse_iterator rbegin() noexcept { return end(); }
285 const_reverse_iterator rbegin() const noexcept { return end(); }
286 const_reverse_iterator crbegin() const noexcept { return cend(); }
287 reverse_iterator rend() noexcept { return begin(); }
288 const_reverse_iterator rend() const noexcept { return begin(); }
289 const_reverse_iterator crend() const noexcept { return cbegin(); }
291 DEF_PLACE_NEWDEL()
294 } // namespace al
296 #endif /* AL_MALLOC_H */