*** empty log message ***
[luabind.git] / luabind / functor.hpp
blob3f45369c2242a9e1ad96d807a349a63be63f33a8
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/error.hpp>
41 namespace luabind
43 //template<class Ret>
44 //class functor;
46 namespace detail
49 struct functor_from;
52 // if the proxy_functor_caller returns non-void
53 template<class Ret, class Tuple>
54 class proxy_functor_caller
56 // template<class T> friend class luabind::functor;
57 public:
59 proxy_functor_caller(luabind::functor<Ret>* o, const Tuple args)
60 : m_func(o)
61 , m_args(args)
62 , m_called(false)
66 proxy_functor_caller(const proxy_functor_caller& rhs)
67 : m_func(rhs.m_func)
68 , m_args(rhs.m_args)
69 , m_called(rhs.m_called)
71 rhs.m_called = true;
74 ~proxy_functor_caller()
76 if (m_called) return;
78 m_called = true;
79 lua_State* L = m_func->lua_state();
81 // get the function
82 m_func->pushvalue();
84 push_args_from_tuple<1>::apply(L, m_args);
85 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
87 #ifndef LUABIND_NO_EXCEPTIONS
88 throw luabind::error(L);
89 #else
90 error_callback_fun e = detail::error_callback::get().err;
91 if (e) e(L);
93 assert(0 && "the lua function threw an error and exceptions are disabled."
94 "if you want to handle this error use luabind::set_error_callback()");
95 std::terminate();
96 #endif
100 operator Ret()
102 typename default_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
104 m_called = true;
105 lua_State* L = m_func->lua_state();
106 #ifndef LUABIND_NO_ERROR_CHECKING
107 if (L == 0)
109 #ifndef LUABIND_NO_EXCEPTIONS
110 throw error(L);
111 #else
112 error_callback_fun e = detail::error_callback::get().err;
113 if (e) e(L);
115 assert(0 && "tried to call uninitialized functor object."
116 "if you want to handle this error use luabind::set_error_callback()");
117 std::terminate();
118 #endif
120 #endif
123 detail::stack_pop p(L, 1); // pop the return value
125 // get the function
126 m_func->pushvalue();
128 push_args_from_tuple<1>::apply(L, m_args);
129 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 1, 0))
131 #ifndef LUABIND_NO_EXCEPTIONS
132 throw luabind::error(L);
133 #else
134 error_callback_fun e = detail::error_callback::get().err;
135 if (e) e(L);
137 assert(0 && "the lua function threw an error and exceptions are disabled."
138 "if you want to handle this error use luabind::set_error_callback()");
139 std::terminate();
140 #endif
143 #ifndef LUABIND_NO_ERROR_CHECKING
145 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
147 #ifndef LUABIND_NO_EXCEPTIONS
148 throw cast_failed(L, LUABIND_TYPEID(Ret));
149 #else
150 cast_failed_callback_fun e = detail::error_callback::get().cast;
151 if (e) e(L, LUABIND_TYPEID(Ret));
153 assert(0 && "the lua function's return value could not be converted."
154 "if you want to handle this error use luabind::set_error_callback()");
155 std::terminate();
156 #endif
158 #endif
159 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
162 template<class Policies>
163 Ret operator[](const Policies& p)
165 typedef typename detail::find_conversion_policy<0, Policies>::type converter_policy;
166 typename converter_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
168 m_called = true;
169 lua_State* L = m_func->lua_state();
170 #ifndef LUABIND_NO_ERROR_CHECKING
171 if (L == 0)
173 #ifndef LUABIND_NO_EXCEPTIONS
174 throw error(L);
175 #else
176 error_callback_fun e = detail::error_callback::get().err;
177 if (e) e(L);
179 assert(0 && "tried to call uninitialized functor object."
180 "if you want to handle this error use luabind::set_error_callback()");
181 std::terminate();
182 #endif
184 #endif
186 detail::stack_pop popper(L, 1); // pop the return value
188 // get the function
189 m_func->pushvalue();
191 detail::push_args_from_tuple<1>::apply(L, m_args, p);
192 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 1, 0))
194 #ifndef LUABIND_NO_EXCEPTIONS
195 throw error(L);
196 #else
197 error_callback_fun e = detail::error_callback::get().err;
198 if (e) e(L);
200 assert(0 && "the lua function threw an error and exceptions are disabled."
201 "if you want to handle this error use luabind::set_error_callback()");
202 std::terminate();
203 #endif
206 #ifndef LUABIND_NO_ERROR_CHECKING
208 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
210 #ifndef LUABIND_NO_EXCEPTIONS
211 throw cast_failed(L, LUABIND_TYPEID(Ret));
212 #else
213 cast_failed_callback_fun e = detail::error_callback::get().cast;
214 if (e) e(L, LUABIND_TYPEID(Ret));
216 assert(0 && "the lua function's return value could not be converted."
217 "if you want to handle this error use luabind::set_error_callback()");
218 std::terminate();
219 #endif
221 #endif
222 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
225 private:
227 luabind::functor<Ret>* m_func;
228 Tuple m_args;
229 mutable bool m_called;
233 // if the proxy_member_caller returns void
234 template<class Tuple>
235 class proxy_functor_void_caller
237 // template<class T> friend class luabind::functor;
238 public:
240 proxy_functor_void_caller(luabind::functor<void>* o, const Tuple args)
241 : m_func(o)
242 , m_args(args)
243 , m_called(false)
247 proxy_functor_void_caller(const proxy_functor_void_caller& rhs)
248 : m_func(rhs.m_func)
249 , m_args(rhs.m_args)
250 , m_called(rhs.m_called)
252 rhs.m_called = true;
255 ~proxy_functor_void_caller()
257 if (m_called) return;
259 m_called = true;
260 lua_State* L = m_func->lua_state();
261 #ifndef LUABIND_NO_ERROR_CHECKING
262 if (L == 0)
264 #ifndef LUABIND_NO_EXCEPTIONS
265 throw error(L);
266 #else
267 error_callback_fun e = detail::error_callback::get().err;
268 if (e) e(L);
270 assert(0 && "tried to call uninitialized functor object."
271 "if you want to handle this error use luabind::set_error_callback()");
272 std::terminate();
273 #endif
275 #endif
278 // get the function
279 m_func->pushvalue();
281 push_args_from_tuple<1>::apply(L, m_args);
282 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
284 #ifndef LUABIND_NO_EXCEPTIONS
285 throw luabind::error(L);
286 #else
287 error_callback_fun e = detail::error_callback::get().err;
288 if (e) e(L);
290 assert(0 && "the lua function threw an error and exceptions are disabled."
291 "if you want to handle this error use luabind::set_error_callback()");
292 std::terminate();
293 #endif
297 template<class Policies>
298 void operator[](const Policies& p)
300 m_called = true;
301 lua_State* L = m_func->lua_state();
302 #ifndef LUABIND_NO_ERROR_CHECKING
303 if (L == 0)
305 #ifndef LUABIND_NO_EXCEPTIONS
306 throw error(L);
307 #else
308 error_callback_fun e = detail::error_callback::get().err;
309 if (e) e(L);
311 assert(0 && "tried to call uninitialized functor object."
312 "if you want to handle this error use luabind::set_error_callback()");
313 std::terminate();
314 #endif
316 #endif
319 // get the function
320 m_func->pushvalue();
322 detail::push_args_from_tuple<1>::apply(L, m_args, p);
323 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
325 #ifndef LUABIND_NO_EXCEPTIONS
326 throw error(L);
327 #else
328 error_callback_fun e = detail::error_callback::get().err;
329 if (e) e(L);
331 assert(0 && "the lua function threw an error and exceptions are disabled."
332 "if you want to handle this error use luabind::set_error_callback()");
333 std::terminate();
334 #endif
338 private:
340 luabind::functor<void>* m_func;
341 Tuple m_args;
342 mutable bool m_called;
346 } // detail
348 template<class Ret>
349 class functor
351 public:
353 functor(lua_State* L, const char* name)
354 : L_(L)
356 lua_pushstring(L, name);
357 lua_gettable(L, LUA_GLOBALSINDEX);
358 ref_.set(L_);
361 functor()
362 : L_(0)
366 functor(const functor<Ret>& obj)
367 : L_(obj.L_)
368 , ref_(obj.ref_)
372 // this is a safe substitute for an implicit converter to bool
373 typedef void (functor::*member_ptr)() const;
374 operator member_ptr() const
376 if (is_valid()) return &functor::dummy;
377 return 0;
380 const functor<Ret>& operator=(const functor<Ret>& rhs)
382 L_ = rhs.L_;
383 ref_ = rhs.ref_;
384 return *this;
387 bool operator==(const functor<Ret>& rhs) const
389 if (!ref_.is_valid() || !rhs.ref_.is_valid()) return false;
390 pushvalue();
391 rhs.pushvalue();
392 bool result = lua_equal(L_, -1, -2) != 0;
393 lua_pop(L_, 2);
394 return result;
397 bool operator!=(const functor<Ret>& rhs) const
399 if (!ref_.is_valid() || !rhs.ref_.is_valid()) return true;
400 pushvalue();
401 rhs.pushvalue();
402 bool result = lua_equal(L_, -1, -2) == 0;
403 lua_pop(L_, 2);
404 return result;
407 inline bool is_valid() const { return ref_.is_valid(); }
409 lua_State* lua_state() const { return L_; }
410 void pushvalue() const { ref_.get(L_); }
412 #define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUABIND_MAX_ARITY, <luabind/functor.hpp>, 1))
413 #include BOOST_PP_ITERATE()
415 // TODO: should be private
417 functor(lua_State* L, detail::lua_reference const& ref)
418 : L_(L)
419 , ref_(ref)
423 private:
425 void dummy() const {}
427 lua_State* L_;
428 detail::lua_reference ref_;
432 #endif // LUABIND_FUNCTOR_HPP_INCLUDED
434 #else
436 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
437 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
439 #if BOOST_PP_ITERATION() > 0
440 template<BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
441 #endif
442 typename boost::mpl::if_<boost::is_void<Ret>
443 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
444 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
445 operator()(BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _)) const
447 typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
448 #if BOOST_PP_ITERATION() == 0
449 tuple_t args;
450 #else
451 tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
452 #endif
454 typedef typename boost::mpl::if_<boost::is_void<Ret>
455 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
456 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
458 return proxy_type(const_cast<luabind::functor<Ret>*>(this), args);
461 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
462 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
464 #endif