#ifndef AL_MALLOC_H #define AL_MALLOC_H #include #include #include /* 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); } namespace al { template struct allocator : public std::allocator { using size_type = size_t; using pointer = T*; using const_pointer = const T*; template struct rebind { using other = allocator; }; pointer allocate(size_type n, const void* = nullptr) { if(n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); void *ret{al_malloc(alignment, n*sizeof(T))}; if(!ret) throw std::bad_alloc(); return static_cast(ret); } void deallocate(pointer p, size_type) { al_free(p); } allocator() : std::allocator() { } allocator(const allocator &a) : std::allocator(a) { } template allocator(const allocator &a) : std::allocator(a) { } }; template 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(__builtin_assume_aligned(ptr, alignment)); #elif defined(_MSC_VER) auto ptrval = reinterpret_cast(ptr); if((ptrval&(alignment-1)) != 0) __assume(0); return reinterpret_cast(ptrval); #else return ptr; #endif } /* std::make_unique was added with C++14, so until we rely on that, make our * own version. */ template std::unique_ptr make_unique(ArgsT&&...args) { return std::unique_ptr{new T{std::forward(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 struct FlexArray { const size_t mSize; alignas(alignment) T mArray[]; static constexpr size_t CalcSizeof(size_t count) noexcept { return std::max(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 *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 */