Add a flexible array template container
[openal-soft.git] / common / almalloc.h
bloba2abc20008de8d767df256531f27921a6186d6fe
1 #ifndef AL_MALLOC_H
2 #define AL_MALLOC_H
4 #include <stddef.h>
6 #include <memory>
7 #include <limits>
9 /* Minimum alignment required by posix_memalign. */
10 #define DEF_ALIGN sizeof(void*)
12 void *al_malloc(size_t alignment, size_t size);
13 void *al_calloc(size_t alignment, size_t size);
14 void al_free(void *ptr) noexcept;
16 size_t al_get_page_size(void) noexcept;
18 /**
19 * Returns non-0 if the allocation function has direct alignment handling.
20 * Otherwise, the standard malloc is used with an over-allocation and pointer
21 * offset strategy.
23 int al_is_sane_alignment_allocator(void) noexcept;
25 #define DEF_NEWDEL(T) \
26 void *operator new(size_t size) \
27 { \
28 void *ret = al_malloc(alignof(T), size); \
29 if(!ret) throw std::bad_alloc(); \
30 return ret; \
31 } \
32 void operator delete(void *block) noexcept { al_free(block); }
34 #define DEF_PLACE_NEWDEL() \
35 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
36 void operator delete(void *block) noexcept { al_free(block); }
38 namespace al {
40 template<typename T, size_t alignment=DEF_ALIGN>
41 struct allocator : public std::allocator<T> {
42 using size_type = size_t;
43 using pointer = T*;
44 using const_pointer = const T*;
46 template<typename U>
47 struct rebind {
48 using other = allocator<U, alignment>;
51 pointer allocate(size_type n, const void* = nullptr)
53 if(n > std::numeric_limits<size_t>::max() / sizeof(T))
54 throw std::bad_alloc();
56 void *ret{al_malloc(alignment, n*sizeof(T))};
57 if(!ret) throw std::bad_alloc();
58 return static_cast<pointer>(ret);
61 void deallocate(pointer p, size_type)
62 { al_free(p); }
64 allocator() : std::allocator<T>() { }
65 allocator(const allocator &a) : std::allocator<T>(a) { }
66 template<class U>
67 allocator(const allocator<U,alignment> &a) : std::allocator<T>(a)
68 { }
71 template<size_t alignment, typename T>
72 inline T* assume_aligned(T *ptr) noexcept
74 static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2");
75 #ifdef __GNUC__
76 return static_cast<T*>(__builtin_assume_aligned(ptr, alignment));
77 #elif defined(_MSC_VER)
78 auto ptrval = reinterpret_cast<uintptr_t>(ptr);
79 if((ptrval&(alignment-1)) != 0) __assume(0);
80 return reinterpret_cast<T*>(ptrval);
81 #else
82 return ptr;
83 #endif
86 /* std::make_unique was added with C++14, so until we rely on that, make our
87 * own version.
89 template<typename T, typename ...ArgsT>
90 std::unique_ptr<T> make_unique(ArgsT&&...args)
91 { return std::unique_ptr<T>{new T{std::forward<ArgsT>(args)...}}; }
94 /* A flexible array type. Used either standalone or at the end of a parent
95 * struct, with placement new, to have a run-time-sized array that's embedded
96 * with its size.
98 template<typename T,size_t alignment=DEF_ALIGN>
99 struct FlexArray {
100 const size_t mSize;
101 alignas(alignment) T mArray[];
103 static constexpr size_t CalcSizeof(size_t count) noexcept
104 { return std::max<size_t>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray)); }
106 FlexArray(size_t size) : mSize{size}
107 { new (mArray) T[mSize]; }
108 ~FlexArray()
110 for(size_t i{0u};i < mSize;++i)
111 mArray[i].~T();
114 FlexArray(const FlexArray&) = delete;
115 FlexArray& operator=(const FlexArray&) = delete;
117 size_t size() const noexcept { return mSize; }
119 T *data() noexcept { return mArray; }
120 const T *data() const noexcept { return mArray; }
122 T& operator[](size_t i) noexcept { return mArray[i]; }
123 const T& operator[](size_t i) const noexcept { return mArray[i]; }
125 T *begin() noexcept { return mArray; }
126 const T *begin() const noexcept { return mArray; }
127 const T *cbegin() const noexcept { return mArray; }
128 T *end() noexcept { return mArray + mSize; }
129 const T *end() const noexcept { return mArray + mSize; }
130 const T *cend() const noexcept { return mArray + mSize; }
132 DEF_PLACE_NEWDEL()
135 } // namespace al
137 #endif /* AL_MALLOC_H */