#ifndef AL_MALLOC_H #define AL_MALLOC_H #include #include #include #include #include #include #include #include #include "pragmadefs.h" namespace gsl { template using owner = T; }; void al_free(gsl::owner ptr) noexcept; [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]] gsl::owner al_malloc(size_t alignment, size_t size); [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]] gsl::owner al_calloc(size_t alignment, size_t size); #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; #define DEF_PLACE_NEWDEL \ void *operator new(size_t) = delete; \ void *operator new[](size_t) = delete; \ void operator delete(gsl::owner block, void*) noexcept { al_free(block); } \ void operator delete(gsl::owner block) noexcept { al_free(block); } \ void operator delete[](gsl::owner block, void*) noexcept { al_free(block); } \ void operator delete[](gsl::owner block) noexcept { al_free(block); } enum FamCount : size_t { }; #define DEF_FAM_NEWDEL(T, FamMem) \ static constexpr size_t Sizeof(size_t count) noexcept \ { \ static_assert(&Sizeof == &T::Sizeof, \ "Incorrect container type specified"); \ return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \ sizeof(T)); \ } \ \ gsl::owner operator new(size_t /*size*/, FamCount count) \ { \ const auto alignment = std::align_val_t{alignof(T)}; \ return ::operator new[](T::Sizeof(count), alignment); \ } \ void operator delete(gsl::owner block, FamCount) noexcept \ { ::operator delete[](block, std::align_val_t{alignof(T)}); } \ void operator delete(gsl::owner block) noexcept \ { ::operator delete[](block, std::align_val_t{alignof(T)}); } \ void *operator new[](size_t /*size*/) = delete; \ void operator delete[](void* /*block*/) = delete; namespace al { template struct allocator { static constexpr auto Alignment = std::max(AlignV, alignof(T)); static constexpr auto AlignVal = std::align_val_t{Alignment}; 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; using is_always_equal = std::true_type; template struct rebind { using other = std::enable_if_t>; }; constexpr explicit allocator() noexcept = default; template constexpr explicit allocator(const allocator&) noexcept { static_assert(Alignment == allocator::Alignment); } gsl::owner allocate(std::size_t n) { if(n > std::numeric_limits::max()/sizeof(T)) throw std::bad_alloc(); return static_cast>(::operator new[](n*sizeof(T), AlignVal)); } void deallocate(gsl::owner p, std::size_t) noexcept { ::operator delete[](gsl::owner{p}, AlignVal); } }; template constexpr bool operator==(const allocator&, const allocator&) noexcept { return allocator::Alignment == allocator::Alignment; } template constexpr bool operator!=(const allocator&, const allocator&) noexcept { return allocator::Alignment != allocator::Alignment; } template constexpr T *to_address(T *p) noexcept { static_assert(!std::is_function::value, "Can't be a function type"); return p; } template constexpr auto to_address(const T &p) noexcept { return ::al::to_address(p.operator->()); } template constexpr T* construct_at(T *ptr, Args&& ...args) noexcept(std::is_nothrow_constructible_v) { /* NOLINTBEGIN(cppcoreguidelines-owning-memory) construct_at doesn't * necessarily handle the address from an owner, while placement new * expects to. */ return ::new(static_cast(ptr)) T{std::forward(args)...}; /* NOLINTEND(cppcoreguidelines-owning-memory) */ } } // namespace al #endif /* AL_MALLOC_H */