luabind的converter和policy
現(xiàn)在的C++設(shè)計(jì),為了保證健壯性和復(fù)用性,特別是GP的流行,往往應(yīng)用了大量的模板,容器,智能指針。但這對(duì)與LUA綁定來說絕對(duì)不是一個(gè)好消息,非常的煩瑣。個(gè)人覺得,在第三方的綁定庫里面,luabind和現(xiàn)代C++設(shè)計(jì)結(jié)合最好,也是靈活性最高的一個(gè)綁定庫。
luabind確實(shí)很強(qiáng)大,但這里就不介紹一般應(yīng)用了,doc中有詳細(xì)的說明,使用也非常的簡單。我主要介紹一下converter和policy,特別是policy,簡直是luabind中的核武器,可以非常方便的讓容器,迭代子與lua相結(jié)合。但遺憾的是,luabind的文檔中并沒有對(duì)自定義convert和policy做一個(gè)詳細(xì)說明,那個(gè)converter的說明,牛頭不對(duì)馬嘴,sample中的any converter,更是無法編譯。
我這里通過容器vector的應(yīng)用來說明,怎么自定義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);
}
毫無疑問,調(diào)用這段lua代碼,得不到任何正確的結(jié)果,甚至當(dāng)你把vector<string>當(dāng)參數(shù)傳給lua,會(huì)得到y(tǒng)ou are trying to use an unregistered type的一個(gè)assert。因?yàn)閘uabind并不知道怎樣去處理vector<string>這個(gè)東西。
最簡單的做法,我們就是通過default_converter的特化,來實(shí)現(xiàn)容器的使用。luabind都是通過default_converter來把call_function的調(diào)用參數(shù)壓入lua調(diào)用棧,所有的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());
}
};
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> >

{};
}
// 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 0; else 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
luabind確實(shí)很強(qiáng)大,但這里就不介紹一般應(yīng)用了,doc中有詳細(xì)的說明,使用也非常的簡單。我主要介紹一下converter和policy,特別是policy,簡直是luabind中的核武器,可以非常方便的讓容器,迭代子與lua相結(jié)合。但遺憾的是,luabind的文檔中并沒有對(duì)自定義convert和policy做一個(gè)詳細(xì)說明,那個(gè)converter的說明,牛頭不對(duì)馬嘴,sample中的any converter,更是無法編譯。
我這里通過容器vector的應(yīng)用來說明,怎么自定義convert和policy。
首先,我們來看這么一段代碼:






































毫無疑問,調(diào)用這段lua代碼,得不到任何正確的結(jié)果,甚至當(dāng)你把vector<string>當(dāng)參數(shù)傳給lua,會(huì)得到y(tǒng)ou are trying to use an unregistered type的一個(gè)assert。因?yàn)閘uabind并不知道怎樣去處理vector<string>這個(gè)東西。
最簡單的做法,我們就是通過default_converter的特化,來實(shí)現(xiàn)容器的使用。luabind都是通過default_converter來把call_function的調(diào)用參數(shù)壓入lua調(diào)用棧,所有的default_converter特化都可以在policy.hpp中找到。比如,將std::string入棧的特化convert就是:



























其中void to(lua_State* L, std::string const& value),是把string壓入棧中。而from是將一個(gè)棧中數(shù)據(jù)轉(zhuǎn)化為string,computer_score檢查棧中數(shù)據(jù)類型是否符合。很簡單,不是嗎?那讓我們來看看,我們的vector應(yīng)該怎么寫。

































































是不是很簡單啊。:) 再運(yùn)行上面那段代碼。。就得到了我們想要的正確結(jié)果:
至于luabind的policy,它就更強(qiáng)大了。我們來看看policy版本的容器,應(yīng)該怎么來做。luabind/contain_policy.hpp就實(shí)現(xiàn)了容器的使用。代碼如下
















































































































































































看一下,眼熟嗎,感覺怎樣?不過是container_converter_lua_to_cpp對(duì)應(yīng)著default_converter::from而container_converter_cpp_to_lua對(duì)應(yīng)著default_converter::to。
當(dāng)然,policy除了converter以為,還有關(guān)于對(duì)象生命周期的控制,具體的可以參加luabind目錄下的其他policy。
posted on 2009-01-08 17:10 clane 閱讀(2710) 評(píng)論(2) 編輯 收藏 引用 所屬分類: LUA 、C++