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