Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Runtime/memory.h --------------------------*- C++ -*-===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // Thin wrapper around malloc()/free() to isolate the dependency, |
10 | // ease porting, and provide an owning pointer. |
11 | |
12 | #ifndef FORTRAN_RUNTIME_MEMORY_H_ |
13 | #define FORTRAN_RUNTIME_MEMORY_H_ |
14 | |
15 | #include "flang/Common/api-attrs.h" |
16 | #include <cassert> |
17 | #include <memory> |
18 | #include <type_traits> |
19 | |
20 | namespace Fortran::runtime { |
21 | |
22 | class Terminator; |
23 | |
24 | [[nodiscard]] RT_API_ATTRS void *AllocateMemoryOrCrash( |
25 | const Terminator &, std::size_t bytes); |
26 | template <typename A> |
27 | [[nodiscard]] RT_API_ATTRS A &AllocateOrCrash(const Terminator &t) { |
28 | return *reinterpret_cast<A *>(AllocateMemoryOrCrash(t, sizeof(A))); |
29 | } |
30 | RT_API_ATTRS void *ReallocateMemoryOrCrash( |
31 | const Terminator &, void *ptr, std::size_t newByteSize); |
32 | RT_API_ATTRS void FreeMemory(void *); |
33 | template <typename A> RT_API_ATTRS void FreeMemory(A *p) { |
34 | FreeMemory(reinterpret_cast<void *>(p)); |
35 | } |
36 | template <typename A> RT_API_ATTRS void FreeMemoryAndNullify(A *&p) { |
37 | FreeMemory(p); |
38 | p = nullptr; |
39 | } |
40 | |
41 | // Very basic implementation mimicking std::unique_ptr. |
42 | // It should work for any offload device compiler. |
43 | // It uses a fixed memory deleter based on FreeMemory(), |
44 | // and does not support array objects with runtime length. |
45 | template <typename A> class OwningPtr { |
46 | public: |
47 | using pointer_type = A *; |
48 | |
49 | OwningPtr() = default; |
50 | RT_API_ATTRS explicit OwningPtr(pointer_type p) : ptr_(p) {} |
51 | RT_API_ATTRS OwningPtr(const OwningPtr &) = delete; |
52 | RT_API_ATTRS OwningPtr &operator=(const OwningPtr &) = delete; |
53 | RT_API_ATTRS OwningPtr(OwningPtr &&other) { |
54 | ptr_ = other.ptr_; |
55 | other.ptr_ = pointer_type{}; |
56 | } |
57 | RT_API_ATTRS OwningPtr &operator=(OwningPtr &&other) { |
58 | if (this != &other) { |
59 | delete_ptr(ptr_); |
60 | ptr_ = other.ptr_; |
61 | other.ptr_ = pointer_type{}; |
62 | } |
63 | return *this; |
64 | } |
65 | constexpr RT_API_ATTRS OwningPtr(std::nullptr_t) : OwningPtr() {} |
66 | |
67 | // Delete the pointer, if owns one. |
68 | RT_API_ATTRS ~OwningPtr() { |
69 | if (ptr_ != pointer_type{}) { |
70 | delete_ptr(ptr_); |
71 | ptr_ = pointer_type{}; |
72 | } |
73 | } |
74 | |
75 | // Release the ownership. |
76 | RT_API_ATTRS pointer_type release() { |
77 | pointer_type p = ptr_; |
78 | ptr_ = pointer_type{}; |
79 | return p; |
80 | } |
81 | |
82 | RT_DIAG_PUSH |
83 | RT_DIAG_DISABLE_CALL_HOST_FROM_DEVICE_WARN |
84 | // Replace the pointer. |
85 | RT_API_ATTRS void reset(pointer_type p = pointer_type{}) { |
86 | std::swap(ptr_, p); |
87 | if (p != pointer_type{}) { |
88 | // Delete the owned pointer. |
89 | delete_ptr(p); |
90 | } |
91 | } |
92 | |
93 | // Exchange the pointer with another object. |
94 | RT_API_ATTRS void swap(OwningPtr &other) { std::swap(ptr_, other.ptr_); } |
95 | RT_DIAG_POP |
96 | |
97 | // Get the stored pointer. |
98 | RT_API_ATTRS pointer_type get() const { return ptr_; } |
99 | |
100 | RT_API_ATTRS explicit operator bool() const { |
101 | return get() != pointer_type{}; |
102 | } |
103 | |
104 | RT_API_ATTRS typename std::add_lvalue_reference<A>::type operator*() const { |
105 | assert(get() != pointer_type{}); |
106 | return *get(); |
107 | } |
108 | |
109 | RT_API_ATTRS pointer_type operator->() const { return get(); } |
110 | |
111 | private: |
112 | RT_API_ATTRS void delete_ptr(pointer_type p) { FreeMemory(p); } |
113 | pointer_type ptr_{}; |
114 | }; |
115 | |
116 | template <typename X, typename Y> |
117 | inline RT_API_ATTRS bool operator!=( |
118 | const OwningPtr<X> &x, const OwningPtr<Y> &y) { |
119 | return x.get() != y.get(); |
120 | } |
121 | |
122 | template <typename X> |
123 | inline RT_API_ATTRS bool operator!=(const OwningPtr<X> &x, std::nullptr_t) { |
124 | return (bool)x; |
125 | } |
126 | |
127 | template <typename X> |
128 | inline RT_API_ATTRS bool operator!=(std::nullptr_t, const OwningPtr<X> &x) { |
129 | return (bool)x; |
130 | } |
131 | |
132 | template <typename A> class SizedNew { |
133 | public: |
134 | explicit RT_API_ATTRS SizedNew(const Terminator &terminator) |
135 | : terminator_{terminator} {} |
136 | |
137 | template <typename... X> |
138 | [[nodiscard]] RT_API_ATTRS OwningPtr<A> operator()( |
139 | std::size_t bytes, X &&...x) { |
140 | return OwningPtr<A>{new (AllocateMemoryOrCrash(terminator_, bytes)) |
141 | A{std::forward<X>(x)...}}; |
142 | } |
143 | |
144 | private: |
145 | const Terminator &terminator_; |
146 | }; |
147 | |
148 | template <typename A> struct New : public SizedNew<A> { |
149 | using SizedNew<A>::SizedNew; |
150 | template <typename... X> |
151 | [[nodiscard]] RT_API_ATTRS OwningPtr<A> operator()(X &&...x) { |
152 | return SizedNew<A>::operator()(sizeof(A), std::forward<X>(x)...); |
153 | } |
154 | }; |
155 | |
156 | template <typename A> struct Allocator { |
157 | using value_type = A; |
158 | explicit Allocator(const Terminator &t) : terminator{t} {} |
159 | template <typename B> |
160 | explicit constexpr Allocator(const Allocator<B> &that) noexcept |
161 | : terminator{that.terminator} {} |
162 | Allocator(const Allocator &) = default; |
163 | Allocator(Allocator &&) = default; |
164 | [[nodiscard]] constexpr A *allocate(std::size_t n) { |
165 | return reinterpret_cast<A *>( |
166 | AllocateMemoryOrCrash(terminator, n * sizeof(A))); |
167 | } |
168 | constexpr void deallocate(A *p, std::size_t) { FreeMemory(p); } |
169 | const Terminator &terminator; |
170 | }; |
171 | } // namespace Fortran::runtime |
172 | |
173 | #endif // FORTRAN_RUNTIME_MEMORY_H_ |
174 |
Warning: This file is not a C or C++ file. It does not have highlighting.