forked from scp-fs2open/fs2open.github.com
/
LuaTable.h
258 lines (212 loc) · 6.09 KB
/
LuaTable.h
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
249
250
251
252
253
254
255
256
257
258
#ifndef LUATABLE_H
#define LUATABLE_H
#pragma once
#include "LuaConvert.h"
#include "LuaValue.h"
#include <iterator>
namespace luacpp {
class LuaTable;
/**
* @brief Utility class for iterating over the contents of a lua table
*
* The elements are returned as key-value pairs of the table
*
* @warning Never manipulate the lua stack while using an instance of this class! It's ok to change the stack but it must
* be in the exact same state when you call the next method of this class.
*/
class LuaTableIterator {
lua_State* _luaState = nullptr;
int _stackTop = 0;
bool _hasElement = false;
std::pair<LuaValue, LuaValue> _currentVal;
public:
/**
* @brief Initializes the iterator with a table
* @param t The table to iterate iver
*/
explicit LuaTableIterator(const LuaTable& t);
~LuaTableIterator();
LuaTableIterator(const LuaTableIterator&) = delete;
LuaTableIterator& operator=(const LuaTableIterator&) = delete;
/**
* @brief Test if there is a valid element
* @return @c true if there is a value, @c false otherwise
*/
bool hasElement();
/**
* @brief Advances the iterator to the next element
*/
void toNextElement();
/**
* @brief Gets the key-value pair of the current element
* @return The key-value pair
*/
std::pair<LuaValue, LuaValue> getElement();
};
/**
* @brief Class to improve handling of lua tables.
*
* This class provides a high-level interface to lua tables without the need to directly call
* lua-API functions.
*
* @see LuaConvert
*/
class LuaTable: public LuaValue {
public:
/**
* @brief STL adaptor for LuaTableIterator
*
* This wraps a shared pointer to an iterator so that this class can be copied like the iterator interface expects
*/
class iterator: public std::iterator<std::input_iterator_tag, std::pair<LuaValue, LuaValue>> {
public:
explicit iterator(const LuaTable& _parent);
iterator();
bool operator==(const iterator& other);
bool operator!=(const iterator& other);
iterator& operator++();
iterator& operator++(int);
std::pair<LuaValue, LuaValue> operator*();
private:
std::shared_ptr<LuaTableIterator> _iter;
bool _atEnd = false;
};
typedef iterator iterator_type;
/**
* @brief Creates a new empty table.
*/
static LuaTable create(lua_State* state);
/**
* @brief Default constructor
*/
LuaTable();
/**
* @brief Copy-constructor
* @param other The other table.
*/
LuaTable(const LuaTable& other);
/**
* Dereferences the stored reference to the table if it exists.
*/
virtual ~LuaTable();
/**
* @brief Sets the metatable.
*
* The given table will be set as the metatable of this table.
*
* @param ref The new metatable.
* @return Always `true`.
*/
bool setMetatable(const LuaTable& ref);
/**
* @brief Sets a new reference.
* This overload checks if the passed reference is a table
*
* @param ref The new reference
* @return void
*/
void setReference(LuaReference ref) override;
/**
* @brief Adds a value to this lua table.
*
* @param index The index value to use.
* @param value The value to set at the index.
*/
template<class IndexType, class ValueType>
void addValue(const IndexType& index, const ValueType& value) {
// Push the table onto the stack by using the reference
this->pushValue();
// Push the index and value onto the stac by using the template functions
convert::pushValue(_luaState, index);
convert::pushValue(_luaState, value);
// Set the value in the table
lua_settable(_luaState, -3);
// And pop the table again
lua_pop(_luaState, 1);
}
/**
* @brief Retrieves a value from the table.
*
* @param index The index where the value is located.
* @param target The target location where the value should be stored.
* @return @c true when the value could be successfully converted, @c false otherwise
*/
template<class IndexType, class ValueType>
bool getValue(const IndexType& index, ValueType& target) {
this->pushValue();
convert::pushValue(_luaState, index);
lua_gettable(_luaState, -2);
bool ret = convert::popValue(_luaState, target);
if (!ret) {
lua_pop(_luaState, 1);
}
lua_pop(_luaState, 1);
return ret;
}
/**
* @brief Gets a value or throws an exception.
* This function gets the specified value from the table and returns it
* or throws an exception if that faild
*
* @param index The index of the value to retrieve
* @return luacpp::ValueType The value
*
* @exception LuaException Thrown when an error occurs while converting the value
*/
template<class ValueType, class IndexType>
// IndexType is last so the compiler can deduce it from the argument
ValueType getValue(const IndexType& index) {
ValueType target;
if (!getValue(index, target)) {
throw LuaException("Failed to get lua value!");
} else {
return target;
}
}
/**
* @brief Gets the length of the table.
*
* Gets size of the table (the same as using the '#' operator in Lua).
*
* @return The size value.
*/
size_t getLength();
/**
* @brief Returns an iterator to the begin of this table
*
* This can be used with STL algorithms or with the C++11 range-base-for-loop
*
* @warning Never manipulate the lua stack while using this iterator!
*
* @return The iterator to the begin of the table
*/
iterator begin();
/**
* @brief Returns an iterator to the end of this table
*
* This can be used with STL algorithms or with the C++11 range-base-for-loop
*
* @return The iterator to the end of the table
*/
iterator end();
};
namespace convert {
template<>
inline LuaTable popValue<LuaTable>(lua_State* luaState, int stackposition, bool remove) {
if (!isValidIndex(luaState, stackposition)) {
throw LuaException("Specified stack position is not valid!");
}
if (!lua_istable(luaState, stackposition)) {
throw LuaException("Specified index is no table!");
} else {
LuaTable target;
target.setReference(UniqueLuaReference::create(luaState, stackposition));
if (remove) {
lua_remove(luaState, stackposition);
}
return target;
}
}
}
}
#endif