xref: /llvm-project/flang/runtime/stack.h (revision e89129ed30d64ed61e38269b1722adc18844a31c)
12177a176SSlava Zakharin //===-- runtime/stack.h -----------------------------------------*- C++ -*-===//
22177a176SSlava Zakharin //
32177a176SSlava Zakharin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42177a176SSlava Zakharin // See https://llvm.org/LICENSE.txt for license information.
52177a176SSlava Zakharin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62177a176SSlava Zakharin //
72177a176SSlava Zakharin //===----------------------------------------------------------------------===//
82177a176SSlava Zakharin 
92177a176SSlava Zakharin // Trivial implementation of stack that can be used on all targets.
102177a176SSlava Zakharin // It is a list based stack with dynamic allocation/deallocation
112177a176SSlava Zakharin // of the list nodes.
122177a176SSlava Zakharin 
132177a176SSlava Zakharin #ifndef FORTRAN_RUNTIME_STACK_H
142177a176SSlava Zakharin #define FORTRAN_RUNTIME_STACK_H
152177a176SSlava Zakharin 
162177a176SSlava Zakharin #include "terminator.h"
172177a176SSlava Zakharin #include "flang/Runtime/memory.h"
182177a176SSlava Zakharin 
192177a176SSlava Zakharin namespace Fortran::runtime {
202177a176SSlava Zakharin // Storage for the Stack elements of type T.
212177a176SSlava Zakharin template <typename T, unsigned N> struct StackStorage {
22*e89129edSSlava Zakharin   RT_API_ATTRS void *getElement(unsigned i) {
232177a176SSlava Zakharin     if (i < N) {
242177a176SSlava Zakharin       return storage[i];
252177a176SSlava Zakharin     } else {
262177a176SSlava Zakharin       return nullptr;
272177a176SSlava Zakharin     }
282177a176SSlava Zakharin   }
29*e89129edSSlava Zakharin   RT_API_ATTRS const void *getElement(unsigned i) const {
302177a176SSlava Zakharin     if (i < N) {
312177a176SSlava Zakharin       return storage[i];
322177a176SSlava Zakharin     } else {
332177a176SSlava Zakharin       return nullptr;
342177a176SSlava Zakharin     }
352177a176SSlava Zakharin   }
362177a176SSlava Zakharin 
372177a176SSlava Zakharin private:
382177a176SSlava Zakharin   // Storage to hold N elements of type T.
392177a176SSlava Zakharin   // It is declared as an array of bytes to avoid
402177a176SSlava Zakharin   // default construction (if any is implied by type T).
412177a176SSlava Zakharin   alignas(T) char storage[N][sizeof(T)];
422177a176SSlava Zakharin };
432177a176SSlava Zakharin 
442177a176SSlava Zakharin // 0-size specialization that provides no storage.
452177a176SSlava Zakharin template <typename T> struct alignas(T) StackStorage<T, 0> {
46*e89129edSSlava Zakharin   RT_API_ATTRS void *getElement(unsigned) { return nullptr; }
47*e89129edSSlava Zakharin   RT_API_ATTRS const void *getElement(unsigned) const { return nullptr; }
482177a176SSlava Zakharin };
492177a176SSlava Zakharin 
502177a176SSlava Zakharin template <typename T, unsigned N = 0> class Stack : public StackStorage<T, N> {
512177a176SSlava Zakharin public:
522177a176SSlava Zakharin   Stack() = delete;
532177a176SSlava Zakharin   Stack(const Stack &) = delete;
542177a176SSlava Zakharin   Stack(Stack &&) = delete;
552177a176SSlava Zakharin   RT_API_ATTRS Stack(Terminator &terminator) : terminator_{terminator} {}
562177a176SSlava Zakharin   RT_API_ATTRS ~Stack() {
572177a176SSlava Zakharin     while (!empty()) {
582177a176SSlava Zakharin       pop();
592177a176SSlava Zakharin     }
602177a176SSlava Zakharin   }
612177a176SSlava Zakharin   RT_API_ATTRS void push(const T &object) {
622177a176SSlava Zakharin     if (void *ptr{this->getElement(size_)}) {
632177a176SSlava Zakharin       new (ptr) T{object};
642177a176SSlava Zakharin     } else {
652177a176SSlava Zakharin       top_ = New<List>{terminator_}(top_, object).release();
662177a176SSlava Zakharin     }
672177a176SSlava Zakharin     ++size_;
682177a176SSlava Zakharin   }
692177a176SSlava Zakharin   RT_API_ATTRS void push(T &&object) {
702177a176SSlava Zakharin     if (void *ptr{this->getElement(size_)}) {
712177a176SSlava Zakharin       new (ptr) T{std::move(object)};
722177a176SSlava Zakharin     } else {
732177a176SSlava Zakharin       top_ = New<List>{terminator_}(top_, std::move(object)).release();
742177a176SSlava Zakharin     }
752177a176SSlava Zakharin     ++size_;
762177a176SSlava Zakharin   }
772177a176SSlava Zakharin   template <typename... Args> RT_API_ATTRS void emplace(Args &&...args) {
782177a176SSlava Zakharin     if (void *ptr{this->getElement(size_)}) {
792177a176SSlava Zakharin       new (ptr) T{std::forward<Args>(args)...};
802177a176SSlava Zakharin     } else {
812177a176SSlava Zakharin       top_ =
822177a176SSlava Zakharin           New<List>{terminator_}(top_, std::forward<Args>(args)...).release();
832177a176SSlava Zakharin     }
842177a176SSlava Zakharin     ++size_;
852177a176SSlava Zakharin   }
862177a176SSlava Zakharin   RT_API_ATTRS T &top() {
872177a176SSlava Zakharin     RUNTIME_CHECK(terminator_, size_ > 0);
882177a176SSlava Zakharin     if (void *ptr{this->getElement(size_ - 1)}) {
892177a176SSlava Zakharin       return *reinterpret_cast<T *>(ptr);
902177a176SSlava Zakharin     } else {
912177a176SSlava Zakharin       RUNTIME_CHECK(terminator_, top_);
922177a176SSlava Zakharin       return top_->object_;
932177a176SSlava Zakharin     }
942177a176SSlava Zakharin   }
952177a176SSlava Zakharin   RT_API_ATTRS const T &top() const {
962177a176SSlava Zakharin     RUNTIME_CHECK(terminator_, size_ > 0);
972177a176SSlava Zakharin     if (void *ptr{this->getElement(size_ - 1)}) {
982177a176SSlava Zakharin       return *reinterpret_cast<const T *>(ptr);
992177a176SSlava Zakharin     } else {
1002177a176SSlava Zakharin       RUNTIME_CHECK(terminator_, top_);
1012177a176SSlava Zakharin       return top_->object_;
1022177a176SSlava Zakharin     }
1032177a176SSlava Zakharin   }
1042177a176SSlava Zakharin   RT_API_ATTRS void pop() {
1052177a176SSlava Zakharin     RUNTIME_CHECK(terminator_, size_ > 0);
1062177a176SSlava Zakharin     if (void *ptr{this->getElement(size_ - 1)}) {
1072177a176SSlava Zakharin       reinterpret_cast<T *>(ptr)->~T();
1082177a176SSlava Zakharin     } else {
1092177a176SSlava Zakharin       RUNTIME_CHECK(terminator_, top_);
1102177a176SSlava Zakharin       List *next{top_->next_};
1112177a176SSlava Zakharin       top_->~List();
1122177a176SSlava Zakharin       FreeMemory(top_);
1132177a176SSlava Zakharin       top_ = next;
1142177a176SSlava Zakharin     }
1152177a176SSlava Zakharin     --size_;
1162177a176SSlava Zakharin   }
1172177a176SSlava Zakharin   RT_API_ATTRS bool empty() const { return size_ == 0; }
1182177a176SSlava Zakharin 
1192177a176SSlava Zakharin private:
1202177a176SSlava Zakharin   struct List {
1212177a176SSlava Zakharin     template <typename... Args>
1222177a176SSlava Zakharin     RT_API_ATTRS List(List *next, Args &&...args)
1232177a176SSlava Zakharin         : next_(next), object_(std::forward<Args>(args)...) {}
1242177a176SSlava Zakharin     RT_API_ATTRS List(List *next, const T &object)
1252177a176SSlava Zakharin         : next_(next), object_(object) {}
1262177a176SSlava Zakharin     RT_API_ATTRS List(List *next, T &&object)
1272177a176SSlava Zakharin         : next_(next), object_(std::move(object)) {}
1282177a176SSlava Zakharin     List *next_{nullptr};
1292177a176SSlava Zakharin     T object_;
1302177a176SSlava Zakharin   };
1312177a176SSlava Zakharin   List *top_{nullptr};
1322177a176SSlava Zakharin   std::size_t size_{0};
1332177a176SSlava Zakharin   Terminator &terminator_;
1342177a176SSlava Zakharin };
1352177a176SSlava Zakharin } // namespace Fortran::runtime
1362177a176SSlava Zakharin #endif // FORTRAN_RUNTIME_STACK_H
137