Como faço para empurrar Uma instância de uma classe C ++ envolvido com gole em uma pilha lua?

StackOverflow https://stackoverflow.com/questions/613282

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu tenho uma classe que está envolvido com gole, e registrado com lua. Posso criar uma instância dessa classe em um script lua, e tudo funciona bem.

Mas dizer que tenho uma instância de uma classe feita em meu código C ++ com uma chamada para novo X, e eu tenho la lua_state L com uma função em que eu quero chamar, que aceita um argumento, uma instância de X ... Como posso chamar essa função. Aqui está (alguns) do código em questão (omiti o material tratamento de erros):

main.cpp

class GuiInst;
extern "C"
{
    int luaopen_engine (lua_State *L);
}

int main()
{
    GuiInst gui=new GuiInst;
    lua_State *L=luaL_newstate();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);
    lua_getglobal(L,"Init");
    //Somehow push gui onto lua stack...
    lua_pcall(L, 1, 0, 0));
    lua_close(L);
}

mainmenu.lua

function Init(gui)
    vregion=gui:CreateComponent("GuiRegionVertical");
end

No momento tudo que eu descobri que pode funcionar é expor algumas funcionalidades do arquivo cpp gole gerado, e chamar isso. Isso é ruim para algumas razões ... não vai funcionar se eu tiver vários modulles e eu tive que alterar a especificação ligação padrão no arquivo gole (usando -DSWIGRUNTIME =).

eu adicionar o seguinte para main.cpp

extern "C"
{
    struct swig_module_info;
    struct swig_type_info;
    int luaopen_engine (lua_State *L);
    swig_module_info *SWIG_Lua_GetModule(lua_State* L);
    void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own);
    swig_type_info *SWIG_TypeQueryModule(swig_module_info *start,swig_module_info *end,const char *name);
}
//and then to push the value...
SWIG_Lua_NewPointerObj(L,gui,SWIG_TypeQueryModule(SWIG_Lua_GetModule(L),SWIG_Lua_GetModule(L),"GuiInst *"),0);

Isso recebe um ponteiro para o módulo, em seguida, um ponteiro para o tipo, em seguida, chama goles funcionar para registrá-lo. Era uma coisa razoável ter que cavar um arquivo que não é suposto ser legível (por isso diz no topo do arquivo) e é apenas confuso! (Mas ela não funciona!)

Com certeza há uma maneira melhor de realizar o que eu estou tentando fazer.

PS a partir de um pov alto nível que eu quero é ter lua não Refcount os componentes GUI que são criados pelo objeto de fábrica em GuiInst, no caso eu vou sobre esta errado. Esta é a minha primeira vez expondo a funcionalidade de uma linguagem de script para além de algumas muito simples (e não-swig) módulos de python, então estou preparado para aceitar o conselho.

Obrigado por qualquer conselho!


A resposta ao comentário por RBerteig

contructor de GuiInst é #defined como privado quando corre swig para evitar lua construir instâncias do mesmo, de modo que não vai funcionar para mim. O que eu estava tentando impedir que foi a seguinte (em lua):

r=engine.GuiRegionVertical()
r:Add(engine.GuiButton())

que chamaria de "g = new guibutton", em seguida, registrá-lo com o GuiRegionVertical (que precisa armazenar um ponteiro por várias razões), em seguida, chamar de "g de exclusão", eo GuiRegionVertical é deixado com um ponteiro pendurado para g.

Eu suspeito que o que realmente precisa acontecer é que GuiRegionVertical :: Add (guibutton *) deve incrementar a contagem de ref do guibutton *, e, em seguida, destruidor de GuiRegionVertical deve diminuir as refcounts de todo o seu conteúdo, embora não tenho certeza como isso deve ser feito com gole.

Isso eliminaria a necessidade para os construtores privados, o objeto de fábrica Gui e os externs desagradáveis.

Am I ir sobre isso errado?

Graças.

Foi útil?

Solução

Não é um simples e resposta direta, que pode não ser a resposta mais eficiente. SWIG produz invólucros para a manipulação de objectos do lado da linguagem de scripting. Para objetos, também sintetiza um construtor embrulhado. Assim, a solução direta é apenas deixar o construtor Lua chamada intérprete de SWIG para criar o novo objeto.

Para a classe engine.GuiInst embrulhado, você quase certamente pode fazer algo como:

int main()
{
    lua_State *L=lua_open();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);

    luaL_dostring(L, "Init(engine.new_GuiInst())");

    lua_close(L);
}

Para um caso one-shot como inicialização roteiro, a pena de funcionamento de uma cadeia constante através luaL_dostring () não é mau de todo. Eu ficaria mais difícil de evitá-lo em um retorno de chamada de evento ou um loop interno, no entanto.

Realmente, parece que deve haver uma maneira de converter um ponteiro diretamente em um objeto embrulhado, eu não vou manchar-lo em meu próprio punhado de SWIG gerado wrappers.

Editar: É claro, o fragmento Lua pode ser decomposto para chamadas de API que obter a tabela de motor global sobre a pilha, extrato dele o membro new_GuiInst, chamá-lo, em seguida, chamar o Init global, mas o pouco de eficiência vem à custa de alguma clareza.

Como para lidar com objetos que não devem ser construídos por acidente no código do usuário, como a questão esclarecida indica, meu primeiro impulso seria deixar SWIG gerar a função de construtor, manter uma referência particular, se necessário mais tarde, e removê-lo Da mesa. Mesmo um módulo C é (normalmente) a uma mesa cujos membros contêm os valores da função. A ser implementado em C não torná-los somente leitura a menos esforço extra é tomada.

Assim, você sempre pode recuperar o valor de engine.new_GuiInst e estacioná-lo no registro (ver luaL_ref() ea discussão em secção 3.5 da Referência Lua manual do LUA_REGISTRYINDEX pseudo-índice para os detalhes) para uso posterior. Então, antes de deixar qualquer executar código de utilizador, basta fazer o equivalente a engine.new_GuiInst = nil. Devo observar que para os limits.h eu tenho jogado com mais recentemente, SWIG criado dois construtores para cada tipo, chamado new_TYPE e TYPE. Ambos eram visíveis na tabela do módulo, e que você gostaria de definir os dois nomes para nil. Se tem muito menos experiência com aulas SWIG embrulho C ++, eo resultado pode ser diferente ...

Você pode querer verificar e rever todo o conteúdo da tabela de engine retornado por SWIG, e criar um objeto proxy que contém apenas os métodos que você deseja disponibilizar para seus usuários. Você também pode alterar a ambiente visto pelo script de usuário para que ele só tem o proxy disponíveis, e nomes do engine procuração também. Tem havido uma grande quantidade de discussão sobre sandboxing scripts de usuário no Lua lista e, ao LUA- usuários wiki .

Outras dicas

Melhor tarde nunca, e esta solução vai ajudar outras pessoas.

void handle_web_request(WebRequest *request, WebResponse *response)
{
  lua_getfield(rackam->lua_state, LUA_GLOBALSINDEX, "handle_web_request");
  SWIG_Lua_NewPointerObj(rackam->lua_state, request, SWIGTYPE_p_WebRequest, 0);
  SWIG_Lua_NewPointerObj(rackam->lua_state, response, SWIGTYPE_p_WebResponse, 0);
  lua_call(rackam->lua_state, 2, 0);
}

Este código deve ser dentro de% {}% blocos em seu arquivo .i, porque SWIGTYPE_p_WebRequest é

#define SWIGTYPE_p_WebResponse swig_types[6]

e swig_types [6] é

static swig_type_info *swig_types[12];

O que significa que swig_types só é acessível a partir do C ++ arquivo do qual ele é definido.

esse trecho em particular é o envio de dois dos meus ponteiros wrappered, assim que chamar handle_web_request (request, response) do C ++ lado das coisas vai executar a função global de lua "handle_web_request" e passá-lo meus dois ponteiros, com a magia SWIG aplicada .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top