added finalizers
[luabind.git] / luabind / scope.hpp
blob9f799c08b96520fc6b9698e2aa72c92bcb790b66
1 // Copyright (c) 2003 Daniel Wallin and Arvid Norberg
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the "Software"),
5 // to deal in the Software without restriction, including without limitation
6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 // and/or sell copies of the Software, and to permit persons to whom the
8 // Software is furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included
11 // in all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
24 #ifndef LUABIND_SCOPE_HPP_INCLUDED
25 #define LUABIND_SCOPE_HPP_INCLUDED
27 #include <vector>
28 #include <string>
29 #include <stack>
31 #include <luabind/detail/ref.hpp>
33 namespace luabind
35 namespace detail
37 struct scoped_sequence;
39 struct scoped_object
41 scoped_object()
45 virtual ~scoped_object() {}
47 virtual void commit(lua_State*) = 0;
48 virtual scoped_object* clone() = 0;
50 scoped_sequence operator,(const scoped_object& rhs) const;
53 struct scoped_sequence : scoped_object
55 scoped_sequence(scoped_object* a, scoped_object* b)
57 this->objects.push_back(a);
58 this->objects.push_back(b);
61 scoped_sequence() {}
63 virtual ~scoped_sequence()
65 for (std::vector<scoped_object*>
66 ::const_iterator i = this->objects.begin()
67 ; i != this->objects.end()
68 ; ++i)
70 scoped_object* ptr = *i;
71 delete ptr;
75 scoped_sequence& operator,(const scoped_object& rhs)
77 objects.push_back(const_cast<scoped_object&>(rhs).clone());
78 return *this;
81 virtual scoped_object* clone()
83 scoped_sequence* copy = new scoped_sequence();
84 copy->objects.swap(this->objects);
85 return copy;
88 virtual void commit(lua_State* L)
90 for (std::vector<scoped_object*>
91 ::const_iterator i = this->objects.begin()
92 ; i != this->objects.end()
93 ; ++i)
95 scoped_object* ptr = *i;
96 ptr->commit(L);
100 mutable std::vector<scoped_object*> objects;
103 inline scoped_sequence scoped_object::operator,(const scoped_object& rhs) const
105 return scoped_sequence(const_cast<scoped_object*>(this)->clone(), const_cast<scoped_object&>(rhs).clone());
109 struct scope_stack
111 std::stack<int> scopes;
113 static int gc(lua_State* L)
115 scope_stack* scopes = static_cast<scope_stack*>(
116 lua_touserdata(L, -1)
119 assert(scopes->scopes.size() == 1);
121 int top = scopes->scopes.top();
122 scopes->scopes.pop();
124 detail::unref(L, top);
126 scopes->~scope_stack();
128 return 0;
131 static int top(lua_State* L)
133 lua_pushstring(L, "__luabind_scope_stack");
134 lua_gettable(L, LUA_REGISTRYINDEX);
136 scope_stack* scopes = static_cast<scope_stack*>(
137 lua_touserdata(L, -1)
140 lua_pop(L, 1);
142 return scopes->scopes.top();
145 static void push(lua_State* L)
147 lua_pushstring(L, "__luabind_scope_stack");
148 lua_gettable(L, LUA_REGISTRYINDEX);
150 scope_stack* scopes = static_cast<scope_stack*>(
151 lua_touserdata(L, -1)
154 lua_pop(L, 1);
156 scopes->scopes.push(detail::ref(L));
159 static void pop(lua_State* L)
161 lua_pushstring(L, "__luabind_scope_stack");
162 lua_gettable(L, LUA_REGISTRYINDEX);
164 scope_stack* scopes = static_cast<scope_stack*>(
165 lua_touserdata(L, -1)
168 lua_pop(L, 1);
170 int n = scopes->scopes.top();
171 scopes->scopes.pop();
172 detail::unref(L, n);
176 class scope : public detail::scoped_object
178 public:
180 static void init(lua_State* L)
182 lua_pushstring(L, "__luabind_scope_stack");
183 lua_gettable(L, LUA_REGISTRYINDEX);
185 scope_stack* scopes = static_cast<scope_stack*>(
186 lua_touserdata(L, -1)
189 lua_pop(L, 1);
191 if (scopes == 0)
193 scopes = static_cast<scope_stack*>(
194 lua_newuserdata(L, sizeof(scope_stack))
197 lua_pushstring(L, "__luabind_scope_stack");
198 lua_pushvalue(L, -2);
199 lua_settable(L, LUA_REGISTRYINDEX);
201 new (scopes) scope_stack();
203 lua_pushvalue(L, LUA_GLOBALSINDEX);
204 scopes->scopes.push(detail::ref(L));
206 lua_newtable(L);
207 lua_pushstring(L, "__gc");
208 lua_pushcclosure(L, scope_stack::gc, 0);
209 lua_settable(L, -3);
210 lua_setmetatable(L, -2);
212 lua_pop(L, 1);
216 scope(lua_State* L, const char* name)
217 : m_state(L)
218 , m_name(name)
220 init(L);
223 scope(const char* name)
224 : m_state(0)
225 , m_name(name)
229 virtual ~scope()
231 for (std::vector<detail::scoped_object*>
232 ::const_iterator i = m_children.begin()
233 ; i != m_children.end()
234 ; ++i)
236 detail::scoped_object* ptr = *i;
237 delete ptr;
241 scope& operator[](detail::scoped_object& x)
243 m_children.push_back(x.clone());
245 if (m_state)
247 this->commit(m_state);
249 for (std::vector<detail::scoped_object*>
250 ::const_iterator i = m_children.begin()
251 ; i != m_children.end()
252 ; ++i)
254 detail::scoped_object* ptr = *i;
255 delete ptr;
258 m_children.clear();
261 return *this;
264 virtual detail::scoped_object* clone()
266 std::vector<detail::scoped_object*> tmp;
267 tmp.swap(this->m_children);
268 scope* copy = new scope(m_name.c_str());
269 copy->m_children.swap(tmp);
270 return copy;
273 virtual void commit(lua_State* L)
275 init(L);
277 detail::getref(L, scope_stack::top(L)); // get current scope
278 lua_pushstring(L, m_name.c_str());
279 lua_gettable(L, -2);
280 lua_remove(L, -2); // remove scope
282 if (lua_isnil(L, -1))
284 lua_pop(L, 1);
286 lua_newtable(L);
287 detail::getref(L, scope_stack::top(L));
288 lua_pushstring(L, m_name.c_str());
289 lua_pushvalue(L, -3);
290 lua_settable(L, -3);
291 lua_pop(L, 1);
294 scope_stack::push(L);
296 for (std::vector<detail::scoped_object*>
297 ::const_iterator i = m_children.begin()
298 ; i != m_children.end()
299 ; ++i)
301 detail::scoped_object* ptr = *i;
302 ptr->commit(L);
305 scope_stack::pop(L);
308 private:
310 mutable std::vector<detail::scoped_object*> m_children;
311 lua_State* m_state;
312 std::string m_name;
315 typedef scope namespace_;
318 #endif // LUABIND_SCOPE_HPP_INCLUDED