summaryrefslogtreecommitdiffstats
path: root/third_party/xsimd/include/xsimd/memory/xsimd_aligned_allocator.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/xsimd/include/xsimd/memory/xsimd_aligned_allocator.hpp')
-rw-r--r--third_party/xsimd/include/xsimd/memory/xsimd_aligned_allocator.hpp349
1 files changed, 349 insertions, 0 deletions
diff --git a/third_party/xsimd/include/xsimd/memory/xsimd_aligned_allocator.hpp b/third_party/xsimd/include/xsimd/memory/xsimd_aligned_allocator.hpp
new file mode 100644
index 0000000000..3918d68a70
--- /dev/null
+++ b/third_party/xsimd/include/xsimd/memory/xsimd_aligned_allocator.hpp
@@ -0,0 +1,349 @@
+/***************************************************************************
+ * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
+ * Martin Renou *
+ * Copyright (c) QuantStack *
+ * Copyright (c) Serge Guelton *
+ * *
+ * 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 <cstddef>
+#include <utility>
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <cstdlib>
+#endif
+
+#include <cassert>
+#include <memory>
+
+#include "../config/xsimd_arch.hpp"
+
+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>;
+ };
+
+ inline aligned_allocator() noexcept;
+ inline aligned_allocator(const aligned_allocator& rhs) noexcept;
+
+ template <class U>
+ inline aligned_allocator(const aligned_allocator<U, Align>& rhs) noexcept;
+
+ inline ~aligned_allocator();
+
+ inline pointer address(reference) noexcept;
+ inline const_pointer address(const_reference) const noexcept;
+
+ inline pointer allocate(size_type n, const void* hint = 0);
+ inline void deallocate(pointer p, size_type n);
+
+ inline size_type max_size() const noexcept;
+ inline size_type size_max() const noexcept;
+
+ template <class U, class... Args>
+ inline void construct(U* p, Args&&... args);
+
+ template <class U>
+ inline void destroy(U* p);
+ };
+
+ template <class T1, size_t Align1, class T2, size_t Align2>
+ inline 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>
+ inline bool operator!=(const aligned_allocator<T1, Align1>& lhs,
+ const aligned_allocator<T2, Align2>& rhs) noexcept;
+
+ inline void* aligned_malloc(size_t size, size_t alignment);
+ inline void aligned_free(void* ptr);
+
+ template <class T>
+ inline 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 defined(_CPPUNWIND) || defined(__cpp_exceptions)
+ if (res == nullptr)
+ throw std::bad_alloc();
+#endif
+ 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);
+ }
+ }
+
+ template <class T, class A = default_arch>
+ using default_allocator = typename std::conditional<A::requires_alignment(),
+ aligned_allocator<T, A::alignment()>,
+ std::allocator<T>>::type;
+}
+
+#endif