AuroraOpenALSoft/common/almalloc.h

245 lines
9.1 KiB
C
Raw Normal View History

#ifndef AL_MALLOC_H
#define AL_MALLOC_H
2019-01-11 16:07:25 +00:00
#include <algorithm>
2019-07-29 16:29:35 +00:00
#include <cstddef>
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
#include "pragmadefs.h"
[[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_malloc(size_t alignment, size_t size);
[[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_calloc(size_t alignment, size_t size);
2018-11-18 08:38:31 +00:00
void al_free(void *ptr) noexcept;
2018-11-18 08:38:31 +00:00
#define DISABLE_ALLOC() \
void *operator new(size_t) = delete; \
void *operator new[](size_t) = delete; \
void operator delete(void*) noexcept = delete; \
void operator delete[](void*) noexcept = delete;
2018-11-18 08:38:31 +00:00
#define DEF_NEWDEL(T) \
void *operator new(size_t size) \
{ \
void *ret = al_malloc(alignof(T), size); \
if(!ret) throw std::bad_alloc(); \
return ret; \
} \
void *operator new[](size_t size) { return operator new(size); } \
void operator delete(void *block) noexcept { al_free(block); } \
void operator delete[](void *block) noexcept { operator delete(block); }
#define DEF_PLACE_NEWDEL() \
void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
2019-09-11 10:59:53 +00:00
void operator delete(void *block, void*) noexcept { al_free(block); } \
void operator delete(void *block) noexcept { al_free(block); } \
void operator delete[](void *block, void*) noexcept { al_free(block); } \
void operator delete[](void *block) noexcept { al_free(block); }
2019-09-11 10:59:53 +00:00
2020-05-19 19:15:57 +00:00
enum FamCount : size_t { };
2019-09-11 10:59:53 +00:00
#define DEF_FAM_NEWDEL(T, FamMem) \
static constexpr size_t Sizeof(size_t count) noexcept \
{ \
return std::max<size_t>(sizeof(T), \
decltype(FamMem)::Sizeof(count, offsetof(T, FamMem))); \
} \
2019-09-11 10:59:53 +00:00
\
2020-05-19 19:15:57 +00:00
void *operator new(size_t /*size*/, FamCount count) \
2019-09-11 10:59:53 +00:00
{ \
2020-05-19 19:15:57 +00:00
if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
2019-09-11 10:59:53 +00:00
return ret; \
throw std::bad_alloc(); \
} \
void *operator new[](size_t /*size*/) = delete; \
void operator delete(void *block, FamCount) { al_free(block); } \
void operator delete(void *block) noexcept { al_free(block); } \
void operator delete[](void* /*block*/) = delete;
2019-09-11 10:59:53 +00:00
namespace al {
#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0
2019-09-11 10:22:10 +00:00
template<typename T, std::size_t alignment=alignof(T)>
struct allocator {
using value_type = T;
using reference = T&;
using const_reference = const T&;
using pointer = T*;
using const_pointer = const T*;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
2019-09-11 10:22:10 +00:00
using is_always_equal = std::true_type;
template<typename U>
struct rebind {
2019-09-11 10:22:10 +00:00
using other = allocator<U, (alignment<alignof(U))?alignof(U):alignment>;
};
allocator() noexcept = default;
template<typename U, std::size_t N>
constexpr allocator(const allocator<U,N>&) noexcept { }
[[gnu::assume_aligned(alignment), gnu::alloc_size(2)]] T *allocate(std::size_t n)
2019-09-11 10:22:10 +00:00
{
if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
2019-09-11 10:22:10 +00:00
if(auto p = static_cast<T*>(al_malloc(alignment, n*sizeof(T)))) return p;
throw std::bad_alloc();
}
2019-09-11 10:22:10 +00:00
void deallocate(T *p, std::size_t) noexcept { al_free(p); }
};
2019-09-11 14:32:14 +00:00
template<typename T, std::size_t N, typename U, std::size_t M>
bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
template<typename T, std::size_t N, typename U, std::size_t M>
bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
2018-12-20 19:46:40 +00:00
template<size_t alignment, typename T>
[[gnu::assume_aligned(alignment)]] inline T* assume_aligned(T *ptr) noexcept { return ptr; }
2018-12-20 19:46:40 +00:00
/* At least VS 2015 complains that 'ptr' is unused when the given type's
* destructor is trivial (a no-op). So disable that warning for this call.
*/
DIAGNOSTIC_PUSH
msc_pragma(warning(disable : 4100))
template<typename T>
inline void destroy_at(T *ptr) { ptr->~T(); }
DIAGNOSTIC_POP
template<typename T>
inline void destroy(T first, const T end)
{
while(first != end)
{
2019-06-21 16:25:09 +00:00
al::destroy_at(std::addressof(*first));
++first;
}
}
template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
inline T destroy_n(T first, N count)
{
if(count != 0)
{
do {
2019-06-21 16:25:09 +00:00
al::destroy_at(std::addressof(*first));
++first;
} while(--count);
}
return first;
}
template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
inline T uninitialized_default_construct_n(T first, N count)
{
using ValueT = typename std::iterator_traits<T>::value_type;
T current{first};
if(count != 0)
{
try {
do {
2020-03-24 00:18:11 +00:00
::new(static_cast<void*>(std::addressof(*current))) ValueT;
++current;
} while(--count);
}
catch(...) {
al::destroy(first, current);
throw;
}
}
return current;
}
/* A flexible array type. Used either standalone or at the end of a parent
* struct, with placement new, to have a run-time-sized array that's embedded
* with its size.
*/
template<typename T, size_t alignment=alignof(T)>
struct FlexArray {
2019-06-08 06:42:31 +00:00
using element_type = T;
2020-03-24 00:18:11 +00:00
using value_type = std::remove_cv_t<T>;
2019-06-08 06:42:31 +00:00
using index_type = size_t;
using difference_type = ptrdiff_t;
2019-06-08 06:42:31 +00:00
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
const index_type mSize;
union {
char mDummy;
alignas(alignment) element_type mArray[1];
};
2019-06-08 06:42:31 +00:00
static std::unique_ptr<FlexArray> Create(index_type count)
{
void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
2020-03-24 00:18:11 +00:00
return std::unique_ptr<FlexArray>{new(ptr) FlexArray{count}};
}
2019-06-08 06:42:31 +00:00
static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
2019-01-12 04:06:23 +00:00
{
return base +
2019-06-08 06:42:31 +00:00
std::max<index_type>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
2019-01-12 04:06:23 +00:00
}
2019-06-08 06:42:31 +00:00
FlexArray(index_type size) : mSize{size}
{ al::uninitialized_default_construct_n(mArray, mSize); }
~FlexArray() { al::destroy_n(mArray, mSize); }
FlexArray(const FlexArray&) = delete;
FlexArray& operator=(const FlexArray&) = delete;
2019-06-08 06:42:31 +00:00
index_type size() const noexcept { return mSize; }
2019-06-30 01:53:20 +00:00
bool empty() const noexcept { return mSize == 0; }
2019-06-08 06:42:31 +00:00
pointer data() noexcept { return mArray; }
const_pointer data() const noexcept { return mArray; }
2019-06-08 06:42:31 +00:00
reference operator[](index_type i) noexcept { return mArray[i]; }
const_reference operator[](index_type i) const noexcept { return mArray[i]; }
2019-06-08 06:42:31 +00:00
reference front() noexcept { return mArray[0]; }
const_reference front() const noexcept { return mArray[0]; }
2019-06-08 06:42:31 +00:00
reference back() noexcept { return mArray[mSize-1]; }
const_reference back() const noexcept { return mArray[mSize-1]; }
2019-06-08 06:42:31 +00:00
iterator begin() noexcept { return mArray; }
const_iterator begin() const noexcept { return mArray; }
const_iterator cbegin() const noexcept { return mArray; }
iterator end() noexcept { return mArray + mSize; }
const_iterator end() const noexcept { return mArray + mSize; }
const_iterator cend() const noexcept { return mArray + mSize; }
2019-06-08 06:42:31 +00:00
reverse_iterator rbegin() noexcept { return end(); }
const_reverse_iterator rbegin() const noexcept { return end(); }
const_reverse_iterator crbegin() const noexcept { return cend(); }
reverse_iterator rend() noexcept { return begin(); }
const_reverse_iterator rend() const noexcept { return begin(); }
const_reverse_iterator crend() const noexcept { return cbegin(); }
DEF_PLACE_NEWDEL()
};
#undef REQUIRES
} // namespace al
#endif /* AL_MALLOC_H */