Lua クラス オブジェクトをスタックにプッシュしようとしています。そのオブジェクトへのポインターは、複数の関数から返すことができます。
言い換えれば、「==」、「~=」などを使用する機能を維持しながらユーザーデータ値をプッシュする必要があるため、同じC++オブジェクトの場合、ユーザーデータポインターは同じでなければなりません。
-- this should push the object onto the stack
local firstObject = GetClassObject();
firstObject:doSomething();
firstObject は lua スクリプトによって保存され、後でコードでこれを再度実行する必要があります。
-- the c++ class pointer has not changed here
-- so I would like to push the same userdata pointer as in the first call...
local object = GetClassObject();
-- if I would not do this the following here would fail... :C
if object == firstObject then
...
私の Push 関数は基本的に、どこかに同じ C++ クラス ポインターがあるかどうかを確認し、関連付けられているユーザーデータ ポインターをプッシュする必要があります (どのようにプッシュしても、オブジェクトは 1:1 で同じように動作するはずです)。
そうでない場合は、新しいユーザーデータを作成 (スタックにプッシュ) し、その内容をクラス オブジェクトに設定する必要があります。
これが私のコードです:
template <typename T>
void Push( const T &tObject )
{
lua_State *L = GetLuaState();
// Here i need to check if such a C++ object (the same tObject)
// already exists!
//
// If so i want to push the associated userdata.
// Object didn't exist yet -> we need a new userdata
void *pUserData = lua_newuserdata( L, sizeof( tObject ) );
*reinterpret_cast<T*>( pUserData ) = tObject;
}
template <typename T>
void Push( const T &tObject, const char *pszTable )
{
Push( tObject );
lua_State *L = GetLuaState();
luaL_getmetatable( L, pszTable );
lua_setmetatable( L, -2 );
}
template <typename T>
T& Get( int nIndex )
{
T *pUserData = reinterpret_cast<T*>( lua_touserdata( GetLuaState(), nIndex ) );
if( pUserData == nullptr )
throw std::exception( "Invalid userdata!" );
return *pUserData;
}
template <typename T>
T& Get( int nIndex, const char *pszTable )
{
T *pUserData = reinterpret_cast<T*>( LuaToUData( nIndex, pszTable ) );
if( pUserData == nullptr )
throw std::exception( "Invalid userdata!" );
return *pUserData;
}
LuaToUData は、lua エラーをスローしないように記述した独自の関数です。
void* LuaToUData( int nIndex, const char *pszTable )
{
void *pUserData = lua_touserdata( g_luaState, nIndex );
if( pUserData != nullptr )
{
if( lua_getmetatable( g_luaState, nIndex ) != 0 )
{
lua_getfield( g_luaState, LUA_REGISTRYINDEX, pszTable );
bool bEqual = ( lua_rawequal( g_luaState, -1, -2 ) == 1 );
lua_pop( g_luaState, 2 );
if( bEqual )
return pUserData;
}
}
return nullptr;
}