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
20namespace Fortran::runtime {
21
22class Terminator;
23
24[[nodiscard]] RT_API_ATTRS void *AllocateMemoryOrCrash(
25 const Terminator &, std::size_t bytes);
26template <typename A>
27[[nodiscard]] RT_API_ATTRS A &AllocateOrCrash(const Terminator &t) {
28 return *reinterpret_cast<A *>(AllocateMemoryOrCrash(t, sizeof(A)));
29}
30RT_API_ATTRS void *ReallocateMemoryOrCrash(
31 const Terminator &, void *ptr, std::size_t newByteSize);
32RT_API_ATTRS void FreeMemory(void *);
33template <typename A> RT_API_ATTRS void FreeMemory(A *p) {
34 FreeMemory(reinterpret_cast<void *>(p));
35}
36template <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.
45template <typename A> class OwningPtr {
46public:
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
111private:
112 RT_API_ATTRS void delete_ptr(pointer_type p) { FreeMemory(p); }
113 pointer_type ptr_{};
114};
115
116template <typename X, typename Y>
117inline RT_API_ATTRS bool operator!=(
118 const OwningPtr<X> &x, const OwningPtr<Y> &y) {
119 return x.get() != y.get();
120}
121
122template <typename X>
123inline RT_API_ATTRS bool operator!=(const OwningPtr<X> &x, std::nullptr_t) {
124 return (bool)x;
125}
126
127template <typename X>
128inline RT_API_ATTRS bool operator!=(std::nullptr_t, const OwningPtr<X> &x) {
129 return (bool)x;
130}
131
132template <typename A> class SizedNew {
133public:
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
144private:
145 const Terminator &terminator_;
146};
147
148template <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
156template <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.

source code of flang/include/flang/Runtime/memory.h