Move a couple types to the source they're used in
[openal-soft.git] / common / almalloc.h
blobb844e5fc1f96ad3a10c4b006ebe1644264290945
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 reference = T&;
74 using const_reference = const T&;
75 using pointer = T*;
76 using const_pointer = const T*;
77 using size_type = std::size_t;
78 using difference_type = std::ptrdiff_t;
79 using is_always_equal = std::true_type;
81 template<typename U>
82 struct rebind {
83 using other = allocator<U, (alignment<alignof(U))?alignof(U):alignment>;
86 allocator() = default;
87 template<typename U, std::size_t N>
88 constexpr allocator(const allocator<U,N>&) noexcept { }
90 T *allocate(std::size_t n)
92 if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
93 if(auto p = static_cast<T*>(al_malloc(alignment, n*sizeof(T)))) return p;
94 throw std::bad_alloc();
96 void deallocate(T *p, std::size_t) noexcept { al_free(p); }
98 template<typename T, std::size_t N, typename U, std::size_t M>
99 bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
100 template<typename T, std::size_t N, typename U, std::size_t M>
101 bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
103 template<size_t alignment, typename T>
104 inline T* assume_aligned(T *ptr) noexcept
106 static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2");
107 #ifdef __GNUC__
108 return static_cast<T*>(__builtin_assume_aligned(ptr, alignment));
109 #elif defined(_MSC_VER)
110 auto ptrval = reinterpret_cast<uintptr_t>(ptr);
111 if((ptrval&(alignment-1)) != 0) __assume(0);
112 return reinterpret_cast<T*>(ptrval);
113 #else
114 return ptr;
115 #endif
118 /* At least VS 2015 complains that 'ptr' is unused when the given type's
119 * destructor is trivial (a no-op). So disable that warning for this call.
121 DIAGNOSTIC_PUSH
122 MVSDIAGNOSTIC(warning(disable : 4100))
123 template<typename T>
124 inline void destroy_at(T *ptr) { ptr->~T(); }
125 DIAGNOSTIC_POP
127 template<typename T>
128 inline void destroy(T first, const T end)
130 while(first != end)
132 al::destroy_at(std::addressof(*first));
133 ++first;
137 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
138 inline T destroy_n(T first, N count)
140 if(count != 0)
142 do {
143 al::destroy_at(std::addressof(*first));
144 ++first;
145 } while(--count);
147 return first;
151 template<typename T>
152 inline void uninitialized_default_construct(T first, const T last)
154 using ValueT = typename std::iterator_traits<T>::value_type;
155 T current{first};
156 try {
157 while(current != last)
159 ::new (static_cast<void*>(std::addressof(*current))) ValueT;
160 ++current;
163 catch(...) {
164 destroy(first, current);
165 throw;
169 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
170 inline T uninitialized_default_construct_n(T first, N count)
172 using ValueT = typename std::iterator_traits<T>::value_type;
173 T current{first};
174 if(count != 0)
176 try {
177 do {
178 ::new (static_cast<void*>(std::addressof(*current))) ValueT;
179 ++current;
180 } while(--count);
182 catch(...) {
183 destroy(first, current);
184 throw;
187 return current;
191 template<typename T0, typename T1>
192 inline T1 uninitialized_move(T0 first, const T0 last, const T1 output)
194 using ValueT = typename std::iterator_traits<T1>::value_type;
195 T1 current{output};
196 try {
197 while(first != last)
199 ::new (static_cast<void*>(std::addressof(*current))) ValueT{std::move(*first)};
200 ++current;
201 ++first;
204 catch(...) {
205 destroy(output, current);
206 throw;
208 return current;
211 template<typename T0, typename N, typename T1, REQUIRES(std::is_integral<N>::value)>
212 inline T1 uninitialized_move_n(T0 first, N count, const T1 output)
214 using ValueT = typename std::iterator_traits<T1>::value_type;
215 T1 current{output};
216 if(count != 0)
218 try {
219 do {
220 ::new (static_cast<void*>(std::addressof(*current))) ValueT{std::move(*first)};
221 ++current;
222 ++first;
223 } while(--count);
225 catch(...) {
226 destroy(output, current);
227 throw;
230 return current;
234 /* std::make_unique was added with C++14, so until we rely on that, make our
235 * own version.
237 template<typename T, typename ...ArgsT>
238 std::unique_ptr<T> make_unique(ArgsT&&...args)
239 { return std::unique_ptr<T>{new T{std::forward<ArgsT>(args)...}}; }
242 /* A flexible array type. Used either standalone or at the end of a parent
243 * struct, with placement new, to have a run-time-sized array that's embedded
244 * with its size.
246 template<typename T, size_t alignment=alignof(T)>
247 struct FlexArray {
248 using element_type = T;
249 using value_type = typename std::remove_cv<T>::type;
250 using index_type = size_t;
251 using difference_type = ptrdiff_t;
253 using pointer = T*;
254 using const_pointer = const T*;
255 using reference = T&;
256 using const_reference = const T&;
258 using iterator = pointer;
259 using const_iterator = const_pointer;
260 using reverse_iterator = std::reverse_iterator<iterator>;
261 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
264 const index_type mSize;
265 DIAGNOSTIC_PUSH
266 GNUDIAGNOSTIC("GCC diagnostic ignored \"-Wpedantic\"")
267 MVSDIAGNOSTIC(warning(disable : 4200))
268 alignas(alignment) element_type mArray[0];
269 DIAGNOSTIC_POP
271 static std::unique_ptr<FlexArray> Create(index_type count)
273 void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
274 return std::unique_ptr<FlexArray>{new (ptr) FlexArray{count}};
276 static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
278 return base +
279 std::max<index_type>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
282 FlexArray(index_type size) : mSize{size}
283 { uninitialized_default_construct_n(mArray, mSize); }
284 ~FlexArray() { destroy_n(mArray, mSize); }
286 FlexArray(const FlexArray&) = delete;
287 FlexArray& operator=(const FlexArray&) = delete;
289 index_type size() const noexcept { return mSize; }
290 bool empty() const noexcept { return mSize == 0; }
292 pointer data() noexcept { return mArray; }
293 const_pointer data() const noexcept { return mArray; }
295 reference operator[](index_type i) noexcept { return mArray[i]; }
296 const_reference operator[](index_type i) const noexcept { return mArray[i]; }
298 reference front() noexcept { return mArray[0]; }
299 const_reference front() const noexcept { return mArray[0]; }
301 reference back() noexcept { return mArray[mSize-1]; }
302 const_reference back() const noexcept { return mArray[mSize-1]; }
304 iterator begin() noexcept { return mArray; }
305 const_iterator begin() const noexcept { return mArray; }
306 const_iterator cbegin() const noexcept { return mArray; }
307 iterator end() noexcept { return mArray + mSize; }
308 const_iterator end() const noexcept { return mArray + mSize; }
309 const_iterator cend() const noexcept { return mArray + mSize; }
311 reverse_iterator rbegin() noexcept { return end(); }
312 const_reverse_iterator rbegin() const noexcept { return end(); }
313 const_reverse_iterator crbegin() const noexcept { return cend(); }
314 reverse_iterator rend() noexcept { return begin(); }
315 const_reverse_iterator rend() const noexcept { return begin(); }
316 const_reverse_iterator crend() const noexcept { return cbegin(); }
318 DEF_PLACE_NEWDEL()
321 #undef REQUIRES
323 } // namespace al
325 #endif /* AL_MALLOC_H */