Line data Source code
1 : // LICENSE HEADER
2 :
3 : #include "lua_table_handle.h"
4 : #include <iostream>
5 : #include <assert.h>
6 : #include "common/util/variant.h"
7 :
8 : extern "C" {
9 : #include "externals/lua/lua.h"
10 : #include "externals/lua/lauxlib.h"
11 : #include "externals/lua/lualib.h"
12 : #include "externals/lua/ldo.h"
13 : }
14 :
15 : #define untested() ( std::cerr << "@@#\n@@@:"<< __FILE__ << ":"<< __LINE__ \
16 : <<":" << __func__ << "\n" )
17 :
18 : namespace ug {
19 : namespace impl {
20 :
21 0 : static ug::Variant pop2var(lua_State* _L)
22 : {
23 0 : int t = lua_type(_L, -1);
24 0 : ug::Variant ret;
25 :
26 0 : if(t == LUA_TTABLE){
27 0 : LuaTableHandle h(_L, -1);
28 0 : ret = ug::Variant(h);
29 0 : }else if(t == LUA_TNUMBER){
30 0 : number n = lua_tonumber(_L, -1);
31 0 : ret = ug::Variant(n);
32 0 : }else if(t == LUA_TBOOLEAN){
33 0 : bool b = lua_toboolean(_L, -1);
34 0 : ret = ug::Variant(b);
35 0 : }else if(lua_isstring(_L, -1)){
36 0 : std::string s(lua_tostring(_L, -1));
37 0 : ret = ug::Variant(s);
38 0 : }else if(t == LUA_TNIL){
39 : }else{
40 0 : std::cerr << "type not handled " << t << "\n";
41 : }
42 :
43 0 : return ret;
44 0 : }
45 :
46 : struct LuaTableHandle_{
47 : public:
48 : LuaTableHandle_(lua_State*, int);
49 : ~LuaTableHandle_();
50 : lua_State* _L{nullptr};
51 : int _ref{0};
52 : int _index{0};
53 :
54 : bool operator==(LuaTableHandle_ const& o) const{
55 0 : return _ref == o._ref;
56 : }
57 : bool operator!=(LuaTableHandle_ const& o) const{
58 : return !operator==(o);
59 : }
60 :
61 0 : static void attach(LuaTableHandle_* c, LuaTableHandle_** to) {
62 : assert(to);
63 0 : if (c == *to) { untested();
64 0 : }else if (!c) { untested();
65 0 : detach(to);
66 0 : }else if (!*to) {
67 0 : ++(c->_attach_count);
68 0 : *to = c;
69 0 : }else if (*c != **to) {
70 : // They are different, usually by edit.
71 0 : detach(to);
72 0 : ++(c->_attach_count);
73 0 : *to = c;
74 0 : }else if (c->_attach_count == 0) { untested();
75 : // The new and old are identical.
76 : // Use the old one.
77 : // The new one is not used anywhere, so throw it away.
78 0 : delete c;
79 0 : }else{ untested();
80 : // The new and old are identical.
81 : // Use the old one.
82 : // The new one is also used somewhere else, so keep it.
83 : }
84 0 : }
85 0 : static void detach(LuaTableHandle_** from) {
86 : assert(from);
87 0 : if (*from) {
88 : assert((**from)._attach_count > 0);
89 0 : --((**from)._attach_count);
90 0 : if ((**from)._attach_count == 0) { untested();
91 0 : delete *from;
92 : }else{
93 : }
94 0 : *from = NULL;
95 : }else{
96 : }
97 0 : }
98 :
99 : size_t size() const{
100 : size_t n = 0;
101 : #if 0 // count them. skip nils.
102 : lua_pushnil(_L);
103 : while (lua_next(_L, _index) != 0) { untested();
104 : lua_pop(_L, 1);
105 : ++n;
106 : }
107 : #else
108 0 : n = lua_objlen(_L, _index);
109 : #endif
110 : return n;
111 : }
112 :
113 0 : ug::Variant get(int const& key) const{
114 0 : lua_rawgeti(_L, LUA_REGISTRYINDEX, _ref);
115 0 : lua_rawgeti(_L, _index, key+1); // lua starts at 1.
116 :
117 0 : ug::Variant ret = pop2var(_L);
118 :
119 0 : lua_pop(_L, 1); // pop value
120 0 : lua_pop(_L, 1); // pop ref
121 :
122 0 : return ret;
123 0 : }
124 0 : ug::Variant get(std::string const& key) const{
125 0 : lua_rawgeti(_L, LUA_REGISTRYINDEX, _ref);
126 0 : lua_getfield(_L, _index, key.c_str());
127 :
128 : // std::cerr << "getfield " << key << " type " << lua_type(_L, -1) << "\n";
129 :
130 0 : ug::Variant ret = pop2var(_L);
131 :
132 0 : lua_pop(_L, 1); // pop value
133 0 : lua_pop(_L, 1); // pop ref
134 0 : return ret;
135 0 : }
136 :
137 : // int get_int() const { }
138 :
139 : private:
140 : int _attach_count{0};
141 : };
142 :
143 0 : LuaTableHandle_::LuaTableHandle_(lua_State* L, int index)
144 : {
145 0 : lua_pushvalue(L, index); // copy table to top of stack.
146 0 : int ref = luaL_ref(L, LUA_REGISTRYINDEX); // pops copy from stack
147 :
148 0 : _ref = ref;
149 0 : _L = L;
150 0 : _index = index;
151 :
152 0 : _attach_count = 0;
153 0 : }
154 :
155 0 : LuaTableHandle_::~LuaTableHandle_()
156 0 : { untested();
157 : assert(!_attach_count);
158 :
159 : // drop reference to table from index.
160 0 : luaL_unref(_L, LUA_REGISTRYINDEX, _ref);
161 0 : }
162 :
163 : } // impl
164 :
165 0 : LuaTableHandle::LuaTableHandle(lua_State* L, int index)
166 0 : : _data(nullptr)
167 : {
168 0 : auto d = new impl::LuaTableHandle_(L, index);
169 0 : impl::LuaTableHandle_::attach(d, &_data);
170 : //lua_settable(L, 0); // lapi.c?
171 : //lua_gettop(L); // lapi.c?
172 0 : }
173 :
174 0 : LuaTableHandle::LuaTableHandle(LuaTableHandle const& p)
175 0 : : _data(nullptr)
176 : {
177 0 : impl::LuaTableHandle_::attach(p._data, &_data);
178 0 : }
179 :
180 0 : LuaTableHandle::LuaTableHandle(LuaTableHandle&& p)
181 0 : : _data(nullptr)
182 : {
183 0 : impl::LuaTableHandle_::attach(p._data, &_data);
184 0 : impl::LuaTableHandle_::detach(&p._data);
185 0 : }
186 :
187 0 : LuaTableHandle::~LuaTableHandle()
188 : {
189 0 : impl::LuaTableHandle_::detach(&_data);
190 0 : }
191 :
192 :
193 0 : LuaTableHandle& LuaTableHandle::operator=(LuaTableHandle const& p)
194 0 : { untested();
195 0 : impl::LuaTableHandle_::attach(p._data, &_data);
196 0 : return *this;
197 : }
198 :
199 0 : LuaTableHandle& LuaTableHandle::operator=(LuaTableHandle&& p)
200 : {
201 0 : impl::LuaTableHandle_::attach(p._data, &_data);
202 0 : impl::LuaTableHandle_::detach(&p._data);
203 0 : return *this;
204 : }
205 :
206 0 : size_t LuaTableHandle::size() const
207 : {
208 : assert(_data);
209 0 : return _data->size();
210 : }
211 :
212 0 : ug::Variant LuaTableHandle::get(std::string const& key) const
213 : {
214 : assert(_data);
215 0 : return _data->get(key);
216 : }
217 :
218 0 : ug::Variant LuaTableHandle::get(int const& key) const
219 : {
220 : assert(_data);
221 0 : return _data->get(key);
222 : }
223 :
224 : } // ug
|