Remove deprecated, performance, and error event types
[openal-soft.git] / common / almalloc.h
blob0949efdcda5f827b7d7872d1b6e67aa8253495f4
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 [[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_malloc(size_t alignment, size_t size);
17 [[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_calloc(size_t alignment, size_t size);
18 void al_free(void *ptr) noexcept;
21 #define DISABLE_ALLOC() \
22 void *operator new(size_t) = delete; \
23 void *operator new[](size_t) = delete; \
24 void operator delete(void*) noexcept = delete; \
25 void operator delete[](void*) noexcept = delete;
27 #define DEF_NEWDEL(T) \
28 void *operator new(size_t size) \
29 { \
30 void *ret = al_malloc(alignof(T), size); \
31 if(!ret) throw std::bad_alloc(); \
32 return ret; \
33 } \
34 void *operator new[](size_t size) { return operator new(size); } \
35 void operator delete(void *block) noexcept { al_free(block); } \
36 void operator delete[](void *block) noexcept { operator delete(block); }
38 #define DEF_PLACE_NEWDEL() \
39 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
40 void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
41 void operator delete(void *block, void*) noexcept { al_free(block); } \
42 void operator delete(void *block) noexcept { al_free(block); } \
43 void operator delete[](void *block, void*) noexcept { al_free(block); } \
44 void operator delete[](void *block) noexcept { al_free(block); }
46 enum FamCount : size_t { };
48 #define DEF_FAM_NEWDEL(T, FamMem) \
49 static constexpr size_t Sizeof(size_t count) noexcept \
50 { \
51 return std::max<size_t>(sizeof(T), \
52 decltype(FamMem)::Sizeof(count, offsetof(T, FamMem))); \
53 } \
55 void *operator new(size_t /*size*/, FamCount count) \
56 { \
57 if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
58 return ret; \
59 throw std::bad_alloc(); \
60 } \
61 void *operator new[](size_t /*size*/) = delete; \
62 void operator delete(void *block, FamCount) { al_free(block); } \
63 void operator delete(void *block) noexcept { al_free(block); } \
64 void operator delete[](void* /*block*/) = delete;
67 namespace al {
69 #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0
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 allocator() noexcept = default;
88 template<typename U, std::size_t N>
89 constexpr allocator(const allocator<U,N>&) noexcept { }
91 [[gnu::assume_aligned(alignment), gnu::alloc_size(2)]] 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 = static_cast<T*>(al_malloc(alignment, n*sizeof(T)))) return 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 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 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)]] inline T* assume_aligned(T *ptr) noexcept { return ptr; }
107 /* At least VS 2015 complains that 'ptr' is unused when the given type's
108 * destructor is trivial (a no-op). So disable that warning for this call.
110 DIAGNOSTIC_PUSH
111 msc_pragma(warning(disable : 4100))
112 template<typename T>
113 inline void destroy_at(T *ptr) { ptr->~T(); }
114 DIAGNOSTIC_POP
116 template<typename T>
117 inline void destroy(T first, const T end)
119 while(first != end)
121 al::destroy_at(std::addressof(*first));
122 ++first;
126 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
127 inline T destroy_n(T first, N count)
129 if(count != 0)
131 do {
132 al::destroy_at(std::addressof(*first));
133 ++first;
134 } while(--count);
136 return first;
140 template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
141 inline T uninitialized_default_construct_n(T first, N count)
143 using ValueT = typename std::iterator_traits<T>::value_type;
144 T current{first};
145 if(count != 0)
147 try {
148 do {
149 ::new(static_cast<void*>(std::addressof(*current))) ValueT;
150 ++current;
151 } while(--count);
153 catch(...) {
154 al::destroy(first, current);
155 throw;
158 return current;
162 /* A flexible array type. Used either standalone or at the end of a parent
163 * struct, with placement new, to have a run-time-sized array that's embedded
164 * with its size.
166 template<typename T, size_t alignment=alignof(T)>
167 struct FlexArray {
168 using element_type = T;
169 using value_type = std::remove_cv_t<T>;
170 using index_type = size_t;
171 using difference_type = ptrdiff_t;
173 using pointer = T*;
174 using const_pointer = const T*;
175 using reference = T&;
176 using const_reference = const T&;
178 using iterator = pointer;
179 using const_iterator = const_pointer;
180 using reverse_iterator = std::reverse_iterator<iterator>;
181 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
184 const index_type mSize;
185 union {
186 char mDummy;
187 alignas(alignment) element_type mArray[1];
190 static std::unique_ptr<FlexArray> Create(index_type count)
192 void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
193 return std::unique_ptr<FlexArray>{new(ptr) FlexArray{count}};
195 static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
197 return base +
198 std::max<index_type>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
201 FlexArray(index_type size) : mSize{size}
202 { al::uninitialized_default_construct_n(mArray, mSize); }
203 ~FlexArray() { al::destroy_n(mArray, mSize); }
205 FlexArray(const FlexArray&) = delete;
206 FlexArray& operator=(const FlexArray&) = delete;
208 index_type size() const noexcept { return mSize; }
209 bool empty() const noexcept { return mSize == 0; }
211 pointer data() noexcept { return mArray; }
212 const_pointer data() const noexcept { return mArray; }
214 reference operator[](index_type i) noexcept { return mArray[i]; }
215 const_reference operator[](index_type i) const noexcept { return mArray[i]; }
217 reference front() noexcept { return mArray[0]; }
218 const_reference front() const noexcept { return mArray[0]; }
220 reference back() noexcept { return mArray[mSize-1]; }
221 const_reference back() const noexcept { return mArray[mSize-1]; }
223 iterator begin() noexcept { return mArray; }
224 const_iterator begin() const noexcept { return mArray; }
225 const_iterator cbegin() const noexcept { return mArray; }
226 iterator end() noexcept { return mArray + mSize; }
227 const_iterator end() const noexcept { return mArray + mSize; }
228 const_iterator cend() const noexcept { return mArray + mSize; }
230 reverse_iterator rbegin() noexcept { return end(); }
231 const_reverse_iterator rbegin() const noexcept { return end(); }
232 const_reverse_iterator crbegin() const noexcept { return cend(); }
233 reverse_iterator rend() noexcept { return begin(); }
234 const_reverse_iterator rend() const noexcept { return begin(); }
235 const_reverse_iterator crend() const noexcept { return cbegin(); }
237 DEF_PLACE_NEWDEL()
240 #undef REQUIRES
242 } // namespace al
244 #endif /* AL_MALLOC_H */