lugre_luabind_direct.h

Go to the documentation of this file.
00001 /*
00002 http://www.opensource.org/licenses/mit-license.php  (MIT-License)
00003 
00004 Copyright (c) 2007 Lugre-Team
00005 
00006 Permission is hereby granted, free of charge, to any person obtaining a copy
00007 of this software and associated documentation files (the "Software"), to deal
00008 in the Software without restriction, including without limitation the rights
00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 copies of the Software, and to permit persons to whom the Software is
00011 furnished to do so, subject to the following conditions:
00012 
00013 The above copyright notice and this permission notice shall be included in
00014 all copies or substantial portions of the Software.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00019 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00022 THE SOFTWARE.
00023 */
00024 #ifndef LUGRE_LUABIND_DIRECT_H
00025 #define LUGRE_LUABIND_DIRECT_H
00026 #include <vector>
00027 #include <string>
00028 #include <stdexcept>
00029 
00030 extern "C" {
00031     #include "lua.h"
00032     #include "lauxlib.h"
00033     #include "lualib.h"
00034 }
00035 
00036 namespace Lugre {
00037 
00038 // from scripting.cpp
00039 struct  luaL_reg make_luaL_reg      (const char *name,lua_CFunction func);
00040 
00041 // experiment to make lua binding using light user data and assigning metatables
00042 // does not do much typechecking -> might be faster, no smartpointable needed
00043 
00044 #define LUABIND_QUICKWRAP_STATIC(methodname,code) \
00045     {   class cTempClass : public cLuaBindDirectQuickWrapHelper { public: \
00046             static int methodname (lua_State *L) { PROFILE code return 0; }\
00047         }; \
00048         lua_register(L,#methodname,&cTempClass::methodname); \
00049     }
00050 #define LUABIND_QUICKWRAP(methodname,code) \
00051     {   class cTempClass : public cLuaBindDirectQuickWrapHelper { public: \
00052             static int methodname (lua_State *L) { PROFILE code return 0; }\
00053         }; \
00054         mlMethod.push_back(make_luaL_reg(#methodname,&cTempClass::methodname)); \
00055     }
00056 // shortcuts using LUABIND_QUICKWRAP in RegisterMethods
00057 //~ LUABIND_QUICKWRAP_STATIC(CreateSomething, { return CreateUData(L,cSomeFactory::getSingleton().CreateSomething()); });
00058 //~ LUABIND_QUICKWRAP(Destroy,              { delete checkudata_alive(L); });
00059 //~ LUABIND_QUICKWRAP(someMethod,           { GetSelf(L).someMethod(ParamInt(L,2)); });
00060 //~ LUABIND_QUICKWRAP(getSomeValue,         { return PushNumber(L,GetSelf(L).getSomeValue()); });
00061 // trick : GetSelf : inside a method of cParentClass : other static methods of cParentClass can be called without cParentClass:: prefix from inside local classes
00062 
00063 
00064 #define LUABIND_DIRECTWRAP_RETURN_ONE_ALTNAME(returnpushfun,newname,methodname,paramcode)   LUABIND_QUICKWRAP(  newname,    { return returnpushfun(L,GetSelf(L).methodname paramcode ); });
00065 #define LUABIND_DIRECTWRAP_RETURN_VOID_ALTNAME(newname,methodname,paramcode)                LUABIND_QUICKWRAP(  newname,    { GetSelf(L).methodname paramcode ; });
00066 
00067 #define LUABIND_DIRECTWRAP_RETURN_ONE_NAMEADD(returnpushfun,methodname,nameadd,paramcode)   LUABIND_DIRECTWRAP_RETURN_ONE_ALTNAME(returnpushfun,methodname##nameadd,methodname,paramcode)
00068 #define LUABIND_DIRECTWRAP_RETURN_VOID_NAMEADD(methodname,nameadd,paramcode)                LUABIND_DIRECTWRAP_RETURN_VOID_ALTNAME(methodname##nameadd,methodname,paramcode)
00069 
00070 #define LUABIND_DIRECTWRAP_RETURN_ONE(returnpushfun,methodname,paramcode)   LUABIND_DIRECTWRAP_RETURN_ONE_ALTNAME(returnpushfun,methodname,methodname,paramcode)
00071 #define LUABIND_DIRECTWRAP_RETURN_VOID(methodname,paramcode)                LUABIND_DIRECTWRAP_RETURN_VOID_ALTNAME(methodname,methodname,paramcode)
00072 
00073 
00074 #define LUABIND_DIRECTWRAP_BASECLASS(classname) RegisterBaseClass(cLuaBindDirect<classname>::GetSingletonPtr(),#classname);
00075         
00076 #define LUABIND_PrefixConstant(prefix,name) cScripting::SetGlobal(L,#name,prefix::name);
00077 
00078 // to be used inside cLuaBindDirectQuickWrapHelper derivates, e.g. cLuaBindDirectOgreHelper
00079 #define LUABIND_DIRECTWRAP_HELPER_ENUM(prefix,name) \
00080     static inline prefix::name  Param##name (lua_State *L,int i)        { return (prefix::name)ParamInt(L,i); }
00081 #define LUABIND_DIRECTWRAP_HELPER_OBJECT(mytype,name) \
00082     static inline mytype&       ParamByRef##name    (lua_State *L,int i)        { return *cLuaBindDirect<mytype>::checkudata_alive(L,i); } \
00083     static inline mytype*       Param##name         (lua_State *L,int i)        { return cLuaBindDirect<mytype>::checkudata_alive(L,i); } \
00084     static inline int           Push##name          (lua_State *L,mytype* v)    { return cLuaBindDirect<mytype>::CreateUData(L,v); }
00085 #define LUABIND_DIRECTWRAP_HELPER_OBJECT_PREFIX(prefix,mytypename) LUABIND_DIRECTWRAP_HELPER_OBJECT(prefix::mytypename,mytypename)
00086 
00087 #define LUABIND_DIRECTWRAP_HELPER_PUSH_COPY(prefix,mytype) \
00088     static inline int           PushCopy##mytype    (lua_State *L,prefix::mytype& v)    { return cLuaBindDirect<prefix::mytype>::CreateUData(L,new prefix::mytype(v)); }
00089             
00091 class cLuaBindDirectQuickWrapHelper { public: 
00092     static inline bool          ParamIsSet      (lua_State *L,int i) { return lua_gettop(L) >= i && !lua_isnil(L,i); }
00093     
00094     static inline std::string   ParamString     (lua_State *L,int i) { return std::string(luaL_checkstring(L,i)); }
00095     static inline int           ParamInt        (lua_State *L,int i) { return luaL_checkint(L,i); }
00096     static inline float         ParamFloat      (lua_State *L,int i) { return luaL_checknumber(L,i); }
00097     static inline lua_Number    ParamNumber     (lua_State *L,int i) { return luaL_checknumber(L,i); }
00098     static inline bool          ParamBool       (lua_State *L,int i) { return lua_isboolean(L,i) ? lua_toboolean(L,i) : luaL_checkint(L,i); }
00099     static inline void*         ParamPointer    (lua_State *L,int i) {
00100         void** p = (void**)lua_touserdata(L,i); // designed for FULL userdata (as light doesn't support metatables -> not used for directbind anymore)
00101         if (p == 0 && !lua_isuserdata(L,i)) luaL_typerror(L, i, lua_typename(L,LUA_TUSERDATA)); // check type + error msg 
00102         return *p; 
00103     }
00104     
00105     static inline void                          ParamFloatArr       (lua_State *L,int i,float* arr,int len) {
00106         if (!lua_istable(L,i)) luaL_typerror(L, i, lua_typename(L,LUA_TTABLE)); // check type + error msg 
00107         for (int k=0;k<len;++k) {
00108             lua_rawgeti(L,i,k+1);
00109             arr[k] = lua_tonumber(L,-1); 
00110             lua_pop(L,1);
00111         }
00112     }
00113     
00114     static inline std::string   ParamStringDefault      (lua_State *L,int i,std::string d)  { return ParamIsSet(L,i) ? ParamString(L,i) : d; }
00115     static inline int           ParamIntDefault         (lua_State *L,int i,int d)          { return ParamIsSet(L,i) ? ParamInt(L,i) : d; }
00116     static inline float         ParamFloatDefault       (lua_State *L,int i,float d)        { return ParamIsSet(L,i) ? ParamFloat(L,i) : d; }
00117     static inline lua_Number    ParamNumberDefault      (lua_State *L,int i,lua_Number d)   { return ParamIsSet(L,i) ? ParamNumber(L,i) : d; }
00118     static inline bool          ParamBoolDefault        (lua_State *L,int i,bool d)         { return ParamIsSet(L,i) ? ParamBool(L,i) : d; }
00119     static inline void*         ParamPointerDefault     (lua_State *L,int i,void* d)        { return ParamIsSet(L,i) ? ParamPointer(L,i) : d; }
00120     
00121     static inline int           PushBool        (lua_State *L,bool v)           { lua_pushboolean(L,v);         return 1; }
00122     static inline int           PushString      (lua_State *L,const char* v)    { lua_pushstring(L,v);          return 1; }
00123     static inline int           PushString      (lua_State *L,std::string v)    { lua_pushstring(L,v.c_str());  return 1; }
00124     static inline int           PushNumber      (lua_State *L,lua_Number v)     { lua_pushnumber(L,v);          return 1; }
00125     static inline int           PushNil         (lua_State *L)                  { lua_pushnil(L);               return 1; }
00126     static inline int           PushPointer     (lua_State *L,void* v)          { lua_pushlightuserdata(L,v);   return 1; }
00127 };
00128 
00129 
00130 
00131 class cLuaBindDirectBase : public cLuaBindDirectQuickWrapHelper { public:   
00132     std::vector<struct luaL_reg> mlMethod;
00133 };
00134 
00135 template<class _T> class cLuaBindDirect : public cLuaBindDirectBase { public:   
00136     
00138     virtual const char* GetLuaTypeName () = 0;
00139     
00141     virtual void RegisterMethods    (lua_State *L) = 0;
00142     
00143     void    RegisterBaseClass   (cLuaBindDirectBase* pBase,const char* szParentClassName) {
00144         if (!pBase) { throw std::runtime_error(strprintf("luabinddirect : failed to load baseclass '%s' of '%s', make sure the baseclass is registered first",szParentClassName,GetLuaTypeName())); }
00145         mlMethod.insert(mlMethod.begin(),pBase->mlMethod.begin(),pBase->mlMethod.end()); // append complete pBase to self
00146     }
00147     
00148     static inline int       CreateUData     (lua_State *L,_T* target) { PROFILE 
00149         if (!target) return 0;
00150         //~ lua_pushlightuserdata(L,target); // obsolete : light userdata does NOT have individual metadata, just a global one for all light -> createA() createB() assert(a.methodA) fails
00151         
00152         void** o = (void**)lua_newuserdata(L,sizeof(void*));
00153         *o = target;
00154         
00155         //~ printf("cLuaBindDirect::CreateUData: singleton:%p\n",GetSingletonPtr());
00156         //~ printf("cLuaBindDirect::CreateUData: typename:%s\n",GetSingletonPtr()->GetLuaTypeName());
00157         luaL_getmetatable(L,GetSingletonPtr()->GetLuaTypeName());
00158         lua_setmetatable(L,-2); // pops table from stack and sets it as metatable at -2 (light-user-data)
00159         return 1; // lightuserdata remains on stack
00160     }
00161     
00163     static inline void      RemoveMetaTable (lua_State *L,int i=1) { PROFILE 
00164         lua_pushnil(L);
00165         lua_setmetatable(L,i); // pops table from stack and sets it as metatable at i (light-user-data)
00166     }
00167     
00169     static inline _T& GetSelf           (lua_State *L,int i=1) { return *(_T*)(*(void**)lua_touserdata(L,i)); }
00170     static inline _T* checkudata        (lua_State *L,int i=1) { return (_T*)(*(void**)lua_touserdata(L,i)); }
00171     static inline _T* checkudata_alive  (lua_State *L,int i=1) { return (_T*)(*(void**)lua_touserdata(L,i)); }
00172     
00173     void    LuaRegister  (lua_State *L) { PROFILE
00174         mlMethod.clear(); // avoid doubling when preparing multithreading / multiple lua states
00175         
00176         // you can also make a nice little macro to avoid double typing :
00177         // #define REGISTER_METHOD(methodname) mlMethod.push_back(make_luaL_reg(#methodname,&cYourDerivedClass::methodname));
00178         // REGISTER_METHOD(Spawn);
00179         
00180         // static methods like this :
00181         // lua_register(L,"CreateBla",  &cYourDerivedClass::CreateBla);
00182         
00183         RegisterMethods(L);
00184         
00185         // now create and register the metatable with the methods...
00186         
00187         int res = luaL_newmetatable(L,GetSingletonPtr()->GetLuaTypeName()); 
00188         if (res != 1) { printf("cLuaBindDirect:LuaRegister : classname already used\n"); }
00189         
00190         // create table with methods (will later be set as metatable.__index)
00191         lua_newtable(L); // pushes new table on stack
00192         for (int i=0;i<mlMethod.size();++i) {
00193             lua_pushcfunction(L,mlMethod[i].func);
00194             lua_setfield(L,-2,mlMethod[i].name); // pops value (cfun)
00195         }
00196         
00197         // set as metatable.__index
00198         lua_setfield(L,-2,"__index"); // pops value (method table)
00199         lua_pop(L,1); // pop metatable, is now in registry, not needed anymore
00200     }
00201     
00202     // internals
00203         
00204     virtual ~cLuaBindDirect(){};
00205     
00206     static cLuaBindDirect<_T>*   GetSingletonPtr    (cLuaBindDirect<_T>* prototype=0) { PROFILE
00207         static cLuaBindDirect<_T>* pSingleton = 0;
00208         if (pSingleton) return pSingleton;      
00209         pSingleton = prototype;
00210         assert(pSingleton);
00211         return pSingleton;
00212     }
00213 };
00214     
00215     
00216 };
00217 
00218 #endif

Generated on Wed Feb 8 06:00:12 2012 for cpp by  doxygen 1.5.6