*** empty log message ***
[luabind.git] / luabind / functor.hpp
blobb0deeb1e1f807489a7f3403617e1ad19530c8d74
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>
42 namespace luabind
44 //template<class Ret>
45 //class functor;
47 namespace detail
50 struct functor_from;
53 // if the proxy_functor_caller returns non-void
54 template<class Ret, class Tuple>
55 class proxy_functor_caller
57 // template<class T> friend class luabind::functor;
58 public:
60 proxy_functor_caller(luabind::functor<Ret>* o, const Tuple args)
61 : m_func(o)
62 , m_args(args)
63 , m_called(false)
67 proxy_functor_caller(const proxy_functor_caller& rhs)
68 : m_func(rhs.m_func)
69 , m_args(rhs.m_args)
70 , m_called(rhs.m_called)
72 rhs.m_called = true;
75 ~proxy_functor_caller()
77 if (m_called) return;
79 m_called = true;
80 lua_State* L = m_func->lua_state();
82 // get the function
83 m_func->pushvalue();
85 push_args_from_tuple<1>::apply(L, m_args);
86 if (pcall(L, boost::tuples::length<Tuple>::value, 0))
88 #ifndef LUABIND_NO_EXCEPTIONS
89 throw luabind::error(L);
90 #else
91 error_callback_fun e = get_error_callback();
92 if (e) e(L);
94 assert(0 && "the lua function threw an error and exceptions are disabled."
95 "if you want to handle this error use luabind::set_error_callback()");
96 std::terminate();
97 #endif
101 operator Ret()
103 typename default_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
105 m_called = true;
106 lua_State* L = m_func->lua_state();
107 #ifndef LUABIND_NO_ERROR_CHECKING
108 if (L == 0)
110 #ifndef LUABIND_NO_EXCEPTIONS
111 throw error(L);
112 #else
113 error_callback_fun e = get_error_callback();
114 if (e) e(L);
116 assert(0 && "tried to call uninitialized functor object."
117 "if you want to handle this error use luabind::set_error_callback()");
118 std::terminate();
119 #endif
121 #endif
124 detail::stack_pop p(L, 1); // pop the return value
126 // get the function
127 m_func->pushvalue();
129 push_args_from_tuple<1>::apply(L, m_args);
130 if (pcall(L, boost::tuples::length<Tuple>::value, 1))
132 #ifndef LUABIND_NO_EXCEPTIONS
133 throw luabind::error(L);
134 #else
135 error_callback_fun e = get_error_callback();
136 if (e) e(L);
138 assert(0 && "the lua function threw an error and exceptions are disabled."
139 "if you want to handle this error use luabind::set_error_callback()");
140 std::terminate();
141 #endif
144 #ifndef LUABIND_NO_ERROR_CHECKING
146 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
148 #ifndef LUABIND_NO_EXCEPTIONS
149 throw cast_failed(L, LUABIND_TYPEID(Ret));
150 #else
151 cast_failed_callback_fun e = get_cast_failed_callback();
152 if (e) e(L, LUABIND_TYPEID(Ret));
154 assert(0 && "the lua function's return value could not be converted."
155 "if you want to handle this error use luabind::set_error_callback()");
156 std::terminate();
157 #endif
159 #endif
160 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
163 template<class Policies>
164 Ret operator[](const Policies& p)
166 typedef typename detail::find_conversion_policy<0, Policies>::type converter_policy;
167 typename converter_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
169 m_called = true;
170 lua_State* L = m_func->lua_state();
171 #ifndef LUABIND_NO_ERROR_CHECKING
172 if (L == 0)
174 #ifndef LUABIND_NO_EXCEPTIONS
175 throw error(L);
176 #else
177 error_callback_fun e = get_error_callback();
178 if (e) e(L);
180 assert(0 && "tried to call uninitialized functor object."
181 "if you want to handle this error use luabind::set_error_callback()");
182 std::terminate();
183 #endif
185 #endif
187 detail::stack_pop popper(L, 1); // pop the return value
189 // get the function
190 m_func->pushvalue();
192 detail::push_args_from_tuple<1>::apply(L, m_args, p);
193 if (pcall(L, boost::tuples::length<Tuple>::value, 1))
195 #ifndef LUABIND_NO_EXCEPTIONS
196 throw error(L);
197 #else
198 error_callback_fun e = get_error_callback();
199 if (e) e(L);
201 assert(0 && "the lua function threw an error and exceptions are disabled."
202 "if you want to handle this error use luabind::set_error_callback()");
203 std::terminate();
204 #endif
207 #ifndef LUABIND_NO_ERROR_CHECKING
209 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
211 #ifndef LUABIND_NO_EXCEPTIONS
212 throw cast_failed(L, LUABIND_TYPEID(Ret));
213 #else
214 cast_failed_callback_fun e = get_cast_failed_callback();
215 if (e) e(L, LUABIND_TYPEID(Ret));
217 assert(0 && "the lua function's return value could not be converted."
218 "if you want to handle this error use luabind::set_error_callback()");
219 std::terminate();
220 #endif
222 #endif
223 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
226 private:
228 luabind::functor<Ret>* m_func;
229 Tuple m_args;
230 mutable bool m_called;
234 // if the proxy_member_caller returns void
235 template<class Tuple>
236 class proxy_functor_void_caller
238 // template<class T> friend class luabind::functor;
239 public:
241 proxy_functor_void_caller(luabind::functor<void>* o, const Tuple args)
242 : m_func(o)
243 , m_args(args)
244 , m_called(false)
248 proxy_functor_void_caller(const proxy_functor_void_caller& rhs)
249 : m_func(rhs.m_func)
250 , m_args(rhs.m_args)
251 , m_called(rhs.m_called)
253 rhs.m_called = true;
256 ~proxy_functor_void_caller()
258 if (m_called) return;
260 m_called = true;
261 lua_State* L = m_func->lua_state();
262 #ifndef LUABIND_NO_ERROR_CHECKING
263 if (L == 0)
265 #ifndef LUABIND_NO_EXCEPTIONS
266 throw error(L);
267 #else
268 error_callback_fun e = get_error_callback();
269 if (e) e(L);
271 assert(0 && "tried to call uninitialized functor object."
272 "if you want to handle this error use luabind::set_error_callback()");
273 std::terminate();
274 #endif
276 #endif
279 // get the function
280 m_func->pushvalue();
282 push_args_from_tuple<1>::apply(L, m_args);
283 if (pcall(L, boost::tuples::length<Tuple>::value, 0))
285 #ifndef LUABIND_NO_EXCEPTIONS
286 throw luabind::error(L);
287 #else
288 error_callback_fun e = get_error_callback();
289 if (e) e(L);
291 assert(0 && "the lua function threw an error and exceptions are disabled."
292 "if you want to handle this error use luabind::set_error_callback()");
293 std::terminate();
294 #endif
298 template<class Policies>
299 void operator[](const Policies& p)
301 m_called = true;
302 lua_State* L = m_func->lua_state();
303 #ifndef LUABIND_NO_ERROR_CHECKING
304 if (L == 0)
306 #ifndef LUABIND_NO_EXCEPTIONS
307 throw error(L);
308 #else
309 error_callback_fun e = get_error_callback();
310 if (e) e(L);
312 assert(0 && "tried to call uninitialized functor object."
313 "if you want to handle this error use luabind::set_error_callback()");
314 std::terminate();
315 #endif
317 #endif
320 // get the function
321 m_func->pushvalue();
323 detail::push_args_from_tuple<1>::apply(L, m_args, p);
324 if (pcall(L, boost::tuples::length<Tuple>::value, 0))
326 #ifndef LUABIND_NO_EXCEPTIONS
327 throw error(L);
328 #else
329 error_callback_fun e = get_error_callback();
330 if (e) e(L);
332 assert(0 && "the lua function threw an error and exceptions are disabled."
333 "if you want to handle this error use luabind::set_error_callback()");
334 std::terminate();
335 #endif
339 private:
341 luabind::functor<void>* m_func;
342 Tuple m_args;
343 mutable bool m_called;
347 } // detail
349 template<class Ret>
350 class functor
352 public:
354 functor(lua_State* L, const char* name)
355 : L_(L)
357 lua_pushstring(L, name);
358 lua_gettable(L, LUA_GLOBALSINDEX);
359 ref_.set(L_);
362 functor()
363 : L_(0)
367 functor(const functor<Ret>& obj)
368 : L_(obj.L_)
369 , ref_(obj.ref_)
373 // this is a safe substitute for an implicit converter to bool
374 typedef void (functor::*member_ptr)() const;
375 operator member_ptr() const
377 if (is_valid()) return &functor::dummy;
378 return 0;
381 const functor<Ret>& operator=(const functor<Ret>& rhs)
383 L_ = rhs.L_;
384 ref_ = rhs.ref_;
385 return *this;
388 bool operator==(const functor<Ret>& rhs) const
390 if (!ref_.is_valid() || !rhs.ref_.is_valid()) return false;
391 pushvalue();
392 rhs.pushvalue();
393 bool result = lua_equal(L_, -1, -2) != 0;
394 lua_pop(L_, 2);
395 return result;
398 bool operator!=(const functor<Ret>& rhs) const
400 if (!ref_.is_valid() || !rhs.ref_.is_valid()) return true;
401 pushvalue();
402 rhs.pushvalue();
403 bool result = lua_equal(L_, -1, -2) == 0;
404 lua_pop(L_, 2);
405 return result;
408 inline bool is_valid() const { return ref_.is_valid(); }
410 lua_State* lua_state() const { return L_; }
411 void pushvalue() const { ref_.get(L_); }
413 #define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUABIND_MAX_ARITY, <luabind/functor.hpp>, 1))
414 #include BOOST_PP_ITERATE()
416 // TODO: should be private
418 functor(lua_State* L, detail::lua_reference const& ref)
419 : L_(L)
420 , ref_(ref)
424 private:
426 void dummy() const {}
428 lua_State* L_;
429 detail::lua_reference ref_;
433 #endif // LUABIND_FUNCTOR_HPP_INCLUDED
435 #else
437 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
438 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
440 #if BOOST_PP_ITERATION() > 0
441 template<BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
442 #endif
443 typename boost::mpl::if_<boost::is_void<Ret>
444 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
445 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
446 operator()(BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _)) const
448 typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
449 #if BOOST_PP_ITERATION() == 0
450 tuple_t args;
451 #else
452 tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
453 #endif
455 typedef typename boost::mpl::if_<boost::is_void<Ret>
456 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
457 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
459 return proxy_type(const_cast<luabind::functor<Ret>*>(this), args);
462 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
463 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
465 #endif