10 #include <type_traits>
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) \
32 static_assert(&operator new == &T::operator new, \
33 "Incorrect container type specified"); \
34 if(void *ret{al_malloc(alignof(T), size)}) \
36 throw std::bad_alloc(); \
38 void *operator new[](size_t size) { return operator new(size); } \
39 void operator delete(void *block) noexcept { al_free(block); } \
40 void operator delete[](void *block) noexcept { operator delete(block); }
42 #define DEF_PLACE_NEWDEL() \
43 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
44 void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
45 void operator delete(void *block, void*) noexcept { al_free(block); } \
46 void operator delete(void *block) noexcept { al_free(block); } \
47 void operator delete[](void *block, void*) noexcept { al_free(block); } \
48 void operator delete[](void *block) noexcept { al_free(block); }
50 enum FamCount : size_t { };
52 #define DEF_FAM_NEWDEL(T, FamMem) \
53 static constexpr size_t Sizeof(size_t count) noexcept \
55 static_assert(&Sizeof == &T::Sizeof, \
56 "Incorrect container type specified"); \
57 return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \
61 void *operator new(size_t /*size*/, FamCount count) \
63 if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
65 throw std::bad_alloc(); \
67 void *operator new[](size_t /*size*/) = delete; \
68 void operator delete(void *block, FamCount) { al_free(block); } \
69 void operator delete(void *block) noexcept { al_free(block); } \
70 void operator delete[](void* /*block*/) = delete;
75 template<typename T, std::size_t Align=alignof(T)>
77 static constexpr std::size_t alignment{std::max(Align, alignof(T))};
81 using const_reference = const T&;
83 using const_pointer = const T*;
84 using size_type = std::size_t;
85 using difference_type = std::ptrdiff_t;
86 using is_always_equal = std::true_type;
90 using other = allocator<U, Align>;
93 constexpr explicit allocator() noexcept = default;
94 template<typename U, std::size_t N>
95 constexpr explicit allocator(const allocator<U,N>&) noexcept { }
97 T *allocate(std::size_t n)
99 if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
100 if(auto p = al_malloc(alignment, n*sizeof(T))) return static_cast<T*>(p);
101 throw std::bad_alloc();
103 void deallocate(T *p, std::size_t) noexcept { al_free(p); }
105 template<typename T, std::size_t N, typename U, std::size_t M>
106 constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
107 template<typename T, std::size_t N, typename U, std::size_t M>
108 constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
112 constexpr T *to_address(T *p) noexcept
114 static_assert(!std::is_function<T>::value, "Can't be a function type");
119 constexpr auto to_address(const T &p) noexcept
120 { return to_address(p.operator->()); }
123 template<typename T, typename ...Args>
124 constexpr T* construct_at(T *ptr, Args&& ...args)
125 noexcept(std::is_nothrow_constructible<T, Args...>::value)
126 { return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...}; }
128 /* At least VS 2015 complains that 'ptr' is unused when the given type's
129 * destructor is trivial (a no-op). So disable that warning for this call.
132 msc_pragma(warning(disable : 4100))
134 constexpr std::enable_if_t<!std::is_array<T>::value>
135 destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
139 constexpr std::enable_if_t<std::is_array<T>::value>
140 destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<std::remove_all_extents_t<T>>::value)
142 for(auto &elem : *ptr)
143 al::destroy_at(std::addressof(elem));
147 constexpr void destroy(T first, T end) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
151 al::destroy_at(std::addressof(*first));
156 template<typename T, typename N>
157 constexpr std::enable_if_t<std::is_integral<N>::value,T>
158 destroy_n(T first, N count) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
163 al::destroy_at(std::addressof(*first));
171 template<typename T, typename N>
172 inline std::enable_if_t<std::is_integral<N>::value,
173 T> uninitialized_default_construct_n(T first, N count)
175 using ValueT = typename std::iterator_traits<T>::value_type;
181 ::new(static_cast<void*>(std::addressof(*current))) ValueT;
186 al::destroy(first, current);
194 /* Storage for flexible array data. This is trivially destructible if type T is
195 * trivially destructible.
197 template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
198 struct FlexArrayStorage {
202 alignas(alignment) T mArray[1];
205 static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
207 const size_t len{sizeof(T)*count};
208 return std::max(offsetof(FlexArrayStorage,mArray)+len, sizeof(FlexArrayStorage)) + base;
211 FlexArrayStorage(size_t size) : mSize{size}
212 { al::uninitialized_default_construct_n(mArray, mSize); }
213 ~FlexArrayStorage() = default;
215 FlexArrayStorage(const FlexArrayStorage&) = delete;
216 FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
219 template<typename T, size_t alignment>
220 struct FlexArrayStorage<T,alignment,false> {
224 alignas(alignment) T mArray[1];
227 static constexpr size_t Sizeof(size_t count, size_t base) noexcept
229 const size_t len{sizeof(T)*count};
230 return std::max(offsetof(FlexArrayStorage,mArray)+len, sizeof(FlexArrayStorage)) + base;
233 FlexArrayStorage(size_t size) : mSize{size}
234 { al::uninitialized_default_construct_n(mArray, mSize); }
235 ~FlexArrayStorage() { al::destroy_n(mArray, mSize); }
237 FlexArrayStorage(const FlexArrayStorage&) = delete;
238 FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
241 /* A flexible array type. Used either standalone or at the end of a parent
242 * struct, with placement new, to have a run-time-sized array that's embedded
245 template<typename T, size_t alignment=alignof(T)>
247 using element_type = T;
248 using value_type = std::remove_cv_t<T>;
249 using index_type = size_t;
250 using difference_type = ptrdiff_t;
253 using const_pointer = const T*;
254 using reference = T&;
255 using const_reference = const T&;
257 using iterator = pointer;
258 using const_iterator = const_pointer;
259 using reverse_iterator = std::reverse_iterator<iterator>;
260 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
262 using Storage_t_ = FlexArrayStorage<element_type,alignment>;
266 static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
267 { return Storage_t_::Sizeof(count, base); }
268 static std::unique_ptr<FlexArray> Create(index_type count)
270 void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
271 return std::unique_ptr<FlexArray>{al::construct_at(static_cast<FlexArray*>(ptr), count)};
274 FlexArray(index_type size) : mStore{size} { }
275 ~FlexArray() = default;
277 index_type size() const noexcept { return mStore.mSize; }
278 bool empty() const noexcept { return mStore.mSize == 0; }
280 pointer data() noexcept { return mStore.mArray; }
281 const_pointer data() const noexcept { return mStore.mArray; }
283 reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
284 const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
286 reference front() noexcept { return mStore.mArray[0]; }
287 const_reference front() const noexcept { return mStore.mArray[0]; }
289 reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
290 const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
292 iterator begin() noexcept { return mStore.mArray; }
293 const_iterator begin() const noexcept { return mStore.mArray; }
294 const_iterator cbegin() const noexcept { return mStore.mArray; }
295 iterator end() noexcept { return mStore.mArray + mStore.mSize; }
296 const_iterator end() const noexcept { return mStore.mArray + mStore.mSize; }
297 const_iterator cend() const noexcept { return mStore.mArray + mStore.mSize; }
299 reverse_iterator rbegin() noexcept { return end(); }
300 const_reverse_iterator rbegin() const noexcept { return end(); }
301 const_reverse_iterator crbegin() const noexcept { return cend(); }
302 reverse_iterator rend() noexcept { return begin(); }
303 const_reverse_iterator rend() const noexcept { return begin(); }
304 const_reverse_iterator crend() const noexcept { return cbegin(); }
311 #endif /* AL_MALLOC_H */