1 //===-- runtime/stack.h -----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Trivial implementation of stack that can be used on all targets.
10 // It is a list based stack with dynamic allocation/deallocation
13 #ifndef FORTRAN_RUNTIME_STACK_H
14 #define FORTRAN_RUNTIME_STACK_H
16 #include "terminator.h"
17 #include "flang/Runtime/memory.h"
19 namespace Fortran::runtime
{
20 // Storage for the Stack elements of type T.
21 template <typename T
, unsigned N
> struct StackStorage
{
22 RT_API_ATTRS
void *getElement(unsigned i
) {
29 RT_API_ATTRS
const void *getElement(unsigned i
) const {
38 // Storage to hold N elements of type T.
39 // It is declared as an array of bytes to avoid
40 // default construction (if any is implied by type T).
41 alignas(T
) char storage
[N
][sizeof(T
)];
44 // 0-size specialization that provides no storage.
45 template <typename T
> struct alignas(T
) StackStorage
<T
, 0> {
46 RT_API_ATTRS
void *getElement(unsigned) { return nullptr; }
47 RT_API_ATTRS
const void *getElement(unsigned) const { return nullptr; }
50 template <typename T
, unsigned N
= 0> class Stack
: public StackStorage
<T
, N
> {
53 Stack(const Stack
&) = delete;
54 Stack(Stack
&&) = delete;
55 RT_API_ATTRS
Stack(Terminator
&terminator
) : terminator_
{terminator
} {}
56 RT_API_ATTRS
~Stack() {
61 RT_API_ATTRS
void push(const T
&object
) {
62 if (void *ptr
{this->getElement(size_
)}) {
65 top_
= New
<List
>{terminator_
}(top_
, object
).release();
69 RT_API_ATTRS
void push(T
&&object
) {
70 if (void *ptr
{this->getElement(size_
)}) {
71 new (ptr
) T
{std::move(object
)};
73 top_
= New
<List
>{terminator_
}(top_
, std::move(object
)).release();
77 template <typename
... Args
> RT_API_ATTRS
void emplace(Args
&&...args
) {
78 if (void *ptr
{this->getElement(size_
)}) {
79 new (ptr
) T
{std::forward
<Args
>(args
)...};
82 New
<List
>{terminator_
}(top_
, std::forward
<Args
>(args
)...).release();
86 RT_API_ATTRS T
&top() {
87 RUNTIME_CHECK(terminator_
, size_
> 0);
88 if (void *ptr
{this->getElement(size_
- 1)}) {
89 return *reinterpret_cast<T
*>(ptr
);
91 RUNTIME_CHECK(terminator_
, top_
);
95 RT_API_ATTRS
const T
&top() const {
96 RUNTIME_CHECK(terminator_
, size_
> 0);
97 if (void *ptr
{this->getElement(size_
- 1)}) {
98 return *reinterpret_cast<const T
*>(ptr
);
100 RUNTIME_CHECK(terminator_
, top_
);
101 return top_
->object_
;
104 RT_API_ATTRS
void pop() {
105 RUNTIME_CHECK(terminator_
, size_
> 0);
106 if (void *ptr
{this->getElement(size_
- 1)}) {
107 reinterpret_cast<T
*>(ptr
)->~T();
109 RUNTIME_CHECK(terminator_
, top_
);
110 List
*next
{top_
->next_
};
117 RT_API_ATTRS
bool empty() const { return size_
== 0; }
121 template <typename
... Args
>
122 RT_API_ATTRS
List(List
*next
, Args
&&...args
)
123 : next_(next
), object_(std::forward
<Args
>(args
)...) {}
124 RT_API_ATTRS
List(List
*next
, const T
&object
)
125 : next_(next
), object_(object
) {}
126 RT_API_ATTRS
List(List
*next
, T
&&object
)
127 : next_(next
), object_(std::move(object
)) {}
128 List
*next_
{nullptr};
132 std::size_t size_
{0};
133 Terminator
&terminator_
;
135 } // namespace Fortran::runtime
136 #endif // FORTRAN_RUNTIME_STACK_H