xref: /petsc/include/petsc/private/cpp/memory.hpp (revision 834855d6effb0d027771461c8e947ee1ce5a1e17)
1 #pragma once
2 
3 #include <petscmacros.h> // PETSC_CPP_VERSION
4 
5 #include <petsc/private/cpp/utility.hpp>
6 #if PETSC_CPP_VERSION < 14
7   #include <petsc/private/cpp/type_traits.hpp> // remove_extent
8 #endif
9 
10 #include <memory>
11 
12 namespace Petsc
13 {
14 
15 namespace util
16 {
17 
18 #if PETSC_CPP_VERSION >= 14
19 using std::make_unique;
20 #else
21 namespace detail
22 {
23 
24 // helpers shamelessly stolen from libcpp
25 template <class T>
26 struct unique_if {
27   using unique_single = std::unique_ptr<T>;
28 };
29 
30 template <class T>
31 struct unique_if<T[]> {
32   using unique_array_unknown_bound = std::unique_ptr<T[]>;
33 };
34 
35 template <class T, std::size_t N>
36 struct unique_if<T[N]> {
37   using unique_array_unknown_bound = void;
38 };
39 
40 } // namespace detail
41 
42 template <class T, class... Args>
43 inline typename detail::unique_if<T>::unique_single make_unique(Args &&...args)
44 {
45   return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
46 }
47 
48 template <class T>
49 inline typename detail::unique_if<T>::unique_array_unknown_bound make_unique(std::size_t n)
50 {
51   return std::unique_ptr<T>(new util::remove_extent_t<T>[n]());
52 }
53 
54 template <class T, class... Args>
55 typename detail::unique_if<T>::unique_array_known_bound make_unique(Args &&...) = delete;
56 #endif // PETSC_CPP_VERSION >= 14
57 
58 #if PETSC_CPP_VERSION >= 20
59 // only use std::destroy_at from C++20 onwards (even though it was introduced in C++17) since
60 // that makes the behavior more uniform for arrays.
61 using std::destroy_at;
62 using std::construct_at;
63 #else
64 template <class T>
destroy_at(T * ptr)65 inline enable_if_t<!std::is_array<T>::value> destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
66 {
67   ptr->~T();
68 }
69 
70 template <class T>
destroy_at(T * ptr)71 inline enable_if_t<std::is_array<T>::value> destroy_at(T *ptr)
72 {
73   for (auto &elem : *ptr) destroy_at(std::addressof(elem));
74 }
75 
76 template <class T, class... Args, class = decltype(::new (std::declval<void *>()) T{std::declval<Args>()...})>
construct_at(T * ptr,Args &&...args)77 inline constexpr T *construct_at(T *ptr, Args &&...args) noexcept(std::is_nothrow_constructible<T, Args...>::value)
78 {
79   return ::new ((void *)ptr) T{std::forward<Args>(args)...};
80 }
81 #endif
82 
83 } // namespace util
84 
85 } // namespace Petsc
86