luabind的converter和policy

luabind的converter和policy

      现在的C++设计,为了保证健壮性和复用性,特别是GP的流行,往往应用了大量的模板,容器,智能指针。但这对与LUA绑定来说绝对不是一个好消息,非常的烦琐。个人觉得,在第三方的绑定库里面,luabind和现代C++设计结合最好,也是灵活性最高的一个绑定库。
      luabind确实很强大,但这里就不介绍一般应用了,doc中有详细的说明,使用也非常的简单。我主要介绍一下converter和policy,特别是policy,简直是luabind中的核武器,可以非常方便的让容器,迭代子与lua相结合。但遗憾的是,luabind的文档中并没有对自定义convert和policy做一个详细说明,那个converter的说明,牛头不对马嘴,sample中的any converter,更是无法编译。
      我这里通过容器vector的应用来说明,怎么自定义convert和policy。
      首先,我们来看这么一段代码:
void  test1( const  vector < string >   & v) 

    copy(v.begin(),v.end(),ostream_iterator
<string>(cout,"\n"));
}
 

vector
< string >  test2() 

    vector
<string> r; 

    r.push_back(
"r");
    r.push_back(
"g");
    r.push_back(
"b");

    
return r; 
}
 

void  main() {

    lua_State
* L = lua_open();
    luaL_openlibs(L);

    open(L);

    module(L) 
        [ 
            def(
"test1"&test1), 
            def(
"test2"&test2)
        ]; 

    luaL_dostring(L,
"test1({\"1\",\"2\",\"3\"}) vec=test2() for k, v in ipairs(vec) do print(k..\":\"..v) end");
    lua_close(L);
}

           毫无疑问,调用这段lua代码,得不到任何正确的结果,甚至当你把vector<string>当参数传给lua,会得到you are trying to use an unregistered type的一个assert。因为luabind并不知道怎样去处理vector<string>这个东西。
   最简单的做法,我们就是通过default_converter的特化,来实现容器的使用。luabind都是通过default_converter来把call_function的调用参数压入lua调用栈,所有的default_converter特化都可以在policy.hpp中找到。比如,将std::string入栈的特化convert就是:
      
template  <>
struct  default_converter < std:: string >
  : native_converter_base
< std:: string >
{
    
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());
    }

}
;

   其中void to(lua_State* L, std::string const& value),是把string压入栈中。而from是将一个栈中数据转化为string,computer_score检查栈中数据类型是否符合。很简单,不是吗?那让我们来看看,我们的vector应该怎么写。
   

namespace  luabind
{
    template 
<class T>
    
struct default_converter<vector<T> >
        : native_converter_base
<vector<T> >
    
{
        
static int compute_score(lua_State* L, int index)
        
{
            
return (lua_type(L, index) == LUA_TTABLE )? 0 : -1;
        }


        vector
<T>  from(lua_State* L, int index)
        
{
            vector
<T> container; 
            luabind::
object tbl(from_stack(L, index)); 
            
            
for (luabind::iterator itr(tbl), end; itr != end; ++itr) 
            

                boost::optional
<T> v = object_cast_nothrow<T>(*itr); 
                
if (v)
                    container.push_back(
*v); 
                }
 
            }
 

            
return container; 
        }


        
void to(lua_State* L, vector<T>  const& container)
        
{
            lua_createtable(L, container.size(), 
0); 

            luabind::
object tbl(from_stack(L, -1)); 
            
int n = 0

            
for (vector<T>::const_iterator itr = container.begin(); itr != container.end(); ++itr) 
            

                tbl[
++n] = *itr; 
            }

        }

    }
;

    template 
<class T>
    
struct default_converter<vector<T>  const&>
        : default_converter
<vector<T> >
    
{};
}

 

     是不是很简单啊。:) 再运行上面那段代码。。就得到了我们想要的正确结果:
   luabind的converter和policy_第1张图片
   
      至于luabind的policy,它就更强大了。我们来看看policy版本的容器,应该怎么来做。luabind/contain_policy.hpp就实现了容器的使用。代码如下

//  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_CONTAINER_POLICY_HPP_INCLUDED
#define  LUABIND_CONTAINER_POLICY_HPP_INCLUDED

#include 
< luabind / config.hpp >
#include 
< luabind / detail / policy.hpp >
#include 
< boost / mpl / apply_wrap.hpp >

namespace  luabind  namespace detail {

    
namespace mpl = boost::mpl;

    template
<class Policies>
    
struct container_converter_lua_to_cpp
    
{
        template
<class T>
        T apply(lua_State
* L, by_const_reference<T>int index)
        
{
            typedef typename T::value_type value_type;

            typedef typename find_conversion_policy
<1, Policies>::type converter_policy;
            typename mpl::apply_wrap2
<converter_policy,value_type,lua_to_cpp>::type converter;

            T container;

            lua_pushnil(L);
            
while (lua_next(L, index))
            
{
                container.push_back(converter.apply(L, LUABIND_DECORATE_TYPE(value_type), 
-1));
                lua_pop(L, 
1); // pop value
            }


            
return container;
        }


        template
<class T>
        T apply(lua_State
* L, by_value<T>int index)
        
{
            
return apply(L, by_const_reference<T>(), index);
        }


        template
<class T>
        
static int match(lua_State* L, by_const_reference<T>int index)
        
{
            
if (lua_istable(L, index)) return 0else return -1;
        }


        template
<class T>
        
void converter_postcall(lua_State*, T, int{}
    }
;

    template
<class Policies>
    
struct container_converter_cpp_to_lua
    
{
        template
<class T>
        
void apply(lua_State* L, const T& container)
        
{
            typedef typename T::value_type value_type;

            typedef typename find_conversion_policy
<1, Policies>::type converter_policy;
            typename mpl::apply_wrap2
<converter_policy,value_type,lua_to_cpp>::type converter;

            lua_newtable(L);

            
int index = 1;

            
for (typename T::const_iterator i = container.begin(); i != container.end(); ++i)
            
{
                converter.apply(L, 
*i);
                lua_rawseti(L, 
-2, index);
                
++index;
            }

        }

    }
;

    template
<int N, class Policies>
//    struct container_policy : converter_policy_tag
    struct container_policy : conversion_policy<N>
    
{
//        BOOST_STATIC_CONSTANT(int, index = N);

        
static void precall(lua_State*const index_map&{}
        
static void postcall(lua_State*const index_map&{}

        
struct only_accepts_nonconst_pointers {};

        template
<class T, class Direction>
        
struct apply
        
{
            typedef typename boost::mpl::if_
<boost::is_same<lua_to_cpp, Direction>
                , container_converter_lua_to_cpp
<Policies>
                , container_converter_cpp_to_lua
<Policies>
            
>::type type;
        }
;
    }
;

}
}


namespace  luabind
{
    template
<int N>
    detail::policy_cons
<detail::container_policy<N, detail::null_type>, detail::null_type> 
    container(LUABIND_PLACEHOLDER_ARG(N)) 
    

        
return detail::policy_cons<detail::container_policy<N, detail::null_type>, detail::null_type>(); 
    }


    template
<int N, class Policies>
    detail::policy_cons
<detail::container_policy<N, Policies>, detail::null_type> 
    container(LUABIND_PLACEHOLDER_ARG(N), 
const Policies&
    

        
return detail::policy_cons<detail::container_policy<N, Policies>, detail::null_type>(); 
    }

}


#endif   //  LUABIND_CONTAINER_POLICY_HPP_INCLUDED

   看一下,眼熟吗,感觉怎样?不过是container_converter_lua_to_cpp对应着default_converter::from而container_converter_cpp_to_lua对应着default_converter::to。
      当然,policy除了converter以为,还有关于对象生命周期的控制,具体的可以参加luabind目录下的其他policy。


 

你可能感兴趣的:(luabind的converter和policy)