vecmem 1.30.0
Loading...
Searching...
No Matches
unique_ptr.hpp
1/*
2 * VecMem project, part of the ACTS project (R&D line)
3 *
4 * (c) 2021-2025 CERN for the benefit of the ACTS project
5 *
6 * Mozilla Public License Version 2.0
7 */
8
9#pragma once
10
11#include <algorithm>
12#include <cstddef>
13#include <memory>
14#include <new>
15#include <type_traits>
16
17#include "vecmem/memory/details/unique_alloc_deleter.hpp"
18#include "vecmem/memory/details/unique_obj_deleter.hpp"
19#include "vecmem/memory/memory_resource.hpp"
20#include "vecmem/vecmem_core_export.hpp"
21
22namespace vecmem {
23namespace details {
24
30template <typename T>
32 return reinterpret_cast<T>(0xf000U);
33}
34
35} // namespace details
36
53template <typename T>
54using unique_obj_ptr = std::unique_ptr<T, details::unique_obj_deleter<T>>;
55
71template <typename T>
72using unique_alloc_ptr = std::unique_ptr<T, details::unique_alloc_deleter<T>>;
73
93template <typename T, typename... Args>
94typename std::enable_if_t<!std::is_array_v<T>, unique_obj_ptr<T>>
95make_unique_obj(memory_resource& m, std::align_val_t alignment, Args&&... a) {
96 /*
97 * Calculate the size of the allocation and use the memory resource to
98 * perform an allocation of the requested size.
99 */
100 std::size_t s = sizeof(T);
101 std::size_t align =
102 std::max(static_cast<std::size_t>(alignment), alignof(T));
103 T* p = static_cast<T*>(m.allocate(s, align));
104
105 /*
106 * Perform a placement-new with forwarded arguments to construct the
107 * object.
108 */
109 new (p) T(std::forward<Args>(a)...);
110
111 /*
112 * Create a new unique_ptr, with its own deleter, and return it.
113 */
115}
116
134template <typename T, typename... Args>
135typename std::enable_if_t<!std::is_array_v<T>, unique_obj_ptr<T>>
136make_unique_obj(memory_resource& m, Args&&... a) {
137 return make_unique_obj<T>(m, std::align_val_t{alignof(T)},
138 std::forward<Args>(a)...);
139}
140
159template <typename T>
160typename std::enable_if_t<std::is_array_v<T> && std::extent_v<T> == 0,
161 unique_obj_ptr<T>>
162make_unique_obj(memory_resource& m, std::size_t n, std::align_val_t alignment) {
163 using pointer_t = typename unique_obj_ptr<T>::deleter_type::pointer_t;
164
165 // Handle the case with zero elements.
166 if (n == 0) {
167 return unique_obj_ptr<T>(details::get_nonexistent_pointer<pointer_t>());
168 }
169
170 /*
171 * Calculate the size of the allocation and use the memory resource to
172 * perform an allocation of the requested size.
173 */
174 std::size_t s = n * sizeof(std::remove_extent_t<T>);
175 std::size_t align = std::max(static_cast<std::size_t>(alignment),
176 alignof(std::remove_extent_t<T>));
177 pointer_t p = static_cast<pointer_t>(m.allocate(s, align));
178
179 /*
180 * Use placement-new to default-construct each of our elements.
181 */
182 for (std::size_t i = 0; i < n; ++i) {
183 new (&p[i]) std::remove_extent_t<T>();
184 }
185
186 /*
187 * Create a new unique_ptr, with its own deleter, and return it.
188 */
190}
191
209template <typename T>
210typename std::enable_if_t<std::is_array_v<T> && std::extent_v<T> == 0,
211 unique_obj_ptr<T>>
212make_unique_obj(memory_resource& m, std::size_t n) {
213 return make_unique_obj<T>(
214 m, n, std::align_val_t{alignof(std::remove_extent_t<T>)});
215}
216
232template <typename T>
234 std::align_val_t alignment) {
235 /*
236 * This method only works on non-array types and bounded array types.
237 */
238 static_assert(!(std::is_array_v<T> && std::extent_v<T> == 0),
239 "Allocation pointer type cannot be an unbounded array.");
240
241 /*
242 * Since we cannot (in general) construct objects in the memory we are
243 * about to allocate, we need to make sure that "bare", unallocated memory
244 * is semantically compatible with construction of the requested type.
245 */
246 static_assert(std::is_trivially_constructible_v<std::remove_extent_t<T>>,
247 "Allocation pointer type must be trivially constructible.");
248
249 using pointer_t =
250 std::conditional_t<std::is_array_v<T>, std::decay_t<T>, T*>;
251
252 /*
253 * Calculate the size of the allocation and use the memory resource to
254 * perform an allocation of the requested size.
255 */
256 std::size_t s = sizeof(T);
257 std::size_t align = std::max(static_cast<std::size_t>(alignment),
258 alignof(std::remove_extent_t<T>));
259 pointer_t p = static_cast<pointer_t>(m.allocate(s, align));
260
261 /*
262 * Create a new unique_ptr, with its own deleter, and return it.
263 */
264 return unique_alloc_ptr<T>(p,
266}
267
294template <typename T>
297 m, std::align_val_t{alignof(std::remove_extent_t<T>)});
298}
299
317template <typename T>
318unique_alloc_ptr<T> make_unique_alloc(memory_resource& m, std::size_t n,
319 std::align_val_t alignment) {
320 /*
321 * This overload only works for unbounded array types.
322 */
323 static_assert(std::is_array_v<T>,
324 "Allocation pointer type must be an array type.");
325 static_assert(std::extent_v<T> == 0,
326 "Allocation pointer type must be unbounded.");
327
328 /*
329 * Since we cannot (in general) construct objects in the memory we are
330 * about to allocate, we need to make sure that "bare", unallocated memory
331 * is semantically compatible with construction of the requested type.
332 */
333 static_assert(std::is_trivially_constructible_v<std::remove_extent_t<T>>,
334 "Allocation pointer type must be trivially constructible.");
335
336 using pointer_t =
337 std::conditional_t<std::is_array_v<T>, std::decay_t<T>, T*>;
338
339 // Handle the case with zero elements.
340 if (n == 0) {
341 return unique_alloc_ptr<T>(
342 details::get_nonexistent_pointer<pointer_t>());
343 }
344
345 /*
346 * Calculate the size of the allocation and use the memory resource to
347 * perform an allocation of the requested size.
348 */
349 std::size_t s = n * sizeof(std::remove_extent_t<T>);
350 std::size_t align = std::max(static_cast<std::size_t>(alignment),
351 alignof(std::remove_extent_t<T>));
352 pointer_t p = static_cast<pointer_t>(m.allocate(s, align));
353
354 /*
355 * Create a new unique_ptr, with its own deleter, and return it.
356 */
357 return unique_alloc_ptr<T>(p,
359}
360
388template <typename T>
389unique_alloc_ptr<T> make_unique_alloc(memory_resource& m, std::size_t n) {
391 m, n, std::align_val_t{alignof(std::remove_extent_t<T>)});
392}
393
432template <typename T, typename C>
433typename std::enable_if_t<!(std::is_array_v<T> && std::extent_v<T> == 0),
434 unique_alloc_ptr<T>>
435make_unique_alloc(memory_resource& m, const T* f, const C& c) {
436 /*
437 * This method only works on non-array types and bounded array types. This
438 * is enforced through SFINAE, so that a call with an unbounded array type,
439 * a count of 0 and an alignment is not ambiguous with this overload.
440 */
441
442 /*
443 * In this case, we are going to immediately copy some (hopefully) live
444 * objects into our new allocation, so trivial constructability is not a
445 * hard requirement. Rather, we must ensure that a memory copy is a valid
446 * way of constructing types, which we do by checking trivial copyability.
447 */
448 static_assert(std::is_trivially_copyable_v<std::remove_extent_t<T>>,
449 "Allocation pointer type must be trivially copyable.");
450
451 using pointer_t =
452 std::conditional_t<std::is_array_v<T>, std::decay_t<T>, T*>;
453
454 /*
455 * Calculate the size of the allocation and use the memory resource to
456 * perform an allocation of the requested size.
457 */
458 std::size_t s = sizeof(T);
459 std::size_t align = alignof(std::remove_extent_t<T>);
460 pointer_t p = static_cast<pointer_t>(m.allocate(s, align));
461
462 c(p, f, s);
463
464 /*
465 * Create a new unique_ptr, with its own deleter, and return it.
466 */
467 return unique_alloc_ptr<T>(p,
469}
470
509template <typename T, typename C>
510unique_alloc_ptr<T> make_unique_alloc(memory_resource& m, std::size_t n,
511 const std::remove_extent_t<T>* f,
512 const C& c) {
513 /*
514 * This overload only works for unbounded array types.
515 */
516 static_assert(std::is_array_v<T>,
517 "Allocation pointer type must be an array type.");
518 static_assert(std::extent_v<T> == 0,
519 "Allocation pointer type must be unbounded.");
520
521 /*
522 * In this case, we are going to immediately copy some (hopefully) live
523 * objects into our new allocation, so trivial constructability is not a
524 * hard requirement. Rather, we must ensure that a memory copy is a valid
525 * way of constructing types, which we do by checking trivial copyability.
526 */
527 static_assert(std::is_trivially_copyable_v<std::remove_extent_t<T>>,
528 "Allocation pointer type must be trivially copyable.");
529
530 using pointer_t =
531 std::conditional_t<std::is_array_v<T>, std::decay_t<T>, T*>;
532
533 // Handle the case with zero elements.
534 if (n == 0) {
535 return unique_alloc_ptr<T>(
536 details::get_nonexistent_pointer<pointer_t>());
537 }
538
539 /*
540 * Calculate the size of the allocation and use the memory resource to
541 * perform an allocation of the requested size.
542 */
543 std::size_t s = n * sizeof(std::remove_extent_t<T>);
544 std::size_t align = alignof(std::remove_extent_t<T>);
545 pointer_t p = static_cast<pointer_t>(m.allocate(s, align));
546
547 c(p, f, s);
548
549 /*
550 * Create a new unique_ptr, with its own deleter, and return it.
551 */
552 return unique_alloc_ptr<T>(p,
554}
555} // namespace vecmem
An allocator class that wraps a memory resource.
Definition allocator.hpp:37
T get_nonexistent_pointer()
Helper function for generating a nonexistent, but still "aligned" pointer.
Definition unique_ptr.hpp:31
Main namespace for the vecmem classes/functions.
Definition atomic_ref.hpp:16
std::unique_ptr< T, details::unique_obj_deleter< T > > unique_obj_ptr
A unique pointer type for non-trivial objects.
Definition unique_ptr.hpp:54
std::unique_ptr< T, details::unique_alloc_deleter< T > > unique_alloc_ptr
A unique pointer type for trivial types.
Definition unique_ptr.hpp:72
std::enable_if_t<!std::is_array_v< T >, unique_obj_ptr< T > > make_unique_obj(memory_resource &m, std::align_val_t alignment, Args &&... a)
Create a unique object pointer to a newly constructed object, with a minimum alignment.
Definition unique_ptr.hpp:95
unique_alloc_ptr< T > make_unique_alloc(memory_resource &m, std::align_val_t alignment)
Create a unique allocation pointer to a type, with a minimum alignment.
Definition unique_ptr.hpp:233
A deleter class for trivial allocations.
Definition unique_alloc_deleter.hpp:33
A deleter class for non-trivial objects.
Definition unique_obj_deleter.hpp:44