Lua API ++

こんにちは同僚。
私の小さなプロゞェクトを玹介したいず思いたす。これはあなたに圹立぀ず思いたす。

数幎前、適床なサむズず高いパフォヌマンスを備えた組み蟌みスクリプト蚀語を探しおいたずきに、Luaに䌚いたした。 Luaはこれらのニヌズを満たすだけでなく、その驚くべきシンプルさず衚珟力にも魅了されたす。

Lua APIに䞍満があるずは蚀えたせん。これは䟿利で䜿いやすい優れた機胜セットです。 蚀語をアプリケヌションに統合し、独自の拡匵機胜を远加しおも問題は発生せず、「萜ずし穎」も発生したせんでした。 しかし、それでも、このC指向のAPIを䜿甚するずき、このプロセスがより䟿利になる可胜性があるずいう考えが残っおいたせんでした。 䟿利なオブゞェクト指向のラッパヌを䜜成する最初の詊みは倱敗したした。利甚可胜な資金では、私は存圚するに倀するものを䜜成できたせんでした。

そしお、 C ++ 11が登堎し 、私を劚げるすべおの障害が取り陀かれより正確に-䞍足しおいるものが远加されたした、パズルが埐々に圢になり始めたした。 2番目のアプロヌチは成功し、その結果、ほずんどの操䜜の自然な構文でかなり軜量なラッパヌラむブラリを䜜成するこずができたした。 私がLua API ++ず呌んだこのラむブラリは、 Lua APIの䟿利な代替品ずしお機胜するこずを目的ずしおいたす。 Lua Workshopでの私のプレれンテヌションに基づいたこの蚘事は、Lua API ++ずその機胜の基本抂念を理解するのに圹立ちたす。



䞻圹


知り合いは、ラむブラリで䜿甚される基本抂念ず、それらの関係から始める必芁がありたす。 予想どおり、これらの抂念は察応するタむプに反映されおいたす。

State
StateはLua州の所有者です。 これは独立したタむプであり、他のラむブラリずは実質的に無関係です。 状態の䜜成ず砎棄の制埡に加えお、ファむル、文字列、およびLua互換機胜を実行する手段のみを提䟛したす。 操䜜䞭に発生した゚ラヌは䟋倖に倉換されたす。

LFunction
ラむブラリ内の他のすべおは、 LFunction 、Lua API ++ず互換性のある特別な圢匏の関数内で発生したす。 これはLua互換機胜に類䌌しおおり、 CFunctionずいう名前が付けられおいCFunction 。 䞻に次の文字を入れるために、特別な関数圢匏が必芁でした

Context
Contextは、関数のコンテキストであり、Luaのすべおの機胜ぞのアクセスセンタヌです。 これを䜿甚しお、グロヌバル倉数、関数の匕数、 レゞストリ、およびupvaluesにアクセスできたす。 ガベヌゞコレクタを管理し、゚ラヌを通知し、耇数の戻り倀を枡し、障害を䜜成できたす。 簡単に蚀えば、 Contextを通じお、トレヌリングの特暩である倀の操䜜に盎接適甚されないすべおが行われたす。

䟡倀
同じ名前のクラスが明確に察応しおいた以前の抂念ずは異なり、Lua API ++の「倀」はやや曖昧ですもちろん、 Valueクラスは存圚したす。 これは䞻に、「オヌプンボヌダヌ」ポリシヌによるもので、Luaでネむティブ倀を自由に移行でき、その逆も可胜です。 Luaの倀が予想される堎合はい぀でも、サポヌトされおいる型のネむティブ倀を眮き換えるこずができ、それらは自動的にLuaスタックに「移動」したす。 暗黙の型倉換挔算子は、倀を反察方向に移動するのに圹立ちたす。実際の型ず期埅される型に互換性がない堎合は、䟋倖でこれを通知したす。
さらに、Luaの倀は、その起源に応じお、共通のむンタヌフェヌスをサポヌトするさたざたなタむプで衚すこずができたす。 このむンタヌフェむスは、倀に察するすべおの有効な操䜜を実装したす。ネむティブ型ぞの明瀺的および暗黙的な倉換、関数呌び出し、むンデックス付け、算術挔算、比范、型チェック、メタテヌブルの曞き蟌みおよび読み取り。

Valref
これは、スタックに配眮された倀ぞのリンクであり、むしろ、Luaスタックの特定のスロットほどではありたせん。 Valrefは、スタック䞊の倀の配眮たたは削陀をValrefしたせんが、倀の操䜜のみに焊点を合わせたす。 Lua API ++ Valrefは、倀を衚す他のタむプのむンタヌフェヌスに埓うモデルずしお機胜したす。

䞀時的な
操䜜の結果である䞀時的な倀では、やや耇雑です。 これらは、操䜜の結果ずしおスタックにプッシュされる たたはプッシュされない倀であり、 䞀床䜿甚されおから削陀されたす。 さらに、操䜜自䜓の匕数は他の操䜜の結果である堎合があり、成功を保蚌するものではありたせん。 たた、䜿甚方法が異なる堎合がありたす。スタックでの読み取りの結果ずしおむンデックスを䜜成するず、キヌの代わりに新しい倀が䜜成され、曞き蟌みの結果ずしお、キヌず蚘録された倀がスタックから削陀されたす。 操䜜の匕数の配眮順序を厳密に監芖する必芁性に぀いおはどうですか そしお、未䜿甚のオブゞェクトをどうするか
倚くの人は、おそらく私が䜕を埗おいるかをすでに掚枬しおいるでしょう。 䞀時的な倀はプロキシタむプによっお衚されたす。 これらは、ナヌザヌが目に芋えないようにテンプレヌトで蚭蚈し、 Valrefむンタヌフェヌスを再珟したす。 それらの䜿甚は簡単、簡単、䟿利ですが、間違いを犯すず、コンパむラヌは山括匧でいっぱいの膚倧な構成で「喜んで」くれたす。

アンカヌ
アンカヌには、1぀以䞊の倀をスタックに「固定」できるため、名前が付けられおいたす。 Valueは単䞀の倀の汎甚的な「アンカヌ」であり、 Tableテヌブル専甚であり、 Valsetは耇数の倀を栌玍したす。



メむンキャラクタヌが衚瀺されたので、それらを䜿甚しお䜕ができるかに぀いお、より詳现な分析を開始できたす。

State

Stateは、コンテキストの初期化に必芁なすべおのアクションを実行するデフォルトのコンストラクタヌがありたす。 別のコンストラクタヌを䜿甚するず、 カスタムメモリ管理関数を䜿甚できたす。 getRawState関数により、Lua APIで䜿甚される状態オブゞェクトぞの生のポむンタヌを芁求できたす。
このセットには、関数runFile 、 runString 、およびcall含たれおおり、簡単なむンタヌプリタヌを䜜成できたす。

最も単玔なむンタヌプリタヌ
 #include <iostream> #include <luapp/lua.hpp> using namespace std; using namespace lua; void interpretLine(State& state, const string& line) { try { state.runString(line); //    } catch(std::exception& e) { //          cerr << e.what() << endl; } } void interpretStream(State& state, istream& in) { string currentLine; while(!in.eof()) { //        getline(in, currentLine); interpretLine(state, currentLine); } } int main() { State state; interpretStream(state, cin); } 




゚ラヌ凊理


ラむブラリで䜿甚されるアプロヌチは、Luaの足元に収たるこずではないため、 TableからではなくTableを䜜成しようずするなど、ラむブラリ自䜓に関連する゚ラヌが蚺断されるか、ナヌザヌコヌドでおそらくむンタヌセプトする必芁がある゚ラヌが蚺断されたす、型キャスト゚ラヌのように。 ラむブラリは、Lua APIの呌び出し時に怜出される可胜性のある゚ラヌを事前に蚺断しようずしたせん。 したがっお、たずえば、実際に数倀である倀に察しお関数呌び出しを䜿甚しようずしおも、䟋倖は発生したせん。 lua_call呌び出し内で怜出され、Luaスタむルの゚ラヌ実行の䞭断ず保護された呌び出しの最も近いポむントに戻るが発生したす。



LFunction


実際、ラむブラリは、サポヌトされおいる型およびメンバヌ関数で動䜜する関数の「透明な」ラッパヌをサポヌトしおいたす。 Lua倀が期埅される関数の名前を単に述べおください。 しかし、Lua API ++が提䟛するすべおのLuaアメニティにアクセスする堎合は、このプロトタむプに埓っおL関数を蚘述する必芁がありたす。
 Retval myFunc(Context& c); 

ここではすべおが簡単です。関数はContextを受け取り、 RetvalはContext::ret関数を介しお任意の数の倀を簡単に返すのに圹立぀特別な型です。

mkcfテンプレヌトを䜿甚するず、 LFunction Luaを友達にできたす。
 int (*myCfunc)(lua_State*) = mkcf<myFunc>; 

このようにしお、関数のラッパヌを明瀺的に䜜成できたす。 「透明な」ラッパヌも機胜したすが、オヌバヌヘッドはわずかに高くなりたす。 䞀方、 mkcfはそれぞれの堎合に個別のラッパヌ関数を䜜成したす。
いずれにしおも、「ラッパヌ」はContextオブゞェクトを䜜成しお関数に枡し、䜜業が完了するず、 Retvalを通じおRetvalれた倀をLuaに枡したす。 ラップされた関数のスコヌプを超えるすべおの䟋倖はキャッチされ、Lua゚ラヌに倉換されたす。
関数はそれ自䜓を返したすか ちょうだい
 Retval retSelf(Context& c) { return c.ret(retSelf, mkcf<retSelf>); //    ,  - } 




Context


関数コンテキストは、Luaぞの䞭倮アクセスノヌドです。 倀の操䜜に盎接関係しないすべおは、 Context介しお行われたす。 私はgod objectに明確に䌌おいるずいうヒントを拒吊したせんが、この堎合、そのような決定はLua APIのアヌキテクチャによっお決定されたす。 Context介しお、ガベヌゞコレクタヌを制埡し、スタックに配眮されたバヌゞョン番号ず倀の数を確認できたす。 Lua APIを盎接䜿甚する必芁がある堎合に備えお、暗黙的にlua_State*に倉換されたす。 この堎合、マゞックLFunction より正確には、信号タむプの静的定数がinitializeExplicitlyれinitializeExplicitly 。これはinitializeExplicitly 。これにより、 LFunction倖郚でContext明瀺的に䜜成できたす。

戻り倀
returnステヌトメントで関数から返された倀を単玔に瀺すのがどんなに玠晎らしいずしおも、これは䞍可胜です。 2぀の最も近い遞択肢から遞択する必芁がありたした。カンマがオヌバヌロヌドされた挔算子たたは関数呌び出しを䜿甚したcな「スタヌタヌ」です。 フレンドシップ機胜が勝ちたした。 したがっお、 LFunctionはLFunction必芁がありたす。これは、控えめな名前ret Contextメ゜ッドにアクセスするこずによっおのみ䜜成できたす。 これは特別な関数です。呌び出された埌、スタックからの倀を捚おないようにスタックを停止したす。したがっお、 returnステヌトメントでのみ盎接䜿甚する必芁がありたす。 ret呌び出しでは、必芁な数の戻り倀をリストできたす。
比范
 return ctx.ret(1, "two", three); 

同等のコヌド
 lua_pushinteger(ctx, 1); lua_pushstring(ctx, "two"); lua_pushvalue(ctx, three); return 3; 



゚ラヌ報告
Retvalを䜜成する唯䞀の方法はret関数を䜿甚するこずであるず䞻匵しお、私は真実に眪を犯しおいたせんが、1぀の譊告がありたす...正匏な芳点から、このタむプを返すerror関数もありたす。 実際、 Retvalが䜜成に到達しないのは、この関数からのリタヌンがないためです。 期埅できる最倧倀は、メッセヌゞをLua゚ラヌ凊理゚ンゞンに枡すこずです。 Lua APIドキュメントでは、 returnステヌトメントでlua_error呌び出しを䜿甚しお、呌び出し䞭に関数が䞭断されるこずを瀺すこずを掚奚しおいたす。 同じアプロヌチがLua API ++でも䜿甚されおいるため、 error Retvalを返すerror宣蚀されおいRetval 。
゚ラヌメッセヌゞを含むLua倀が匕数ずしお䜿甚され、特にwhere関数が文字列を䜜成しお珟圚の関数を説明する行を䜜成できるため、ここでの連結は非垞に適切です。 メッセヌゞがたったく指定されおいない堎合、同じ倀が䜿甚されたす。
 if(verbose) return ctx.error(ctx.where() & " intentional error " & 42); else return ctx.error(); //   ,  return ctx.error(ctx.where()); 

同等のコヌド
 if(verbose) { luaL_where(ctx, 0); lua_pushstring(ctx, " intentional error "); lua_pushinteger(ctx, 42); lua_concat(ctx, 3); return lua_error(ctx); } else { luaL_where(ctx, 0); return lua_error(ctx); } 


環境ぞのアクセス
私たちのContextは明らかに䟡倀の䞻な源です。 実際、圌らはどこから来たのでしょうか
Contextクラスのパブリックメンバヌずしお蚭蚈されたアクセスオブゞェクトが提䟛されおいるため、環境のさたざたな興味深い堎所にアクセスできたす。 それらはすべお、倀の読み取りず曞き蟌みを蚱可したす。

たず第䞀に、これらargs 、関数の匕数です。 ナヌザヌがアクセスできない特別なタむプが䜜成された他のアクセスオブゞェクトずは異なり、通垞の定数Valsetがここで䜿甚されたす。 その䞍倉性ずは、サむズを倉曎できないこずだけを意味したすが、匕数の意味を曞き換えるこずは健康のためです。 ValsetはSTL互換のコンテナずしお䜜成されたため、その䞭の芁玠の番号付けは0から始たりたす。他の堎合、ラむブラリはLuaの芏則に埓い、むンデックス付けが1から始たるこずを意味したす。
 if(ctx.args.size() > 1 && ctx.args[0].is<string>()) {...}; 

同等のコヌド
  if(nArgs > 1 && lua_isstring(ctx, 1) ) {...}; 

2番目は、グロヌバル倉数ぞのアクセスです。 globalオブゞェクトは、文字列によっおむンデックス付けされたす。
 ctx.global["answer"] = 42; //      ,   

同等のコヌド
 lua_pushinteger(ctx, 42); lua_setglobal(ctx, "answer"); 

LFunctionもクロヌゞャである堎合、敎数むンデックス1から始たるすべおの倀が正しいを䜿甚しお、倀に栌玍されおいる倀にアクセスできたす。 栌玍されおいる倀の数を知る方法はありたせん。これはすでにわかっおいるず想定されおいたす。

レゞストリからアクセスできるLuaレゞストリは、2぀の方法で䜿甚されたす。 文字列キヌにより、ナヌザヌデヌタのメタテヌブルがそこに栌玍されたす。 敎数キヌは、レゞストリを倀のストアずしお䜿甚するずきに䜿甚されたす。 キヌは、 registry.storeを呌び出すこずによっお䜜成され、その埌registry.storeぞの読み取りず曞き蟌みに䜿甚され、倀が消去され、キヌが解攟されるず、 nil曞き蟌たれたす。
 auto k = ctx.registry.store(ctx.upvalues[1]); // decltype(k) == int ctx.registry [k] = nil; //  k       store 

同等のコヌド
 lua_pushvalue(ctx, lua_upvalueindex(1)); auto k = luaL_ref(ctx, LUA_REGISTRYINDEX); luaL_unref(ctx, LUA_REGISTRYINDEX, k); 

機胜
先ほど、Luaを䜿甚しおクロヌゞャを䜜成できるず述べたした。 Contextオブゞェクトはこれにclosure関数を䜿甚したす。 closure関数は、 CFunctionずクロヌゞャヌに栌玍される倀を受け取りたす。 結果は䞀時オブゞェクト、぀たり完党なLua倀です。
CFunction代わりに、 CFunctionをすぐに指定できたすが、この明るさには独自の䟡栌がありたす。 最初の䞊䜍倀は、結果のクロヌゞャヌで予玄されたすラッパヌはどのLFunctionでも同じであるため、関数のアドレスはそこに栌玍されたす。 同じ関数がLFunction透過的な移行に䜿甚され、同じ結果になりたす。 これは、䜕も予玄しないmkcfテンプレヌトずの違いですが、関数ごずに個別のラッパヌ関数を䜜成したす。

チャンクを䜜成するこずもできたすコンパむルされたLuaコヌド。 テキスト自䜓はchunkメ゜ッドを䜿甚しおコンパむルされ、ファむルのコンテンツはloadを䜿甚しおコンパむルされload 。 「完了しお忘れられた」堎合、 runStringずたったく同じrunStringずrunFileがありたす。 䜿甚に関しおは、チャンクは䞀般的な機胜です。

wrapメ゜ッドを䜿甚しお、互換性のない関数からクロヌゞャヌを䜜成するこずもできたす。 Luaスタックから匕数を取り、関数で受け入れられる倀に倉換し、呌び出しを行い、結果を戻り倀ずしおLuaスタックに配眮するラッパヌを自動的に䜜成したす。 デフォルトでは、これはナヌザヌデヌタを含むすべおのサポヌトされおいるタむプで機胜したす。 これで十分でない堎合たずえば、 vectorに栌玍された行で䜕かをする必芁がある堎合、 特別なマクロを䜿甚しお、ある方向たたは別の方向ぞの倉換を指定するこずもできたす。
関数を暗黙的に移行するずきに機胜するのはwrap 。 兄匟のvwrapメ゜ッドはほずんどすべお同じこずを行い、ラップされる関数によっお返される倀のみを無芖したす。



䟡倀の移行


Lua API ++は、次のネむティブタむプをサポヌトしおいたす。
数倀
int
unsigned int
long long
unsigned long long
float
double
ひも
const char*
std::string
機胜
CFunction: int (*) (lua_State*)
LFunction: Retval (*) (Context&)
任意の関数
メンバヌ関数
雑倚
Nil
bool
LightUserData: void*
登録ナヌザヌタむプ

衚にリストされおいる型の倀はLuaスタックに移行でき、その逆も可胜ですもちろん、 Nilず「ラッパヌ」関数は䟋倖で、ラッパヌぞのポむンタヌのたたです。
倀型に組み蟌たれた暗黙的な倉換挔算子ずcastテンプレヌト関数を䜿甚しお、逆移行が実行されたす。Lua倀に、目的のデヌタに倉換できないデヌタが含たれおいる堎合、䟋倖がスロヌされたす。 optcast関数は、䟋倖ではなく「フォヌルバック」倀を返したす。
 int a = val; auto b = val.cast<int>(); auto c = val.optcast<int>(42); 

同等のコヌド
 if(!lua_isnumber(ctx, valIdx)){ lua_pushstring(ctx, "Conversion error"); return lua_error(ctx); } int a = lua_tointeger(ctx, valIdx); if(!lua_isnumber(ctx, valIdx)){ lua_pushstring(ctx, "Conversion error"); return lua_error(ctx); } auto b = lua_tointeger(ctx, valIdx); auto c = lua_isnumber(ctx, valIdx) ? lua_tointeger(ctx, valIdx) : 42; 


is関数を䜿甚しお目的の型ずの互換性を確認し、typeを䜿甚しお、保存されおいる倀の型を盎接確認できたす。
 if(val.is<double>()) ...; if(val.type() == ValueTypes::Number) ...; 




単䞀倀操䜜


割り圓お
Valueがある堎合、䞀般的なケヌスでは、他のValueずネむティブの䞡方に䜕かを割り圓おるこずができたす。 ただし、これは䞀時的な倀、たずえば関数呌び出しの結果や長さには適甚されたせん。 =蚘号の巊偎にあるず、トリッキヌな゚ラヌが発生したす。 ただし、むンデックス付けやメタテヌブルなど、その他の䞀時的な倀の割り圓おは非垞に受け入れられたす。 実行されたアクションの意味に埓っお、割り圓おられるものずできないものを掚枬するのは簡単です。

メタテヌブル
mtメ゜ッドは、読み取りず曞き蟌みが可胜な倀のメタテヌブルぞのアクセスを提䟛したす。
 { Table mt = val.mt(); val.mt() = nil; } 

同等のコヌド
 if(!lua_getmetatable(ctx, valIdx)){ lua_pushstring(ctx, "The value has no metatable"); return lua_error(ctx); } int mtIdx = lua_gettop(ctx); lua_pushnil(ctx); lua_setmetatable(ctx, valIdx); lua_pop(ctx, 1); 


長さ
len関数の操䜜は、Luaのバヌゞョンによっお異なりたす。5.1互換モヌドではネむティブのsize_t返し、5.2モヌドでは䞀時的な倀を返したす。

玢匕付け
テヌブルのキヌ芁玠はむンデックスによっおアクセスされ、キヌはサポヌトされおいる任意のタむプにするこずができたす。 ただし、関数をラップするず、新しいクロヌゞャが䜜成されるこずを芚えおおく必芁がありたす。
 void myFunc(); Retval example(Context& c) { Table t(c); t[myFunc] = 42; //  myFunc   ... assert(t[myFunc].is<Nil>()); //   -  ,   . t[mkcf<example>] = 42.42; //     CFunction,   "" assert(t[mkcf<example>] == 42.42); } 

同等のコヌド
 void myFunc(); int wrapped_void_void(lua_State* s) { if(!lua_islightuserdata(ctx, lua_upvalueindex(1))) { lua_pushstring(ctx, "Conversion error"); return lua_error(ctx); } void (*fptr) () = reinterpret_cast<void(*)()>(lua_touserdata(ctx, lua_upvalueindex(1))); fptr(); return 0; } int mkcf_myFunc(lua_State* s) { myFunc(); return 0; } int example(lua_State* ctx) { lua_createtable(ctx, 0, 0); int t = lua_gettop(ctx); lua_pushlightuserdata(ctx, reinterpret_cast<void*>(&myFunc)); lua_pushcclosure(ctx, &wrapped_void_void, 1); lua_pushinteger(ctx, 42); lua_settable(ctx, t); lua_pushlightuserdata(ctx, reinterpret_cast<void*>(&myFunc)); lua_pushcclosure(ctx, &wrapped_void_void, 1); lua_gettable(ctx, t); assert(lua_isnil(ctx, -1)); lua_pushcfunction(ctx, &mkcf_myFunc); lua_pushnumber(ctx, 42.42); lua_settable(ctx, t); lua_pushcfunction(ctx, &mkcf_myFunc); lua_gettable(ctx, t); lua_pushnumber(ctx, 42.42); int result = lua_compare(ctx, -1, -2, LUA_OPEQ); lua_pop(ctx, 2); assert(result == 1); } 


関数呌び出し
Lua関数は、通垞の括匧を䜿甚しお呌び出されたす。 もっず衚珟力豊かなものが必芁な堎合のために、明瀺的な呌び出しのためのcallメ゜ッドがありたす。 pcall呌び出しぱラヌを防ぎたす。
 int x = fn(1); int y = fn.call(1); //    int z = fn.pcall(1); //     ,    

耇数の戻り倀
呌び出しの結果を通垞の倀ずしお安党に䜿甚できるこずがわかりたした。 しかし、䞀床に耇数の倀を返す関数はどうでしょうか たずえば、Luaでこのような関数を䜿甚したす。
 function mrv() return 2, 3, 4; end 

䞀床にいく぀かのオプションがありたす。
たず、呌び出し匏を䜿甚せずに呌び出しの結果を完党に無芖できたす。 返されるすべおの倀は単玔にスロヌされたす。
 mrv(); 

同等のコヌド
 lua_pushvalue(ctx, mrvIdx); lua_call(ctx, 0, 0); 

次に、呌び出し匏を通垞のLua倀ずしお䜿甚できたす。 次に、最初に返された倀のみが䜿甚され関数が䜕も返さない堎合はnil 、残りは再びスロヌされたす。
 Value x = mrv(); // x == 2 

同等のコヌド
 lua_pushvalue(ctx, mrvIdx); lua_call(ctx, 0, 1); int x = lua_gettop(ctx); 

第䞉に、倀のシヌケンスたずえば、関数パラメヌタヌを含むコンテキストでは、呌び出し匏が展開されたす返された倀はシヌケンスの䞀郚になりたす。
 print(1, mrv(), 5); //  1 2 3 4 5 

同等のコヌド
 lua_pushvalue(ctx, printIdx); int oldtop = lua_gettop(ctx); lua_pushinteger(ctx, 1); lua_pushvalue(ctx, mrvIdx); lua_call(ctx, 0, LUA_MULTRET); lua_pushinteger(ctx, 5); int nArgs = lua_gettop(ctx) - oldtop; lua_call(ctx, nArgs, 0); 

第4に、このためにValsetに考案されたすべおをValsetに保存するこずができたす。
 Valset vs = mrv.pcall(); // vs.size() == 3, vs.success() == true 

同等のコヌド
 int vsBegin = lua_gettop(ctx) + 1; lua_pushvalue(ctx, mrvIdx); bool vsSuccess = lua_pcall(ctx, 0, LUA_MULTRET) == LUA_OK; int vsSize = lua_gettop(ctx) + 1 - vsBegin; 

Valsetは、保護された呌び出しが成功したかどうかも蚘憶したすこの情報を取埗する唯䞀の方法です。 倱敗した堎合は、゚ラヌメッセヌゞが含たれたす。 嬉しいこずに、 Valsetは呌び出し匏ず同じ方法で倀のリストに展開できたす。
 print(1, vs, 5); //  1 2 3 4 5 

同等のコヌド
 lua_pushvalue(ctx, printIdx); int oldTop = lua_gettop(ctx); lua_pushInteger(ctx, 1); lua_pushvalue(ctx, mrvIdx); for(auto i = 0; i < vsSize; ++i) lua_pushvalue(ctx, vsBegin + i); lua_pushinteger(ctx, 5); int nArgs = lua_gettop(ctx) - oldtop; lua_call(ctx, nArgs, 0); 

Valset . STL- STL, «» Valref . Valset , push_back pop_back . Valref , ( Valset ), . , .




, Value- , :
 string s = "The answer to question " & val & " is " & 42; 

 lua_pushstring(ctx, "The answer to question "); lua_pushvalue(ctx, valIdx); lua_pushstring(ctx, " is "); lua_pushinteger(ctx, 42); lua_concat(ctx, 4); string s = lua_tostring(ctx, -1); lua_pop(ctx, 1); 

& . , «» . , Valset .

Lua, .

5.2 , , «» ^ .




, Table , Valref . , , , . raw , , , iterate , for_each . , iterate ( , , ), -. Valref true , false , . :
 Table t = ctx.global["myTable"]; t.iterate([] (Valref k, Valref v) { cout << int(k) << int(v); }); 

 lua_getglobal(ctx, "myTable"); if(!lua_istable(ctx, -1)){ lua_pushstring(ctx, "Conversion error"); return lua_error(ctx); } int t = lua_gettop(ctx); lua_pushnil(ctx); size_t visited = 0; while(lua_next(ctx, t)) { ++ visited; if(!lua_isnumber(ctx, -2) || !lua_isnumber(ctx, -1)){ lua_pushstring(ctx, "Conversion error"); return lua_error(ctx); } cout << lua_tointeger(ctx, -2) << lua_tointeger(ctx, -1); lua_pop(ctx, 1); } 

iterate .

Table — array records . .
 fn(Table::array(ctx, "one", 42, Table::array(ctx, 1, 2, 3))); //  ? ! 

 lua_pushvalue(ctx, fn); lua_createtable(ctx, 3, 0); lua_pushinteger(ctx, 1); lua_pushstring(ctx, "one"); lua_settable(ctx, -3); lua_pushinteger(ctx, 2); lua_pushinteger(ctx, 42); lua_settable(ctx, -3); lua_pushinteger(ctx, 3); lua_createtable(ctx, 3, 0); lua_pushinteger(ctx, 1); lua_pushinteger(ctx, 1); lua_settable(ctx, -3); lua_pushinteger(ctx, 2); lua_pushinteger(ctx, 2); lua_settable(ctx, -3); lua_pushinteger(ctx, 3); lua_pushinteger(ctx, 3); lua_settable(ctx, -3); lua_settable(ctx, -3); lua_call(ctx, 1, 0); 

, . , array , 1. , Valset .

records , -. .
 x.mt() = Table::records(ctx, "__index", xRead, "__newindex", xWrite, "__gc", xDestroy ); 

 lua_createtable(ctx, 0, 3); lua_pushstring(ctx, "__index"); lua_pushlightuserdata(ctx, reinterpret_cast<void*>(&xRead)); lua_pushcclosure(ctx, &wrapped_signature_1, 1); lua_settable(ctx, -3); lua_pushstring(ctx, "__newindex"); lua_pushlightuserdata(ctx, reinterpret_cast<void*>(&xWrite)); lua_pushcclosure(ctx, &wrapped_signature_2, 1); lua_settable(ctx, -3); lua_pushstring(ctx, "__gc"); lua_pushlightuserdata(ctx, reinterpret_cast<void*>(&xDestroy)); lua_pushcclosure(ctx, &wrapped_signature_3, 1); lua_settable(ctx, -3); lua_setmetatable(ctx, x); 




. - , : , cast , .
. LUAPP_USERDATA . , , . , registry -, :
 LUAPP_USERDATA(MyType, "MyType Lua ID") Retval setup(Context& ctx) { ctx.mt<MyType>() = Table::records(ctx); //   ,     ctx.registry["MyType Lua ID"] } 

Lua . , , «» , — .

Lua , Lua . Lua API++ placement new , , . POD-. , , .

. , -, , . , Lua , :
 #include <vector> using dvec = std::vector<double>; //      LUAPP_USERDATA(dvec, "Number array") //      dvec aCreate(size_t size) //    . { //  -       . return dvec(size); //  RVO        } void aDestroy(dvec& self) //  -        . { self.~dvec(); } void aWrite(dvec& self, size_t index, double val) //          __newindex { self.at(index) = val; //     at,     Lua } Retval setup(Context& c) { //   c.mt<dvec>() = Table::records(c, //     "__index", static_cast<double& (dvec::*)(size_t)> (&dvec::at), //         at //    (const  -const),      "__newindex", aWrite, "__len", dvec::size, //   size  vector ,    "__gc", aDestroy ); c.global["createArray"] = aCreate; //      return c.ret(); } 




おわりに


, Lua . Lua API ++, . Lua Lua API (coroutine, string buffers, ).

, Lua API, Lua. inline , Lua API , , Link time code generation (LTO GCC). header-only. inline Lua.

, C++11 , Lua STL. Boost Unit Test Framework .

Lua 5.2 ( 5.3 ), 5.1, LuaJIT.

Lua API++ MIT — , Lua, . HTML, .

, - .

Source: https://habr.com/ru/post/J201860/


All Articles