Don't let a function end without a return
[openal-soft.git] / common / almalloc.h
blobe021337b8d75911fbfbc0d4ae5f5f94b59b056a3
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>
14 #ifdef _MSC_VER
15 #define DIAGNOSTIC_PUSH __pragma(warning(push))
16 #define GNUDIAGNOSTIC(x)
17 #define MVSDIAGNOSTIC(...) __pragma(__VA_ARGS__)
18 #define DIAGNOSTIC_POP __pragma(warning(pop))
19 #elif defined(__GNUC__) || defined(__clang__)
20 #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
21 #define GNUDIAGNOSTIC(x) _Pragma(x)
22 #define MVSDIAGNOSTIC(...)
23 #define DIAGNOSTIC_POP _Pragma("GCC diagnostic push")
24 #else
25 #define DIAGNOSTIC_PUSH
26 #define GNUDIAGNOSTIC(x)
27 #define MVSDIAGNOSTIC(...)
28 #define DIAGNOSTIC_POP
29 #endif
31 void *al_malloc(size_t alignment, size_t size);
32 void *al_calloc(size_t alignment, size_t size);
33 void al_free(void *ptr) noexcept;
36 #define DEF_NEWDEL(T) \
37 void *operator new(size_t size) \
38 { \
39 void *ret = al_malloc(alignof(T), size); \
40 if(!ret) throw std::bad_alloc(); \
41 return ret; \
42 } \
43 void operator delete(void *block) noexcept { al_free(block); }
45 #define DEF_PLACE_NEWDEL() \
46 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
47 void operator delete(void *block, void*) noexcept { al_free(block); } \
48 void operator delete(void *block) noexcept { al_free(block); }
50 struct FamCount { size_t mCount; };
52 #define DEF_FAM_NEWDEL(T, FamMem) \
53 static constexpr size_t Sizeof(size_t count) noexcept \
54 { return decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)); } \
56 void *operator new(size_t /*size*/, FamCount fam) \
57 { \
58 if(void *ret{al_malloc(alignof(T), T::Sizeof(fam.mCount))}) \
59 return ret; \
60 throw std::bad_alloc(); \
61 } \
62 void operator delete(void *block, FamCount) { al_free(block); } \
63 void operator delete(void *block) noexcept { al_free(block); }
66 namespace al {
68 #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0
70 template<typename T, std::size_t alignment=alignof(T)>
71 struct allocator {
72 using value_type = T;
73 using is_always_equal = std::true_type;
75 template<typename U>
76 struct rebind {
77 using other = allocator<U, (alignment<alignof(U))?alignof(U):alignment>;
80 allocator() = default;
81 template<typename U, std::size_t N>
82 constexpr allocator(const allocator<U,N>&) noexcept { }
84 T *allocate(std::size_t n)
86 if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
87 if(auto p = static_cast<T*>(al_malloc(alignment, n*sizeof(T)))) return p;
88 throw std::bad_alloc();
90 void deallocate(T *p, std::size_t) noexcept { al_free(p); }
92 template<typename T, std::size_t N, typename U, std::size_t M>
93 bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
94 template<typename T, std::size_t N, typename U, std::size_t M>
95 bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
97 template<size_t alignment, typename T>
98 inline T* assume_aligned(T *ptr) noexcept
100 static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2");
101 #ifdef __GNUC__
102 return static_cast<T*>(__builtin_assume_aligned(ptr, alignment));
103 #elif defined(_MSC_VER)
104 auto ptrval = reinterpret_cast<uintptr_t>(ptr);
105 if((ptrval&(alignment-1)) != 0) __assume(0);
106 return reinterpret_cast<T*>(ptrval);
107 #else
108 return ptr;
109 #endif
112 /* At least VS 2015 complains that 'ptr' is unused when the given type's
113 * destructor is trivial (a no-op). So disable that warning for this call.
115 DIAGNOSTIC_PUSH
116 MVSDIAGNOSTIC(warning(disable : 4100))
117 template<typename T>
118 inline void destroy_at(T *ptr) { ptr->~T(); }
119 DIAGNOSTIC_POP
121 template<typename T>
122 inline void destroy(T first, const T end)
124 while(first != end)
126 al::destroy_at(std::addressof(*first));
127 ++first;
131 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
132 inline T destroy_n(T first, N count)
134 if(count != 0)
136 do {
137 al::destroy_at(std::addressof(*first));
138 ++first;
139 } while(--count);
141 return first;
145 template<typename T>
146 inline void uninitialized_default_construct(T first, const T last)
148 using ValueT = typename std::iterator_traits<T>::value_type;
149 T current{first};
150 try {
151 while(current != last)
153 ::new (static_cast<void*>(std::addressof(*current))) ValueT;
154 ++current;
157 catch(...) {
158 destroy(first, current);
159 throw;
163 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
164 inline T uninitialized_default_construct_n(T first, N count)
166 using ValueT = typename std::iterator_traits<T>::value_type;
167 T current{first};
168 if(count != 0)
170 try {
171 do {
172 ::new (static_cast<void*>(std::addressof(*current))) ValueT;
173 ++current;
174 } while(--count);
176 catch(...) {
177 destroy(first, current);
178 throw;
181 return current;
185 template<typename T0, typename T1>
186 inline T1 uninitialized_move(T0 first, const T0 last, const T1 output)
188 using ValueT = typename std::iterator_traits<T1>::value_type;
189 T1 current{output};
190 try {
191 while(first != last)
193 ::new (static_cast<void*>(std::addressof(*current))) ValueT{std::move(*first)};
194 ++current;
195 ++first;
198 catch(...) {
199 destroy(output, current);
200 throw;
202 return current;
205 template<typename T0, typename N, typename T1, REQUIRES(std::is_integral<N>::value)>
206 inline T1 uninitialized_move_n(T0 first, N count, const T1 output)
208 using ValueT = typename std::iterator_traits<T1>::value_type;
209 T1 current{output};
210 if(count != 0)
212 try {
213 do {
214 ::new (static_cast<void*>(std::addressof(*current))) ValueT{std::move(*first)};
215 ++current;
216 ++first;
217 } while(--count);
219 catch(...) {
220 destroy(output, current);
221 throw;
224 return current;
228 /* std::make_unique was added with C++14, so until we rely on that, make our
229 * own version.
231 template<typename T, typename ...ArgsT>
232 std::unique_ptr<T> make_unique(ArgsT&&...args)
233 { return std::unique_ptr<T>{new T{std::forward<ArgsT>(args)...}}; }
236 /* A flexible array type. Used either standalone or at the end of a parent
237 * struct, with placement new, to have a run-time-sized array that's embedded
238 * with its size.
240 template<typename T, size_t alignment=alignof(T)>
241 struct FlexArray {
242 using element_type = T;
243 using value_type = typename std::remove_cv<T>::type;
244 using index_type = size_t;
245 using difference_type = ptrdiff_t;
247 using pointer = T*;
248 using const_pointer = const T*;
249 using reference = T&;
250 using const_reference = const T&;
252 using iterator = pointer;
253 using const_iterator = const_pointer;
254 using reverse_iterator = std::reverse_iterator<iterator>;
255 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
258 const index_type mSize;
259 DIAGNOSTIC_PUSH
260 GNUDIAGNOSTIC("GCC diagnostic ignored \"-Wpedantic\"")
261 MVSDIAGNOSTIC(warning(disable : 4200))
262 alignas(alignment) element_type mArray[0];
263 DIAGNOSTIC_POP
265 static std::unique_ptr<FlexArray> Create(index_type count)
267 void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
268 return std::unique_ptr<FlexArray>{new (ptr) FlexArray{count}};
270 static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
272 return base +
273 std::max<index_type>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
276 FlexArray(index_type size) : mSize{size}
277 { uninitialized_default_construct_n(mArray, mSize); }
278 ~FlexArray() { destroy_n(mArray, mSize); }
280 FlexArray(const FlexArray&) = delete;
281 FlexArray& operator=(const FlexArray&) = delete;
283 index_type size() const noexcept { return mSize; }
284 bool empty() const noexcept { return mSize == 0; }
286 pointer data() noexcept { return mArray; }
287 const_pointer data() const noexcept { return mArray; }
289 reference operator[](index_type i) noexcept { return mArray[i]; }
290 const_reference operator[](index_type i) const noexcept { return mArray[i]; }
292 reference front() noexcept { return mArray[0]; }
293 const_reference front() const noexcept { return mArray[0]; }
295 reference back() noexcept { return mArray[mSize-1]; }
296 const_reference back() const noexcept { return mArray[mSize-1]; }
298 iterator begin() noexcept { return mArray; }
299 const_iterator begin() const noexcept { return mArray; }
300 const_iterator cbegin() const noexcept { return mArray; }
301 iterator end() noexcept { return mArray + mSize; }
302 const_iterator end() const noexcept { return mArray + mSize; }
303 const_iterator cend() const noexcept { return mArray + mSize; }
305 reverse_iterator rbegin() noexcept { return end(); }
306 const_reverse_iterator rbegin() const noexcept { return end(); }
307 const_reverse_iterator crbegin() const noexcept { return cend(); }
308 reverse_iterator rend() noexcept { return begin(); }
309 const_reverse_iterator rend() const noexcept { return begin(); }
310 const_reverse_iterator crend() const noexcept { return cbegin(); }
312 DEF_PLACE_NEWDEL()
315 #undef REQUIRES
317 } // namespace al
319 #endif /* AL_MALLOC_H */