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