Přijďte si zasprintovat na Djangu, jiném Python open-source projektu, nebo jen potkat ostatní vývojáře!
… více »Letos v říjnu se v Praze uskuteční hned několik konferencí. Odehraje se zde nově vzniklá konference LinuxDays. K ní se přidá čtvrtý ročník openSUSE Conference, dvanáctý ročník SUSE Labs conference a aby to nebylo málo, přidá se i první ročník Gentoo miniconf. A to vše ve stejné dny a na stejném místě.
… více »Dnes jsem zveřejnil novou verzi OFTL (0.8). Nově přináší reorganizovaný layout souborů a nový modul, interface do Lua (buď LuaC nebo LuaJIT).
Tento modul je založený na objektech a referencích a integruje se dobře s ostatními typy v knihovně. Už není třeba starat se o stack v Lua (o ten se interface stará sám) i když je stále povoleno přistupovat k Lua state pointeru a kombinovat tento interface libovolně s klasickým C API.
Design je inspirovaný knihovnou LuaD pro programovací jazyk D. Do menší míry se využívá C++11 (variadic templates, implementované v g++ 4.4).
Důvod vytvoření tohoto modulu je samozřejmě použití v OctaForge, protože engine dostane systém pluginů a s tím i možnost pro pluginy exportovat vlastní funkce do Lua sandboxu, a tam je potřeba jednoduše použitelný interface.
Celkově je modul rozdělen na několik tříd. Všechny jsou uloženy v jednom namespace, "lua". Základní a hlavní je třída "State", která obsahuje lua_State pointer, globální tabulku, registry tabulku a traceback, kromě několika dalších metod které se starají o získávání globálních proměnných a spouštění kódu.
Kromě toho je tu ještě další namespace, "stack". To se stará o jednotnou správu stacku (typově generické funkce jako push, pop apod.).
Ostatní třídy zahrnují:
Jak je možné vidět, design je dost jednoduchý a nekope se s designem klasického API, takže není nutné dělat žádné věci, které by významně redukovaly výkon, a přitom modul neztrácí nic z uživatelské přívětivosti.
OFTL::lua je možné použít v jakékoliv C++ aplikaci, které už využívá C API a postupně přesouvat celou aplikaci. Stačí jeden inklůd:
#include "OFTL/lua.h"
Pak je třeba někde inicializovat stavovou třídu (State). To se dělá takto:
lua::State lua;
Je dobré si otevřít nějaké knihovny, alespoň tu základní.
lua.open_base();
Pokud má být dostupný traceback přímo z C++, tak je třeba otevřít i "debug" (open_debug). Pro otevření všech knihoven stačí použít lua.open_libs().
Tím je vše nastaveno a už je možné modul používat.
Pokud chci zavolat globální funkci:
lua::Function print = lua.get<lua::Function>("print");
print("hello world!");
To se samozřejmě dá udělat i zavoláním Lua kódu:
lua.do_string("print('hello world!')");
Pro nastavení globální proměnné:
lua["nazev"] = 15;
lua["jina_promenna"] = "baz";
Pak pro opětovné získání:
printf("jina_promenna: %s\n", lua["jina_promenna"].to<const char*>());
Co když chci udělat C++ funkci přístupnou z Lua? Jednoduché:
typedef types::Vector<lua::Object> objvec_t;
void moje_fce(const lua::State& state)
{
objvec_t args = state.get_stack<lua::Object>();
for (objvec_t::cit it = args.begin(); it != args.end(); ++it)
{
switch (it->type())
{
case lua::TYPE_STRING:
printf("arg: %s\n", it->to<const char*>());
break;
case lua::TYPE_NUMBER:
printf("arg: %i / %f\n", it->to<int>(), it->to<float>());
break;
case lua::TYPE_BOOLEAN:
printf("arg: %i\n", it->to<bool>());
break;
default:
printf("arg: unknown\n");
break;
}
}
state.push_value(10);
state.push_value("foobar");
}
....
lua["moje_fce"] = &moje_fce;
lua::Function f = lua.get<lua::Function>("moje_fce");
// vypíše postupně argumenty
// retvals bude obsahovat dva objekty, první s hodnotou 10, druhý s foobar
objvec_t retvals = f("abcd", 5, 10, 3.14, true);
printf("%i %s\n", retvals[0].to<int>(), retvals[1].to<const char*>());
lua.do_string("a, b = moje_fce(5, 10, 'foo')");
Teď, co když chci provést operaci na řetězci v Lua? Použiju typ Dynamic!
lua::Dynamic str = lua.wrap<lua::Dynamic>("hello C!");
objvec_t retvals = str.call("gsub", "C", "Lua");
// vypíše "Hello Lua!" a počet nahrazení, tzn. 1
printf("%s: %i", retvals[0].to<const char*>(), retvals[1].to<int>());
Co když chci vytvořit globální tabulku "foo", která bude obsahovat klíče "bar" a "baz" s hodnotami 5 a další tabulkou - polem o hodnotách 10 a 15?
lua::Table foo = lua.new_table();
foo["bar"] = 5;
lua::Table baz = lua.new_table();
baz[0] = 10;
baz[1] = 15;
foo["baz"] = baz;
lua["foo"] = foo;
Kromě toho mám tabulku "meta" typu lua::Table a chci, aby byla metatabulkou tabulky foo. To taky udělám snadno:
lua.get<lua::Table>("foo").set_metatable(meta);
Stejně snadno ji můžu i získat:
lua::Table meta = lua.get<lua::Table>("foo").get_metatable();
Alternativně, kromě lua.get<T>(name) se dá použít i:
lua::Table meta = lua["foo"].to<lua::Table>.get_metatable();
A to se dá aplikovat i na všechny předchozí příklady.
Modul toho umí ještě více, ale to by bylo na dlouhý článek :) Na Githubu OFTL se budou pravidelně objevovat nové ukázky. Na závěr ještě ukážu, jak pomocí OFTL::lua zpřístupnit C funkci udělanou pomocí Lua C API.
int capi_function(lua_State *L)
{
printf("arg1: %s\n", lua_tostring(L, 1));
lua_pushstring(L, "foo");
lua_pushnumber(L, 3.14f);
return 2;
}
...
lua["capi_function"] = &capi_function;
lua::Function f = lua["capi_function"].to<lua::Function>();
// u všech funkcí jde i konverze do lua_CFunction, tzn. nativního function pointeru, který bere lua_State* jako argument
lua_CFunction f = lua["capi_function"].to<lua_CFunction>();
Jak lze vidět, je to velice jednoduché a umožňuje to snadnou interakci.
Tím bych asi skončil .. doufám, že modul alespoň někoho zaujal :) a díky za přečtení.
Tiskni
Sdílej: