File: stack.h

package info (click to toggle)
llvm-toolchain-20 1%3A20.1.8-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,111,696 kB
  • sloc: cpp: 7,438,781; ansic: 1,393,871; asm: 1,012,926; python: 241,771; f90: 86,635; objc: 75,411; lisp: 42,144; pascal: 17,286; sh: 8,596; ml: 5,082; perl: 4,730; makefile: 3,591; awk: 3,523; javascript: 2,251; xml: 892; fortran: 672
file content (136 lines) | stat: -rw-r--r-- 4,034 bytes parent folder | download | duplicates (2)
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