#ifndef AL_MALLOC_H
|
|
#define AL_MALLOC_H
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <memory>
|
|
#include <limits>
|
|
#include <algorithm>
|
|
|
|
/* Minimum alignment required by posix_memalign. */
|
|
#define DEF_ALIGN sizeof(void*)
|
|
|
|
void *al_malloc(size_t alignment, size_t size);
|
|
void *al_calloc(size_t alignment, size_t size);
|
|
void al_free(void *ptr) noexcept;
|
|
|
|
size_t al_get_page_size(void) noexcept;
|
|
|
|
/**
|
|
* Returns non-0 if the allocation function has direct alignment handling.
|
|
* Otherwise, the standard malloc is used with an over-allocation and pointer
|
|
* offset strategy.
|
|
*/
|
|
int al_is_sane_alignment_allocator(void) noexcept;
|
|
|
|
#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 delete(void *block) noexcept { al_free(block); }
|
|
|
|
#define DEF_PLACE_NEWDEL() \
|
|
void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
|
|
void operator delete(void *block) noexcept { al_free(block); } \
|
|
void operator delete(void* /*block*/, void* /*ptr*/) noexcept { }
|
|
|
|
namespace al {
|
|
|
|
template<typename T, size_t alignment=DEF_ALIGN>
|
|
struct allocator : public std::allocator<T> {
|
|
using size_type = size_t;
|
|
using pointer = T*;
|
|
using const_pointer = const T*;
|
|
|
|
template<typename U>
|
|
struct rebind {
|
|
using other = allocator<U, alignment>;
|
|
};
|
|
|
|
pointer allocate(size_type n, const void* = nullptr)
|
|
{
|
|
if(n > std::numeric_limits<size_t>::max() / sizeof(T))
|
|
throw std::bad_alloc();
|
|
|
|
void *ret{al_malloc(alignment, n*sizeof(T))};
|
|
if(!ret) throw std::bad_alloc();
|
|
return static_cast<pointer>(ret);
|
|
}
|
|
|
|
void deallocate(pointer p, size_type)
|
|
{ al_free(p); }
|
|
|
|
allocator() : std::allocator<T>() { }
|
|
allocator(const allocator &a) : std::allocator<T>(a) { }
|
|
template<class U>
|
|
allocator(const allocator<U,alignment> &a) : std::allocator<T>(a)
|
|
{ }
|
|
};
|
|
|
|
template<size_t alignment, typename T>
|
|
inline T* assume_aligned(T *ptr) noexcept
|
|
{
|
|
static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2");
|
|
#ifdef __GNUC__
|
|
return static_cast<T*>(__builtin_assume_aligned(ptr, alignment));
|
|
#elif defined(_MSC_VER)
|
|
auto ptrval = reinterpret_cast<uintptr_t>(ptr);
|
|
if((ptrval&(alignment-1)) != 0) __assume(0);
|
|
return reinterpret_cast<T*>(ptrval);
|
|
#else
|
|
return ptr;
|
|
#endif
|
|
}
|
|
|
|
/* std::make_unique was added with C++14, so until we rely on that, make our
|
|
* own version.
|
|
*/
|
|
template<typename T, typename ...ArgsT>
|
|
std::unique_ptr<T> make_unique(ArgsT&&...args)
|
|
{ return std::unique_ptr<T>{new T{std::forward<ArgsT>(args)...}}; }
|
|
|
|
|
|
/* 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=DEF_ALIGN>
|
|
struct FlexArray {
|
|
const size_t mSize;
|
|
alignas(alignment) T mArray[];
|
|
|
|
static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
|
|
{
|
|
return base +
|
|
std::max<size_t>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
|
|
}
|
|
|
|
FlexArray(size_t size) : mSize{size}
|
|
{ new (mArray) T[mSize]; }
|
|
~FlexArray()
|
|
{
|
|
for(size_t i{0u};i < mSize;++i)
|
|
mArray[i].~T();
|
|
}
|
|
|
|
FlexArray(const FlexArray&) = delete;
|
|
FlexArray& operator=(const FlexArray&) = delete;
|
|
|
|
size_t size() const noexcept { return mSize; }
|
|
|
|
T *data() noexcept { return mArray; }
|
|
const T *data() const noexcept { return mArray; }
|
|
|
|
T& operator[](size_t i) noexcept { return mArray[i]; }
|
|
const T& operator[](size_t i) const noexcept { return mArray[i]; }
|
|
|
|
T& front() noexcept { return mArray[0]; }
|
|
const T& front() const noexcept { return mArray[0]; }
|
|
|
|
T& back() noexcept { return mArray[mSize-1]; }
|
|
const T& back() const noexcept { return mArray[mSize-1]; }
|
|
|
|
T *begin() noexcept { return mArray; }
|
|
const T *begin() const noexcept { return mArray; }
|
|
const T *cbegin() const noexcept { return mArray; }
|
|
T *end() noexcept { return mArray + mSize; }
|
|
const T *end() const noexcept { return mArray + mSize; }
|
|
const T *cend() const noexcept { return mArray + mSize; }
|
|
|
|
DEF_PLACE_NEWDEL()
|
|
};
|
|
|
|
} // namespace al
|
|
|
|
#endif /* AL_MALLOC_H */
|