%PDF- %PDF-
Direktori : /usr/include/xsimd/memory/ |
Current File : //usr/include/xsimd/memory/xsimd_aligned_allocator.hpp |
/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * * Martin Renou * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XSIMD_ALIGNED_ALLOCATOR_HPP #define XSIMD_ALIGNED_ALLOCATOR_HPP #include <algorithm> #include <memory> #include <cstddef> #include <stdlib.h> #include <cassert> #include "../config/xsimd_align.hpp" #if defined(XSIMD_ALLOCA) #if defined(__GNUC__) #include <alloca.h> #elif defined(_MSC_VER) #include <malloc.h> #endif #endif namespace xsimd { /** * @class aligned_allocator * @brief Allocator for aligned memory * * The aligned_allocator class template is an allocator that * performs memory allocation aligned by the specified value. * * @tparam T type of objects to allocate. * @tparam Align alignment in bytes. */ template <class T, size_t Align> class aligned_allocator { public: using value_type = T; using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using size_type = size_t; using difference_type = ptrdiff_t; static constexpr size_t alignment = Align; template <class U> struct rebind { using other = aligned_allocator<U, Align>; }; aligned_allocator() noexcept; aligned_allocator(const aligned_allocator& rhs) noexcept; template <class U> aligned_allocator(const aligned_allocator<U, Align>& rhs) noexcept; ~aligned_allocator(); pointer address(reference) noexcept; const_pointer address(const_reference) const noexcept; pointer allocate(size_type n, const void* hint = 0); void deallocate(pointer p, size_type n); size_type max_size() const noexcept; size_type size_max() const noexcept; template <class U, class... Args> void construct(U* p, Args&&... args); template <class U> void destroy(U* p); }; template <class T1, size_t Align1, class T2, size_t Align2> bool operator==(const aligned_allocator<T1, Align1>& lhs, const aligned_allocator<T2, Align2>& rhs) noexcept; template <class T1, size_t Align1, class T2, size_t Align2> bool operator!=(const aligned_allocator<T1, Align1>& lhs, const aligned_allocator<T2, Align2>& rhs) noexcept; void* aligned_malloc(size_t size, size_t alignment); void aligned_free(void* ptr); template <class T> size_t get_alignment_offset(const T* p, size_t size, size_t block_size); /************************************ * aligned_allocator implementation * ************************************/ /** * Default constructor. */ template <class T, size_t A> inline aligned_allocator<T, A>::aligned_allocator() noexcept { } /** * Copy constructor. */ template <class T, size_t A> inline aligned_allocator<T, A>::aligned_allocator(const aligned_allocator&) noexcept { } /** * Extended copy constructor. */ template <class T, size_t A> template <class U> inline aligned_allocator<T, A>::aligned_allocator(const aligned_allocator<U, A>&) noexcept { } /** * Destructor. */ template <class T, size_t A> inline aligned_allocator<T, A>::~aligned_allocator() { } /** * Returns the actual address of \c r even in presence of overloaded \c operator&. * @param r the object to acquire address of. * @return the actual address of \c r. */ template <class T, size_t A> inline auto aligned_allocator<T, A>::address(reference r) noexcept -> pointer { return &r; } /** * Returns the actual address of \c r even in presence of overloaded \c operator&. * @param r the object to acquire address of. * @return the actual address of \c r. */ template <class T, size_t A> inline auto aligned_allocator<T, A>::address(const_reference r) const noexcept -> const_pointer { return &r; } /** * Allocates <tt>n * sizeof(T)</tt> bytes of uninitialized memory, aligned by \c A. * The alignment may require some extra memory allocation. * @param n the number of objects to allocate storage for. * @param hint unused parameter provided for standard compliance. * @return a pointer to the first byte of a memory block suitably aligned and sufficient to * hold an array of \c n objects of type \c T. */ template <class T, size_t A> inline auto aligned_allocator<T, A>::allocate(size_type n, const void*) -> pointer { pointer res = reinterpret_cast<pointer>(aligned_malloc(sizeof(T) * n, A)); if (res == nullptr) throw std::bad_alloc(); return res; } /** * Deallocates the storage referenced by the pointer p, which must be a pointer obtained by * an earlier call to allocate(). The argument \c n must be equal to the first argument of the call * to allocate() that originally produced \c p; otherwise, the behavior is undefined. * @param p pointer obtained from allocate(). * @param n number of objects earlier passed to allocate(). */ template <class T, size_t A> inline void aligned_allocator<T, A>::deallocate(pointer p, size_type) { aligned_free(p); } /** * Returns the maximum theoretically possible value of \c n, for which the * call allocate(n, 0) could succeed. * @return the maximum supported allocated size. */ template <class T, size_t A> inline auto aligned_allocator<T, A>::max_size() const noexcept -> size_type { return size_type(-1) / sizeof(T); } /** * This method is deprecated, use max_size() instead */ template <class T, size_t A> inline auto aligned_allocator<T, A>::size_max() const noexcept -> size_type { return size_type(-1) / sizeof(T); } /** * Constructs an object of type \c T in allocated uninitialized memory * pointed to by \c p, using placement-new. * @param p pointer to allocated uninitialized memory. * @param args the constructor arguments to use. */ template <class T, size_t A> template <class U, class... Args> inline void aligned_allocator<T, A>::construct(U* p, Args&&... args) { new ((void*)p) U(std::forward<Args>(args)...); } /** * Calls the destructor of the object pointed to by \c p. * @param p pointer to the object that is going to be destroyed. */ template <class T, size_t A> template <class U> inline void aligned_allocator<T, A>::destroy(U* p) { p->~U(); } /** * @defgroup allocator_comparison Comparison operators */ /** * @ingroup allocator_comparison * Compares two aligned memory allocator for equality. Since allocators * are stateless, return \c true iff <tt>A1 == A2</tt>. * @param lhs aligned_allocator to compare. * @param rhs aligned_allocator to compare. * @return true if the allocators have the same alignment. */ template <class T1, size_t A1, class T2, size_t A2> inline bool operator==(const aligned_allocator<T1, A1>& lhs, const aligned_allocator<T2, A2>& rhs) noexcept { return lhs.alignment == rhs.alignment; } /** * @ingroup allocator_comparison * Compares two aligned memory allocator for inequality. Since allocators * are stateless, return \c true iff <tt>A1 != A2</tt>. * @param lhs aligned_allocator to compare. * @param rhs aligned_allocator to compare. * @return true if the allocators have different alignments. */ template <class T1, size_t A1, class T2, size_t A2> inline bool operator!=(const aligned_allocator<T1, A1>& lhs, const aligned_allocator<T2, A2>& rhs) noexcept { return !(lhs == rhs); } /**************************************** * aligned malloc / free implementation * ****************************************/ namespace detail { inline void* xaligned_malloc(size_t size, size_t alignment) { assert(((alignment & (alignment - 1)) == 0) && "alignment must be a power of two"); assert((alignment >= sizeof(void*)) && "alignment must be at least the size of a pointer"); void* res = nullptr; #ifdef _WIN32 res = _aligned_malloc(size, alignment); #else if(posix_memalign(&res, alignment, size) != 0) { res = nullptr; } #endif return res; } inline void xaligned_free(void* ptr) { #ifdef _WIN32 _aligned_free(ptr); #else free(ptr); #endif } } inline void* aligned_malloc(size_t size, size_t alignment) { return detail::xaligned_malloc(size, alignment); } inline void aligned_free(void* ptr) { detail::xaligned_free(ptr); } template <class T> inline size_t get_alignment_offset(const T* p, size_t size, size_t block_size) { // size_t block_size = simd_traits<T>::size; if (block_size == 1) { // The simd_block consists of exactly one scalar so that all // elements of the array // are "well" aligned. return 0; } else if (size_t(p) & (sizeof(T) - 1)) { // The array is not aligned to the size of a single element, so that // no element // of the array is well aligned return size; } else { size_t block_mask = block_size - 1; return std::min<size_t>( (block_size - ((size_t(p) / sizeof(T)) & block_mask)) & block_mask, size); } } } #endif