Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
aligned_buffer.hpp
Go to the documentation of this file.
1#pragma once
2
19#include "initialization.hpp"
20
21#include <algorithm>
22#include <complex>
23#include <cstddef>
24#include <cstdlib>
25#include <memory>
26#include <new>
27#include <type_traits>
28
29namespace uni20
30{
31namespace detail
32{
33
37template <typename T> struct aligned_deleter
38{
39 void operator()(T* p) const noexcept
40 {
41 if (!p) return;
42#if defined(_MSC_VER)
43 _aligned_free(p);
44#else
45 std::free(p);
46#endif
47 }
48};
49
53template <typename T> struct aligned_destructor_deleter
54{
55 std::size_t count;
56 explicit aligned_destructor_deleter(std::size_t n) noexcept : count(n) {}
57
58 void operator()(T* p) const noexcept
59 {
60 if (!p) return;
61 // invoke destructor on each element
62 for (std::size_t i = 0; i < count; ++i)
63 {
64 p[i].~T();
65 }
66#if defined(_MSC_VER)
67 _aligned_free(p);
68#else
69 std::free(p);
70#endif
71 }
72};
73
80inline void* allocate_raw(std::size_t bytes, std::size_t align)
81{
82 void* ptr = nullptr;
83#if defined(_MSC_VER)
84 ptr = _aligned_malloc(bytes, align);
85 if (!ptr) throw std::bad_alloc();
86#else
87 // posix_memalign only cares that:
88 // - align is pow-2 and ≥ sizeof(void*)
89 // - size can be any value
90 if (int err = posix_memalign(&ptr, align, bytes); err)
91 {
92 throw std::bad_alloc();
93 }
94#endif
95
96 return ptr;
97}
98
102template <typename T> using aligned_buf_t = std::unique_ptr<T[], aligned_deleter<T>>;
103
107template <typename T> using aligned_buf_with_dtor_t = std::unique_ptr<T[], aligned_destructor_deleter<T>>;
108
109} // namespace detail
110
120template <typename T> detail::aligned_buf_t<T> allocate_uninitialized_buffer(std::size_t N, std::size_t align = 64)
121{
122 if (N == 0) return detail::aligned_buf_t<T>{nullptr, detail::aligned_deleter<T>{}};
123 auto result = detail::aligned_buf_t<T>(static_cast<T*>(detail::allocate_raw(sizeof(T) * N, align)),
124 detail::aligned_deleter<T>{});
125 if constexpr (uninitialized_ok<T>)
126 {
127 detail::initialize_host_elements(result.get(), N, StorageInitialization::Uninitialized);
128 }
129 return result;
130}
131
142template <typename T> auto allocate_temporary_buffer(std::size_t N, std::size_t align = 64)
143{
144 if constexpr (uninitialized_ok<T>)
145 {
146 // raw memory, no ctors/dtors
147 return allocate_uninitialized_buffer<T>(N, align);
148 }
149 else
150 {
151 if (N == 0)
152 {
153 return detail::aligned_buf_with_dtor_t<T>{nullptr, detail::aligned_destructor_deleter<T>{0}};
154 }
155 // allocate raw
156 void* raw = detail::allocate_raw(sizeof(T) * N, align);
157 T* ptr = static_cast<T*>(raw);
158
159 // default-construct each element
160 for (std::size_t i = 0; i < N; ++i)
161 {
162 ::new (static_cast<void*>(ptr + i)) T();
163 }
164
165 // return with deleter that runs dtors then frees
166 return detail::aligned_buf_with_dtor_t<T>(ptr, detail::aligned_destructor_deleter<T>{N});
167 }
168}
169
179template <typename T> auto allocate_temporary_buffer_uninitialized(std::size_t N, std::size_t align = 64)
180{
181 if constexpr (uninitialized_ok<T>)
182 {
183 // trivially‐copyable → raw storage, no dtors
184 return allocate_uninitialized_buffer<T>(N, align);
185 }
186 else
187 {
188 if (N == 0)
189 {
190 return detail::aligned_buf_with_dtor_t<T>{nullptr, detail::aligned_destructor_deleter<T>{0}};
191 }
192 void* raw = detail::allocate_raw(sizeof(T) * N, align);
193 T* ptr = static_cast<T*>(raw);
194 // *** no placement‐new here! user must do it. ***
195 return detail::aligned_buf_with_dtor_t<T>(ptr, detail::aligned_destructor_deleter<T>{N});
196 }
197}
198
199} // namespace uni20
Whether raw allocation may establish storage for T without construction.
Definition common/initialization.hpp:46
auto allocate_temporary_buffer_uninitialized(std::size_t N, std::size_t align=64)
Allocate a temporary buffer of T[N] that is always uninitialized.
Definition aligned_buffer.hpp:179
auto allocate_temporary_buffer(std::size_t N, std::size_t align=64)
Allocate a temporary buffer of T[N] aligned to align.
Definition aligned_buffer.hpp:142
detail::aligned_buf_t< T > allocate_uninitialized_buffer(std::size_t N, std::size_t align=64)
Allocate raw, aligned storage for T[N] without running constructors or destructors.
Definition aligned_buffer.hpp:120
Definition data_table.cpp:8
Definition async/async.hpp:26
std::size_t bytes
Definition presentation.cpp:18