// license:GPL-2.0+ // copyright-holders:Couriersud /* * palloc.h * */ #ifndef PALLOC_H_ #define PALLOC_H_ #include "pconfig.h" #include "pstring.h" #include "ptypes.h" #include #include #include #include #include #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) #include #endif namespace plib { //============================================================ // Memory allocation //============================================================ #if (USE_ALIGNED_ALLOCATION) static inline void *paligned_alloc( size_t alignment, size_t size ) { #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) return _aligned_malloc(size, alignment); #elif defined(__APPLE__) void* p; if (::posix_memalign(&p, alignment, size) != 0) { p = nullptr; } return p; #else return aligned_alloc(alignment, size); #endif } static inline void pfree( void *ptr ) { // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) free(ptr); } #else static inline void *paligned_alloc( size_t alignment, size_t size ) { unused_var(alignment); return ::operator new(size); } static inline void pfree( void *ptr ) { ::operator delete(ptr); } #endif template /*inline */ C14CONSTEXPR T *assume_aligned_ptr(T *p) noexcept { static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)"); static_assert(is_pow2(ALIGN), "Alignment must be a power of 2"); //auto t = reinterpret_cast(p); //if (t & (ALIGN-1)) // printf("alignment error!"); #if (USE_ALIGNED_HINTS) return reinterpret_cast(__builtin_assume_aligned(p, ALIGN)); #else return p; #endif } template constexpr const T *assume_aligned_ptr(const T *p) noexcept { static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)"); static_assert(is_pow2(ALIGN), "Alignment must be a power of 2"); #if (USE_ALIGNED_HINTS) return reinterpret_cast(__builtin_assume_aligned(p, ALIGN)); #else return p; #endif } template inline T *pnew(Args&&... args) { auto *p = paligned_alloc(alignof(T), sizeof(T)); return new(p) T(std::forward(args)...); } template inline void pdelete(T *ptr) { ptr->~T(); pfree(ptr); } template inline T* pnew_array(const std::size_t num) { return new T[num](); } template inline void pdelete_array(T *ptr) { delete [] ptr; } template struct pdefault_deleter { constexpr pdefault_deleter() noexcept = default; template::value>::type> pdefault_deleter(const pdefault_deleter&) noexcept { } void operator()(T *p) const { pdelete(p); } }; template > class owned_ptr { public: owned_ptr() : m_ptr(nullptr), m_is_owned(true) { } template friend class owned_ptr; owned_ptr(SC *p, bool owned) noexcept : m_ptr(p), m_deleter(), m_is_owned(owned) { } owned_ptr(SC *p, bool owned, D deleter) noexcept : m_ptr(p), m_deleter(deleter), m_is_owned(owned) { } owned_ptr(const owned_ptr &r) = delete; owned_ptr & operator =(owned_ptr &r) = delete; template owned_ptr & operator =(owned_ptr &&r) { if (m_is_owned && (m_ptr != nullptr)) //delete m_ptr; m_deleter(m_ptr); m_is_owned = r.m_is_owned; m_ptr = r.m_ptr; m_deleter = r.m_deleter; r.m_is_owned = false; r.m_ptr = nullptr; return *this; } owned_ptr(owned_ptr &&r) noexcept { m_is_owned = r.m_is_owned; m_ptr = r.m_ptr; m_deleter = r.m_deleter; r.m_is_owned = false; r.m_ptr = nullptr; } owned_ptr &operator=(owned_ptr &&r) noexcept { if (m_is_owned && (m_ptr != nullptr)) //delete m_ptr; m_deleter(m_ptr); m_is_owned = r.m_is_owned; m_ptr = r.m_ptr; m_deleter = r.m_deleter; r.m_is_owned = false; r.m_ptr = nullptr; return *this; } template owned_ptr(owned_ptr &&r) noexcept { m_ptr = static_cast(r.get()); m_is_owned = r.is_owned(); m_deleter = r.m_deleter; r.release(); } ~owned_ptr() noexcept { if (m_is_owned && (m_ptr != nullptr)) { //delete m_ptr; m_deleter(m_ptr); } m_is_owned = false; m_ptr = nullptr; } SC * release() { SC *tmp = m_ptr; m_is_owned = false; m_ptr = nullptr; return tmp; } bool is_owned() const { return m_is_owned; } SC * operator ->() const { return m_ptr; } SC & operator *() const { return *m_ptr; } SC * get() const { return m_ptr; } private: SC *m_ptr; D m_deleter; bool m_is_owned; }; template using unique_ptr = std::unique_ptr>; template plib::unique_ptr make_unique(Args&&... args) { return plib::unique_ptr(pnew(std::forward(args)...)); } template static owned_ptr make_owned(Args&&... args) { owned_ptr a(pnew(std::forward(args)...), true); return std::move(a); } //============================================================ // Aligned allocator for use with containers //============================================================ template class aligned_allocator { public: using value_type = T; static constexpr const std::size_t align_size = ALIGN; static_assert(align_size >= alignof(T) && (align_size % alignof(T)) == 0, "ALIGN must be greater than alignof(T) and a multiple"); aligned_allocator() noexcept = default; ~aligned_allocator() noexcept = default; aligned_allocator(const aligned_allocator&) noexcept = default; aligned_allocator& operator=(const aligned_allocator&) noexcept = delete; aligned_allocator(aligned_allocator&&) noexcept = default; aligned_allocator& operator=(aligned_allocator&&) = delete; template aligned_allocator(const aligned_allocator& rhs) noexcept { unused_var(rhs); } template struct rebind { using other = aligned_allocator; }; T* allocate(std::size_t n) { return reinterpret_cast(paligned_alloc(ALIGN, sizeof(T) * n)); } void deallocate(T* p, std::size_t n) noexcept { unused_var(n); pfree(p); } template friend bool operator==(const aligned_allocator& lhs, const aligned_allocator& rhs) noexcept; template friend class aligned_allocator; }; template /*friend*/ inline bool operator==(const aligned_allocator& lhs, const aligned_allocator& rhs) noexcept { unused_var(lhs, rhs); return A1 == A2; } template /*friend*/ inline bool operator!=(const aligned_allocator& lhs, const aligned_allocator& rhs) noexcept { return !(lhs == rhs); } //============================================================ // traits to determine alignment size and stride size // from types supporting alignment //============================================================ PDEFINE_HAS_MEMBER(has_align, align_size); template struct align_traits { static constexpr const std::size_t align_size = alignof(std::max_align_t); static constexpr const std::size_t value_size = sizeof(typename T::value_type); #if 0 static constexpr const std::size_t stride_size = ((value_size % align_size) == 0 ? 1 //T is a multiple of align_size : ((align_size % value_size) != 0 ? align_size // align_size is not a multiple of T : align_size / value_size)); #else static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size; #endif }; template struct align_traits::value, void>::type> { static constexpr const std::size_t align_size = T::align_size; static constexpr const std::size_t value_size = sizeof(typename T::value_type); #if 0 static constexpr const std::size_t stride_size = ((value_size % align_size) == 0 ? 1 //T is a multiple of align_size : ((align_size % value_size) != 0 ? align_size // align_size is not a multiple of T : align_size / value_size)); #else static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size; #endif }; //============================================================ // Aligned vector //============================================================ // FIXME: needs a separate file template class aligned_vector : public std::vector> { public: using base = std::vector>; using reference = typename base::reference; using const_reference = typename base::const_reference; using pointer = typename base::pointer; using const_pointer = typename base::const_pointer; using size_type = typename base::size_type; using base::base; C14CONSTEXPR reference operator[](size_type i) noexcept { return assume_aligned_ptr(&(base::operator[](0)))[i]; } constexpr const_reference operator[](size_type i) const noexcept { return assume_aligned_ptr(&(base::operator[](0)))[i]; } pointer data() noexcept { return assume_aligned_ptr(base::data()); } const_pointer data() const noexcept { return assume_aligned_ptr(base::data()); } }; } // namespace plib #endif /* PALLOC_H_ */