Release 1.20.1
[openal-soft.git] / common / almalloc.h
blob1a1e25571ba0dfc7f2db0bff6ac66575eb797d4b
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_malloc(size_t alignment, size_t size);
17 void *al_calloc(size_t alignment, size_t size);
18 void al_free(void *ptr) noexcept;
21 #define DEF_NEWDEL(T) \
22 void *operator new(size_t size) \
23 { \
24 void *ret = al_malloc(alignof(T), size); \
25 if(!ret) throw std::bad_alloc(); \
26 return ret; \
27 } \
28 void operator delete(void *block) noexcept { al_free(block); }
30 #define DEF_PLACE_NEWDEL() \
31 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
32 void operator delete(void *block, void*) noexcept { al_free(block); } \
33 void operator delete(void *block) noexcept { al_free(block); }
35 struct FamCount { size_t mCount; };
37 #define DEF_FAM_NEWDEL(T, FamMem) \
38 static constexpr size_t Sizeof(size_t count) noexcept \
39 { return decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)); } \
41 void *operator new(size_t /*size*/, FamCount fam) \
42 { \
43 if(void *ret{al_malloc(alignof(T), T::Sizeof(fam.mCount))}) \
44 return ret; \
45 throw std::bad_alloc(); \
46 } \
47 void operator delete(void *block, FamCount) { al_free(block); } \
48 void operator delete(void *block) noexcept { al_free(block); }
51 namespace al {
53 #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0
55 template<typename T, std::size_t alignment=alignof(T)>
56 struct allocator {
57 using value_type = T;
58 using reference = T&;
59 using const_reference = const T&;
60 using pointer = T*;
61 using const_pointer = const T*;
62 using size_type = std::size_t;
63 using difference_type = std::ptrdiff_t;
64 using is_always_equal = std::true_type;
66 template<typename U>
67 struct rebind {
68 using other = allocator<U, (alignment<alignof(U))?alignof(U):alignment>;
71 allocator() = default;
72 template<typename U, std::size_t N>
73 constexpr allocator(const allocator<U,N>&) noexcept { }
75 T *allocate(std::size_t n)
77 if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
78 if(auto p = static_cast<T*>(al_malloc(alignment, n*sizeof(T)))) return p;
79 throw std::bad_alloc();
81 void deallocate(T *p, std::size_t) noexcept { al_free(p); }
83 template<typename T, std::size_t N, typename U, std::size_t M>
84 bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
85 template<typename T, std::size_t N, typename U, std::size_t M>
86 bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
88 template<size_t alignment, typename T>
89 inline T* assume_aligned(T *ptr) noexcept
91 static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2");
92 #ifdef __GNUC__
93 return static_cast<T*>(__builtin_assume_aligned(ptr, alignment));
94 #elif defined(_MSC_VER)
95 auto ptrval = reinterpret_cast<uintptr_t>(ptr);
96 if((ptrval&(alignment-1)) != 0) __assume(0);
97 return reinterpret_cast<T*>(ptrval);
98 #else
99 return ptr;
100 #endif
103 /* At least VS 2015 complains that 'ptr' is unused when the given type's
104 * destructor is trivial (a no-op). So disable that warning for this call.
106 DIAGNOSTIC_PUSH
107 msc_pragma(warning(disable : 4100))
108 template<typename T>
109 inline void destroy_at(T *ptr) { ptr->~T(); }
110 DIAGNOSTIC_POP
112 template<typename T>
113 inline void destroy(T first, const T end)
115 while(first != end)
117 al::destroy_at(std::addressof(*first));
118 ++first;
122 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
123 inline T destroy_n(T first, N count)
125 if(count != 0)
127 do {
128 al::destroy_at(std::addressof(*first));
129 ++first;
130 } while(--count);
132 return first;
136 template<typename T>
137 inline void uninitialized_default_construct(T first, const T last)
139 using ValueT = typename std::iterator_traits<T>::value_type;
140 T current{first};
141 try {
142 while(current != last)
144 ::new (static_cast<void*>(std::addressof(*current))) ValueT;
145 ++current;
148 catch(...) {
149 al::destroy(first, current);
150 throw;
154 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
155 inline T uninitialized_default_construct_n(T first, N count)
157 using ValueT = typename std::iterator_traits<T>::value_type;
158 T current{first};
159 if(count != 0)
161 try {
162 do {
163 ::new (static_cast<void*>(std::addressof(*current))) ValueT;
164 ++current;
165 } while(--count);
167 catch(...) {
168 al::destroy(first, current);
169 throw;
172 return current;
176 template<typename T0, typename T1>
177 inline T1 uninitialized_move(T0 first, const T0 last, const T1 output)
179 using ValueT = typename std::iterator_traits<T1>::value_type;
180 T1 current{output};
181 try {
182 while(first != last)
184 ::new (static_cast<void*>(std::addressof(*current))) ValueT{std::move(*first)};
185 ++current;
186 ++first;
189 catch(...) {
190 al::destroy(output, current);
191 throw;
193 return current;
196 template<typename T0, typename N, typename T1, REQUIRES(std::is_integral<N>::value)>
197 inline T1 uninitialized_move_n(T0 first, N count, const T1 output)
199 using ValueT = typename std::iterator_traits<T1>::value_type;
200 T1 current{output};
201 if(count != 0)
203 try {
204 do {
205 ::new (static_cast<void*>(std::addressof(*current))) ValueT{std::move(*first)};
206 ++current;
207 ++first;
208 } while(--count);
210 catch(...) {
211 al::destroy(output, current);
212 throw;
215 return current;
219 /* std::make_unique was added with C++14, so until we rely on that, make our
220 * own version.
222 template<typename T, typename ...ArgsT>
223 std::unique_ptr<T> make_unique(ArgsT&&...args)
224 { return std::unique_ptr<T>{new T{std::forward<ArgsT>(args)...}}; }
227 /* A flexible array type. Used either standalone or at the end of a parent
228 * struct, with placement new, to have a run-time-sized array that's embedded
229 * with its size.
231 template<typename T, size_t alignment=alignof(T)>
232 struct FlexArray {
233 using element_type = T;
234 using value_type = typename std::remove_cv<T>::type;
235 using index_type = size_t;
236 using difference_type = ptrdiff_t;
238 using pointer = T*;
239 using const_pointer = const T*;
240 using reference = T&;
241 using const_reference = const T&;
243 using iterator = pointer;
244 using const_iterator = const_pointer;
245 using reverse_iterator = std::reverse_iterator<iterator>;
246 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
249 const index_type mSize;
250 DIAGNOSTIC_PUSH
251 std_pragma("GCC diagnostic ignored \"-Wpedantic\"")
252 msc_pragma(warning(disable : 4200))
253 alignas(alignment) element_type mArray[0];
254 DIAGNOSTIC_POP
256 static std::unique_ptr<FlexArray> Create(index_type count)
258 void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
259 return std::unique_ptr<FlexArray>{new (ptr) FlexArray{count}};
261 static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
263 return base +
264 std::max<index_type>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
267 FlexArray(index_type size) : mSize{size}
268 { al::uninitialized_default_construct_n(mArray, mSize); }
269 ~FlexArray() { al::destroy_n(mArray, mSize); }
271 FlexArray(const FlexArray&) = delete;
272 FlexArray& operator=(const FlexArray&) = delete;
274 index_type size() const noexcept { return mSize; }
275 bool empty() const noexcept { return mSize == 0; }
277 pointer data() noexcept { return mArray; }
278 const_pointer data() const noexcept { return mArray; }
280 reference operator[](index_type i) noexcept { return mArray[i]; }
281 const_reference operator[](index_type i) const noexcept { return mArray[i]; }
283 reference front() noexcept { return mArray[0]; }
284 const_reference front() const noexcept { return mArray[0]; }
286 reference back() noexcept { return mArray[mSize-1]; }
287 const_reference back() const noexcept { return mArray[mSize-1]; }
289 iterator begin() noexcept { return mArray; }
290 const_iterator begin() const noexcept { return mArray; }
291 const_iterator cbegin() const noexcept { return mArray; }
292 iterator end() noexcept { return mArray + mSize; }
293 const_iterator end() const noexcept { return mArray + mSize; }
294 const_iterator cend() const noexcept { return mArray + mSize; }
296 reverse_iterator rbegin() noexcept { return end(); }
297 const_reverse_iterator rbegin() const noexcept { return end(); }
298 const_reverse_iterator crbegin() const noexcept { return cend(); }
299 reverse_iterator rend() noexcept { return begin(); }
300 const_reverse_iterator rend() const noexcept { return begin(); }
301 const_reverse_iterator crend() const noexcept { return cbegin(); }
303 DEF_PLACE_NEWDEL()
306 #undef REQUIRES
308 } // namespace al
310 #endif /* AL_MALLOC_H */