简体   繁体   English

如何使用SWIG为C ++ std :: vector生成Lua迭代器?

[英]How to generate Lua iterators for C++ std::vector using SWIG?

In lua/std_vector.i in SWIG 2.0.8 comment says: 在SWIG 2.0.8的lua/std_vector.i中,注释说:

And no support for iterators & insert/erase 而且不支持迭代器和插入/擦除

but maybe someone knows how to do it? 但也许有人知道该怎么做?

For example, it's possible to add # length operator by defining __len (it may work by accident, I've found it by trials and errors): 例如,可以通过定义__len来添加#长度运算符(它可能偶然起作用,我已经通过__len试验发现了它):

%include "std_vector.i"
%extend std::vector { int __len(void*) { return self->size(); } }
namespace std {
    %template(PointVector) vector<fityk::Point>;
}

I've tried similar trick with __call , but I'm stuck. 我已经尝试了__call类似技巧,但是我被卡住了。 SWIG wrapping gets in the way. SWIG包装会妨碍您的操作。 I've tried using %native , but I couldn't make it work together with %extend . 我尝试使用%native ,但无法使其与%extend一起使用。

I don't know how to do it in SWIG template, but I managed to plug __call to SWIG-generated metatable from C++, after calling luaopen_module : 我不知道如何在SWIG模板中执行此操作,但是在调用luaopen_module之后,我设法从C ++将__call插入到SWIG生成的元表中:

    SWIG_Lua_get_class_metatable(L_, PointVector);
    SWIG_Lua_add_function(L_, "__call", lua_vector_iterator);

So the vector can be used as iterator. 因此向量可以用作迭代器。 A bit awkward 2 in 1, but works: 2合1有点尴尬,但可以:

> = points
<PointVector userdata: 190FBE8>
> for n, p in points do print(n, p) end
0       (24.0154; 284; 16.8523)
1       (24.0541; 343; 18.5203)

The iterator returns index and value, like enumerate() in Python, and Lua passes the index back to the iterator next time (3rd arg on the stack). 迭代器返回索引和值,就像Python中的enumerate()一样,Lua下次将索引传递回迭代器(堆栈中的第3个arg)。 I haven't seen this behaviour documented, so I may rely on implementation details. 我没有看到有关此行为的记录,因此我可能依赖于实现细节。

Here is the function used as __call() : 这是用作__call()的函数:

// SWIG-wrapped vector is indexed from 0. Return (n, vec[n]) starting from n=0.
static int lua_vector_iterator(lua_State* L)
{
    assert(lua_isuserdata(L,1)); // in SWIG everything is wrapped as userdata
    int idx = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1) + 1;

    // no lua_len() in 5.1, let's call size() directly
    lua_getfield(L, 1, "size");
    lua_pushvalue(L, 1); // arg: vector as userdata
    lua_call(L, 1, 1);   // call vector<>::size(this)
    int size = lua_tonumber(L, -1);

    if (idx >= size) {
        lua_settop(L, 0);
        return 0;
    }

    lua_settop(L, 1);
    lua_pushnumber(L, idx); // index, to be returned
    lua_pushvalue(L, -1);   // the same index, to access value
    lua_gettable(L, 1);     // value, to be returned
    lua_remove(L, 1);
    return 2;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM