1 #include "LuaException.h"
2 #include "LuaTable.h"
3
4 namespace luacpp {
create(lua_State * state)5 LuaTable LuaTable::create(lua_State* state) {
6 LuaTable table;
7
8 lua_newtable(state);
9
10 table.setReference(UniqueLuaReference::create(state));
11
12 lua_pop(state, 1);
13
14 return table;
15 }
16
LuaTable()17 LuaTable::LuaTable() : LuaValue() {
18 }
19
LuaTable(const LuaTable & other)20 LuaTable::LuaTable(const LuaTable& other) : LuaValue(other) {
21 }
22
~LuaTable()23 LuaTable::~LuaTable() {
24 }
25
setMetatable(const LuaTable & table)26 bool LuaTable::setMetatable(const LuaTable& table) {
27 if (!table.getReference()->isValid()) {
28 throw LuaException("Meta table reference is not valid!");
29 }
30
31 this->pushValue(_luaState);
32 table.pushValue(_luaState);
33
34 lua_setmetatable(_luaState, -2);
35
36 lua_pop(_luaState, 1);
37
38 return true;
39 }
40
setReference(const LuaReference & ref)41 void LuaTable::setReference(const LuaReference& ref) {
42 lua_State* L = ref->getState();
43
44 ref->pushValue(L);
45
46 if (lua_type(L, -1) != LUA_TTABLE) {
47 lua_pop(L, 1);
48 throw LuaException("Reference does not refere to a table!");
49 } else {
50 lua_pop(L, 1);
51 LuaValue::setReference(ref);
52 }
53 }
54
getLength() const55 size_t LuaTable::getLength() const {
56 this->pushValue(_luaState);
57
58 size_t length = lua_objlen(_luaState, -1);
59
60 lua_pop(_luaState, 1);
61
62 return length;
63 }
64
iterator(const LuaTable & parent)65 LuaTable::iterator::iterator(const LuaTable& parent) {
66 _iter.reset(new LuaTableIterator(parent));
67
68 // Ensure that this value is correct if we try to iterate over an empty table
69 _atEnd = !_iter->hasElement();
70 }
iterator()71 LuaTable::iterator::iterator() : _iter(nullptr), _atEnd(true) {
72 }
operator ==(const iterator & other)73 bool LuaTable::iterator::operator==(const iterator& other) {
74 return _atEnd == other._atEnd;
75 }
operator !=(const LuaTable::iterator & other)76 bool LuaTable::iterator::operator!=(const LuaTable::iterator& other) {
77 return !(*this == other);
78 }
operator ++()79 LuaTable::iterator& LuaTable::iterator::operator++() {
80 _iter->toNextElement();
81
82 _atEnd = !_iter->hasElement();
83
84 return *this;
85 }
operator ++(int)86 LuaTable::iterator& LuaTable::iterator::operator++(int) {
87 return ++(*this); // Post-fix operator doesn't make sense for us.
88 }
operator *()89 std::pair<LuaValue, LuaValue> LuaTable::iterator::operator*() {
90 return _iter->getElement();
91 }
92
begin() const93 LuaTable::iterator LuaTable::begin() const {
94 iterator iter(*this);
95
96 // This will call lua_next and automatically handle the end of the table
97 return iter;
98 }
end() const99 LuaTable::iterator LuaTable::end() const { // NOLINT(readability-convert-member-functions-to-static)
100 return iterator(); // Empty iterator
101 }
102
LuaTableIterator(const LuaTable & t)103 LuaTableIterator::LuaTableIterator(const LuaTable& t) : _luaState(t.getLuaState()) {
104 _stackTop = lua_gettop(_luaState);
105
106 t.pushValue(_luaState);
107 lua_pushnil(_luaState);
108
109 toNextElement();
110 }
~LuaTableIterator()111 LuaTableIterator::~LuaTableIterator() {
112 lua_settop(_luaState, _stackTop);
113 }
hasElement()114 bool LuaTableIterator::hasElement() {
115 return _hasElement;
116 }
toNextElement()117 void LuaTableIterator::toNextElement() {
118 auto ret = lua_next(_luaState, -2);
119
120 _hasElement = ret != 0;
121
122 if (_hasElement) {
123 LuaValue key;
124 key.setReference(UniqueLuaReference::create(_luaState, -2));
125
126 LuaValue value;
127 value.setReference(UniqueLuaReference::create(_luaState, -1));
128
129 _currentVal = std::make_pair(key, value);
130
131 // Remove value from stack
132 lua_pop(_luaState, 1);
133 }
134 }
getElement()135 std::pair<LuaValue, LuaValue> LuaTableIterator::getElement() {
136 return _currentVal;
137 }
138
popValue(lua_State * luaState,LuaTable & target,int stackposition,bool remove)139 bool convert::popValue(lua_State* luaState, LuaTable& target, int stackposition, bool remove) {
140 if (!internal::isValidIndex(luaState, stackposition)) {
141 return false;
142 }
143
144 if (!lua_istable(luaState, stackposition)) {
145 return false;
146 } else {
147 target.setReference(UniqueLuaReference::create(luaState, stackposition));
148
149 if (remove) {
150 lua_remove(luaState, stackposition);
151 }
152
153 return true;
154 }
155 }
156
157 }
158