*** empty log message ***
[luabind.git] / luabind / functor.hpp
blob7644252d7641d2f7053abe15ecd7378c840b8f4c
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.
23 #if !BOOST_PP_IS_ITERATING
25 #ifndef LUABIND_FUNCTOR_HPP_INCLUDED
26 #define LUABIND_FUNCTOR_HPP_INCLUDED
28 #include <boost/preprocessor/repeat.hpp>
29 #include <boost/preprocessor/repetition/enum_params.hpp>
30 #include <boost/preprocessor/repetition/enum_params.hpp>
31 #include <boost/preprocessor/iteration/iterate.hpp>
32 #include <boost/type_traits/is_void.hpp>
33 #include <boost/mpl/if.hpp>
35 #include <luabind/config.hpp>
36 #include <luabind/detail/policy.hpp>
37 #include <luabind/detail/convert_to_lua.hpp>
38 #include <luabind/detail/error.hpp>
40 namespace luabind
42 //template<class Ret>
43 //class functor;
45 namespace detail
48 struct functor_from;
51 // if the proxy_functor_caller returns non-void
52 template<class Ret, class Tuple>
53 class proxy_functor_caller
55 // template<class T> friend class luabind::functor;
56 public:
58 proxy_functor_caller(luabind::functor<Ret>* o, const Tuple args)
59 : m_func(o)
60 , m_args(args)
61 , m_called(false)
65 proxy_functor_caller(const proxy_functor_caller& rhs)
66 : m_func(rhs.m_func)
67 , m_args(rhs.m_args)
68 , m_called(rhs.m_called)
70 rhs.m_called = true;
73 ~proxy_functor_caller()
75 if (m_called) return;
77 m_called = true;
78 lua_State* L = m_func->lua_state();
80 // get the function
81 m_func->pushvalue();
83 push_args_from_tuple<1>::apply(L, m_args);
84 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
86 #ifndef LUABIND_NO_EXCEPTIONS
87 throw luabind::error();
88 #else
89 assert(0);
90 #endif
94 operator Ret()
96 typename default_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
98 m_called = true;
99 lua_State* L = m_func->lua_state();
100 detail::stack_pop p(L, 1); // pop the return value
102 // get the function
103 m_func->pushvalue();
105 push_args_from_tuple<1>::apply(L, m_args);
106 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 1, 0))
108 #ifndef LUABIND_NO_EXCEPTIONS
109 throw luabind::error();
110 #else
111 assert(0);
112 #endif
115 #ifndef LUABIND_NO_ERROR_CHECKING
116 #ifndef LUABIND_NO_EXCEPTIONS
118 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
120 throw cant_convert_return_value();
122 #else
123 assert(converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) >= 0);
124 #endif
125 #endif
126 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
129 template<class Policies>
130 Ret operator[](const Policies& p)
132 typedef typename detail::find_conversion_policy<0, Policies>::type converter_policy;
133 typename converter_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
135 m_called = true;
136 lua_State* L = m_func->lua_state();
137 detail::stack_pop popper(L, 1); // pop the return value
139 // get the function
140 m_func->pushvalue();
142 detail::push_args_from_tuple<1>::apply(L, m_args, p);
143 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 1, 0))
145 #ifndef LUABIND_NO_EXCEPTIONS
146 throw error();
147 #else
148 assert(0);
149 #endif
152 #ifndef LUABIND_NO_ERROR_CHECKING
153 #ifndef LUABIND_NO_EXCEPTIONS
155 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
157 throw cant_convert_return_value();
159 #else
160 assert(converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) >= 0);
161 #endif
162 #endif
163 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
166 private:
168 luabind::functor<Ret>* m_func;
169 Tuple m_args;
170 mutable bool m_called;
174 // if the proxy_member_caller returns void
175 template<class Tuple>
176 class proxy_functor_void_caller
178 // template<class T> friend class luabind::functor;
179 public:
181 proxy_functor_void_caller(luabind::functor<void>* o, const Tuple args)
182 : m_func(o)
183 , m_args(args)
184 , m_called(false)
188 proxy_functor_void_caller(const proxy_functor_void_caller& rhs)
189 : m_func(rhs.m_func)
190 , m_args(rhs.m_args)
191 , m_called(rhs.m_called)
193 rhs.m_called = true;
196 ~proxy_functor_void_caller()
198 if (m_called) return;
200 m_called = true;
201 lua_State* L = m_func->lua_state();
203 // get the function
204 m_func->pushvalue();
206 push_args_from_tuple<1>::apply(L, m_args);
207 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
209 #ifndef LUABIND_NO_EXCEPTIONS
210 throw luabind::error();
211 #else
212 assert(0);
213 #endif
217 template<class Policies>
218 void operator[](const Policies& p)
220 m_called = true;
221 lua_State* L = m_func->lua_state();
223 // get the function
224 m_func->pushvalue();
226 detail::push_args_from_tuple<1>::apply(L, m_args, p);
227 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
229 #ifndef LUABIND_NO_EXCEPTIONS
230 throw error();
231 #else
232 assert(0);
233 #endif
237 private:
239 luabind::functor<void>* m_func;
240 Tuple m_args;
241 mutable bool m_called;
245 } // detail
247 template<class Ret>
248 class functor
250 public:
252 functor(lua_State* L, const char* name) : L_(L)
254 lua_pushstring(L, name);
255 lua_gettable(L, LUA_GLOBALSINDEX);
256 ref_ = detail::ref(L);
259 functor()
260 : L_(0)
261 , ref_(LUA_NOREF)
265 functor(const functor<Ret>& obj): L_(obj.L_)
267 lua_getref(L_, obj.ref_);
268 ref_ = detail::ref(L_);
271 ~functor()
273 if (ref_ != LUA_NOREF) detail::unref(L_, ref_);
276 // this is a safe substitute for an implicit converter to bool
277 typedef void (functor::*member_ptr)() const;
278 operator member_ptr() const
280 if (is_valid()) return &functor::dummy;
281 return 0;
284 const functor<Ret>& operator=(const functor<Ret>& rhs)
286 L_ = rhs.L_;
287 lua_getref(L_, rhs.ref_);
288 ref_ = detail::ref(L_);
289 return *this;
292 bool operator==(const functor<Ret>& rhs) const
294 if (ref_ == LUA_NOREF || rhs.ref_ == LUA_NOREF) return false;
295 pushvalue();
296 rhs.pushvalue();
297 bool result = lua_equal(L_, -1, -2) != 0;
298 lua_pop(L_, 2);
299 return result;
302 bool operator!=(const functor<Ret>& rhs) const
304 if (ref_ == LUA_NOREF || rhs.ref_ == LUA_NOREF) return true;
305 pushvalue();
306 rhs.pushvalue();
307 bool result = lua_equal(L_, -1, -2) == 0;
308 lua_pop(L_, 2);
309 return result;
312 inline bool is_valid() const { return ref_ != LUA_NOREF; }
314 lua_State* lua_state() const { return L_; }
315 void pushvalue() const { lua_getref(L_, ref_); }
317 #define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUABIND_MAX_ARITY, <luabind/functor.hpp>, 1))
318 #include BOOST_PP_ITERATE()
320 // TODO: should be private
322 functor(lua_State* L, int ref)
323 : L_(L)
324 , ref_(ref)
328 private:
330 void dummy() const {}
332 lua_State* L_;
333 int ref_;
337 #endif // LUABIND_FUNCTOR_HPP_INCLUDED
339 #else
341 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
342 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
344 #if BOOST_PP_ITERATION() > 0
345 template<BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
346 #endif
347 typename boost::mpl::if_<boost::is_void<Ret>
348 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
349 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
350 operator()(BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _)) const
352 typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
353 #if BOOST_PP_ITERATION() == 0
354 tuple_t args;
355 #else
356 tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
357 #endif
359 typedef typename boost::mpl::if_<boost::is_void<Ret>
360 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
361 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
363 return proxy_type(const_cast<luabind::functor<Ret>*>(this), args);
366 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
367 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
369 #endif