| //===-- 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 |