*** empty log message ***
[luabind.git] / luabind / functor.hpp
blobccb38f4c8d3fc8a09ba6318f3b750766ab184f69
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/prefix.hpp>
36 #include <luabind/config.hpp>
37 #include <luabind/detail/policy.hpp>
38 #include <luabind/detail/convert_to_lua.hpp>
39 #include <luabind/detail/pcall.hpp>
40 #include <luabind/error.hpp>
41 #include <luabind/detail/stack_utils.hpp>
43 namespace luabind
45 //template<class Ret>
46 //class functor;
48 namespace detail
51 struct functor_from;
54 // if the proxy_functor_caller returns non-void
55 template<class Ret, class Tuple>
56 class proxy_functor_caller
58 // template<class T> friend class luabind::functor;
59 public:
61 proxy_functor_caller(luabind::functor<Ret>* o, const Tuple args)
62 : m_func(o)
63 , m_args(args)
64 , m_called(false)
68 proxy_functor_caller(const proxy_functor_caller& rhs)
69 : m_func(rhs.m_func)
70 , m_args(rhs.m_args)
71 , m_called(rhs.m_called)
73 rhs.m_called = true;
76 ~proxy_functor_caller()
78 if (m_called) return;
80 m_called = true;
81 lua_State* L = m_func->lua_state();
83 // get the function
84 m_func->pushvalue();
86 push_args_from_tuple<1>::apply(L, m_args);
87 if (pcall(L, boost::tuples::length<Tuple>::value, 0))
89 #ifndef LUABIND_NO_EXCEPTIONS
90 throw luabind::error(L);
91 #else
92 error_callback_fun e = get_error_callback();
93 if (e) e(L);
95 assert(0 && "the lua function threw an error and exceptions are disabled."
96 "if you want to handle this error use luabind::set_error_callback()");
97 std::terminate();
98 #endif
102 operator Ret()
104 typename default_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
106 m_called = true;
107 lua_State* L = m_func->lua_state();
108 #ifndef LUABIND_NO_ERROR_CHECKING
109 if (L == 0)
111 #ifndef LUABIND_NO_EXCEPTIONS
112 throw error(L);
113 #else
114 error_callback_fun e = get_error_callback();
115 if (e) e(L);
117 assert(0 && "tried to call uninitialized functor object."
118 "if you want to handle this error use luabind::set_error_callback()");
119 std::terminate();
120 #endif
122 #endif
125 detail::stack_pop p(L, 1); // pop the return value
127 // get the function
128 m_func->pushvalue();
130 push_args_from_tuple<1>::apply(L, m_args);
131 if (pcall(L, boost::tuples::length<Tuple>::value, 1))
133 #ifndef LUABIND_NO_EXCEPTIONS
134 throw luabind::error(L);
135 #else
136 error_callback_fun e = get_error_callback();
137 if (e) e(L);
139 assert(0 && "the lua function threw an error and exceptions are disabled."
140 "if you want to handle this error use luabind::set_error_callback()");
141 std::terminate();
142 #endif
145 #ifndef LUABIND_NO_ERROR_CHECKING
147 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
149 #ifndef LUABIND_NO_EXCEPTIONS
150 throw cast_failed(L, LUABIND_TYPEID(Ret));
151 #else
152 cast_failed_callback_fun e = get_cast_failed_callback();
153 if (e) e(L, LUABIND_TYPEID(Ret));
155 assert(0 && "the lua function's return value could not be converted."
156 "if you want to handle this error use luabind::set_error_callback()");
157 std::terminate();
158 #endif
160 #endif
161 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
164 template<class Policies>
165 Ret operator[](const Policies& p)
167 typedef typename detail::find_conversion_policy<0, Policies>::type converter_policy;
168 typename converter_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
170 m_called = true;
171 lua_State* L = m_func->lua_state();
172 #ifndef LUABIND_NO_ERROR_CHECKING
173 if (L == 0)
175 #ifndef LUABIND_NO_EXCEPTIONS
176 throw error(L);
177 #else
178 error_callback_fun e = get_error_callback();
179 if (e) e(L);
181 assert(0 && "tried to call uninitialized functor object."
182 "if you want to handle this error use luabind::set_error_callback()");
183 std::terminate();
184 #endif
186 #endif
188 detail::stack_pop popper(L, 1); // pop the return value
190 // get the function
191 m_func->pushvalue();
193 detail::push_args_from_tuple<1>::apply(L, m_args, p);
194 if (pcall(L, boost::tuples::length<Tuple>::value, 1))
196 #ifndef LUABIND_NO_EXCEPTIONS
197 throw error(L);
198 #else
199 error_callback_fun e = get_error_callback();
200 if (e) e(L);
202 assert(0 && "the lua function threw an error and exceptions are disabled."
203 "if you want to handle this error use luabind::set_error_callback()");
204 std::terminate();
205 #endif
208 #ifndef LUABIND_NO_ERROR_CHECKING
210 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
212 #ifndef LUABIND_NO_EXCEPTIONS
213 throw cast_failed(L, LUABIND_TYPEID(Ret));
214 #else
215 cast_failed_callback_fun e = get_cast_failed_callback();
216 if (e) e(L, LUABIND_TYPEID(Ret));
218 assert(0 && "the lua function's return value could not be converted."
219 "if you want to handle this error use luabind::set_error_callback()");
220 std::terminate();
221 #endif
223 #endif
224 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
227 private:
229 luabind::functor<Ret>* m_func;
230 Tuple m_args;
231 mutable bool m_called;
235 // if the proxy_member_caller returns void
236 template<class Tuple>
237 class proxy_functor_void_caller
239 // template<class T> friend class luabind::functor;
240 public:
242 proxy_functor_void_caller(luabind::functor<void>* o, const Tuple args)
243 : m_func(o)
244 , m_args(args)
245 , m_called(false)
249 proxy_functor_void_caller(const proxy_functor_void_caller& rhs)
250 : m_func(rhs.m_func)
251 , m_args(rhs.m_args)
252 , m_called(rhs.m_called)
254 rhs.m_called = true;
257 ~proxy_functor_void_caller()
259 if (m_called) return;
261 m_called = true;
262 lua_State* L = m_func->lua_state();
263 #ifndef LUABIND_NO_ERROR_CHECKING
264 if (L == 0)
266 #ifndef LUABIND_NO_EXCEPTIONS
267 throw error(L);
268 #else
269 error_callback_fun e = get_error_callback();
270 if (e) e(L);
272 assert(0 && "tried to call uninitialized functor object."
273 "if you want to handle this error use luabind::set_error_callback()");
274 std::terminate();
275 #endif
277 #endif
280 // get the function
281 m_func->pushvalue();
283 push_args_from_tuple<1>::apply(L, m_args);
284 if (pcall(L, boost::tuples::length<Tuple>::value, 0))
286 #ifndef LUABIND_NO_EXCEPTIONS
287 throw luabind::error(L);
288 #else
289 error_callback_fun e = get_error_callback();
290 if (e) e(L);
292 assert(0 && "the lua function threw an error and exceptions are disabled."
293 "if you want to handle this error use luabind::set_error_callback()");
294 std::terminate();
295 #endif
299 template<class Policies>
300 void operator[](const Policies& p)
302 m_called = true;
303 lua_State* L = m_func->lua_state();
304 #ifndef LUABIND_NO_ERROR_CHECKING
305 if (L == 0)
307 #ifndef LUABIND_NO_EXCEPTIONS
308 throw error(L);
309 #else
310 error_callback_fun e = get_error_callback();
311 if (e) e(L);
313 assert(0 && "tried to call uninitialized functor object."
314 "if you want to handle this error use luabind::set_error_callback()");
315 std::terminate();
316 #endif
318 #endif
321 // get the function
322 m_func->pushvalue();
324 detail::push_args_from_tuple<1>::apply(L, m_args, p);
325 if (pcall(L, boost::tuples::length<Tuple>::value, 0))
327 #ifndef LUABIND_NO_EXCEPTIONS
328 throw error(L);
329 #else
330 error_callback_fun e = get_error_callback();
331 if (e) e(L);
333 assert(0 && "the lua function threw an error and exceptions are disabled."
334 "if you want to handle this error use luabind::set_error_callback()");
335 std::terminate();
336 #endif
340 private:
342 luabind::functor<void>* m_func;
343 Tuple m_args;
344 mutable bool m_called;
348 } // detail
350 template<class Ret>
351 class functor
353 public:
355 functor(lua_State* L, const char* name)
356 : L_(L)
358 lua_pushstring(L, name);
359 lua_gettable(L, LUA_GLOBALSINDEX);
360 ref_.set(L_);
363 functor()
364 : L_(0)
368 functor(const functor<Ret>& obj)
369 : L_(obj.L_)
370 , ref_(obj.ref_)
374 // this is a safe substitute for an implicit converter to bool
375 typedef void (functor::*member_ptr)() const;
376 operator member_ptr() const
378 if (is_valid()) return &functor::dummy;
379 return 0;
382 const functor<Ret>& operator=(const functor<Ret>& rhs)
384 L_ = rhs.L_;
385 ref_ = rhs.ref_;
386 return *this;
389 bool operator==(const functor<Ret>& rhs) const
391 if (!ref_.is_valid() || !rhs.ref_.is_valid()) return false;
392 pushvalue();
393 rhs.pushvalue();
394 bool result = lua_equal(L_, -1, -2) != 0;
395 lua_pop(L_, 2);
396 return result;
399 bool operator!=(const functor<Ret>& rhs) const
401 if (!ref_.is_valid() || !rhs.ref_.is_valid()) return true;
402 pushvalue();
403 rhs.pushvalue();
404 bool result = lua_equal(L_, -1, -2) == 0;
405 lua_pop(L_, 2);
406 return result;
409 inline bool is_valid() const { return ref_.is_valid(); }
411 lua_State* lua_state() const { return L_; }
412 void pushvalue() const { ref_.get(L_); }
414 void reset()
416 L_ = 0;
417 ref_.reset();
420 #define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUABIND_MAX_ARITY, <luabind/functor.hpp>, 1))
421 #include BOOST_PP_ITERATE()
423 // TODO: should be private
425 functor(lua_State* L, detail::lua_reference const& ref)
426 : L_(L)
427 , ref_(ref)
431 private:
433 void dummy() const {}
435 lua_State* L_;
436 detail::lua_reference ref_;
440 #endif // LUABIND_FUNCTOR_HPP_INCLUDED
442 #else
444 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
445 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
447 #if BOOST_PP_ITERATION() > 0
448 template<BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
449 #endif
450 typename boost::mpl::if_<boost::is_void<Ret>
451 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
452 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
453 operator()(BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _)) const
455 typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
456 #if BOOST_PP_ITERATION() == 0
457 tuple_t args;
458 #else
459 tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
460 #endif
462 typedef typename boost::mpl::if_<boost::is_void<Ret>
463 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
464 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
466 return proxy_type(const_cast<luabind::functor<Ret>*>(this), args);
469 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
470 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
472 #endif