-
-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathstack.h
More file actions
248 lines (197 loc) · 5.57 KB
/
stack.h
File metadata and controls
248 lines (197 loc) · 5.57 KB
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/* Copyright (c) 2024 Julian Benda
*
* This file is part of inkCPP which is released under MIT license.
* See file LICENSE.txt or go to
* https://github.com/JBenda/inkcpp for full license details.
*/
#pragma once
#include "config.h"
#include "value.h"
#include "collections/restorable.h"
#include "array.h"
#include "snapshot_impl.h"
namespace ink
{
namespace runtime
{
namespace internal
{
class string_table;
struct entry {
hash_t name = 0;
value data;
};
enum class frame_type : uint32_t {
function,
tunnel,
thread
};
class basic_stack : protected restorable<entry>
{
protected:
basic_stack(entry* data, size_t size);
// base class
using base = restorable<entry>;
public:
inline config::statistics::container statistics() const { return base::statistics(); }
virtual ~basic_stack() = default;
// Sets existing value, or creates a new one at this callstack entry
void set(hash_t name, const value& val);
// Gets an existing value, or nullptr
const value* get(hash_t name) const;
value* get(hash_t name);
value* get_from_frame(int ci, hash_t name);
// pushes a new frame onto the stack
// @param eval if evaluation mode was active
template<frame_type>
void push_frame(offset_t return_to, bool eval);
// Pops a frame (and all temporary variables) from the callstack.
offset_t pop_frame(frame_type* type, bool& eval);
// Returns true if there are any frames on the stack
bool has_frame(frame_type* type = nullptr) const;
// Clears the entire stack
void clear();
// Garbage collection
void mark_used(string_table&, list_table&) const;
// == Threading ==
// Forks a new thread from the current callstack and returns that thread's unique id
thread_t fork_thread();
// Mark a thread as "done". It's callstack is still preserved until collapse_to_thread is
// called.
void complete_thread(thread_t thread);
// Collapses the callstack to the state of a single thread
void collapse_to_thread(thread_t thread);
// == Save/Restore ==
void save();
void restore();
void forget();
// replace all pointer in current frame with values from _stack
void fetch_values(basic_stack& _stack);
// push all values to other _stack
void push_values(basic_stack& _stack);
// snapshot interface
size_t snap(unsigned char* data, const snapper&) const;
const unsigned char* snap_load(const unsigned char* data, const loader&);
private:
entry& add(hash_t name, const value& val);
const entry* pop();
entry* do_thread_jump_pop(const iterator& jump);
// thread ids
thread_t _next_thread = 0;
thread_t _backup_next_thread = 0;
static const hash_t NulledHashId = ~0U;
};
template<>
void basic_stack::push_frame<frame_type::function>(offset_t return_to, bool eval);
template<>
void basic_stack::push_frame<frame_type::tunnel>(offset_t return_to, bool eval);
template<>
void basic_stack::push_frame<frame_type::thread>(offset_t return_to, bool eval);
/**
* @brief stack for call history and temporary variables
* @tparam N initial capacity of stack
* @tparam Dynamic weather or not expand if stack is full
*/
template<size_t N, bool Dynamic = false>
class stack : public basic_stack
{
public:
stack()
: basic_stack(&_stack[0], N)
{
}
private:
// stack
entry _stack[N];
};
template<size_t N>
class stack<N, true> : public basic_stack
{
public:
stack()
: basic_stack(nullptr, 0)
{
}
protected:
virtual void overflow(entry*& buffer, size_t& size) override
{
if (! buffer) {
buffer = _stack.data();
size = _stack.capacity();
} else {
_stack.extend();
buffer = _stack.data();
size = _stack.capacity();
}
}
private:
managed_array<entry, true, N> _stack;
};
class basic_eval_stack : protected restorable<value>
{
protected:
basic_eval_stack(value* data, size_t size);
using base = restorable<value>;
public:
virtual ~basic_eval_stack() = default;
config::statistics::container statistics() const { return base::statistics(); }
// Push value onto the stack
void push(const value&);
// Pop a value off the stack
value pop();
// Gets the top value without popping
const value& top() const;
// Gets the top non null value without popping
const value& top_value() const;
// Check if the stack is empty
bool is_empty() const;
// Clear stack
void clear();
/** Mark used strings and lists for garbage collection */
void mark_used(string_table&, list_table&) const;
// == Save/Restore ==
void save();
void restore();
void forget();
// snapshot interface
size_t snap(unsigned char* data, const snapper& snapper) const
{
return base::snap(data, snapper);
}
const unsigned char* snap_load(const unsigned char* data, const loader& loader)
{
return base::snap_load(data, loader);
}
};
template<size_t N, bool dynamic = false>
class eval_stack : public basic_eval_stack
{
public:
eval_stack()
: basic_eval_stack(_stack, N)
{
}
private:
value _stack[N];
};
template<size_t N>
class eval_stack<N, true> : public basic_eval_stack
{
public:
eval_stack()
: basic_eval_stack(nullptr, 0)
{
}
protected:
virtual void overflow(value*& buffer, size_t& size) override
{
_stack.extend();
buffer = _stack.data();
size = _stack.capacity();
}
private:
managed_array<value, true, N> _stack;
};
} // namespace internal
} // namespace runtime
} // namespace ink