2#include <boost/container/vector.hpp>
3#include <boost/predef.h>
20#if defined(__linux__) || defined(__unix__) || defined(__unix) || defined(__APPLE__) \
21 || defined(__EMSCRIPTEN__)
22#define OSSIA_HAS_POSIX_MEMALIGN 1
24#define OSSIA_HAS_POSIX_MEMALIGN 0
30#if defined(__has_builtin)
31#if __has_builtin(__builtin_assume_aligned)
32#define OSSIA_HAS_ASSUME_ALIGNED 1
34#elif defined(__GNUC__)
35#define OSSIA_HAS_ASSUME_ALIGNED 1
37#if !defined(OSSIA_HAS_ASSUME_ALIGNED)
38#define OSSIA_HAS_ASSUME_ALIGNED 0
43#if defined(__has_cpp_attribute)
44#if __has_cpp_attribute(gnu::assume_aligned)
45#define OSSIA_ASSUME_ALIGNED_RETURN(N) [[gnu::assume_aligned(N)]]
48#if !defined(OSSIA_ASSUME_ALIGNED_RETURN)
49#define OSSIA_ASSUME_ALIGNED_RETURN(N)
65template <std::
size_t Align = pod_vector_alignment,
typename T>
68 static_assert(Align > 0 && (Align & (Align - 1)) == 0,
"Align must be a power of two");
69#if OSSIA_HAS_ASSUME_ALIGNED
70 return static_cast<T*
>(__builtin_assume_aligned(p, Align));
76#if defined(_MSC_VER) && defined(_DEBUG)
82 template <
typename... Args>
83 explicit pod_allocator(Args&&...) noexcept
87 pod_allocator() noexcept = default;
88 pod_allocator(const pod_allocator&) noexcept = default;
89 pod_allocator(pod_allocator&&) noexcept = default;
90 pod_allocator& operator=(const pod_allocator&) noexcept = default;
91 pod_allocator& operator=(pod_allocator&&) noexcept = default;
93 static inline T* allocate(std::
size_t num) noexcept {
return new T[num]; }
95 static inline void deallocate(T* p, std::size_t)
noexcept {
delete[] p; }
98 operator==(
const pod_allocator& lhs,
const pod_allocator& rhs)
noexcept
103 operator!=(
const pod_allocator& lhs,
const pod_allocator& rhs)
noexcept
113 using value_type = T;
115 pod_allocator() noexcept = default;
116 pod_allocator(const pod_allocator&) noexcept = default;
117 pod_allocator(pod_allocator&&) noexcept = default;
118 pod_allocator& operator=(const pod_allocator&) noexcept = default;
119 pod_allocator& operator=(pod_allocator&&) noexcept = default;
121 static inline T* allocate(std::
size_t num) noexcept
124 std::is_standard_layout_v<T> && std::is_trivial_v<T>,
125 "can only be used with POD types");
127 alignof(T) <=
alignof(std::max_align_t),
128 "type must not have specific alignment requirements");
130 return (T*)std::malloc(
sizeof(T) * num);
133 static inline void deallocate(T* p, std::size_t)
noexcept { std::free(p); }
135 friend inline bool operator==(pod_allocator lhs, pod_allocator rhs)
noexcept
139 friend inline bool operator!=(pod_allocator lhs, pod_allocator rhs)
noexcept
153template <
class T, std::
size_t Align>
162 using value_type = T;
164 static constexpr std::size_t alignment = Align;
165 static_assert(Align > 0 && (Align & (Align - 1)) == 0,
"Align must be a power of two");
172 static constexpr bool needs_aligned_alloc = Align >
alignof(std::max_align_t);
185 OSSIA_ASSUME_ALIGNED_RETURN(Align)
186 static inline T* allocate(std::size_t num)
noexcept
189 std::is_standard_layout_v<T> && std::is_trivial_v<T>,
190 "can only be used with POD types");
192 alignof(T) <=
alignof(std::max_align_t),
193 "type must not have specific alignment requirements");
195 const std::size_t bytes =
sizeof(T) * num;
198 if constexpr(needs_aligned_alloc)
201 p = ::_aligned_malloc(bytes, Align);
202#elif OSSIA_HAS_POSIX_MEMALIGN
204 static_assert(Align >=
sizeof(
void*));
205 if(::posix_memalign(&p, Align, bytes) != 0)
207#elif defined(__cpp_aligned_new)
208 p = ::operator
new(bytes, std::align_val_t(Align), std::nothrow);
212 static_assert(Align <= 255,
"the offset has to fit in one byte");
213 if(
void*
const root = std::malloc(bytes + Align))
215 const auto pb = std::uintptr_t(root);
218 const auto pptr = (pb + Align) & ~std::uintptr_t(Align - 1);
219 *((
unsigned char*)pptr - 1) = (
unsigned char)(pptr - pb);
226 p = std::malloc(bytes);
229 return ossia::assume_aligned<Align>(
static_cast<T*
>(p));
232 static inline void deallocate(T* p, std::size_t)
noexcept
234 if constexpr(needs_aligned_alloc)
238#elif OSSIA_HAS_POSIX_MEMALIGN
240#elif defined(__cpp_aligned_new)
241 ::operator
delete(p, std::align_val_t(Align), std::nothrow);
245 const auto count = *((
unsigned char*)p - 1);
246 std::free((
unsigned char*)p - count);
274 using other = pod_allocator_avx2<U>;
278 pod_allocator_avx2() noexcept = default;
281 pod_allocator_avx2(const pod_allocator_avx2<U>&) noexcept
287using pod_vector = boost::container::vector<T, pod_allocator_avx2<T>>;
289using int_vector = pod_vector<int>;
290using float_vector = pod_vector<float>;
291using double_vector = pod_vector<double>;
297 return ossia::assume_aligned<pod_vector_alignment>(v.data());
300[[nodiscard]]
inline const T*
aligned_data(
const pod_vector<T>& v)
noexcept
302 return ossia::assume_aligned<pod_vector_alignment>(v.data());
T * assume_aligned(T *p) noexcept
Tell the optimizer that p is aligned on Align bytes.
Definition pod_vector.hpp:66
constexpr std::size_t pod_vector_alignment
Alignment guaranteed by pod_allocator_avx2, and thus by ossia::pod_vector.
Definition pod_vector.hpp:55
T * aligned_data(pod_vector< T > &v) noexcept
v.data(), with the alignment guarantee made visible to the optimizer
Definition pod_vector.hpp:295
An allocator which guarantees that the memory is aligned on Align.
Definition pod_vector.hpp:155