1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
//===-- runtime/stack.h -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Trivial implementation of stack that can be used on all targets.
// It is a list based stack with dynamic allocation/deallocation
// of the list nodes.
#ifndef FORTRAN_RUNTIME_STACK_H
#define FORTRAN_RUNTIME_STACK_H
#include "terminator.h"
#include "flang/Runtime/memory.h"
namespace Fortran::runtime {
// Storage for the Stack elements of type T.
template <typename T, unsigned N> struct StackStorage {
RT_API_ATTRS void *getElement(unsigned i) {
if (i < N) {
return storage[i];
} else {
return nullptr;
}
}
RT_API_ATTRS const void *getElement(unsigned i) const {
if (i < N) {
return storage[i];
} else {
return nullptr;
}
}
private:
// Storage to hold N elements of type T.
// It is declared as an array of bytes to avoid
// default construction (if any is implied by type T).
alignas(T) char storage[N][sizeof(T)];
};
// 0-size specialization that provides no storage.
template <typename T> struct alignas(T) StackStorage<T, 0> {
RT_API_ATTRS void *getElement(unsigned) { return nullptr; }
RT_API_ATTRS const void *getElement(unsigned) const { return nullptr; }
};
template <typename T, unsigned N = 0> class Stack : public StackStorage<T, N> {
public:
Stack() = delete;
Stack(const Stack &) = delete;
Stack(Stack &&) = delete;
RT_API_ATTRS Stack(Terminator &terminator) : terminator_{terminator} {}
RT_API_ATTRS ~Stack() {
while (!empty()) {
pop();
}
}
RT_API_ATTRS void push(const T &object) {
if (void *ptr{this->getElement(size_)}) {
new (ptr) T{object};
} else {
top_ = New<List>{terminator_}(top_, object).release();
}
++size_;
}
RT_API_ATTRS void push(T &&object) {
if (void *ptr{this->getElement(size_)}) {
new (ptr) T{std::move(object)};
} else {
top_ = New<List>{terminator_}(top_, std::move(object)).release();
}
++size_;
}
template <typename... Args> RT_API_ATTRS void emplace(Args &&...args) {
if (void *ptr{this->getElement(size_)}) {
new (ptr) T{std::forward<Args>(args)...};
} else {
top_ =
New<List>{terminator_}(top_, std::forward<Args>(args)...).release();
}
++size_;
}
RT_API_ATTRS T &top() {
RUNTIME_CHECK(terminator_, size_ > 0);
if (void *ptr{this->getElement(size_ - 1)}) {
return *reinterpret_cast<T *>(ptr);
} else {
RUNTIME_CHECK(terminator_, top_);
return top_->object_;
}
}
RT_API_ATTRS const T &top() const {
RUNTIME_CHECK(terminator_, size_ > 0);
if (void *ptr{this->getElement(size_ - 1)}) {
return *reinterpret_cast<const T *>(ptr);
} else {
RUNTIME_CHECK(terminator_, top_);
return top_->object_;
}
}
RT_API_ATTRS void pop() {
RUNTIME_CHECK(terminator_, size_ > 0);
if (void *ptr{this->getElement(size_ - 1)}) {
reinterpret_cast<T *>(ptr)->~T();
} else {
RUNTIME_CHECK(terminator_, top_);
List *next{top_->next_};
top_->~List();
FreeMemory(top_);
top_ = next;
}
--size_;
}
RT_API_ATTRS bool empty() const { return size_ == 0; }
private:
struct List {
template <typename... Args>
RT_API_ATTRS List(List *next, Args &&...args)
: next_(next), object_(std::forward<Args>(args)...) {}
RT_API_ATTRS List(List *next, const T &object)
: next_(next), object_(object) {}
RT_API_ATTRS List(List *next, T &&object)
: next_(next), object_(std::move(object)) {}
List *next_{nullptr};
T object_;
};
List *top_{nullptr};
std::size_t size_{0};
Terminator &terminator_;
};
} // namespace Fortran::runtime
#endif // FORTRAN_RUNTIME_STACK_H
|