1 //===-- 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 <memory>
16
17 namespace Fortran::runtime {
18
19 class Terminator;
20
21 [[nodiscard]] void *AllocateMemoryOrCrash(
22 const Terminator &, std::size_t bytes);
AllocateOrCrash(const Terminator & t)23 template <typename A> [[nodiscard]] A &AllocateOrCrash(const Terminator &t) {
24 return *reinterpret_cast<A *>(AllocateMemoryOrCrash(t, sizeof(A)));
25 }
26 void FreeMemory(void *);
FreeMemory(A * p)27 template <typename A> void FreeMemory(A *p) {
28 FreeMemory(reinterpret_cast<void *>(p));
29 }
FreeMemoryAndNullify(A * & p)30 template <typename A> void FreeMemoryAndNullify(A *&p) {
31 FreeMemory(p);
32 p = nullptr;
33 }
34
35 template <typename A> struct OwningPtrDeleter {
operatorOwningPtrDeleter36 void operator()(A *p) { FreeMemory(p); }
37 };
38
39 template <typename A> using OwningPtr = std::unique_ptr<A, OwningPtrDeleter<A>>;
40
41 template <typename A> class SizedNew {
42 public:
SizedNew(const Terminator & terminator)43 explicit SizedNew(const Terminator &terminator) : terminator_{terminator} {}
44 template <typename... X>
operator()45 [[nodiscard]] OwningPtr<A> operator()(std::size_t bytes, X &&...x) {
46 return OwningPtr<A>{new (AllocateMemoryOrCrash(terminator_, bytes))
47 A{std::forward<X>(x)...}};
48 }
49
50 private:
51 const Terminator &terminator_;
52 };
53
54 template <typename A> struct New : public SizedNew<A> {
55 using SizedNew<A>::SizedNew;
operatorNew56 template <typename... X> [[nodiscard]] OwningPtr<A> operator()(X &&...x) {
57 return SizedNew<A>::operator()(sizeof(A), std::forward<X>(x)...);
58 }
59 };
60
61 template <typename A> struct Allocator {
62 using value_type = A;
AllocatorAllocator63 explicit Allocator(const Terminator &t) : terminator{t} {}
64 template <typename B>
AllocatorAllocator65 explicit constexpr Allocator(const Allocator<B> &that) noexcept
66 : terminator{that.terminator} {}
67 Allocator(const Allocator &) = default;
68 Allocator(Allocator &&) = default;
allocateAllocator69 [[nodiscard]] constexpr A *allocate(std::size_t n) {
70 return reinterpret_cast<A *>(
71 AllocateMemoryOrCrash(terminator, n * sizeof(A)));
72 }
deallocateAllocator73 constexpr void deallocate(A *p, std::size_t) { FreeMemory(p); }
74 const Terminator &terminator;
75 };
76 } // namespace Fortran::runtime
77
78 #endif // FORTRAN_RUNTIME_MEMORY_H_
79