// Copyright (c) 2003 Daniel Wallin and Arvid Norberg // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE // OR OTHER DEALINGS IN THE SOFTWARE. #ifndef LUABIND_POLICY_HPP_INCLUDED #define LUABIND_POLICY_HPP_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace luabind { namespace detail { struct conversion_policy_base {}; } template struct conversion_policy : detail::conversion_policy_base { BOOST_STATIC_CONSTANT(int, index = N); BOOST_STATIC_CONSTANT(bool, has_arg = HasArg); }; class index_map { public: index_map(const int* m): m_map(m) {} int operator[](int index) const { return m_map[index]; } private: const int* m_map; }; // template class functor; class weak_ref; } namespace luabind { namespace detail { template struct policy_cons { typedef H head; typedef T tail; template policy_cons > operator,(policy_cons) { return policy_cons >(); } template policy_cons > operator+(policy_cons) { return policy_cons >(); } template policy_cons > operator|(policy_cons) { return policy_cons >(); } }; struct indirection_layer { template indirection_layer(const T&); }; yes_t is_policy_cons_test(const null_type&); template yes_t is_policy_cons_test(const policy_cons&); no_t is_policy_cons_test(...); template struct is_policy_cons { static const T& t; BOOST_STATIC_CONSTANT(bool, value = sizeof(is_policy_cons_test(t)) == sizeof(yes_t)); typedef boost::mpl::bool_ type; }; template struct is_string_literal { static no_t helper(indirection_layer); static yes_t helper(const char*); }; template<> struct is_string_literal { static no_t helper(indirection_layer); }; namespace mpl = boost::mpl; template void make_pointee_instance(lua_State* L, T& x, mpl::true_, Clone) { if (get_pointer(x)) { make_instance(L, x); } else { lua_pushnil(L); } } template void make_pointee_instance(lua_State* L, T& x, mpl::false_, mpl::true_) { std::auto_ptr ptr(new T(x)); make_instance(L, ptr); } template void make_pointee_instance(lua_State* L, T& x, mpl::false_, mpl::false_) { make_instance(L, &x); } template void make_pointee_instance(lua_State* L, T& x, Clone) { make_pointee_instance(L, x, has_get_pointer(), Clone()); } // ********** pointer converter *********** struct pointer_converter { typedef pointer_converter type; typedef mpl::false_ is_native; pointer_converter() : result(0) {} void* result; int const consumed_args(...) { return 1; } template void apply(lua_State* L, T* ptr) { if (ptr == 0) { lua_pushnil(L); return; } if (luabind::get_back_reference(L, ptr)) return; make_instance(L, ptr); } template T* apply(lua_State*, by_pointer, int) { return static_cast(result); } template int match(lua_State* L, by_pointer, int index) { if (lua_isnil(L, index)) return 0; object_rep* obj = get_instance(L, index); if (obj == 0) return -1; if (obj->is_const()) return -1; std::pair s = obj->get_instance(registered_class::id); result = s.first; return s.second; } template void converter_postcall(lua_State*, by_pointer, int) {} }; // ******* value converter ******* struct value_converter { typedef value_converter type; typedef mpl::false_ is_native; int const consumed_args(...) { return 1; } value_converter() : result(0) {} void* result; template void apply(lua_State* L, T x) { if (luabind::get_back_reference(L, x)) return; make_pointee_instance(L, x, mpl::true_()); } template T apply(lua_State*, by_value, int) { return *static_cast(result); } template int match(lua_State* L, by_value, int index) { // special case if we get nil in, try to match the holder type if (lua_isnil(L, index)) return -1; object_rep* obj = get_instance(L, index); if (obj == 0) return -1; std::pair s = obj->get_instance(registered_class::id); result = s.first; return s.second; } template void converter_postcall(lua_State*, T, int) {} }; // ******* const pointer converter ******* struct const_pointer_converter { typedef const_pointer_converter type; typedef mpl::false_ is_native; int const consumed_args(...) { return 1; } const_pointer_converter() : result(0) {} void* result; template void apply(lua_State* L, const T* ptr) { if (ptr == 0) { lua_pushnil(L); return; } if (luabind::get_back_reference(L, ptr)) return; make_instance(L, ptr); } template T const* apply(lua_State*, by_const_pointer, int) { return static_cast(result); } template int match(lua_State* L, by_const_pointer, int index) { if (lua_isnil(L, index)) return 0; object_rep* obj = get_instance(L, index); if (obj == 0) return -1; // if the type is not one of our own registered types, classify it as a non-match std::pair s = obj->get_instance(registered_class::id); if (s.second >= 0 && !obj->is_const()) s.second += 10; result = s.first; return s.second; } template void converter_postcall(lua_State*, T, int) {} }; // ******* reference converter ******* struct ref_converter : pointer_converter { typedef ref_converter type; typedef mpl::false_ is_native; int const consumed_args(...) { return 1; } template void apply(lua_State* L, T& ref) { if (luabind::get_back_reference(L, ref)) return; make_pointee_instance(L, ref, mpl::false_()); } template T& apply(lua_State* L, by_reference, int index) { assert(!lua_isnil(L, index)); return *pointer_converter::apply(L, by_pointer(), index); } template int match(lua_State* L, by_reference, int index) { object_rep* obj = get_instance(L, index); if (obj == 0) return -1; if (obj->is_const()) return -1; std::pair s = obj->get_instance(registered_class::id); result = s.first; return s.second; } template void converter_postcall(lua_State*, T, int) {} }; // ******** const reference converter ********* struct const_ref_converter { typedef const_ref_converter type; typedef mpl::false_ is_native; int const consumed_args(...) { return 1; } const_ref_converter() : result(0) {} void* result; template void apply(lua_State* L, T const& ref) { if (luabind::get_back_reference(L, ref)) return; make_pointee_instance(L, ref, mpl::false_()); } template T const& apply(lua_State*, by_const_reference, int) { return *static_cast(result); } template int match(lua_State* L, by_const_reference, int index) { object_rep* obj = get_instance(L, index); if (obj == 0) return -1; // if the type is not one of our own registered types, classify it as a non-match std::pair s = obj->get_instance(registered_class::id); if (s.second >= 0 && !obj->is_const()) s.second += 10; result = s.first; return s.second; } template void converter_postcall(lua_State*, by_const_reference, int) { } }; // ****** enum converter ******** struct enum_converter { typedef enum_converter type; typedef mpl::true_ is_native; int const consumed_args(...) { return 1; } void apply(lua_State* L, int val) { lua_pushnumber(L, val); } template T apply(lua_State* L, by_value, int index) { return static_cast(static_cast(lua_tonumber(L, index))); } template static int match(lua_State* L, by_value, int index) { if (lua_isnumber(L, index)) return 0; else return -1; } template T apply(lua_State* L, by_const_reference, int index) { return static_cast(static_cast(lua_tonumber(L, index))); } template static int match(lua_State* L, by_const_reference, int index) { if (lua_isnumber(L, index)) return 0; else return -1; } template void converter_postcall(lua_State*, T, int) {} }; template struct value_wrapper_converter { typedef value_wrapper_converter type; typedef mpl::true_ is_native; int const consumed_args(...) { return 1; } template T apply(lua_State* L, by_const_reference, int index) { return T(from_stack(L, index)); } template T apply(lua_State* L, by_value, int index) { return apply(L, by_const_reference(), index); } template static int match(lua_State* L, by_const_reference, int index) { return value_wrapper_traits::check(L, index) ? (std::numeric_limits::max)() / LUABIND_MAX_ARITY : -1; } template static int match(lua_State* L, by_value, int index) { return match(L, by_const_reference(), index); } void converter_postcall(...) {} template void apply(lua_State* interpreter, T const& value_wrapper) { value_wrapper_traits::unwrap(interpreter, value_wrapper); } }; template struct default_converter_generator : mpl::eval_if< is_value_wrapper_arg , value_wrapper_converter , mpl::eval_if< boost::is_enum::type> , enum_converter , mpl::eval_if< is_nonconst_pointer , pointer_converter , mpl::eval_if< is_const_pointer , const_pointer_converter , mpl::eval_if< is_nonconst_reference , ref_converter , mpl::eval_if< is_const_reference , const_ref_converter , value_converter > > > > > > {}; } // namespace detail // *********** default_policy ***************** template struct default_converter : detail::default_converter_generator::type {}; template > struct native_converter_base { typedef boost::mpl::true_ is_native; int const consumed_args(...) { return 1; } template void converter_postcall(lua_State*, U const&, int) {} int match(lua_State* L, detail::by_value, int index) { return derived().compute_score(L, index); } int match(lua_State* L, detail::by_value, int index) { return derived().compute_score(L, index); } int match(lua_State* L, detail::by_const_reference, int index) { return derived().compute_score(L, index); } T apply(lua_State* L, detail::by_value, int index) { return derived().from(L, index); } T apply(lua_State* L, detail::by_value, int index) { return derived().from(L, index); } T apply(lua_State* L, detail::by_const_reference, int index) { return derived().from(L, index); } void apply(lua_State* L, T const& value) { derived().to(L, value); } Derived& derived() { return static_cast(*this); } }; template lua_Integer as_lua_integer(T v) { return static_cast(v); } template lua_Number as_lua_number(T v) { return static_cast(v); } # define LUABIND_NUMBER_CONVERTER(type, kind) \ template <> \ struct default_converter \ : native_converter_base \ { \ int compute_score(lua_State* L, int index) \ { \ return lua_type(L, index) == LUA_TNUMBER ? 0 : -1; \ }; \ \ type from(lua_State* L, int index) \ { \ return static_cast(BOOST_PP_CAT(lua_to, kind)(L, index)); \ } \ \ void to(lua_State* L, type const& value) \ { \ BOOST_PP_CAT(lua_push, kind)(L, BOOST_PP_CAT(as_lua_, kind)(value)); \ } \ }; \ \ template <> \ struct default_converter \ : default_converter \ {}; \ \ template <> \ struct default_converter \ : default_converter \ {}; LUABIND_NUMBER_CONVERTER(char, integer) LUABIND_NUMBER_CONVERTER(signed char, integer) LUABIND_NUMBER_CONVERTER(unsigned char, integer) LUABIND_NUMBER_CONVERTER(signed short, integer) LUABIND_NUMBER_CONVERTER(unsigned short, integer) LUABIND_NUMBER_CONVERTER(signed int, integer) LUABIND_NUMBER_CONVERTER(signed long long, integer) LUABIND_NUMBER_CONVERTER(unsigned int, number) LUABIND_NUMBER_CONVERTER(unsigned long, number) LUABIND_NUMBER_CONVERTER(unsigned long long, number) LUABIND_NUMBER_CONVERTER(signed long, integer) LUABIND_NUMBER_CONVERTER(float, number) LUABIND_NUMBER_CONVERTER(double, number) LUABIND_NUMBER_CONVERTER(long double, number) # undef LUABIND_NUMBER_CONVERTER template <> struct default_converter : native_converter_base { static int compute_score(lua_State* L, int index) { return lua_type(L, index) == LUA_TBOOLEAN ? 0 : -1; } bool from(lua_State* L, int index) { return lua_toboolean(L, index) == 1; } void to(lua_State* L, bool value) { lua_pushboolean(L, value); } }; template <> struct default_converter : default_converter {}; template <> struct default_converter : default_converter {}; template <> struct default_converter : native_converter_base { static int compute_score(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING ? 0 : -1; } std::string from(lua_State* L, int index) { return std::string(lua_tostring(L, index), lua_strlen(L, index)); } void to(lua_State* L, std::string const& value) { lua_pushlstring(L, value.data(), value.size()); } }; template <> struct default_converter : default_converter {}; template <> struct default_converter : default_converter {}; template <> struct default_converter { typedef boost::mpl::true_ is_native; int const consumed_args(...) { return 1; } template static int match(lua_State* L, U, int index) { int type = lua_type(L, index); return (type == LUA_TSTRING || type == LUA_TNIL) ? 0 : -1; } template char const* apply(lua_State* L, U, int index) { return lua_tostring(L, index); } void apply(lua_State* L, char const* str) { lua_pushstring(L, str); } template void converter_postcall(lua_State*, U, int) {} }; template <> struct default_converter : default_converter {}; template <> struct default_converter : default_converter {}; template struct default_converter : default_converter {}; template struct default_converter : default_converter {}; template <> struct default_converter { int const consumed_args(...) { return 0; } template lua_State* apply(lua_State* L, U, int) { return L; } template static int match(lua_State*, U, int) { return 0; } template void converter_postcall(lua_State*, U, int) {} }; namespace detail { struct default_policy : converter_policy_tag { BOOST_STATIC_CONSTANT(bool, has_arg = true); template static void precall(lua_State*, T, int) {} template struct apply { typedef default_converter type; }; }; template struct is_primitive : default_converter::is_native {}; // ============== new policy system ================= template struct find_conversion_policy; template struct find_conversion_impl { template struct apply { typedef typename find_conversion_policy::type type; }; }; template<> struct find_conversion_impl { template struct apply { typedef typename Policies::head head; typedef typename Policies::tail tail; BOOST_STATIC_CONSTANT(bool, found = (N == head::index)); typedef typename boost::mpl::if_c::type >::type type; }; }; template struct find_conversion_impl2 { template struct apply : find_conversion_impl< boost::is_base_and_derived::value >::template apply { }; }; template<> struct find_conversion_impl2 { template struct apply { typedef default_policy type; }; }; template struct find_conversion_policy : find_conversion_impl2::template apply { }; template struct policy_list_postcall { typedef typename List::head head; typedef typename List::tail tail; static void apply(lua_State* L, const index_map& i) { head::postcall(L, i); policy_list_postcall::apply(L, i); } }; template<> struct policy_list_postcall { static void apply(lua_State*, const index_map&) {} }; // ================================================== // ************** precall and postcall on policy_cons ********************* template struct policy_precall { typedef typename List::head head; typedef typename List::tail tail; static void apply(lua_State* L, int index) { head::precall(L, index); policy_precall::apply(L, index); } }; template<> struct policy_precall { static void apply(lua_State*, int) {} }; template struct policy_postcall { typedef typename List::head head; typedef typename List::tail tail; static void apply(lua_State* L, int index) { head::postcall(L, index); policy_postcall::apply(L, index); } }; template<> struct policy_postcall { static void apply(lua_State*, int) {} }; }} // namespace luabind::detail namespace luabind { namespace { #if defined(__GNUC__) && ( \ (BOOST_VERSION < 103500) \ || (BOOST_VERSION < 103900 && (__GNUC__ * 100 + __GNUC_MINOR__ <= 400)) \ || (__GNUC__ * 100 + __GNUC_MINOR__ < 400)) static inline boost::arg<0> return_value() { return boost::arg<0>(); } static inline boost::arg<0> result() { return boost::arg<0>(); } # define LUABIND_PLACEHOLDER_ARG(N) boost::arg(*)() #elif defined(BOOST_MSVC) || defined(__MWERKS__) \ || (BOOST_VERSION >= 103900 && defined(__GNUC__) \ && (__GNUC__ * 100 + __GNUC_MINOR__ == 400)) static boost::arg<0> return_value; static boost::arg<0> result; # define LUABIND_PLACEHOLDER_ARG(N) boost::arg #else boost::arg<0> return_value; boost::arg<0> result; # define LUABIND_PLACEHOLDER_ARG(N) boost::arg #endif }} #endif // LUABIND_POLICY_HPP_INCLUDED