├── .gitignore ├── LICENSE ├── example ├── example.lua ├── embedded.cpp └── example.cpp ├── README.md └── luaaa.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Others 35 | .vs 36 | .vscode 37 | example/example 38 | example/vs2015 39 | example/example 40 | example/embedded 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 gengyong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/example.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | luaaa = {} 4 | function luaaa:extend(base, obj) 5 | derived = obj or {} 6 | derived.new = function(self, ...) 7 | o = base.new(...) 8 | setmetatable(self, getmetatable(o)) 9 | self["@"] = o 10 | return self 11 | end 12 | return derived 13 | end 14 | 15 | function luaaa:base(obj) 16 | if (type(obj) == "table") then 17 | return obj["@"] 18 | end 19 | return nil 20 | end 21 | 22 | 23 | function serialize(obj) 24 | local str = "" 25 | local t = type(obj) 26 | if t == "number" then 27 | str = str .. obj 28 | elseif t == "boolean" then 29 | str = str .. tostring(obj) 30 | elseif t == "string" then 31 | str = str .. obj 32 | elseif t == "table" then 33 | str = str .. "{" 34 | for k, v in pairs(obj) do 35 | str = str .. "[" .. serialize(k) .. "]=" .. serialize(v) .. "," 36 | end 37 | local metatable = getmetatable(obj) 38 | if metatable ~= nil and type(metatable.__index) == "table" then 39 | for k, v in pairs(metatable.__index) do 40 | str = str .. "[" .. serialize(k) .. "]=" .. serialize(v) .. "," 41 | end 42 | end 43 | str = str .. "}" 44 | elseif t == "nil" then 45 | str = "nil" 46 | else 47 | error("can not serialize a " .. t .. " type.") 48 | end 49 | return str 50 | end 51 | 52 | function luaCallback(param) 53 | return param + 1 54 | end 55 | 56 | function testAwesomeCat() 57 | local a = AwesomeCat.new ("BINGO") 58 | for key,value in pairs(getmetatable(a)) do 59 | print(key, value) 60 | end 61 | 62 | a:setAge(2); 63 | print(a) 64 | a:eat({"fish", "milk", "cookie", "rice"}); 65 | print(a) 66 | print("cat test: send params to c++: (0:0, 1:1, 2:2, 3:3, 4:4)"); 67 | a:test(0, 1, 2, 3, 4) 68 | a:speak("Thanks!") 69 | if not WITHOUT_CPP_STDLIB then 70 | print(a:testFunctor1(99999, 88888)) 71 | print(a:testFunctor2(77777, 66666)) 72 | a:testfunctor(luaCallback) 73 | end 74 | 75 | a.say = "I am a cat!"; 76 | a.age = 12 77 | print("=================== a.age:", a.age) 78 | a.name = "HeroCat"; 79 | print("=================== a.name:", a.name) 80 | a.prop1 = "white"; 81 | print("=================== a.prop1:", a.prop1) 82 | if not WITHOUT_CPP_STDLIB then 83 | a.prop2 = 9999123; 84 | print("=================== a.prop2:", a.prop2) 85 | a.prop3 = { 'aaa', 'bbb', 'ccc', 'ddd' }; 86 | print("=================== a.prop3:", serialize(a.prop3)) 87 | a.prop4 = 1.234; 88 | print("=================== a.prop3:", a.prop4) 89 | end 90 | 91 | end 92 | 93 | function testAwesomeMod() 94 | print("===================before assign AwesomeMod.notexists:", AwesomeMod.notexists2) 95 | AwesomeMod.notexists2 = "asdadsasda"; 96 | print("=================== after assign AwesomeMod.notexists:", AwesomeMod.notexists2) 97 | 98 | AwesomeMod.prop1 = "white"; 99 | print("=================== AwesomeMod.prop1:", AwesomeMod.prop1) 100 | if not WITHOUT_CPP_STDLIB then 101 | AwesomeMod.prop2 = 9999123; 102 | print("=================== AwesomeMod.prop2:", AwesomeMod.prop2) 103 | AwesomeMod.prop3 = "abcdefg"; 104 | print("=================== AwesomeMod.prop3:", serialize(AwesomeMod.prop3)) 105 | AwesomeMod.prop4 = 1.234; 106 | print("=================== AwesomeMod.prop4:", AwesomeMod.prop4) 107 | end 108 | 109 | print ("AwesomeMod.cint:" .. AwesomeMod.cint) 110 | print ("AwesomeMod.cstr:" .. AwesomeMod.cstr) 111 | print ("AwesomeMod.dict:") 112 | for k,v in pairs(AwesomeMod.dict) do 113 | print(tostring(k) .. "=" .. tostring(v)) 114 | end 115 | 116 | print ("-------- AwesomeMod.testSet() --------") 117 | AwesomeMod.testSet({11, 12, "13", 14, "15", 16, 17, 18, "2019", "2020"}, {5, 4, 3, 2, 1}); 118 | 119 | 120 | print ("-------- AwesomeMod.testSetSet() --------") 121 | AwesomeMod.testSetSet({ 122 | {}, 123 | {"what", "who", "where"}, 124 | {797, 454, 828, "something"}, 125 | {"alpha, beta", "gamma"} 126 | }); 127 | 128 | print ("-------- AwesomeMod.testMapMap() --------") 129 | AwesomeMod.testMapMap({ 130 | animal = { 131 | dog = "woof", 132 | cat = "meow", 133 | cow = "moo" 134 | }, 135 | rank = { 136 | first = "Tom", 137 | second = "Lee", 138 | third = "Mike" 139 | } 140 | }); 141 | 142 | if not WITHOUT_CPP_STDLIB then 143 | print("-------- AwesomeMod.testTuple() --------") 144 | local values = AwesomeMod.testTuple({"a duck", 999, 1.234}) 145 | print("Lua got multiple values from c++:") 146 | for i = 1, #values do 147 | print("[" .. i .. "]" .. values[i]) 148 | end 149 | 150 | -- AwesomeMod.testTuple2() accept only empty tuple 151 | local values2 = AwesomeMod.testTuple2({"a duck", 999, 1.234}) 152 | print("Lua got empty tuple from c++.") 153 | for k,v in pairs(values2) do 154 | print("[" .. tostring(k) .. "]" .. tostring(v)) 155 | end 156 | end 157 | 158 | print("-------- AwesomeMod.testMultipleParams() --------") 159 | AwesomeMod.testMultipleParams(0,1,"two",3.3,44.44) 160 | 161 | print("-------- AwesomeMod.testPosition() --------") 162 | local positionA = { x = 100, y = 200, z = 300 } 163 | local positionB = { x = 11, y = 22, z = 33 } 164 | local result = AwesomeMod.testPosition(positionA, positionB) 165 | print("positionA["..serialize(positionA).."] + positionB["..serialize(positionB).."] = "..serialize(result)) 166 | 167 | if not WITHOUT_CPP_STDLIB then 168 | print("-------- AwesomeMod.testFunctor --------") 169 | print(AwesomeMod.testFunctor1(123, 456.78)) 170 | print(AwesomeMod.testFunctor2(789, 111.11)) 171 | end 172 | 173 | end 174 | 175 | 176 | function testCallback () 177 | local f = function(a, b, c) 178 | print ("lua testCallback:") 179 | print (" param a:" .. tostring (a)) 180 | print (" param b:" .. tostring (b)) 181 | print (" param c:" .. tostring (c)) 182 | print (" return b * b(" .. tostring(b * b) ..") as result to c++.\n") 183 | return b * b; 184 | end 185 | 186 | AwesomeMod.testCallback(f, 5555, "lua text") 187 | end 188 | 189 | function testCallbackFunctor () 190 | if not WITHOUT_CPP_STDLIB then 191 | local f = function(a, b, c) 192 | print ("lua testCallbackFunctor:") 193 | print (" param a:" .. tostring (a)) 194 | print (" param b:" .. tostring (b)) 195 | print (" param c:" .. tostring (c)) 196 | print (" return b * b(" .. tostring(b * b) ..") as result to c++.\n") 197 | return b * b; 198 | end 199 | AwesomeMod.testCallbackFunctor(f, 8888, "lua text from testCallbackFunctor") 200 | end 201 | 202 | end 203 | 204 | function testAutoGC () 205 | local cat = AwesomeCat.new("IWILLLEAVE"); 206 | cat:speak("I will leave ...") 207 | cat = nil; 208 | collectgarbage () 209 | end 210 | 211 | 212 | function testSingletonAndGC() 213 | local world = SingletonWorld.new("chaos"); 214 | print("new world tag:"..world:getTag()) 215 | world = nil 216 | collectgarbage() 217 | 218 | local world = SingletonWorld.getInstance(); 219 | print("singleton world tag:"..world:getTag()) 220 | world = nil 221 | collectgarbage() 222 | 223 | 224 | local world = SingletonWorld.newInstance("new instance"); 225 | print("new world instance tag:"..world:getTag()) 226 | world = nil 227 | collectgarbage() 228 | 229 | local world=SingletonWorld.managedInstance("managed instance"); 230 | print("managed world instance tag:"..world:getTag()) 231 | world = nil 232 | collectgarbage() 233 | end 234 | 235 | 236 | function testClassInheritance() 237 | SpecialCat = luaaa:extend(AwesomeCat, {value = 1}) 238 | 239 | function SpecialCat:onlyInSpecial() 240 | print(self:getName() .. " has a special cat function") 241 | print(self:getName() .. " has value:" .. self.value) 242 | end 243 | 244 | function SpecialCat:speak(text) 245 | print("Special cat[" .. self:getName() .. "] says: " .. text) 246 | end 247 | 248 | sss = SpecialCat:new("sss") 249 | sss:onlyInSpecial() 250 | sss:speak("I am Special Cat!") 251 | print("call base class's method speak():") 252 | luaaa:base(sss):speak("I am Special and Awesome Cat!") 253 | 254 | end 255 | 256 | print ("\nLUAAA_WITHOUT_CPP_STDLIB:", WITHOUT_CPP_STDLIB); 257 | 258 | print ("\n\n-- 1 --. Test auto GC\n") 259 | testAutoGC(); 260 | 261 | print ("\n\n-- 2 --. Test AwesomeCat class\n") 262 | testAwesomeCat(); 263 | 264 | print ("\n\n-- 3 --. Test AwesomeMod module\n") 265 | testAwesomeMod (); 266 | 267 | print ("\n\n-- 4 --. Test others\n") 268 | print ("pi = " .. pi .. "\n") 269 | 270 | print ("\n\n-- 5 --. Test Callback\n") 271 | testCallback(); 272 | 273 | print ("\n\n-- 6 --. Test CallbackFunctor\n") 274 | testCallbackFunctor(); 275 | 276 | print ("\n\n-- 7 --. Test Class Inheritance\n") 277 | testClassInheritance(); 278 | 279 | print ("\n>>>>" .. collectgarbage ("count")) 280 | collectgarbage () 281 | print ("\n<<<<" .. collectgarbage ("count")) 282 | 283 | print("\n\n-- 8 --. Test Singleton and GC\n") 284 | testSingletonAndGC() 285 | 286 | print("\n>>>>"..collectgarbage("count")) 287 | collectgarbage() 288 | print("\n<<<<"..collectgarbage("count")) 289 | 290 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Introduction 3 | 4 | Luaaa is a simple tool to bind c++ class to lua. 5 | 6 | It was implemented intent to use only one header file, with simple interface, easy to integrate to existing project. 7 | 8 | With luaaa, you don't need to write wrapper codes for existing class/function, and you don't need to run any other tool to generate wrapper codes. Just define the class to export and enjoy using it in lua. 9 | 10 | Luaaa has no dependencies to other libs but lua and c++11 standard lib, no cpp files. 11 | 12 | To use it, just copy and include 'luaaa.hpp' in source file. 13 | 14 | feel free to report bugs. 15 | ## Features 16 | 17 | * simple. 18 | * no wrapper codes. 19 | * works with lua from 5.1 to 5.4, and luajit. 20 | 21 | ## Quick Start 22 | 23 | export a class to lua: 24 | ```cpp 25 | 26 | // include luaaa file 27 | #include "luaaa.hpp" 28 | using namespace luaaa; 29 | 30 | 31 | // Your existing class 32 | class Cat 33 | { 34 | public: 35 | Cat(); 36 | virtual ~Cat(); 37 | public: 38 | void setName(const std::string&); 39 | const std::string& getName() const; 40 | void eat(const std::list& foods); 41 | static void speak(const std::string& w); 42 | //... 43 | private: 44 | //... 45 | }; 46 | 47 | 48 | lua_State * state; // create and init lua 49 | 50 | // To export it: 51 | LuaClass luaCat(state, "AwesomeCat"); 52 | luaCat.ctor(); 53 | luaCat.fun("setName", &Cat::setName); 54 | luaCat.fun("getName", &Cat::getName); 55 | luaCat.fun("eat", &Cat::eat); 56 | // static member fuction was exported as Lua class member fuction. 57 | // from Lua, call it as same as other member fuctions. 58 | luaCat.fun("speak", &Cat::speak); 59 | luaCat.def("tag", "Cat"); 60 | 61 | // Done. 62 | 63 | ``` 64 | 65 | ok, then you can access lua class "AwesomeCat" from lua. 66 | ```lua 67 | 68 | local cat = AwesomeCat.new("Bingo"); 69 | cat:eat({"fish", "milk", "cookie", "odd thing" }); 70 | cat:speak("Thanks!"); 71 | 72 | ``` 73 | 74 | you can add property to AwesomeCat: 75 | ```cpp 76 | luaCat.set("name", &Cat::setName); 77 | luaCat.get("name", &Cat::getName); 78 | luaCat.set("age", &Cat::setAge); 79 | luaCat.get("age", &Cat::getAge); 80 | ``` 81 | 82 | then you can access property from lua as below: 83 | ```lua 84 | local oldName = cat.name; 85 | print("cat's old name:", oldName); 86 | cat.name = "NewName"; 87 | print("cat's new name:", cat.name); 88 | ``` 89 | for the property getter, property type depends on the return value of getter function. 90 | 91 | property getter accepts a function likes below: 92 | ```cpp 93 | // 1) member function of origin c++ class which has no parameter 94 | luaCat.get("name", &Cat::getName); 95 | 96 | // 2) global function which has no parameter 97 | //std::string getProp1() { 98 | // return "whatever"; 99 | //} 100 | luaCat.get("prop1", getProp1); 101 | 102 | // 3) global function which has origin c++ class as the only ONE parameter, parameter can be const or non-const. 103 | //std::string getProp2(const Cat& cat) { 104 | // return cat.name; 105 | //} 106 | luaCat.get("prop2", getProp2); 107 | 108 | // 4) a lambda function which has no parameter 109 | luaCat.get("prop3", []() -> float { return 0.123f; }); 110 | 111 | // 5) a lambda function which has origin c++ class as the only ONE parameter, parameter can be const or non-const. 112 | luaCat.get("prop4", [](Cat& cat) -> float { return cat.getWeight(); }); 113 | 114 | ``` 115 | 116 | for the property setter, property type depends on the parameter of setter function. 117 | 118 | property setter accepts a function likes below: 119 | ```cpp 120 | // 1) member function of origin c++ class which has only ONE parameter 121 | // in lua, 122 | // cat.name = "some thing..."; 123 | // will call c++ function: 124 | // catObject.setName("some thing..."); 125 | luaCat.set("name", &Cat::setName); 126 | // in lua, 127 | // cat.age = 2; 128 | // will call c++ function: 129 | // catObject.setAge(2); 130 | luaCat.set("age", &Cat::setAge); 131 | 132 | // 2) global function which has only ONE parameter 133 | //void setProp1(cons std::string p) { 134 | // // do some thing... 135 | //} 136 | // in lua, 137 | // cat.prop1 = "prop value"; 138 | // will call c++ function: 139 | // setProp1("prop value"); 140 | luaCat.set("prop1", setProp1); 141 | 142 | // 3) global function which accepts an origin c++ class and an extra parameter, origin c++ class can be const or non-const. 143 | //void setProp2(Cat& cat, const std::string p) { 144 | // cat.setName(p); 145 | //} 146 | // in lua, 147 | // cat.prop2 = "prop value"; 148 | // will call c++ function: 149 | // setProp2(catObject, "prop value"); 150 | luaCat.set("prop2", setProp2); 151 | 152 | // 4) lambda function which has only ONE parameter 153 | luaCat.set("prop3", [](float val) -> void { printf("set prop3=%f\n", val); }); 154 | 155 | // 5) lambda function which accepts an origin c++ class and an extra parameter, origin c++ class can be const or non-const. 156 | luaCat.set("prop4", [](Cat& cat, float val) -> void { cat.setWeight(val); }); 157 | ``` 158 | 159 | if a property has only getter, it's read-only, if it has only setter, it's write-only, or if has both setter and getter, it can be read&write. 160 | 161 | if write a read-only property, or read a write-only property from lua, a lua exception will be rised: 162 | 163 | for example, with below defination: 164 | ```cpp 165 | LuaClass luaCat(state, "AnotherCat"); 166 | luaCat.ctor(); 167 | luaCat.set("name", &Cat::setName); 168 | luaCat.get("age", &Cat::getAge); 169 | ``` 170 | 171 | in lua: 172 | ```lua 173 | local cat = AnotherCat.new("Orange"); 174 | print("Cat name:", cat.name); 175 | ``` 176 | will rise below exception: 177 | ```bash 178 | lua err: [string "console"]:79: attempt to read Write-Only property 'name' of 'AwesomeCat' 179 | ``` 180 | 181 | ```lua 182 | local cat = AnotherCat.new("Orange"); 183 | cat.age = 10; 184 | ``` 185 | will rise below exception: 186 | ```bash 187 | lua err: [string "console"]:1: attempt to write Read-Only property 'age' of 'AwesomeCat' 188 | ``` 189 | 190 | 191 | to export constructors, for example, instance getter of singleton pattern: 192 | ```cpp 193 | LuaClass luaWorld(L, "SingletonWorld"); 194 | /// use class constructor as instance spawner, default destructor will be called from gc. 195 | luaWorld.ctor(); 196 | 197 | /// use static function as instance spawner, default destructor will be called from gc. 198 | luaWorld.ctor("newInstance", &SingletonWorld::newInstance); 199 | 200 | /// use static function as instance spawner and static function as delete function which be called from gc. 201 | luaWorld.ctor("managedInstance", &SingletonWorld::newInstance , &SingletonWorld::delInstance); 202 | 203 | /// for singleton pattern, set deleter(gc) to nullptr to avoid singleton instance be destroyed. 204 | luaWorld.ctor("getInstance", &SingletonWorld::getInstance, nullptr); 205 | ``` 206 | instance spawner and delete function can be static member function or global function, 207 | and delete function must accept one instance pointer which to be collect back or delete. 208 | 209 | 210 | A 'ctor'(constructor) is always required for LuaClass, you can define more than one 'ctor'. 211 | In most case, a 'ctor' likes below is enought: 212 | ```cpp 213 | LuaClass luaCls(luaState, 'XXXname'); 214 | luaCls.ctor(); 215 | ``` 216 | 217 | > above codes will define a lua object constructor named as 'new', in lua `XXXname.new()` equivalent to C++: 218 | 219 | ```cpp 220 | new XXX(); 221 | ``` 222 | 223 | > or change constructor name to 'create': 224 | 225 | ```cpp 226 | luaCls.ctor("create"); 227 | ``` 228 | 229 | > if C++ constructor is not the default constructor, add sigature to match C++ class constructor: 230 | 231 | ```cpp 232 | luaCls.ctor('create'); 233 | ``` 234 | 235 | > which defines a lua object constructor named as 'create', in lua `XXXname.create("string param")` equivalent to C++: 236 | 237 | ```cpp 238 | new XXX("string param"); 239 | ``` 240 | 241 | 242 | static member function, global fuctions or constant can be export in module. 243 | module has no constructor or destructor. 244 | ```cpp 245 | 246 | #include "luaaa.hpp" 247 | using namespace luaaa; 248 | 249 | void func1(int); 250 | void func2(int, int, int); 251 | int func3(int, const char *, float, int, int , float); 252 | bool globalFunc(const std::string&, const std::map&); 253 | 254 | lua_State * state; 255 | 256 | /* 257 | init lua state here... 258 | */ 259 | 260 | LuaModule(state, "moduleName") MyMod; 261 | MyMod.fun("func1", func1); 262 | MyMod 263 | .fun("func2", func2) 264 | .fun("func3", func3) 265 | .def("cstr", "this is cstring"); 266 | 267 | // or export function or some value to global(just emit module name) 268 | LuaModule(state) 269 | .fun("globalFunc", globalFunc) 270 | .def("cint", 12345) 271 | .def("dict", std::set({"cat", "dog", "cow"})); 272 | 273 | // etc... 274 | 275 | // Done. 276 | 277 | ``` 278 | 279 | ok, then access it from lua: 280 | ```lua 281 | -- access module members 282 | MyMod.func1(123) 283 | MyMod.func2(123, "456", 523.3) 284 | MyMod.func3(123, "string or any can be cast to string", 1.23, "1000", "2000", "9.876") 285 | print(MyMod.cstr) 286 | 287 | -- call global function 288 | globalFunc("string or any thing can be cast to string", { key = "table will be cast to map"}) 289 | 290 | -- print global value 'dict' comes from c++ 291 | for k,v in pairs(dict) do 292 | print(tostring(k) .. " = " .. tostring(v)) 293 | end 294 | 295 | ``` 296 | 297 | to export c++ functions with same name, for example: 298 | ```cpp 299 | bool samename(const std::string&); 300 | void samename(int); 301 | 302 | class MyClass 303 | { 304 | public: 305 | void sameNameFunc(int, int); 306 | void sameNameFunc(int); 307 | bool sameNameFunc(); 308 | }; 309 | ``` 310 | in this case, function signature is required here to know which function should be exported: 311 | ```cpp 312 | MyMod.fun("func1", (bool(*)(const std::string&)) samename); 313 | MyMod.fun("func2", (void(*)(int)) samename); 314 | 315 | LuaClass(state, "MyClass") 316 | .fun("sameNameFunc1", (void(MyClass::*)(int, int)) &MyClass::sameNameFunc) 317 | .fun("sameNameFunc2", (void(MyClass::*)(int) &MyClass::sameNameFunc)) 318 | .fun("sameNameFunc3", (bool(MyClass::*)() &MyClass::sameNameFunc)); 319 | ``` 320 | 321 | to export lambda function: 322 | ```cpp 323 | MyMod.fun("lambdaFunc", [](int a, int b) -> int { 324 | return a * b; 325 | }); 326 | ``` 327 | 328 | 329 | 330 | 331 | to extend exported lua class, add below codes to your project: 332 | ```lua 333 | -- put utility functions to name space 'luaaa' 334 | luaaa = {} 335 | 336 | -- create subclass for base, obj can be exist table or nil 337 | function luaaa:extend(base, obj) 338 | derived = obj or {} 339 | derived.new = function(self, ...) 340 | o = base.new(...) 341 | setmetatable(self, getmetatable(o)) 342 | self["@"] = o 343 | return self 344 | end 345 | return derived 346 | end 347 | 348 | -- get base class of obj 349 | function luaaa:base(obj) 350 | if (type(obj) == "table") then 351 | return obj["@"] 352 | end 353 | return nil 354 | end 355 | 356 | ``` 357 | 358 | extends exported lua class as below: 359 | ```lua 360 | SpecialCat = luaaa:extend(AwesomeCat, {value = 1}) 361 | -- or: 362 | -- SpecialCat = luaaa:extend(AwesomeCat) 363 | -- in this case there no attribute was extended 364 | 365 | function SpecialCat:onlyInSpecial() 366 | print(self:getName() .. " has a special cat function") 367 | print("Special cat " .. self:getName() .." has value:" .. self.value) 368 | end 369 | 370 | function SpecialCat:speak(text) 371 | print("Special cat[" .. self:getName() .. "] says: " .. text) 372 | -- call override base method: 373 | luaaa:base(self):speak(text) 374 | end 375 | ``` 376 | 377 | then use SpecialCat: 378 | ```lua 379 | xxx = SpecialCat:new("xxx") 380 | xxx:speak("I am a special cat.") 381 | xxx:onlyInSpecial() 382 | ``` 383 | 384 | ## Advanced Topic 385 | 386 | 387 | 388 | ## Run Example 389 | 390 | ### 1. Linux / Unix / Macos 391 | 392 | 1. install lua dev libs 393 | ```bash 394 | # debian/ubuntu 395 | $ sudo apt install lua5.3-dev 396 | # redhat/centos/fedora 397 | $ sudo yum install lua5.3-dev 398 | ``` 399 | 400 | 401 | 2. build & run. 402 | ```bash 403 | $ cd example 404 | $ g++ -std=c++11 example.cpp -I/usr/include/lua5.3 -o example -g -lstdc++ -llua5.3 405 | $ ./example 406 | ``` 407 | 408 | or use LLVM: 409 | ```bash 410 | $ cd example 411 | $ clang -std=c++11 example.cpp -I/usr/include/lua5.3 -o example -g -lstdc++ -llua5.3 412 | $ ./example 413 | ``` 414 | 415 | for embedded device, declare 'LUAAA_WITHOUT_CPP_STDLIB' to disable c++ stdlib. 416 | ``` 417 | $ cd example 418 | $ gcc -fno-exceptions -fno-rtti -std=c++11 embedded.cpp -I/usr/include/lua5.3 -o embedded -g -llua5.3 -DLUAAA_WITHOUT_CPP_STDLIB 419 | $ ./embedded 420 | ``` 421 | 422 | ### 2. Visual C++ 423 | 424 | Of course you know how to do it. 425 | 426 | 427 | ## License 428 | 429 | See the LICENSE file. 430 | -------------------------------------------------------------------------------- /example/embedded.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define LUAAA_WITHOUT_CPP_STDLIB 1 8 | 9 | #include "../luaaa.hpp" 10 | 11 | #define LOG printf 12 | 13 | #if defined(_MSC_VER) 14 | # define strncpy strncpy_s 15 | #endif 16 | 17 | 18 | //=============================================================================== 19 | using namespace luaaa; 20 | class MyType { 21 | public: 22 | MyType() :m_dummy(0) { 23 | LOG("MyType::MyType\n"); 24 | } 25 | virtual ~MyType() { 26 | LOG("MyType::~MyType\n"); 27 | } 28 | private: 29 | int m_dummy; 30 | }; 31 | 32 | class MyTypeB { 33 | public: 34 | MyTypeB() :m_dummy(0) { 35 | LOG("MyTypeB::MyTypeB\n"); 36 | } 37 | virtual ~MyTypeB() { 38 | LOG("MyTypeB::~MyTypeB\n"); 39 | } 40 | private: 41 | int m_dummy; 42 | }; 43 | 44 | void test1() 45 | { 46 | lua_State* L = luaL_newstate(); 47 | LuaClass myLuaType(L, "MyType"); 48 | myLuaType.ctor(); 49 | LOG("export MyType 1.\n"); 50 | 51 | LuaClass myLuaTypeB(L, "MyTypeB"); 52 | myLuaTypeB.ctor(); 53 | LOG("export MyTypeB 1.\n"); 54 | 55 | luaL_dostring(L, "local a = MyType.new();local b = MyTypeB.new();"); 56 | 57 | LOG("ready to close....\n"); 58 | 59 | lua_close(L); 60 | } 61 | 62 | void test2() 63 | { 64 | lua_State* L = luaL_newstate(); 65 | LuaClass myLuaType(L, "MyType"); 66 | myLuaType.ctor(); 67 | printf("export MyType 2.\n"); 68 | 69 | lua_gc(L, LUA_GCCOLLECT, 0); 70 | 71 | LuaClass myLuaTypeB(L, "MyTypeB"); 72 | myLuaTypeB.ctor(); 73 | LOG("export MyTypeB 2.\n"); 74 | 75 | lua_gc(L, LUA_GCCOLLECT, 0); 76 | 77 | luaL_dostring(L, "local a = MyType.new();local b = MyTypeB.new();"); 78 | 79 | lua_gc(L, LUA_GCCOLLECT, 0); 80 | 81 | LOG("ready to close2....\n"); 82 | 83 | lua_close(L); 84 | } 85 | 86 | void testExportMoreThanOnce() { 87 | test1(); 88 | test2(); 89 | } 90 | 91 | //=============================================================================== 92 | void bindToLUA(lua_State *); 93 | 94 | void runLuaExample(lua_State * ls) 95 | { 96 | bindToLUA(ls); 97 | 98 | LOG("------------------------------------------\n"); 99 | if (luaL_dofile(ls, "example.lua")) 100 | { 101 | LOG("lua err: %s", lua_tostring(ls, -1)); 102 | lua_pop(ls, 1); 103 | } 104 | } 105 | 106 | 107 | int main() 108 | { 109 | testExportMoreThanOnce(); 110 | 111 | const luaL_Reg lualibs[] = { 112 | { LUA_COLIBNAME, luaopen_base }, 113 | { LUA_LOADLIBNAME, luaopen_package }, 114 | { LUA_TABLIBNAME, luaopen_table }, 115 | { LUA_IOLIBNAME, luaopen_io }, 116 | { LUA_OSLIBNAME, luaopen_os }, 117 | { LUA_STRLIBNAME, luaopen_string }, 118 | { LUA_MATHLIBNAME, luaopen_math }, 119 | { LUA_DBLIBNAME, luaopen_debug }, 120 | { NULL, NULL } 121 | }; 122 | 123 | auto ls = luaL_newstate(); 124 | 125 | if (ls != NULL) 126 | { 127 | const luaL_Reg *lib = lualibs; 128 | for (; lib->func; lib++) { 129 | lua_pushcfunction(ls, lib->func); 130 | lua_pushstring(ls, lib->name); 131 | lua_call(ls, 1, 0); 132 | } 133 | 134 | runLuaExample(ls); 135 | 136 | lua_close(ls); 137 | } 138 | return 0; 139 | } 140 | 141 | 142 | //=============================================================================== 143 | // example class 144 | //=============================================================================== 145 | #ifndef __PLACEMENT_NEW_INLINE 146 | void * operator new(size_t sz, void * p) { 147 | return p; 148 | } 149 | 150 | void operator delete(void *, void *) noexcept { 151 | } 152 | #endif 153 | 154 | void * operator new(size_t sz) { 155 | return malloc(sz); 156 | } 157 | void operator delete(void * p) noexcept { 158 | free(p); 159 | } 160 | 161 | void * operator new[](size_t sz) { 162 | return malloc(sz); 163 | } 164 | 165 | void operator delete[](void* p) { 166 | return free(p); 167 | } 168 | 169 | 170 | class Cat 171 | { 172 | public: 173 | Cat() 174 | : m_age(1), m_weight(1.0f) 175 | { 176 | LOG("Cat: a cat spawn at %p.\n", this); 177 | } 178 | 179 | Cat(const char * name) 180 | : m_age(1), m_weight(1.0f) 181 | { 182 | strncpy(m_name, name, sizeof(m_name)); 183 | LOG("Cat: %s spawn at %p\n", m_name, this); 184 | } 185 | 186 | ~Cat() 187 | { 188 | LOG("Cat: cat[%p] %s is free.\n", this, m_name); 189 | } 190 | 191 | const char * getName() const { 192 | return m_name; 193 | } 194 | 195 | 196 | const char * setName(const char * name) 197 | { 198 | strncpy(m_name, name, sizeof(m_name)); 199 | return m_name; 200 | } 201 | 202 | int setAge(const int age) 203 | { 204 | m_age = age; 205 | return m_age; 206 | } 207 | 208 | int getAge() const 209 | { 210 | return m_age; 211 | } 212 | 213 | void eat(lua_State * L) 214 | { 215 | if (lua_istable(L, -1)) 216 | { 217 | lua_pushnil(L); 218 | while (0 != lua_next(L, -2)) 219 | { 220 | const int top = lua_gettop(L); 221 | const char * food = luaaa::LuaStack::get(L, top); 222 | 223 | LOG("%s eat %s.\n", m_name, food); 224 | m_weight += 0.1f; 225 | 226 | lua_pop(L, 1); 227 | } 228 | lua_pop(L, 0); 229 | } 230 | 231 | LOG("%s is getting fatter.\n", m_name); 232 | return; 233 | } 234 | 235 | void test(int a, const char * b, float c, const char * d, const char * e) 236 | { 237 | LOG("cat test: got params from lua: [0: %d, 1:%s, 2:%f, 3:%s, 4:%s]\n", a, b, c, d, e); 238 | } 239 | 240 | const char * toString() const 241 | { 242 | static char buf[128]; 243 | snprintf(buf, sizeof(buf), "%s is a cat, he is %d years old, has a weight of %f kg.", m_name, m_age, m_weight); 244 | return buf; 245 | } 246 | 247 | static void speak(const char * w) 248 | { 249 | LOG("%s, miaow~~\n", w); 250 | } 251 | 252 | private: 253 | char m_name[32]; 254 | int m_age; 255 | float m_weight; 256 | }; 257 | 258 | 259 | class SingletonWorld 260 | { 261 | public: 262 | static SingletonWorld * getInstance() { 263 | if (s_instance == nullptr) { 264 | s_instance = new SingletonWorld("singleton"); 265 | } 266 | return s_instance; 267 | } 268 | 269 | static SingletonWorld * newInstance(const char * tagName) { 270 | return new SingletonWorld(tagName); 271 | } 272 | 273 | static void delInstance(SingletonWorld * instance) { 274 | delete instance; 275 | } 276 | public: 277 | const char * getTag() const { 278 | return mTag; 279 | } 280 | 281 | SingletonWorld() { 282 | snprintf(mTag, sizeof(mTag), "%s", "default"); 283 | LOG("SingletonWorld[%s] constructed.\n", mTag); 284 | } 285 | 286 | SingletonWorld(const char * tagName) { 287 | snprintf(mTag, sizeof(mTag), "%s", tagName); 288 | LOG("SingletonWorld[%s] constructed.\n", mTag); 289 | } 290 | 291 | ~SingletonWorld() { 292 | LOG("SingletonWorld[%s] destructed.\n", mTag); 293 | } 294 | private: 295 | char mTag[16]; 296 | static SingletonWorld * s_instance; 297 | }; 298 | 299 | SingletonWorld * SingletonWorld::s_instance = nullptr; 300 | 301 | class Position { 302 | public: 303 | float x; 304 | float y; 305 | float z; 306 | 307 | Position():x(0), y(0), z(0) {} 308 | Position(float fx, float fy, float fz):x(fx), y(fy), z(fz) {} 309 | }; 310 | 311 | 312 | 313 | //=============================================================================== 314 | // example c++ functions 315 | //=============================================================================== 316 | void testSet() 317 | { 318 | LOG("testSet: [unsupported]\n"); 319 | } 320 | 321 | void testSetSet() 322 | { 323 | LOG("testSetSet: [unsupported]\n"); 324 | } 325 | 326 | 327 | void testMapMap() 328 | { 329 | LOG("testMapMap: [unsupported]\n"); 330 | } 331 | 332 | void testMultipleParams(int a, int b, const char * c, float d, double e) 333 | { 334 | LOG("c++ testCallback: got params from lua: [0: %d, 1:%d, 2:%s, 3:%f, 4:%g]\n", a, b, c, d, e); 335 | } 336 | 337 | void testCallback(int (*f)(const char *, int, float), int val, const char * str) 338 | { 339 | char strbuf[128]; 340 | snprintf(strbuf, sizeof(strbuf), "a string from c:%s", str); 341 | auto result = f(strbuf, val, 1.2345678f); 342 | LOG("c++ testCallback: got result from lua callback: %d\n", result); 343 | } 344 | 345 | //=============================================== 346 | // declare custom LuaStack operators 347 | //=============================================== 348 | // for GCC, it must be delcared in namespace luaaa. 349 | namespace luaaa { 350 | template<> struct LuaStack 351 | { 352 | inline static Position get(lua_State * L, int idx) 353 | { 354 | Position result; 355 | if (lua_istable(L, idx)) 356 | { 357 | lua_pushnil(L); 358 | while (0 != lua_next(L, idx)) 359 | { 360 | const int top = lua_gettop(L); 361 | const char * name = LuaStack::get(L, top - 1); 362 | if (strncmp(name, "x", 1) == 0) { 363 | result.x = LuaStack::get(L, top); 364 | } 365 | else if (strncmp(name, "y", 1) == 0) { 366 | result.y = LuaStack::get(L, top); 367 | } 368 | else if (strncmp(name, "z", 1) == 0) { 369 | result.z = LuaStack::get(L, top); 370 | } 371 | lua_pop(L, 1); 372 | } 373 | lua_pop(L, 0); 374 | } 375 | return result; 376 | } 377 | 378 | inline static void put(lua_State * L, const Position & v) 379 | { 380 | lua_newtable(L); 381 | LuaStack::put(L, "x"); 382 | LuaStack::put(L, v.x); 383 | lua_rawset(L, -3); 384 | LuaStack::put(L, "y"); 385 | LuaStack::put(L, v.y); 386 | lua_rawset(L, -3); 387 | LuaStack::put(L, "z"); 388 | LuaStack::put(L, v.z); 389 | lua_rawset(L, -3); 390 | } 391 | }; 392 | } 393 | 394 | Position testPosition(const Position& a, const Position& b) 395 | { 396 | return Position(a.x + b.x, a.y + b.y, a.z + b.z); 397 | } 398 | 399 | 400 | //=============================================== 401 | // below shows ho to bind c++ with lua 402 | //=============================================== 403 | using namespace luaaa; 404 | 405 | const char * getProp1(const Cat& cat) { 406 | return cat.getName(); 407 | } 408 | 409 | void setProp1(Cat& cat, const char * val) { 410 | cat.setName(val); 411 | } 412 | 413 | void bindToLUA(lua_State * L) 414 | { 415 | // bind class to lua 416 | LuaClass luaCat(L, "AwesomeCat"); 417 | luaCat.ctor(); 418 | luaCat.fun("setName", &Cat::setName); 419 | luaCat.fun("getName", &Cat::getName); 420 | luaCat.fun("setAge", &Cat::setAge); 421 | luaCat.fun("getAge", &Cat::getAge); 422 | luaCat.fun("eat", &Cat::eat); 423 | luaCat.fun("test", &Cat::test); 424 | luaCat.fun("speak", &Cat::speak); 425 | luaCat.fun("__tostring", &Cat::toString); 426 | luaCat.def("tag", "Animal"); 427 | 428 | luaCat.set("say", &Cat::speak); 429 | luaCat.set("name", &Cat::setName); 430 | luaCat.get("name", &Cat::getName); 431 | luaCat.set("age", &Cat::setAge); 432 | luaCat.get("age", &Cat::getAge); 433 | 434 | luaCat.set("prop1", setProp1); 435 | luaCat.get("prop1", getProp1); 436 | 437 | // bind singleton class to lua 438 | LuaClass luaWorld(L, "SingletonWorld"); 439 | /// use class constructor as instance spawner, default destructor will be called from gc. 440 | luaWorld.ctor(); 441 | /// use static function as instance spawner, default destructor will be called from gc. 442 | luaWorld.ctor("newInstance", &SingletonWorld::newInstance); 443 | /// use static function as instance spawner and static function as delete function which be called from gc. 444 | luaWorld.ctor("managedInstance", &SingletonWorld::newInstance , &SingletonWorld::delInstance); 445 | /// for singleton pattern, set deleter(gc) to nullptr to avoid singleton instance be destroyed. 446 | luaWorld.ctor("getInstance", &SingletonWorld::getInstance, nullptr); 447 | luaWorld.fun("getTag", &SingletonWorld::getTag); 448 | 449 | 450 | 451 | // define a module with name "AwesomeMod" 452 | LuaModule awesomeMod(L, "AwesomeMod"); 453 | awesomeMod.def("cint", 20190101); 454 | awesomeMod.def("cstr", "this is c string"); 455 | 456 | const char * dict[] = { 457 | "AMICUS", "AMOS", "AMTRAK", "ANGELICA", "ANNIE OAKLEY", 458 | "BEETHOVEN", "BERTHA", "BESSEYA", "BILLIE JEAN", "BIMBO", 459 | "BISS", "DECATHLON", "DELIRIUM", "DELIUS", "DEMPSEY" 460 | }; 461 | 462 | awesomeMod.def("dict", dict, sizeof(dict)/sizeof(dict[0])); 463 | 464 | int dict2[] = { 465 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 466 | }; 467 | awesomeMod.def("dict2", dict2, sizeof(dict2) / sizeof(dict2[0])); 468 | 469 | awesomeMod.fun("testSet", testSet); 470 | awesomeMod.fun("testSetSet", testSetSet); 471 | awesomeMod.fun("testMapMap", testMapMap); 472 | awesomeMod.fun("testMultipleParams", testMultipleParams); 473 | awesomeMod.fun("testCallback", testCallback); 474 | awesomeMod.fun("testPosition", testPosition); 475 | 476 | // put something to global, just emit the module name 477 | LuaModule(L).def("pi", 3.1415926535897932); 478 | 479 | LuaModule(L).def("WITHOUT_CPP_STDLIB", true); 480 | 481 | // operations can be chained. 482 | LuaClass(L, "int") 483 | .ctor("new") 484 | .def("type", "[c int *]") 485 | .def("max", INT_MAX) 486 | .def("min", INT_MIN); 487 | 488 | } 489 | 490 | 491 | -------------------------------------------------------------------------------- /example/example.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../luaaa.hpp" 10 | 11 | #define LOG printf 12 | 13 | 14 | void bindToLUA(lua_State *); 15 | 16 | void runLuaExample(lua_State * ls) 17 | { 18 | bindToLUA(ls); 19 | 20 | do { 21 | LOG("------------------------------------------\n"); 22 | std::stringstream buffer; 23 | std::ifstream file("example.lua"); 24 | if (file) 25 | { 26 | buffer << file.rdbuf(); 27 | file.close(); 28 | } 29 | 30 | 31 | int err = luaL_loadbuffer(ls, buffer.str().c_str(), buffer.str().length(), "console"); 32 | if (err == 0) 33 | { 34 | err = lua_pcall(ls, 0, 0, 0); 35 | } 36 | 37 | if (err) 38 | { 39 | LOG("lua err: %s", lua_tostring(ls, -1)); 40 | lua_pop(ls, 1); 41 | } 42 | 43 | } while (std::cin.get() != 27); 44 | 45 | } 46 | 47 | 48 | int main() 49 | { 50 | auto ls = luaL_newstate(); 51 | luaL_openlibs(ls); 52 | 53 | if (ls != NULL) 54 | { 55 | runLuaExample(ls); 56 | 57 | lua_close(ls); 58 | } 59 | return 0; 60 | } 61 | 62 | 63 | 64 | //=============================================================================== 65 | // example c++ class 66 | //=============================================================================== 67 | 68 | 69 | class Cat 70 | { 71 | public: 72 | Cat() 73 | : m_age(1), m_weight(1.0f) 74 | { 75 | LOG("Cat: a cat spawn at %p.\n", this); 76 | } 77 | 78 | Cat(const std::string& name) 79 | : m_name(name), m_age(1), m_weight(1.0f) 80 | { 81 | LOG("Cat: %s spawn at %p\n", m_name.c_str(), this); 82 | } 83 | 84 | ~Cat() 85 | { 86 | LOG("Cat: cat[%p] %s is free.\n", this, m_name.c_str()); 87 | } 88 | 89 | const std::string& getName() const { 90 | LOG("Cat:get name\n"); 91 | return m_name; 92 | } 93 | 94 | 95 | const std::string& setName(const std::string& name) 96 | { 97 | LOG("Cat:set name to %s\n", name.c_str()); 98 | m_name = name; 99 | return m_name; 100 | } 101 | 102 | int setAge(const int age) 103 | { 104 | LOG("Cat:set age to %d\n", age); 105 | m_age = age; 106 | return m_age; 107 | } 108 | 109 | int getAge() const 110 | { 111 | LOG("Cat:get age\n"); 112 | return m_age; 113 | } 114 | 115 | float setWeight(float w) 116 | { 117 | LOG("Cat:set weight to %f\n", w); 118 | m_weight = w; 119 | return m_weight; 120 | } 121 | 122 | float getWeight() const 123 | { 124 | LOG("Cat:get weight\n"); 125 | return m_weight; 126 | } 127 | 128 | void eat(const std::list& foods) 129 | { 130 | for (auto & it : foods) 131 | { 132 | LOG("%s eat %s.\n", m_name.c_str(), it.c_str()); 133 | m_weight += 0.1f; 134 | } 135 | LOG("%s is getting fatter.\n", m_name.c_str()); 136 | } 137 | 138 | void test(int a, const std::string& b, float c, const std::string& d, const std::string& e) 139 | { 140 | LOG("cat test: got params from lua: [0: %d, 1:%s, 2:%f, 3:%s, 4:%s]\n", a, b.c_str(), c, d.c_str(), e.c_str()); 141 | } 142 | 143 | std::string toString() const 144 | { 145 | std::stringstream result; 146 | result << m_name << " is a cat, he is " << m_age <<" years old, has a weight of " << m_weight << " kg."; 147 | return result.str(); 148 | } 149 | 150 | static void speak(const std::string& w) 151 | { 152 | LOG("%s, miaow~~\n", w.c_str()); 153 | } 154 | 155 | void testfunctor(std::function callback) 156 | { 157 | int result = callback(42); 158 | LOG("Callback with argument 42 leads to %d.\n", result); 159 | } 160 | 161 | public: 162 | std::string prop1; 163 | std::set prop3; 164 | private: 165 | std::string m_name; 166 | int m_age; 167 | float m_weight; 168 | }; 169 | 170 | 171 | std::string getProp1(const Cat& cat) { 172 | printf("*** READ prop1 ***\n"); 173 | return cat.prop1; 174 | } 175 | 176 | void setProp1(Cat& cat, const std::string& val) { 177 | printf("*** WRITE prop1 ***\n"); 178 | cat.prop1 = val; 179 | } 180 | 181 | 182 | class SingletonWorld 183 | { 184 | public: 185 | static SingletonWorld * getInstance() { 186 | static SingletonWorld instance("singleton"); 187 | return &instance; 188 | } 189 | 190 | static SingletonWorld * newInstance(const std::string tagName) { 191 | return new SingletonWorld(tagName); 192 | } 193 | 194 | static void delInstance(SingletonWorld * instance) { 195 | delete instance; 196 | } 197 | public: 198 | const std::string getTag() const { 199 | return mTag; 200 | } 201 | 202 | SingletonWorld() { 203 | mTag = "default"; 204 | LOG("SingletonWorld[%s] constructed.\n", mTag.c_str()); 205 | } 206 | 207 | SingletonWorld(const std::string& tagName) : mTag(tagName) { 208 | LOG("SingletonWorld[%s] constructed.\n", mTag.c_str()); 209 | } 210 | 211 | ~SingletonWorld() { 212 | LOG("SingletonWorld[%s] destructed.\n", mTag.c_str()); 213 | } 214 | private: 215 | std::string mTag; 216 | }; 217 | 218 | class Position { 219 | public: 220 | float x; 221 | float y; 222 | float z; 223 | 224 | Position():x(0), y(0), z(0) {} 225 | Position(float fx, float fy, float fz):x(fx), y(fy), z(fz) {} 226 | }; 227 | 228 | 229 | 230 | //=============================================================================== 231 | // example c functions 232 | //=============================================================================== 233 | void testSet(const std::set& s1, const std::set& s2) 234 | { 235 | LOG("testSet: set size: s1:%lu s2:%lu\n", s1.size(), s2.size()); 236 | LOG("--------------------------\n"); 237 | LOG("s1:"); 238 | for (auto it = s1.begin(); it != s1.end(); ++it) 239 | { 240 | LOG("%d ", *it); 241 | } 242 | LOG("\ns2:"); 243 | for (auto it = s2.begin(); it != s2.end(); ++it) 244 | { 245 | LOG("%d ", *it); 246 | } 247 | LOG("\n--------------------------\n"); 248 | } 249 | 250 | void testSetSet(const std::multiset>& s) 251 | { 252 | LOG("testSetSet: multiset> size: %lu\n", s.size()); 253 | LOG("--------------------------\n"); 254 | for (auto it = s.begin(); it != s.end(); ++it) 255 | { 256 | LOG("=>set size: %lu\n", it->size()); 257 | for (auto nit = it->begin(); nit != it->end(); ++nit) 258 | { 259 | LOG("'%s', ", nit->c_str()); 260 | } 261 | LOG("\n"); 262 | } 263 | LOG("\n--------------------------\n"); 264 | } 265 | 266 | 267 | void testMapMap(const std::map>& s) 268 | { 269 | LOG("testMapMap: map> size: %lu\n", s.size()); 270 | LOG("--------------------------\n"); 271 | for (auto it = s.begin(); it != s.end(); ++it) 272 | { 273 | LOG("'%s' => map size: %lu\n", it->first.c_str(), it->second.size()); 274 | for (auto nit = it->second.begin(); nit != it->second.end(); ++nit) 275 | { 276 | LOG("%s = %s, ", nit->first.c_str(), nit->second.c_str()); 277 | } 278 | LOG("\n"); 279 | } 280 | LOG("\n--------------------------\n"); 281 | } 282 | 283 | 284 | const std::tuple testTuple(std::tuple info) { 285 | LOG("c++ load lua list to tuple:\n"); 286 | LOG("\t0: '%s'\n", std::get<0>(info).c_str()); 287 | LOG("\t1: %d\n", std::get<1>(info)); 288 | LOG("\t2: %g\n", std::get<2>(info)); 289 | LOG("c++ returns tuple to lua:\n"); 290 | return std::tuple(123, "string A", "string B", 0.123f); 291 | } 292 | 293 | const std::tuple<> testTuple2(std::tuple<> info) { 294 | LOG("c++ load lua list to empty tuple.\n"); 295 | LOG("c++ returns empty tuple to lua:\n"); 296 | return std::tuple<>(); 297 | } 298 | 299 | void testMultipleParams(int a, int b, const std::string& c, float d, double e) 300 | { 301 | LOG("c++ testCallback: got params from lua: [0: %d, 1: %d, 2: %s, 3: %f, 4: %g]\n", a, b, c.c_str(), d, e); 302 | } 303 | 304 | 305 | void testCallback(int (*f)(const std::string&, int, float), int val, const std::string& str) 306 | { 307 | auto result = f("a string from c++:" + str, val, 1.2345678f); 308 | LOG("c++ testCallback: got result from lua callback: %d\n", result); 309 | } 310 | 311 | void testCallbackFunctor(std::function f, int val, const std::string& str) 312 | { 313 | auto result = f("a string from c++:" + str, val, 8.7654321f); 314 | LOG("c++ testCallbackFunctor: got result from lua callback: %d\n", result); 315 | } 316 | 317 | 318 | //=============================================== 319 | // declare custom LuaStack operators 320 | //=============================================== 321 | // for GCC, it must be delcared in namespace luaaa. 322 | namespace luaaa { 323 | template<> struct LuaStack 324 | { 325 | inline static Position get(lua_State * L, int idx) 326 | { 327 | auto dict = LuaStack>::get(L, idx); 328 | return Position(dict.find("x")->second, dict.find("y")->second, dict.find("z")->second); 329 | } 330 | 331 | inline static void put(lua_State * L, const Position & v) 332 | { 333 | std::map dict; 334 | dict["x"] = v.x; 335 | dict["y"] = v.y; 336 | dict["z"] = v.z; 337 | LuaStack::put(L, dict); 338 | } 339 | }; 340 | } 341 | //*/ 342 | 343 | Position testPosition(const Position& a, const Position& b) 344 | { 345 | return Position(a.x + b.x, a.y + b.y, a.z + b.z); 346 | } 347 | 348 | 349 | //=============================================== 350 | // below shows ho to bind c++ with lua 351 | //=============================================== 352 | using namespace luaaa; 353 | 354 | 355 | int module__index(lua_State* state) { 356 | LOG("~~~~~~~~~~~~~~~~~~module__index:~~~~~~~~~~~~~~~~~~~"); 357 | lua_pushinteger(state, 999); 358 | return 1; 359 | } 360 | 361 | int module__newindex(lua_State* state) { 362 | LOG("~~~~~~~~~~~~~~~~~~module__newindex:~~~~~~~~~~~~~~~~~~~"); 363 | lua_rawset(state, -3); 364 | return 0; 365 | } 366 | 367 | void moduleSetProp1(const std::string& val) { 368 | LOG("moduleSetProp1:%s", val.c_str()); 369 | return; 370 | } 371 | 372 | 373 | const char* moduleGetProp1() { 374 | LOG("moduleGetProp1"); 375 | return "string as prop1 value"; 376 | } 377 | 378 | int moduleSetProp2(int val) { 379 | LOG("moduleSetProp2:%d", val); 380 | return val; 381 | } 382 | 383 | const char* moduleGetProp2() { 384 | LOG("moduleGetProp2"); 385 | return "string as prop2 value"; 386 | } 387 | 388 | 389 | 390 | void bindToLUA(lua_State * L) 391 | { 392 | // bind class to lua 393 | LuaClass luaCat(L, "AwesomeCat"); 394 | luaCat.ctor(); 395 | luaCat.fun("setName", &Cat::setName); 396 | luaCat.fun("getName", &Cat::getName); 397 | luaCat.fun("setAge", &Cat::setAge); 398 | luaCat.fun("getAge", &Cat::getAge); 399 | luaCat.fun("eat", &Cat::eat); 400 | luaCat.fun("speak", &Cat::speak); 401 | luaCat.fun("test", &Cat::test); 402 | luaCat.fun("testfunctor", &Cat::testfunctor); 403 | luaCat.fun(std::string("testFunctor1"), [](int n1, int n2) -> int { 404 | LOG("testFunctor1:%d, %d\n", n1, n2); 405 | return n1 * n2; 406 | }); 407 | luaCat.fun("testFunctor2", std::function([](int n1, int n2) { 408 | LOG("testFunctor2:%d, %d\n", n1, n2); 409 | })); 410 | luaCat.fun("__tostring", &Cat::toString); 411 | luaCat.def("tag", "Animal"); 412 | 413 | luaCat.set("say", &Cat::speak); 414 | luaCat.set("name", &Cat::setName); 415 | luaCat.get("name", &Cat::getName); 416 | luaCat.set("age", &Cat::setAge); 417 | luaCat.get("age", &Cat::getAge); 418 | 419 | luaCat.set("prop1", setProp1); 420 | luaCat.get("prop1", getProp1); 421 | luaCat.set("prop2", [](const Cat& cat, float val) -> void { printf("set prop2=%f\n", val); /*cat.setWeight(val)*/; }); 422 | luaCat.get("prop2", [](Cat& cat) -> float { printf("get prop2\n"); return cat.getWeight(); }); 423 | luaCat.set(std::string("prop3"), [](Cat& cat, const std::set& val) { printf("set prop3\n"); cat.prop3 = val; }); 424 | luaCat.get(std::string("prop3"), [](const Cat& cat) -> std::set { printf("get prop3\n"); return cat.prop3; }); 425 | luaCat.set(std::string("prop4"), [](float val) { printf("set prop4=%f\n", val); }); 426 | luaCat.get(std::string("prop4"), []() -> float { printf("get prop4\n"); return 0.123f; }); 427 | 428 | // rise compile error 429 | //luaCat.set(std::string("prop5"), [](float val, int v2) { printf("set prop5=%f\n", val); }); 430 | //luaCat.get(std::string("prop5"), [](int) -> float { printf("get prop5\n"); return 0.123f; }); 431 | 432 | 433 | // bind singleton class to lua 434 | LuaClass luaWorld(L, "SingletonWorld"); 435 | /// use class default constructor as instance spawner, default destructor will be called from gc. 436 | luaWorld.ctor(); 437 | /// use class constructor as instance spawner, default destructor will be called from gc. 438 | luaWorld.ctor("createWithName"); 439 | /// use static function as instance spawner, default destructor will be called from gc. 440 | luaWorld.ctor("newInstance", &SingletonWorld::newInstance); 441 | /// use static function as instance spawner and static function as delete function which be called from gc. 442 | luaWorld.ctor("managedInstance", &SingletonWorld::newInstance , &SingletonWorld::delInstance); 443 | /// for singleton pattern, set deleter(gc) to nullptr to avoid singleton instance be destroyed. 444 | luaWorld.ctor("getInstance", &SingletonWorld::getInstance, nullptr); 445 | luaWorld.fun("getTag", &SingletonWorld::getTag); 446 | 447 | 448 | // define a module with name "AwesomeMod" 449 | LuaModule awesomeMod(L, "AwesomeMod"); 450 | awesomeMod.def("cint", 20190101); 451 | awesomeMod.def("cstr", "this is c string"); 452 | awesomeMod.def("acat", luaCat); 453 | 454 | std::list dict { 455 | "AMICUS", "AMOS", "AMTRAK", "ANGELICA", "ANNIE OAKLEY", 456 | "BEETHOVEN", "BERTHA", "BESSEYA", "BILLIE JEAN", "BIMBO", 457 | "BISS", "DECATHLON", "DELIRIUM", "DELIUS", "DEMPSEY" 458 | }; 459 | 460 | awesomeMod.def("dict", dict); 461 | 462 | // c++11 standard conatiners(array, vector, deque, list, forward_list, set/multiset, map/multimap, unordered_set/unordered_multiset, unordered_map/unordered_multimap) 463 | awesomeMod.fun("testSet", testSet); 464 | awesomeMod.fun("testSetSet", testSetSet); 465 | awesomeMod.fun("testMapMap", testMapMap); 466 | awesomeMod.fun("testMultipleParams", testMultipleParams); 467 | awesomeMod.fun("testTuple", testTuple); 468 | awesomeMod.fun("testTuple2", testTuple2); 469 | awesomeMod.fun("testCallback", testCallback); 470 | awesomeMod.fun("testCallbackFunctor", testCallbackFunctor); 471 | awesomeMod.fun("testPosition", testPosition); 472 | awesomeMod.fun("testFunctor1", [](int a, float b) { 473 | LOG("awesomeMod call testFunctor1: %d, %f", a, b); 474 | }); 475 | awesomeMod.fun("testFunctor2", [](int a, float b) -> float { 476 | LOG("awesomeMod call testFunctor2(%d * %f = %f):", a, b, a*b); 477 | return a * b; 478 | }); 479 | 480 | awesomeMod.set("prop1", moduleSetProp1); 481 | awesomeMod.get("prop1", moduleGetProp1); 482 | awesomeMod.set("prop2", moduleSetProp2); 483 | awesomeMod.get("prop2", moduleGetProp2); 484 | awesomeMod.set(std::string("prop3"), [](const std::string& val) { printf("set prop3=%s\n", val.c_str()); }); 485 | awesomeMod.get(std::string("prop3"), []() -> std::string { printf("get prop3\n"); return "string as prop3"; }); 486 | awesomeMod.set(std::string("prop4"), [](float val) { printf("set prop4=%f\n", val); }); 487 | awesomeMod.get(std::string("prop4"), [](){ printf("get prop4\n"); return 0.123f; }); 488 | 489 | awesomeMod.fun("__index", module__index); 490 | awesomeMod.fun("__newindex", module__newindex); 491 | 492 | // put something to global, just emit the module name 493 | LuaModule(L).def("pi", 3.1415926535897932); 494 | 495 | LuaModule(L).def("WITHOUT_CPP_STDLIB", !!LUAAA_WITHOUT_CPP_STDLIB); 496 | 497 | // operations can be chained. 498 | LuaClass(L, "int") 499 | .ctor("new") 500 | .def("type", std::string("[c int *]")) 501 | .def("max", INT_MAX) 502 | .def("min", INT_MIN); 503 | 504 | } 505 | 506 | -------------------------------------------------------------------------------- /luaaa.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (c) 2019 gengyong 4 | https://github.com/gengyong/luaaa 5 | licensed under MIT License. 6 | */ 7 | 8 | #ifndef HEADER_LUAAA_HPP 9 | #define HEADER_LUAAA_HPP 10 | 11 | #define LUAAA_NS luaaa 12 | #define LUAAA_VER_MAJOR (1) 13 | #define LUAAA_VER_MINOR (4) 14 | 15 | /// if you want to disable C++ std libs, set to 1 16 | #ifndef LUAAA_WITHOUT_CPP_STDLIB 17 | #define LUAAA_WITHOUT_CPP_STDLIB 0 18 | #endif 19 | 20 | #ifndef LUAAA_DEBUG 21 | #define LUAAA_DEBUG 0 22 | #endif 23 | 24 | /// enable to check LuaClass constructor name conflict 25 | /// exposed constructor should have unique name, otherwise the early one will be overwriten. 26 | #ifndef LUAAA_CHECK_CONSTRUCTOR_NAME_CONFLICT 27 | #define LUAAA_CHECK_CONSTRUCTOR_NAME_CONFLICT 1 28 | #endif 29 | 30 | #ifndef LUAAA_FEATURE_PROPERTY 31 | #define LUAAA_FEATURE_PROPERTY 1 32 | #endif 33 | 34 | extern "C" 35 | { 36 | #include "lua.h" 37 | #include "lualib.h" 38 | #include "lauxlib.h" 39 | } 40 | 41 | #if !defined LUA_VERSION_NUM || LUA_VERSION_NUM <= 501 42 | inline void luaL_setfuncs(lua_State * L, const luaL_Reg * l, int nup) { 43 | luaL_checkstack(L, nup + 1, "too many upvalues"); 44 | for (; l->name != nullptr; l++) { 45 | int i; 46 | lua_pushstring(L, l->name); 47 | for (i = 0; i < nup; i++) 48 | lua_pushvalue(L, -(nup + 1)); 49 | lua_pushcclosure(L, l->func, nup); 50 | lua_settable(L, -(nup + 3)); 51 | } 52 | lua_pop(L, nup); 53 | } 54 | 55 | inline void luaL_setmetatable(lua_State * L, const char * tname) { 56 | luaL_getmetatable(L, tname); 57 | lua_setmetatable(L, -2); 58 | } 59 | #endif 60 | 61 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE) 62 | # define USE_NEW_MODULE_REGISTRY 1 63 | #else 64 | # define USE_NEW_MODULE_REGISTRY 0 65 | #endif 66 | 67 | #include 68 | #include 69 | #include 70 | 71 | #if defined(_MSC_VER) 72 | # define RTTI_CLASS_NAME(a) typeid(a).name() //vc always has this operator even if RTTI was disabled. 73 | #elif __GXX_RTTI 74 | # define RTTI_CLASS_NAME(a) typeid(a).name() 75 | #elif _HAS_STATIC_RTTI 76 | # define RTTI_CLASS_NAME(a) typeid(a).name() 77 | #else 78 | # define RTTI_CLASS_NAME(a) "?" 79 | #endif 80 | 81 | #if LUAAA_WITHOUT_CPP_STDLIB 82 | # include 83 | # include 84 | #else 85 | # if defined(__GNUC__) 86 | # include 87 | # endif 88 | # include 89 | # include 90 | #endif 91 | 92 | #if LUAAA_DEBUG 93 | inline size_t LUAAA_DUMP_OBJECT(char* buffer, size_t buflen, lua_State * L, int idx, int indent=0) { 94 | char prefix[32] = {0}; 95 | if (indent > sizeof(prefix) - 1) { 96 | indent = sizeof(prefix) - 1; 97 | } 98 | for (int i = 0; i < indent; i++) { 99 | prefix[i] = '\t'; 100 | } 101 | switch (lua_type(L, idx)) { 102 | default: 103 | return snprintf(buffer, buflen, "<%s>(%p)", luaL_typename(L, idx), lua_topointer(L, idx)); 104 | case LUA_TNUMBER: 105 | case LUA_TSTRING: 106 | return snprintf(buffer, buflen, "\"%s\"", lua_tostring(L, idx)); 107 | case LUA_TBOOLEAN: 108 | return snprintf(buffer, buflen, "%s", (lua_toboolean(L, idx) ? "true" : "false")); 109 | case LUA_TNIL: 110 | return snprintf(buffer, buflen, "%s", "nil"); 111 | case LUA_TTABLE: 112 | int ret = 0; 113 | if (luaL_getmetafield(L, idx, "__name")) { 114 | ret = snprintf(buffer, buflen, "<%s>(%p):", lua_tostring(L, -1), lua_topointer(L, idx)); 115 | lua_pop(L, 1); 116 | } else { 117 | ret = snprintf(buffer, buflen, "<%s>(%p):", luaL_typename(L, idx), lua_topointer(L, idx)); 118 | } 119 | if (ret > 0) { 120 | size_t wrote = ret; 121 | lua_pushnil(L); 122 | while (lua_next(L, idx)) { 123 | const int top = lua_gettop(L); 124 | if (buflen > wrote) { 125 | ret = snprintf(buffer + wrote, buflen - wrote, "\n%s", prefix); 126 | if (ret > 0) { 127 | wrote += ret; 128 | } 129 | } 130 | 131 | if (buflen > wrote) { 132 | lua_pushvalue(L, top - 1); 133 | ret = snprintf(buffer + wrote, buflen - wrote, "\"%s\":", lua_tostring(L, -1)); 134 | lua_pop(L, 1); 135 | if (ret > 0) { 136 | wrote += ret; 137 | } 138 | } 139 | 140 | if (buflen > wrote) { 141 | if (lua_topointer(L, top) == lua_topointer(L, idx)) { 142 | ret = snprintf(buffer + wrote, buflen - wrote, "(%p)", lua_topointer(L, top)); 143 | } else { 144 | if (indent < 3) 145 | { 146 | ret = LUAAA_DUMP_OBJECT(buffer + wrote, buflen - wrote, L, top, indent + 1); 147 | } 148 | else 149 | { 150 | ret = snprintf(buffer + wrote, buflen - wrote, "..."); 151 | } 152 | } 153 | if (ret > 0) { 154 | wrote += ret; 155 | } 156 | } 157 | lua_pop(L, 1); 158 | } 159 | //lua_pop(L, 0); 160 | return wrote; 161 | } 162 | } 163 | return 0; 164 | } 165 | 166 | inline void LUAAA_DUMP(lua_State * L, const char * name = "") { 167 | printf(">>>>>>>>>>>>>>>>>>>>>>>>>[%s]\n", name); 168 | char buffer[4096] = {0}; 169 | int top = lua_gettop(L); 170 | for (int i = 1; i <= top; i++) { 171 | LUAAA_DUMP_OBJECT(buffer, sizeof(buffer) - 1, L, i, 1); 172 | printf("%d\t%s\n", i, buffer); 173 | } 174 | printf("<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 175 | } 176 | #else 177 | # define LUAAA_DUMP(L,...) 178 | #endif 179 | 180 | #if LUAAA_CHECK_CONSTRUCTOR_NAME_CONFLICT 181 | # define luaaa_check_constructor_name_conflict(ctorName) { \ 182 | lua_getglobal(m_state, (LuaClass::klassName)); \ 183 | if (!lua_isnil(m_state, -1)) { \ 184 | lua_pushstring(m_state, ctorName); \ 185 | lua_gettable(m_state, -2); \ 186 | if (!lua_isnil(m_state, -1)) { \ 187 | printf("Error: LuaClass<%s>::ctor has duplicated name:`%s`\n", LuaClass::klassName, ctorName);\ 188 | } \ 189 | lua_pop(m_state, 1); \ 190 | } \ 191 | lua_pop(m_state, 1); \ 192 | } 193 | #else 194 | # define luaaa_check_constructor_name_conflict(ctorName) 195 | #endif 196 | 197 | namespace LUAAA_NS 198 | { 199 | #if !LUAAA_WITHOUT_CPP_STDLIB 200 | // to_function 201 | template 202 | struct function_traits : public function_traits {}; 203 | 204 | template 205 | struct function_traits 206 | { 207 | using function_type = std::function; 208 | }; 209 | 210 | template 211 | using function_type_t = typename function_traits::function_type; 212 | 213 | template 214 | function_type_t to_function(F& f) 215 | { 216 | return static_cast>(f); 217 | } 218 | 219 | // to_class_getter_function 220 | template 221 | struct class_getter_function_traits : public class_getter_function_traits {}; 222 | 223 | template 224 | struct class_getter_function_traits 225 | { 226 | static_assert((sizeof...(ARGS) == 0) && (std::is_same::type, typename std::decay::type>::value), "Error: property getter does not accept param except current Class reference."); 227 | using function_type = std::function; 228 | }; 229 | 230 | template 231 | struct class_getter_function_traits 232 | { 233 | using function_type = std::function; 234 | }; 235 | 236 | template 237 | using class_getter_function_type_t = typename class_getter_function_traits::function_type; 238 | 239 | template 240 | class_getter_function_type_t to_class_getter_function(F& f) 241 | { 242 | return static_cast>(f); 243 | } 244 | 245 | // to_class_setter_function 246 | template 247 | struct class_setter_function_traits : public class_setter_function_traits {}; 248 | 249 | 250 | template 251 | struct class_setter_function_traits 252 | { 253 | static_assert((sizeof...(ARGS) == 0) || ((sizeof...(ARGS) == 1) && std::is_same::type, typename std::decay::type>::value), "Error: property setter accepts only [1 value] or [self instance and 1 value]."); 254 | using function_type = std::function; 255 | }; 256 | 257 | template 258 | struct class_setter_function_traits 259 | { 260 | using function_type = std::function; 261 | }; 262 | 263 | template 264 | using class_setter_function_type_t = typename class_setter_function_traits::function_type; 265 | 266 | template 267 | class_setter_function_type_t to_class_setter_function(F& f) 268 | { 269 | return static_cast>(f); 270 | } 271 | 272 | // to_module_getter_function 273 | template 274 | struct module_getter_function_traits : public module_getter_function_traits {}; 275 | 276 | template 277 | struct module_getter_function_traits 278 | { 279 | static_assert((sizeof...(ARGS) == 0), "Error: property getter does not accept param."); 280 | using function_type = std::function; 281 | }; 282 | 283 | template 284 | struct module_getter_function_traits 285 | { 286 | static_assert((sizeof...(ARGS) == 0), "Error: property getter does not accept param."); 287 | using function_type = std::function; 288 | }; 289 | 290 | template 291 | using module_getter_function_type_t = typename module_getter_function_traits::function_type; 292 | 293 | template 294 | module_getter_function_type_t to_module_getter_function(F& f) 295 | { 296 | return static_cast>(f); 297 | } 298 | 299 | // to_module_setter_function 300 | template 301 | struct module_setter_function_traits : public module_setter_function_traits {}; 302 | 303 | template 304 | struct module_setter_function_traits 305 | { 306 | static_assert((sizeof...(ARGS) == 0), "Error: property setter accepts only 1 value."); 307 | using function_type = std::function; 308 | }; 309 | 310 | template 311 | struct module_setter_function_traits 312 | { 313 | static_assert((sizeof...(ARGS) == 0), "Error: property setter accepts only 1 value."); 314 | using function_type = std::function; 315 | }; 316 | 317 | template 318 | using module_setter_function_type_t = typename module_setter_function_traits::function_type; 319 | 320 | template 321 | module_setter_function_type_t to_module_setter_function(F& f) 322 | { 323 | return static_cast>(f); 324 | } 325 | #endif 326 | 327 | //======================================================== 328 | // Lua Class 329 | //======================================================== 330 | 331 | template struct LuaClass; 332 | 333 | //======================================================== 334 | // Lua stack operator 335 | //======================================================== 336 | 337 | template struct LuaStack 338 | { 339 | inline static T& get(lua_State * state, int idx) 340 | { 341 | #if LUAAA_WITHOUT_CPP_STDLIB 342 | luaL_argcheck(state, LuaClass::klassName != nullptr, 1, "cpp class not export"); 343 | #else 344 | luaL_argcheck(state, LuaClass::klassName != nullptr, 1, (std::string("cpp class `") + RTTI_CLASS_NAME(T) + "` not export").c_str()); 345 | #endif 346 | if (lua_istable(state, idx)) { 347 | #if !defined LUA_VERSION_NUM || LUA_VERSION_NUM <= 502 348 | if (lua_getmetatable(state, idx)) { 349 | lua_getfield(state, LUA_REGISTRYINDEX, LuaClass::klassName); 350 | if (lua_rawequal(state, -1, -2)) { 351 | lua_getfield(state, idx, "@"); 352 | if (lua_type(state, -1) == LUA_TUSERDATA) { 353 | T ** t = (T**)luaL_checkudata(state, -1, LuaClass::klassName); 354 | luaL_argcheck(state, t != nullptr && *t != nullptr, 1, "invalid user data"); 355 | return (**t); 356 | } 357 | } 358 | } 359 | #else 360 | if (luaL_getmetafield(state, idx, "__name") == LUA_TSTRING) { 361 | if (LuaClass::klassName && strcmp(lua_tostring(state, -1), LuaClass::klassName) == 0) { 362 | if (lua_getfield(state, idx, "@") == LUA_TUSERDATA) { 363 | T ** t = (T**)luaL_checkudata(state, -1, LuaClass::klassName); 364 | luaL_argcheck(state, t != nullptr && *t != nullptr, 1, "invalid user data"); 365 | return (**t); 366 | } 367 | } 368 | } 369 | #endif 370 | } 371 | T ** t = (T**)luaL_checkudata(state, idx, LuaClass::klassName); 372 | luaL_argcheck(state, t != nullptr && *t != nullptr, 1, "invalid user data"); 373 | return (**t); 374 | } 375 | 376 | inline static void put(lua_State * L, T * t) 377 | { 378 | lua_pushlightuserdata(L, t); 379 | } 380 | }; 381 | 382 | template struct LuaStack : public LuaStack {}; 383 | template struct LuaStack : public LuaStack {}; 384 | template struct LuaStack : public LuaStack {}; 385 | 386 | template struct LuaStack : public LuaStack 387 | { 388 | inline static void put(lua_State * L, volatile T & t) 389 | { 390 | LuaStack::put(L, const_cast(t)); 391 | } 392 | }; 393 | 394 | template struct LuaStack : public LuaStack 395 | { 396 | inline static void put(lua_State * L, const volatile T & t) 397 | { 398 | LuaStack::put(L, const_cast(t)); 399 | } 400 | }; 401 | 402 | template struct LuaStack : public LuaStack 403 | { 404 | inline static void put(lua_State * L, T && t) 405 | { 406 | LuaStack::put(L, std::forward(t)); 407 | } 408 | }; 409 | 410 | template struct LuaStack 411 | { 412 | inline static T * get(lua_State * state, int idx) 413 | { 414 | if (lua_islightuserdata(state, idx)) 415 | { 416 | T * t = (T*)lua_touserdata(state, idx); 417 | return t; 418 | } 419 | else if (lua_isuserdata(state, idx)) 420 | { 421 | if (LuaClass::klassName != nullptr) 422 | { 423 | T ** t = (T**)luaL_checkudata(state, idx, LuaClass::klassName); 424 | luaL_argcheck(state, t != nullptr && *t != nullptr, 1, "invalid user data"); 425 | return *t; 426 | } 427 | if (LuaClass::klassName != nullptr) 428 | { 429 | T ** t = (T**)luaL_checkudata(state, idx, LuaClass::klassName); 430 | luaL_argcheck(state, t != nullptr && *t != nullptr, 1, "invalid user data"); 431 | return *t; 432 | } 433 | } 434 | return nullptr; 435 | } 436 | 437 | inline static void put(lua_State * L, T * t) 438 | { 439 | lua_pushlightuserdata(L, t); 440 | } 441 | }; 442 | 443 | template<> 444 | struct LuaStack 445 | { 446 | inline static float get(lua_State * L, int idx) 447 | { 448 | if (lua_isnumber(L, idx) || lua_isstring(L, idx)) 449 | { 450 | return float(lua_tonumber(L, idx)); 451 | } 452 | else 453 | { 454 | luaL_checktype(L, idx, LUA_TNUMBER); 455 | } 456 | return 0; 457 | } 458 | 459 | inline static void put(lua_State * L, const float & t) 460 | { 461 | lua_pushnumber(L, t); 462 | } 463 | }; 464 | 465 | template<> 466 | struct LuaStack 467 | { 468 | inline static double get(lua_State * L, int idx) 469 | { 470 | if (lua_isnumber(L, idx) || lua_isstring(L, idx)) 471 | { 472 | return double(lua_tonumber(L, idx)); 473 | } 474 | else 475 | { 476 | luaL_checktype(L, idx, LUA_TNUMBER); 477 | } 478 | return 0; 479 | } 480 | 481 | inline static void put(lua_State * L, const double & t) 482 | { 483 | lua_pushnumber(L, t); 484 | } 485 | }; 486 | 487 | template<> 488 | struct LuaStack 489 | { 490 | inline static int get(lua_State * L, int idx) 491 | { 492 | if (lua_isnumber(L, idx) || lua_isstring(L, idx)) 493 | { 494 | return int(lua_tointeger(L, idx)); 495 | } 496 | else 497 | { 498 | luaL_checktype(L, idx, LUA_TNUMBER); 499 | } 500 | return 0; 501 | } 502 | 503 | inline static void put(lua_State * L, const int & t) 504 | { 505 | lua_pushinteger(L, t); 506 | } 507 | }; 508 | 509 | template<> 510 | struct LuaStack 511 | { 512 | inline static bool get(lua_State * L, int idx) 513 | { 514 | luaL_checktype(L, idx, LUA_TBOOLEAN); 515 | return lua_toboolean(L, idx) != 0; 516 | } 517 | 518 | inline static void put(lua_State * L, const bool & t) 519 | { 520 | lua_pushboolean(L, t); 521 | } 522 | }; 523 | 524 | template<> 525 | struct LuaStack 526 | { 527 | inline static const char * get(lua_State * L, int idx) 528 | { 529 | switch (lua_type(L, idx)) 530 | { 531 | case LUA_TBOOLEAN: 532 | return (lua_toboolean(L, idx) ? "true" : "false"); 533 | case LUA_TNUMBER: 534 | return lua_tostring(L, idx); 535 | case LUA_TSTRING: 536 | return lua_tostring(L, idx); 537 | default: 538 | luaL_checktype(L, idx, LUA_TSTRING); 539 | break; 540 | } 541 | return ""; 542 | } 543 | 544 | inline static void put(lua_State * L, const char * s) 545 | { 546 | lua_pushstring(L, s); 547 | } 548 | }; 549 | 550 | template<> 551 | struct LuaStack 552 | { 553 | inline static char * get(lua_State * L, int idx) 554 | { 555 | return const_cast(LuaStack::get(L, idx)); 556 | } 557 | 558 | inline static void put(lua_State * L, const char * s) 559 | { 560 | LuaStack::put(L, s); 561 | } 562 | }; 563 | 564 | #if !LUAAA_WITHOUT_CPP_STDLIB 565 | template<> 566 | struct LuaStack 567 | { 568 | inline static std::string get(lua_State * L, int idx) 569 | { 570 | return LuaStack::get(L, idx); 571 | } 572 | 573 | inline static void put(lua_State * L, const std::string& s) 574 | { 575 | LuaStack::put(L, s.c_str()); 576 | } 577 | }; 578 | #endif 579 | 580 | template<> 581 | struct LuaStack 582 | { 583 | inline static lua_State * get(lua_State * L, int) 584 | { 585 | return L; 586 | } 587 | 588 | inline static void put(lua_State *, lua_State *) 589 | { 590 | // do thing here. 591 | } 592 | }; 593 | 594 | // push ret data to stack 595 | template 596 | inline void LuaStackReturn(lua_State * L, T t) 597 | { 598 | lua_settop(L, 0); 599 | LuaStack::put(L, t); 600 | } 601 | 602 | 603 | #define IMPLEMENT_CALLBACK_INVOKER(CALLCONV) \ 604 | template \ 605 | struct LuaStack \ 606 | { \ 607 | typedef RET(CALLCONV*FTYPE)(ARGS...); \ 608 | inline static FTYPE get(lua_State * L, int idx) \ 609 | { \ 610 | static lua_State * cacheLuaState = nullptr; \ 611 | static int cacheLuaFuncId = 0; \ 612 | struct HelperClass \ 613 | { \ 614 | static RET CALLCONV f_callback(ARGS... args) \ 615 | { \ 616 | lua_rawgeti(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); \ 617 | if (lua_isfunction(cacheLuaState, -1)) \ 618 | { \ 619 | int initParams[] = { (LuaStack::put(cacheLuaState, args), 0)..., 0 }; (void)initParams; \ 620 | if (lua_pcall(cacheLuaState, sizeof...(ARGS), 1, 0) != 0) \ 621 | { \ 622 | lua_error(cacheLuaState); \ 623 | } \ 624 | luaL_unref(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); \ 625 | } \ 626 | else \ 627 | { \ 628 | lua_pushnil(cacheLuaState); \ 629 | } \ 630 | return LuaStack::get(cacheLuaState, lua_gettop(cacheLuaState)); \ 631 | } \ 632 | }; \ 633 | if (lua_isfunction(L, idx)) \ 634 | { \ 635 | cacheLuaState = L; \ 636 | lua_pushvalue(L, idx); \ 637 | cacheLuaFuncId = luaL_ref(L, LUA_REGISTRYINDEX); \ 638 | return HelperClass::f_callback; \ 639 | } \ 640 | return nullptr; \ 641 | } \ 642 | inline void put(lua_State * L, FTYPE f) \ 643 | { \ 644 | lua_pushcfunction(L, NonMemberFunctionCaller(f)); \ 645 | } \ 646 | }; \ 647 | template \ 648 | struct LuaStack \ 649 | { \ 650 | typedef void(CALLCONV*FTYPE)(ARGS...); \ 651 | inline static FTYPE get(lua_State * L, int idx) \ 652 | { \ 653 | static lua_State * cacheLuaState = nullptr; \ 654 | static int cacheLuaFuncId = 0; \ 655 | struct HelperClass \ 656 | { \ 657 | static void CALLCONV f_callback(ARGS... args) \ 658 | { \ 659 | lua_rawgeti(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); \ 660 | if (lua_isfunction(cacheLuaState, -1)) \ 661 | { \ 662 | int initParams[] = { (LuaStack::put(cacheLuaState, args), 0)..., 0 }; (void)initParams; \ 663 | if (lua_pcall(cacheLuaState, sizeof...(ARGS), 1, 0) != 0) \ 664 | { \ 665 | lua_error(cacheLuaState); \ 666 | } \ 667 | luaL_unref(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); \ 668 | } \ 669 | return; \ 670 | } \ 671 | }; \ 672 | if (lua_isfunction(L, idx)) \ 673 | { \ 674 | cacheLuaState = L; \ 675 | lua_pushvalue(L, idx); \ 676 | cacheLuaFuncId = luaL_ref(L, LUA_REGISTRYINDEX); \ 677 | return HelperClass::f_callback; \ 678 | } \ 679 | return nullptr; \ 680 | } \ 681 | inline void put(lua_State * L, FTYPE f) \ 682 | { \ 683 | lua_pushcfunction(L, NonMemberFunctionCaller(f)); \ 684 | } \ 685 | }; 686 | 687 | #if !LUAAA_WITHOUT_CPP_STDLIB 688 | template 689 | struct LuaStack> 690 | { 691 | typedef std::function FTYPE; 692 | inline static FTYPE get(lua_State * L, int idx) 693 | { 694 | static lua_State * cacheLuaState = nullptr; 695 | static int cacheLuaFuncId = 0; 696 | struct HelperClass 697 | { 698 | static RET f_callback(ARGS... args) 699 | { 700 | lua_rawgeti(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); 701 | if (lua_isfunction(cacheLuaState, -1)) 702 | { 703 | int initParams[] = { (LuaStack::put(cacheLuaState, args), 0)..., 0 }; (void)initParams; 704 | if (lua_pcall(cacheLuaState, sizeof...(ARGS), 1, 0) != 0) 705 | { 706 | lua_error(cacheLuaState); 707 | } 708 | luaL_unref(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); 709 | } 710 | else 711 | { 712 | lua_pushnil(cacheLuaState); 713 | } 714 | return LuaStack::get(cacheLuaState, lua_gettop(cacheLuaState)); 715 | } 716 | }; 717 | if (lua_isfunction(L, idx)) 718 | { 719 | cacheLuaState = L; 720 | lua_pushvalue(L, idx); 721 | cacheLuaFuncId = luaL_ref(L, LUA_REGISTRYINDEX); 722 | return HelperClass::f_callback; 723 | } 724 | return nullptr; 725 | } 726 | inline void put(lua_State * L, FTYPE f) 727 | { 728 | lua_pushcfunction(L, NonMemberFunctionCaller(f)); 729 | } 730 | }; 731 | 732 | template 733 | struct LuaStack> 734 | { 735 | typedef std::function FTYPE; 736 | inline static FTYPE get(lua_State * L, int idx) 737 | { 738 | static lua_State * cacheLuaState = nullptr; 739 | static int cacheLuaFuncId = 0; 740 | struct HelperClass 741 | { 742 | static void f_callback(ARGS... args) 743 | { 744 | lua_rawgeti(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); 745 | if (lua_isfunction(cacheLuaState, -1)) 746 | { 747 | int initParams[] = { (LuaStack::put(cacheLuaState, args), 0)..., 0 }; 748 | if (lua_pcall(cacheLuaState, sizeof...(ARGS), 1, 0) != 0) 749 | { 750 | lua_error(cacheLuaState); 751 | } 752 | luaL_unref(cacheLuaState, LUA_REGISTRYINDEX, cacheLuaFuncId); 753 | } 754 | return; 755 | } 756 | }; 757 | if (lua_isfunction(L, idx)) 758 | { 759 | cacheLuaState = L; 760 | lua_pushvalue(L, idx); 761 | cacheLuaFuncId = luaL_ref(L, LUA_REGISTRYINDEX); 762 | return HelperClass::f_callback; 763 | } 764 | return nullptr; 765 | } 766 | inline void put(lua_State * L, FTYPE f) 767 | { 768 | lua_pushcfunction(L, NonMemberFunctionCaller(f)); 769 | } 770 | }; 771 | #endif 772 | 773 | //======================================================== 774 | // index generation helper 775 | //======================================================== 776 | template 777 | struct indices 778 | { 779 | using next = indices; 780 | }; 781 | 782 | template 783 | struct make_indices 784 | { 785 | using type = typename make_indices::type::next; 786 | }; 787 | 788 | template<> 789 | struct make_indices<0> 790 | { 791 | using type = indices<>; 792 | }; 793 | 794 | //======================================================== 795 | // non-member function caller & static member function caller 796 | //======================================================== 797 | template 798 | TRET LuaInvokeImpl(lua_State* state, void* calleePtr, size_t skip, indices) 799 | { 800 | return (*(FTYPE*)(calleePtr))(LuaStack::get(state, Ns + 1 + skip)...); 801 | } 802 | 803 | template 804 | inline TRET LuaInvoke(lua_State* state, void* calleePtr, size_t skip) 805 | { 806 | return LuaInvokeImpl(state, calleePtr, skip, typename make_indices::type()); 807 | } 808 | 809 | 810 | #define IMPLEMENT_FUNCTION_CALLER(CALLERNAME, CALLCONV, SKIPPARAM) \ 811 | template \ 812 | lua_CFunction CALLERNAME(TRET(CALLCONV*func)(ARGS...)) \ 813 | { \ 814 | typedef decltype(func) FTYPE; (void)(func); \ 815 | struct HelperClass \ 816 | { \ 817 | static int Invoke(lua_State* state) \ 818 | { \ 819 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); \ 820 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); \ 821 | if (calleePtr) \ 822 | { \ 823 | LuaStackReturn(state, LuaInvoke(state, calleePtr, SKIPPARAM)); \ 824 | return 1; \ 825 | } \ 826 | return 0; \ 827 | } \ 828 | }; \ 829 | return HelperClass::Invoke; \ 830 | } \ 831 | template \ 832 | lua_CFunction CALLERNAME(void(CALLCONV*func)(ARGS...)) \ 833 | { \ 834 | typedef decltype(func) FTYPE; (void)(func); \ 835 | struct HelperClass \ 836 | { \ 837 | static int Invoke(lua_State* state) \ 838 | { \ 839 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); \ 840 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); \ 841 | if (calleePtr) \ 842 | { \ 843 | LuaInvoke(state, calleePtr, SKIPPARAM); \ 844 | } \ 845 | return 0; \ 846 | } \ 847 | }; \ 848 | return HelperClass::Invoke; \ 849 | } 850 | 851 | #if defined(_MSC_VER) 852 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, __cdecl, 0); 853 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, __cdecl, 1); 854 | IMPLEMENT_CALLBACK_INVOKER(__cdecl); 855 | 856 | # ifdef _M_CEE 857 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, __clrcall, 0); 858 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, __clrcall, 1); 859 | IMPLEMENT_CALLBACK_INVOKER(__clrcall); 860 | # endif 861 | 862 | # if defined(_M_IX86) && !defined(_M_CEE) 863 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, __fastcall, 0); 864 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, __fastcall, 1); 865 | IMPLEMENT_CALLBACK_INVOKER(__fastcall); 866 | # endif 867 | 868 | # ifdef _M_IX86 869 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, __stdcall, 0); 870 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, __stdcall, 1); 871 | IMPLEMENT_CALLBACK_INVOKER(__stdcall); 872 | # endif 873 | 874 | # if ((defined(_M_IX86) && _M_IX86_FP >= 2) || defined(_M_X64)) && !defined(_M_CEE) 875 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, __vectorcall, 0); 876 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, __vectorcall, 1); 877 | IMPLEMENT_CALLBACK_INVOKER(__vectorcall); 878 | # endif 879 | #elif defined(__clang__) 880 | # define _NOTHING 881 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, _NOTHING, 0); 882 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, _NOTHING, 1); 883 | IMPLEMENT_CALLBACK_INVOKER(_NOTHING); 884 | # undef _NOTHING 885 | #elif defined(__GNUC__) 886 | # define _NOTHING 887 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, _NOTHING, 0); 888 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, _NOTHING, 1); 889 | IMPLEMENT_CALLBACK_INVOKER(_NOTHING); 890 | # undef _NOTHING 891 | #else 892 | # define _NOTHING 893 | IMPLEMENT_FUNCTION_CALLER(NonMemberFunctionCaller, _NOTHING, 0); 894 | IMPLEMENT_FUNCTION_CALLER(MemberFunctionCaller, _NOTHING, 1); 895 | IMPLEMENT_CALLBACK_INVOKER(_NOTHING); 896 | # undef _NOTHING 897 | #endif 898 | 899 | //======================================================== 900 | // member function invoker 901 | //======================================================== 902 | template 903 | TRET LuaInvokeInstanceMemberImpl(lua_State* state, void* calleePtr, indices) 904 | { 905 | return (LuaStack::get(state, 1).**(FTYPE*)(calleePtr))(LuaStack::get(state, Ns + 2)...); 906 | } 907 | 908 | template 909 | inline TRET LuaInvokeInstanceMember(lua_State* state, void* calleePtr) 910 | { 911 | return LuaInvokeInstanceMemberImpl(state, calleePtr, typename make_indices::type()); 912 | } 913 | 914 | 915 | template 916 | lua_CFunction MemberFunctionCaller(TRET(TCLASS::*func)(ARGS...)) 917 | { 918 | typedef decltype(func) FTYPE; (void)(func); 919 | struct HelperClass 920 | { 921 | static int Invoke(lua_State* state) 922 | { 923 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 924 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 925 | if (calleePtr) 926 | { 927 | LuaStackReturn(state, LuaInvokeInstanceMember(state, calleePtr)); 928 | return 1; 929 | } 930 | return 0; 931 | } 932 | }; 933 | return HelperClass::Invoke; 934 | } 935 | 936 | template 937 | lua_CFunction MemberFunctionCaller(TRET(TCLASS::*func)(ARGS...)const) 938 | { 939 | typedef decltype(func) FTYPE; (void)(func); 940 | struct HelperClass 941 | { 942 | static int Invoke(lua_State* state) 943 | { 944 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 945 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 946 | if (calleePtr) 947 | { 948 | LuaStackReturn(state, LuaInvokeInstanceMember(state, calleePtr)); 949 | return 1; 950 | } 951 | return 0; 952 | } 953 | }; 954 | return HelperClass::Invoke; 955 | } 956 | 957 | template 958 | lua_CFunction MemberFunctionCaller(void(TCLASS::*func)(ARGS...)) 959 | { 960 | typedef decltype(func) FTYPE; (void)(func); 961 | struct HelperClass 962 | { 963 | static int Invoke(lua_State* state) 964 | { 965 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 966 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 967 | if (calleePtr) 968 | { 969 | LuaInvokeInstanceMember(state, calleePtr); 970 | } 971 | return 0; 972 | } 973 | }; 974 | return HelperClass::Invoke; 975 | } 976 | 977 | template 978 | lua_CFunction MemberFunctionCaller(void(TCLASS::*func)(ARGS...)const) 979 | { 980 | typedef decltype(func) FTYPE; (void)(func); 981 | struct HelperClass 982 | { 983 | static int Invoke(lua_State* state) 984 | { 985 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 986 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 987 | if (calleePtr) 988 | { 989 | LuaInvokeInstanceMember(state, calleePtr); 990 | } 991 | return 0; 992 | } 993 | }; 994 | return HelperClass::Invoke; 995 | } 996 | 997 | #if !LUAAA_WITHOUT_CPP_STDLIB 998 | template 999 | lua_CFunction MemberFunctionCaller(const std::function& func) 1000 | { 1001 | typedef std::function FTYPE; (void)(func); 1002 | struct HelperClass 1003 | { 1004 | static int Invoke(lua_State* state) 1005 | { 1006 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1007 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 1008 | if (calleePtr) 1009 | { 1010 | LuaStackReturn(state, LuaInvoke(state, calleePtr, 1)); 1011 | return 1; 1012 | } 1013 | return 0; 1014 | } 1015 | }; 1016 | return HelperClass::Invoke; 1017 | } 1018 | 1019 | template 1020 | lua_CFunction MemberFunctionCaller(const std::function& func) 1021 | { 1022 | typedef std::function FTYPE; (void)(func); 1023 | struct HelperClass 1024 | { 1025 | static int Invoke(lua_State* state) 1026 | { 1027 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1028 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 1029 | if (calleePtr) 1030 | { 1031 | LuaInvoke(state, calleePtr, 1); 1032 | } 1033 | return 0; 1034 | } 1035 | }; 1036 | return HelperClass::Invoke; 1037 | } 1038 | 1039 | template 1040 | lua_CFunction NonMemberFunctionCaller(const std::function& func) 1041 | { 1042 | typedef std::function FTYPE; (void)(func); 1043 | struct HelperClass 1044 | { 1045 | static int Invoke(lua_State* state) 1046 | { 1047 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1048 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 1049 | if (calleePtr) 1050 | { 1051 | LuaStackReturn(state, LuaInvoke(state, calleePtr, 0)); 1052 | return 1; 1053 | } 1054 | return 0; 1055 | } 1056 | }; 1057 | return HelperClass::Invoke; 1058 | } 1059 | 1060 | template 1061 | lua_CFunction NonMemberFunctionCaller(const std::function& func) 1062 | { 1063 | typedef std::function FTYPE; (void)(func); 1064 | struct HelperClass 1065 | { 1066 | static int Invoke(lua_State* state) 1067 | { 1068 | void * calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1069 | luaL_argcheck(state, calleePtr, 1, "cpp closure function not found."); 1070 | if (calleePtr) 1071 | { 1072 | LuaInvoke(state, calleePtr, 0); 1073 | } 1074 | return 0; 1075 | } 1076 | }; 1077 | return HelperClass::Invoke; 1078 | } 1079 | #endif 1080 | 1081 | //======================================================== 1082 | // constructor invoker 1083 | //======================================================== 1084 | template 1085 | struct PlacementConstructorCaller 1086 | { 1087 | static TCLASS * Invoke(lua_State * state, void * mem, size_t skip) 1088 | { 1089 | return InvokeImpl(state, mem, typename make_indices::type(), skip); 1090 | } 1091 | 1092 | private: 1093 | template 1094 | static TCLASS * InvokeImpl(lua_State * state, void * mem, indices, size_t skip) 1095 | { 1096 | return new(mem) TCLASS(LuaStack::get(state, Ns + 1 + skip)...); 1097 | } 1098 | }; 1099 | 1100 | //======================================================== 1101 | // Destructor invoker 1102 | //======================================================== 1103 | template::value> 1104 | struct DestructorCaller 1105 | { 1106 | static void Invoke(TCLASS * obj) 1107 | { 1108 | delete obj; 1109 | } 1110 | }; 1111 | 1112 | template 1113 | struct DestructorCaller 1114 | { 1115 | static void Invoke(TCLASS * obj) 1116 | { 1117 | // do thing here. 1118 | } 1119 | }; 1120 | 1121 | //======================================================== 1122 | // export class 1123 | //======================================================== 1124 | template 1125 | struct LuaClass 1126 | { 1127 | friend struct DestructorCaller; 1128 | template friend struct LuaStack; 1129 | friend struct LuaModule; 1130 | 1131 | typedef struct _UserDataDetail { 1132 | TCLASS * obj; 1133 | int (*dtor)(_UserDataDetail*); 1134 | void* free_func; 1135 | } UserDataDetail; 1136 | 1137 | public: 1138 | LuaClass(lua_State * state, const char * name, const luaL_Reg * functions = nullptr) 1139 | : m_state(state) 1140 | { 1141 | assert(state != nullptr); 1142 | assert(klassName == nullptr); 1143 | 1144 | #if LUAAA_WITHOUT_CPP_STDLIB 1145 | luaL_argcheck(state, (klassName == nullptr), 1, "LuaCalss name conflict, use LuaClass to identify them"); 1146 | #else 1147 | luaL_argcheck(state, (klassName == nullptr), 1, (std::string("C++ class `") + RTTI_CLASS_NAME(TCLASS) + "` bind to conflict lua name `" + name + "`, origin name: `" + klassName + "`. use use LuaClass to identify them.").c_str()); 1148 | #endif 1149 | 1150 | struct HelperClass { 1151 | static int f__clsgc(lua_State*) { 1152 | LuaClass::klassName = nullptr; 1153 | return 0; 1154 | } 1155 | 1156 | static int f__objgc(lua_State* state) { 1157 | if (lua_isuserdata(state, -1)) { 1158 | auto uData = (UserDataDetail*)luaL_checkudata(state, -1, (LuaClass::klassName)); 1159 | if (uData) 1160 | { 1161 | lua_getmetatable(state, -1); 1162 | lua_getfield(state, -1, "!__gc"); 1163 | if (lua_isfunction(state, -1)) 1164 | { 1165 | lua_insert(state, 1); 1166 | lua_pcall(state, lua_gettop(state) - 1, 0, 0); 1167 | } 1168 | 1169 | if (uData->dtor) 1170 | { 1171 | return (uData->dtor)(uData); 1172 | } 1173 | } 1174 | } 1175 | return 0; 1176 | } 1177 | 1178 | #if LUAAA_FEATURE_PROPERTY 1179 | static int f_internal_index(lua_State* state) 1180 | { 1181 | const char* key = luaL_checkstring(state, 2); 1182 | if (!key) 1183 | { 1184 | lua_pushnil(state); 1185 | return 1; 1186 | } 1187 | 1188 | lua_getmetatable(state, 1); 1189 | lua_getfield(state, -1, key); 1190 | if (!lua_isnil(state, -1)) 1191 | { 1192 | return 1; 1193 | } 1194 | 1195 | lua_pop(state, 1); 1196 | 1197 | char internal_name[256]; 1198 | snprintf(internal_name, sizeof(internal_name), "<%s", key); 1199 | 1200 | lua_getfield(state, -1, internal_name); 1201 | if (lua_isfunction(state, -1)) 1202 | { 1203 | lua_insert(state, 1); 1204 | lua_pcall(state, lua_gettop(state) - 1, 1, 0); 1205 | } 1206 | else if (lua_isnil(state, -1)) 1207 | { 1208 | // check if user defined __index method 1209 | lua_pop(state, 1); 1210 | lua_getfield(state, -1, "!__index"); 1211 | if (lua_isfunction(state, -1)) 1212 | { 1213 | lua_insert(state, 1); 1214 | lua_pcall(state, lua_gettop(state) - 1, 0, 0); 1215 | } 1216 | else if (lua_istable(state, -1)) 1217 | { 1218 | lua_replace(state, 1); 1219 | lua_pop(state, 1); 1220 | lua_rawget(state, 1); 1221 | } 1222 | else 1223 | { 1224 | lua_pop(state, 1); 1225 | snprintf(internal_name, sizeof(internal_name), ">%s", key); 1226 | lua_getfield(state, -1, internal_name); 1227 | if (lua_isfunction(state, -1)) 1228 | { 1229 | // Yes, there are something write-only, e.g., stdout, printer, digital io pin in output mode. 1230 | luaL_error(state, "attempt to read Write-Only property '%s' of '%s'", key, LuaClass::klassName); 1231 | } 1232 | else 1233 | { 1234 | // do nothing here. nil will be return. 1235 | // luaL_error(state, "attempt to access Non-existing property '%s' of '%s'", key, LuaClass::klassName); 1236 | } 1237 | } 1238 | } 1239 | return 1; 1240 | } 1241 | 1242 | static int f_internal_newindex(lua_State* state) 1243 | { 1244 | const char* key = luaL_checkstring(state, 2); 1245 | if (!key) 1246 | { 1247 | lua_pushnil(state); 1248 | return 1; 1249 | } 1250 | 1251 | char internal_name[256]; 1252 | snprintf(internal_name, sizeof(internal_name), ">%s", key); 1253 | 1254 | 1255 | lua_getmetatable(state, 1); 1256 | lua_getfield(state, -1, internal_name); 1257 | if (lua_isfunction(state, -1)) 1258 | { 1259 | lua_insert(state, 1); 1260 | lua_pcall(state, lua_gettop(state) - 1, 0, 0); 1261 | } 1262 | else if (lua_istable(state, 1)) // if is extended lua class 1263 | { 1264 | lua_pop(state, 2); 1265 | lua_rawset(state, 1); 1266 | } 1267 | else 1268 | { 1269 | // check if user defined __newindex method 1270 | lua_pop(state, 1); 1271 | lua_getfield(state, -1, "!__newindex"); 1272 | if (lua_isfunction(state, -1)) 1273 | { 1274 | lua_insert(state, 1); 1275 | lua_pcall(state, lua_gettop(state) - 1, 0, 0); 1276 | } 1277 | else if (lua_istable(state, -1)) 1278 | { 1279 | lua_replace(state, 1); 1280 | lua_pop(state, 1); 1281 | lua_rawset(state, 1); 1282 | } 1283 | else 1284 | { 1285 | lua_pop(state, 1); 1286 | snprintf(internal_name, sizeof(internal_name), "<%s", key); 1287 | lua_getfield(state, -1, internal_name); 1288 | if (lua_isfunction(state, -1)) 1289 | { 1290 | luaL_error(state, "attempt to write Read-Only property '%s' of '%s'", key, LuaClass::klassName); 1291 | } 1292 | else 1293 | { 1294 | luaL_error(state, "attempt to access Non-existing property '%s' of '%s'", key, LuaClass::klassName); 1295 | } 1296 | } 1297 | } 1298 | return 0; 1299 | } 1300 | #endif 1301 | }; 1302 | 1303 | size_t strBufLen = strlen(name) + 1; 1304 | klassName = reinterpret_cast(lua_newuserdata(state, strBufLen + 1)); 1305 | memcpy(klassName, name, strBufLen); 1306 | 1307 | klassName[strBufLen - 1] = '$'; 1308 | klassName[strBufLen] = 0; 1309 | luaL_newmetatable(state, klassName); 1310 | luaL_Reg clsgc[] = { { "__gc", HelperClass::f__clsgc }, { nullptr, nullptr } }; 1311 | luaL_setfuncs(state, clsgc, 0); 1312 | lua_setmetatable(state, -2); 1313 | 1314 | klassName[strBufLen - 1] = 0; 1315 | luaL_newmetatable(state, klassName); 1316 | luaL_Reg objgc[] = { 1317 | { "__gc", HelperClass::f__objgc }, 1318 | #if LUAAA_FEATURE_PROPERTY 1319 | { "__index", HelperClass::f_internal_index }, 1320 | { "__newindex", HelperClass::f_internal_newindex }, 1321 | #endif 1322 | { nullptr, nullptr } 1323 | }; 1324 | luaL_setfuncs(state, objgc, 0); 1325 | 1326 | #if !LUAAA_FEATURE_PROPERTY 1327 | // if not register __index function, uncomment below codes 1328 | lua_pushvalue(state, -1); 1329 | lua_setfield(state, -2, "__index"); 1330 | #endif 1331 | 1332 | lua_pushvalue(state, -2); 1333 | lua_setfield(state, -2, "$"); 1334 | 1335 | if (functions) 1336 | { 1337 | luaL_setfuncs(state, functions, 0); 1338 | } 1339 | 1340 | lua_pop(state, 2); 1341 | } 1342 | 1343 | #if !LUAAA_WITHOUT_CPP_STDLIB 1344 | LuaClass(lua_State * state, const std::string& name, const luaL_Reg * functions = nullptr) 1345 | : LuaClass(state, name.c_str(), functions) 1346 | {} 1347 | #endif 1348 | 1349 | template 1350 | inline LuaClass& ctor(const char * name = "new") 1351 | { 1352 | struct HelperClass { 1353 | static int f_dtor(typename LuaClass::UserDataDetail * uData) { 1354 | if (uData && uData->obj) 1355 | { 1356 | (uData->obj)->~TCLASS(); 1357 | } 1358 | return 0; 1359 | } 1360 | 1361 | static int f_new(lua_State* state) { 1362 | auto uData = (typename LuaClass::UserDataDetail*)lua_newuserdata(state, sizeof(LuaClass::UserDataDetail) + sizeof(TCLASS)); 1363 | if (uData) 1364 | { 1365 | TCLASS * obj = PlacementConstructorCaller::Invoke(state, (void*)(uData + 1), 0); 1366 | if (obj) 1367 | { 1368 | uData->obj = obj; 1369 | uData->dtor = HelperClass::f_dtor; 1370 | luaL_setmetatable(state, (LuaClass::klassName)); 1371 | return 1; 1372 | } 1373 | lua_pop(state, 1); 1374 | } 1375 | lua_pushnil(state); 1376 | return 1; 1377 | } 1378 | }; 1379 | 1380 | luaaa_check_constructor_name_conflict(name); 1381 | 1382 | luaL_Reg constructor[] = { { name, HelperClass::f_new }, { nullptr, nullptr } }; 1383 | #if USE_NEW_MODULE_REGISTRY 1384 | lua_getglobal(m_state, klassName); 1385 | if (lua_isnil(m_state, -1)) 1386 | { 1387 | lua_pop(m_state, 1); 1388 | lua_newtable(m_state); 1389 | } 1390 | luaL_setfuncs(m_state, constructor, 0); 1391 | lua_setglobal(m_state, klassName); 1392 | #else 1393 | luaL_openlib(m_state, klassName, constructor, 0); 1394 | #endif 1395 | return (*this); 1396 | } 1397 | 1398 | template 1399 | inline LuaClass& ctor(const char * name, TCLASS*(*spawner)(ARGS...)) { 1400 | typedef decltype(spawner) SPAWNERFTYPE; 1401 | struct HelperClass { 1402 | static int f_dtor(typename LuaClass::UserDataDetail* uData) { 1403 | if (uData && uData->obj) 1404 | { 1405 | DestructorCaller::Invoke(uData->obj); 1406 | } 1407 | return 0; 1408 | } 1409 | 1410 | static int f_new(lua_State* state) { 1411 | void * spawner = lua_touserdata(state, lua_upvalueindex(1)); 1412 | luaL_argcheck(state, spawner, 1, "cpp closure spawner not found."); 1413 | if (spawner) { 1414 | auto uData = (typename LuaClass::UserDataDetail*)lua_newuserdata(state, sizeof(LuaClass::UserDataDetail)); 1415 | if (uData) 1416 | { 1417 | auto obj = LuaInvoke(state, spawner, 0); 1418 | if (obj) 1419 | { 1420 | uData->obj = obj; 1421 | uData->dtor = HelperClass::f_dtor; 1422 | luaL_setmetatable(state, (LuaClass::klassName)); 1423 | return 1; 1424 | } 1425 | lua_pop(state, 1); 1426 | } 1427 | } 1428 | lua_pushnil(state); 1429 | return 1; 1430 | } 1431 | }; 1432 | 1433 | luaaa_check_constructor_name_conflict(name); 1434 | 1435 | luaL_Reg constructor[] = { { name, HelperClass::f_new }, { nullptr, nullptr } }; 1436 | #if USE_NEW_MODULE_REGISTRY 1437 | lua_getglobal(m_state, klassName); 1438 | if (lua_isnil(m_state, -1)) 1439 | { 1440 | lua_pop(m_state, 1); 1441 | lua_newtable(m_state); 1442 | } 1443 | #endif 1444 | 1445 | SPAWNERFTYPE * spawnerPtr = (SPAWNERFTYPE*)lua_newuserdata(m_state, sizeof(SPAWNERFTYPE)); 1446 | #if LUAAA_WITHOUT_CPP_STDLIB 1447 | luaL_argcheck(m_state, spawnerPtr != nullptr, 1, "faild to alloc mem to store spawner for ctor"); 1448 | #else 1449 | luaL_argcheck(m_state, spawnerPtr != nullptr, 1, (std::string("faild to alloc mem to store spawner for ctor `") + name + "`").c_str()); 1450 | #endif 1451 | if (!spawnerPtr) 1452 | { 1453 | lua_pop(m_state, 1); 1454 | return (*this); 1455 | } 1456 | 1457 | memset(spawnerPtr, 0, sizeof(SPAWNERFTYPE)); 1458 | *spawnerPtr = spawner; 1459 | 1460 | #if USE_NEW_MODULE_REGISTRY 1461 | luaL_setfuncs(m_state, constructor, 1); 1462 | lua_setglobal(m_state, klassName); 1463 | #else 1464 | luaL_openlib(m_state, klassName, constructor, 1); 1465 | #endif 1466 | return (*this); 1467 | } 1468 | 1469 | template 1470 | inline LuaClass& ctor(const char * name, TCLASS*(*spawner)(ARGS...), TRET(*deleter)(TCLASS*)){ 1471 | typedef decltype(spawner) SPAWNERFTYPE; 1472 | typedef decltype(deleter) DELETERFTYPE; 1473 | 1474 | struct HelperClass { 1475 | static int f_dtor(typename LuaClass::UserDataDetail* uData) { 1476 | if (uData && uData->obj && uData->free_func) 1477 | { 1478 | (*(DELETERFTYPE*)(uData->free_func))(uData->obj); 1479 | } 1480 | return 0; 1481 | } 1482 | 1483 | static int f_new(lua_State* state) { 1484 | void * spawner = lua_touserdata(state, lua_upvalueindex(1)); 1485 | luaL_argcheck(state, spawner, 1, "cpp closure spawner not found."); 1486 | 1487 | void * deleter = lua_touserdata(state, lua_upvalueindex(2)); 1488 | luaL_argcheck(state, deleter, 2, "cpp closure deleter not found."); 1489 | 1490 | if (spawner) { 1491 | auto uData = (typename LuaClass::UserDataDetail*)lua_newuserdata(state, sizeof(LuaClass::UserDataDetail)); 1492 | if (uData) 1493 | { 1494 | auto obj = LuaInvoke(state, spawner, 0); 1495 | if (obj) 1496 | { 1497 | uData->obj = obj; 1498 | uData->dtor = HelperClass::f_dtor; 1499 | uData->free_func = deleter; 1500 | luaL_setmetatable(state, (LuaClass::klassName)); 1501 | return 1; 1502 | } 1503 | lua_pop(state, 1); 1504 | } 1505 | } 1506 | lua_pushnil(state); 1507 | return 1; 1508 | } 1509 | }; 1510 | 1511 | #if USE_NEW_MODULE_REGISTRY 1512 | lua_getglobal(m_state, klassName); 1513 | if (lua_isnil(m_state, -1)) 1514 | { 1515 | lua_pop(m_state, 1); 1516 | lua_newtable(m_state); 1517 | } 1518 | #endif 1519 | 1520 | SPAWNERFTYPE * spawnerPtr = (SPAWNERFTYPE*)lua_newuserdata(m_state, sizeof(SPAWNERFTYPE)); 1521 | #if LUAAA_WITHOUT_CPP_STDLIB 1522 | luaL_argcheck(m_state, spawnerPtr != nullptr, 0, ("faild to alloc mem to store spawner for ctor")); 1523 | #else 1524 | luaL_argcheck(m_state, spawnerPtr != nullptr, 0, (std::string("faild to alloc mem to store spawner for ctor `") + name + "`").c_str()); 1525 | #endif 1526 | if (!spawnerPtr) 1527 | { 1528 | lua_pop(m_state, 2); 1529 | return (*this); 1530 | } 1531 | 1532 | memset(spawnerPtr, 0, sizeof(SPAWNERFTYPE)); 1533 | *spawnerPtr = spawner; 1534 | 1535 | DELETERFTYPE * deleterPtr = (DELETERFTYPE*)lua_newuserdata(m_state, sizeof(DELETERFTYPE)); 1536 | #if LUAAA_WITHOUT_CPP_STDLIB 1537 | luaL_argcheck(m_state, deleterPtr != nullptr, 0, ("faild to alloc mem to store deleter for ctor")); 1538 | #else 1539 | luaL_argcheck(m_state, deleterPtr != nullptr, 0, (std::string("faild to alloc mem to store deleter for ctor `") + name + "`").c_str()); 1540 | #endif 1541 | if (!deleterPtr) 1542 | { 1543 | lua_pop(m_state, 3); 1544 | return (*this); 1545 | } 1546 | 1547 | memset(deleterPtr, 0, sizeof(DELETERFTYPE)); 1548 | *deleterPtr = deleter; 1549 | 1550 | luaL_Reg constructor[] = { { name, HelperClass::f_new }, { nullptr, nullptr } }; 1551 | #if USE_NEW_MODULE_REGISTRY 1552 | luaL_setfuncs(m_state, constructor, 2); 1553 | lua_setglobal(m_state, klassName); 1554 | #else 1555 | luaL_openlib(m_state, klassName, constructor, 2); 1556 | #endif 1557 | return (*this); 1558 | } 1559 | 1560 | template 1561 | inline LuaClass& ctor(const char * name, TCLASS*(*spawner)(ARGS...), std::nullptr_t) { 1562 | typedef decltype(spawner) SPAWNERFTYPE; 1563 | 1564 | struct HelperClass { 1565 | static int f_new(lua_State* state) { 1566 | void * spawner = lua_touserdata(state, lua_upvalueindex(1)); 1567 | luaL_argcheck(state, spawner, 1, "cpp closure spawner not found."); 1568 | if (spawner) { 1569 | auto uData = (typename LuaClass::UserDataDetail*)lua_newuserdata(state, sizeof(LuaClass::UserDataDetail)); 1570 | if (uData) 1571 | { 1572 | auto obj = LuaInvoke(state, spawner, 0); 1573 | if (obj) 1574 | { 1575 | uData->obj = obj; 1576 | uData->dtor = nullptr; 1577 | luaL_setmetatable(state, (LuaClass::klassName)); 1578 | return 1; 1579 | } 1580 | lua_pop(state, 1); 1581 | } 1582 | } 1583 | lua_pushnil(state); 1584 | return 1; 1585 | } 1586 | 1587 | }; 1588 | 1589 | luaaa_check_constructor_name_conflict(name); 1590 | 1591 | #if USE_NEW_MODULE_REGISTRY 1592 | lua_getglobal(m_state, klassName); 1593 | if (lua_isnil(m_state, -1)) 1594 | { 1595 | lua_pop(m_state, 1); 1596 | lua_newtable(m_state); 1597 | } 1598 | #endif 1599 | SPAWNERFTYPE * spawnerPtr = (SPAWNERFTYPE*)lua_newuserdata(m_state, sizeof(SPAWNERFTYPE)); 1600 | #if LUAAA_WITHOUT_CPP_STDLIB 1601 | luaL_argcheck(m_state, spawnerPtr != nullptr, 1, "faild to alloc mem to store spawner for ctor of cpp class"); 1602 | #else 1603 | luaL_argcheck(m_state, spawnerPtr != nullptr, 1, (std::string("faild to alloc mem to store spawner for ctor `") + name + "`").c_str()); 1604 | #endif 1605 | if (!spawnerPtr) 1606 | { 1607 | lua_pop(m_state, 1); 1608 | return (*this); 1609 | } 1610 | 1611 | memset(spawnerPtr, 0, sizeof(SPAWNERFTYPE)); 1612 | *spawnerPtr = spawner; 1613 | 1614 | luaL_Reg constructor[] = { { name, HelperClass::f_new }, { nullptr, nullptr } }; 1615 | #if USE_NEW_MODULE_REGISTRY 1616 | luaL_setfuncs(m_state, constructor, 1); 1617 | lua_setglobal(m_state, klassName); 1618 | #else 1619 | luaL_openlib(m_state, klassName, constructor, 1); 1620 | #endif 1621 | return (*this); 1622 | } 1623 | 1624 | 1625 | #if !LUAAA_WITHOUT_CPP_STDLIB 1626 | template 1627 | inline LuaClass& ctor(const std::string& name) 1628 | { 1629 | return ctor(name.c_str()); 1630 | } 1631 | 1632 | template 1633 | inline LuaClass& ctor(const std::string& name, TCLASS*(*spawner)(ARGS...)) { 1634 | return ctor(name.c_str(), spawner); 1635 | } 1636 | 1637 | template 1638 | inline LuaClass& ctor(const std::string& name, TCLASS*(*spawner)(ARGS...), TRET(*deleter)(TCLASS*)) { 1639 | return ctor(name.c_str(), spawner, deleter); 1640 | } 1641 | 1642 | template 1643 | inline LuaClass& ctor(const std::string& name, TCLASS*(*spawner)(ARGS...), std::nullptr_t) { 1644 | return ctor(name.c_str(), spawner, nullptr); 1645 | } 1646 | #endif 1647 | 1648 | private: 1649 | template 1650 | inline LuaClass& _registerClassFunction(const char* name, lua_CFunction caller, F f) 1651 | { 1652 | luaL_getmetatable(m_state, klassName); 1653 | if (strcmp(name, "__gc") == 0) 1654 | { 1655 | lua_pushstring(m_state, "!__gc"); 1656 | } 1657 | #if LUAAA_FEATURE_PROPERTY 1658 | else if (strcmp(name, "__index") == 0) 1659 | { 1660 | lua_pushstring(m_state, "!__index"); 1661 | } 1662 | else if (strcmp(name, "__newindex") == 0) 1663 | { 1664 | lua_pushstring(m_state, "!__newindex"); 1665 | } 1666 | #endif 1667 | else 1668 | { 1669 | lua_pushstring(m_state, name); 1670 | } 1671 | 1672 | F* funPtr = (F*)lua_newuserdata(m_state, sizeof(F)); 1673 | #if LUAAA_WITHOUT_CPP_STDLIB 1674 | luaL_argcheck(m_state, funPtr != nullptr, 1, "faild to alloc mem to store function"); 1675 | #else 1676 | luaL_argcheck(m_state, funPtr != nullptr, 1, (std::string("faild to alloc mem to store function `") + name + "`").c_str()); 1677 | #endif 1678 | if (funPtr) 1679 | { 1680 | memset(funPtr, 0, sizeof(F)); 1681 | *funPtr = f; 1682 | lua_pushcclosure(m_state, caller, 1); 1683 | lua_settable(m_state, -3); 1684 | lua_pop(m_state, 1); 1685 | } 1686 | else 1687 | { 1688 | lua_pop(m_state, 2); 1689 | } 1690 | return (*this); 1691 | } 1692 | 1693 | private: 1694 | template 1695 | inline LuaClass& _funImpl(const char * name, F f) 1696 | { 1697 | return _registerClassFunction(name, MemberFunctionCaller(f), f); 1698 | } 1699 | 1700 | public: 1701 | template 1702 | inline LuaClass& fun(const char * name, FRET(FCLASS::*f)(FARGS...)) 1703 | { 1704 | return _funImpl(name, f); 1705 | } 1706 | 1707 | template 1708 | inline LuaClass& fun(const char * name, FRET(FCLASS::*f)(FARGS...) const) 1709 | { 1710 | return _funImpl(name, f); 1711 | } 1712 | 1713 | template 1714 | inline LuaClass& fun(const char * name, void(FCLASS::*f)(FARGS...)) 1715 | { 1716 | return _funImpl(name, f); 1717 | } 1718 | 1719 | template 1720 | inline LuaClass& fun(const char * name, void(FCLASS::*f)(FARGS...) const) 1721 | { 1722 | return _funImpl(name, f); 1723 | } 1724 | 1725 | template 1726 | inline LuaClass& fun(const char * name, FRET(*f)(FARGS...)) 1727 | { 1728 | return _funImpl(name, f); 1729 | } 1730 | 1731 | template 1732 | inline LuaClass& fun(const char * name, void(*f)(FARGS...)) 1733 | { 1734 | return _funImpl(name, f); 1735 | } 1736 | 1737 | #if !LUAAA_WITHOUT_CPP_STDLIB 1738 | // register lambdas as lua class function 1739 | template 1740 | inline LuaClass& fun(const char * name, const std::function& f) 1741 | { 1742 | return _funImpl>(name, f); 1743 | } 1744 | 1745 | template 1746 | inline LuaClass& fun(const char * name, const std::function& f) 1747 | { 1748 | return _funImpl>(name, f); 1749 | } 1750 | 1751 | template 1752 | inline LuaClass& fun(const char * name, F f) 1753 | { 1754 | return fun(name, to_function(f)); 1755 | } 1756 | #endif 1757 | 1758 | inline LuaClass& fun(const char * name, lua_CFunction f) 1759 | { 1760 | luaL_getmetatable(m_state, klassName); 1761 | if (strcmp(name, "__gc") == 0) 1762 | { 1763 | lua_pushstring(m_state, "!__gc"); 1764 | } 1765 | #if LUAAA_FEATURE_PROPERTY 1766 | else if (strcmp(name, "__index") == 0) 1767 | { 1768 | lua_pushstring(m_state, "!__index"); 1769 | } 1770 | else if (strcmp(name, "__newindex") == 0) 1771 | { 1772 | lua_pushstring(m_state, "!__newindex"); 1773 | } 1774 | #endif 1775 | else 1776 | { 1777 | lua_pushstring(m_state, name); 1778 | } 1779 | lua_pushcclosure(m_state, f, 0); 1780 | lua_settable(m_state, -3); 1781 | lua_pop(m_state, 1); 1782 | return (*this); 1783 | } 1784 | 1785 | template 1786 | inline LuaClass& def(const char * name, const V& val) 1787 | { 1788 | luaL_getmetatable(m_state, klassName); 1789 | lua_pushstring(m_state, name); 1790 | LuaStack::put(m_state, val); 1791 | lua_settable(m_state, -3); 1792 | lua_pop(m_state, 1); 1793 | return (*this); 1794 | } 1795 | 1796 | // disable cast from "const char [#]" to "char (*)[#]" 1797 | inline LuaClass& def(const char* name, const char* str) 1798 | { 1799 | luaL_getmetatable(m_state, klassName); 1800 | lua_pushstring(m_state, name); 1801 | LuaStack::put(m_state, str); 1802 | lua_settable(m_state, -3); 1803 | lua_pop(m_state, 1); 1804 | return (*this); 1805 | } 1806 | 1807 | private: 1808 | template 1809 | inline LuaClass& _getterImpl(const char* name, lua_CFunction invoker, F f) 1810 | { 1811 | #if LUAAA_FEATURE_PROPERTY 1812 | char internal_name[256]; 1813 | snprintf(internal_name, sizeof(internal_name), "<%s", name); 1814 | return _registerClassFunction(internal_name, invoker, f); 1815 | #else 1816 | return *this; 1817 | #endif 1818 | } 1819 | 1820 | template 1821 | inline LuaClass& _setterImpl(const char* name, lua_CFunction invoker, F f) 1822 | { 1823 | #if LUAAA_FEATURE_PROPERTY 1824 | char internal_name[256]; 1825 | snprintf(internal_name, sizeof(internal_name), ">%s", name); 1826 | return _registerClassFunction(internal_name, invoker, f); 1827 | #else 1828 | return *this; 1829 | #endif 1830 | } 1831 | 1832 | public: 1833 | template 1834 | inline LuaClass& get(const char* name, P(*f)()) 1835 | { 1836 | struct HelperClass { 1837 | typedef decltype(f) FTYPE; 1838 | static inline int Invoke(lua_State* state) { 1839 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1840 | if (calleePtr) 1841 | { 1842 | LuaStackReturn

(state, (*(FTYPE*)(calleePtr))()); 1843 | } 1844 | else 1845 | { 1846 | lua_pushnil(state); 1847 | } 1848 | return 1; 1849 | } 1850 | }; 1851 | return _getterImpl(name, HelperClass::Invoke, f); 1852 | } 1853 | 1854 | template 1855 | inline LuaClass& get(const char* name, P(*f)(const TCLASS&)) 1856 | { 1857 | struct HelperClass { 1858 | static inline int Invoke(lua_State* state) { 1859 | typedef decltype(f) FTYPE; 1860 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1861 | if (calleePtr) 1862 | { 1863 | LuaStackReturn

(state, (*(FTYPE*)(calleePtr))(LuaStack::get(state, 1))); 1864 | } 1865 | else 1866 | { 1867 | lua_pushnil(state); 1868 | } 1869 | return 1; 1870 | } 1871 | }; 1872 | return _getterImpl(name, HelperClass::Invoke, f); 1873 | } 1874 | 1875 | template 1876 | inline LuaClass& get(const char* name, P(FCLASS::*f)()const) 1877 | { 1878 | static_assert(std::is_same, std::decay>::value, "Error: prop function can be member function of only associated class"); 1879 | struct HelperClass { 1880 | static inline int Invoke(lua_State* state) { 1881 | typedef decltype(f) FTYPE; 1882 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1883 | if (calleePtr) 1884 | { 1885 | LuaStackReturn

(state, (LuaStack::get(state, 1).**(FTYPE*)(calleePtr))()); 1886 | } 1887 | else 1888 | { 1889 | lua_pushnil(state); 1890 | } 1891 | return 1; 1892 | } 1893 | }; 1894 | return _getterImpl(name, HelperClass::Invoke, f); 1895 | } 1896 | 1897 | 1898 | template 1899 | inline LuaClass& set(const char* name, TRET(*f)(P)) 1900 | { 1901 | struct HelperClass { 1902 | static inline int Invoke(lua_State* state) { 1903 | typedef decltype(f) FTYPE; 1904 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1905 | if (calleePtr) 1906 | { 1907 | (*(FTYPE*)(calleePtr))(LuaStack

::get(state, 3)); 1908 | } 1909 | return 0; 1910 | } 1911 | }; 1912 | return _setterImpl(name, HelperClass::Invoke, f); 1913 | } 1914 | 1915 | template 1916 | inline LuaClass& set(const char* name, TRET(FCLASS::* f)(P)) 1917 | { 1918 | static_assert(std::is_same, std::decay>::value, "prop function can be member function of only associated class"); 1919 | struct HelperClass { 1920 | static inline int Invoke(lua_State* state) { 1921 | typedef decltype(f) FTYPE; 1922 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1923 | if (calleePtr) 1924 | { 1925 | (LuaStack::get(state, 1).**(FTYPE*)(calleePtr))(LuaStack

::get(state, 3)); 1926 | } 1927 | return 0; 1928 | } 1929 | }; 1930 | return _setterImpl(name, HelperClass::Invoke, f); 1931 | } 1932 | 1933 | template 1934 | inline LuaClass& set(const char* name, TRET(*f)(TCLASS&, P)) 1935 | { 1936 | struct HelperClass { 1937 | static inline int Invoke(lua_State* state) { 1938 | typedef decltype(f) FTYPE; 1939 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1940 | if (calleePtr) 1941 | { 1942 | (*(FTYPE*)(calleePtr))(LuaStack::get(state, 1), LuaStack

::get(state, 3)); 1943 | } 1944 | return 0; 1945 | } 1946 | }; 1947 | return _setterImpl(name, HelperClass::Invoke, f); 1948 | } 1949 | 1950 | 1951 | public: 1952 | #if !LUAAA_WITHOUT_CPP_STDLIB 1953 | // access prop from lambdas 1954 | template 1955 | inline LuaClass& get(const char* name, std::function f) 1956 | { 1957 | struct HelperClass { 1958 | static inline int Invoke(lua_State* state) { 1959 | typedef decltype(f) FTYPE; 1960 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1961 | if (calleePtr) 1962 | { 1963 | LuaStackReturn

(state, (*(FTYPE*)(calleePtr))()); 1964 | } 1965 | else 1966 | { 1967 | lua_pushnil(state); 1968 | } 1969 | return 1; 1970 | } 1971 | }; 1972 | return _getterImpl(name, HelperClass::Invoke, f); 1973 | } 1974 | 1975 | template 1976 | inline LuaClass& get(const char* name, std::function f) 1977 | { 1978 | struct HelperClass { 1979 | 1980 | static inline int Invoke(lua_State* state) { 1981 | typedef decltype(f) FTYPE; 1982 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 1983 | if (calleePtr) 1984 | { 1985 | LuaStackReturn

(state, (*(FTYPE*)(calleePtr))(LuaStack::get(state, 1))); 1986 | } 1987 | else 1988 | { 1989 | lua_pushnil(state); 1990 | } 1991 | return 1; 1992 | } 1993 | }; 1994 | return _getterImpl(name, HelperClass::Invoke, f); 1995 | } 1996 | 1997 | template 1998 | inline LuaClass& get(const char* name, std::function f) 1999 | { 2000 | struct HelperClass { 2001 | static inline int Invoke(lua_State* state) { 2002 | typedef decltype(f) FTYPE; 2003 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2004 | if (calleePtr) 2005 | { 2006 | LuaStackReturn

(state, (*(FTYPE*)(calleePtr))(LuaStack::get(state, 1))); 2007 | } 2008 | else 2009 | { 2010 | lua_pushnil(state); 2011 | } 2012 | return 1; 2013 | } 2014 | }; 2015 | return _getterImpl(name, HelperClass::Invoke, f); 2016 | } 2017 | 2018 | template 2019 | inline LuaClass& get(const char* name, F f) 2020 | { 2021 | return get(name, to_class_getter_function(f)); 2022 | } 2023 | 2024 | template 2025 | inline LuaClass& set(const char* name, std::function f) 2026 | { 2027 | struct HelperClass { 2028 | static inline int Invoke(lua_State* state) { 2029 | typedef decltype(f) FTYPE; 2030 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2031 | if (calleePtr) 2032 | { 2033 | (*(FTYPE*)(calleePtr))(LuaStack

::get(state, 3)); 2034 | } 2035 | return 0; 2036 | } 2037 | }; 2038 | return _setterImpl(name, HelperClass::Invoke, f); 2039 | } 2040 | 2041 | template 2042 | inline LuaClass& set(const char* name, std::function f) 2043 | { 2044 | struct HelperClass { 2045 | static inline int Invoke(lua_State* state) { 2046 | typedef decltype(f) FTYPE; 2047 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2048 | if (calleePtr) 2049 | { 2050 | (*(FTYPE*)(calleePtr))(LuaStack::get(state, 1), LuaStack

::get(state, 3)); 2051 | } 2052 | return 0; 2053 | } 2054 | }; 2055 | return _setterImpl(name, HelperClass::Invoke, f); 2056 | } 2057 | 2058 | template 2059 | inline LuaClass& set(const char* name, std::function f) 2060 | { 2061 | struct HelperClass { 2062 | static inline int Invoke(lua_State* state) { 2063 | typedef decltype(f) FTYPE; 2064 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2065 | if (calleePtr) 2066 | { 2067 | (*(FTYPE*)(calleePtr))(LuaStack::get(state, 1), LuaStack

::get(state, 3)); 2068 | } 2069 | return 0; 2070 | } 2071 | }; 2072 | return _setterImpl(name, HelperClass::Invoke, f); 2073 | } 2074 | 2075 | //template 2076 | //inline LuaClass& set(const char* name, std::function f) 2077 | //{ 2078 | // //static_assert(false, "Error: invalid signature of setter function"); 2079 | // assert(!"Error: invalid signature of setter function"); 2080 | // return (*this); 2081 | //} 2082 | 2083 | template 2084 | inline LuaClass& set(const char* name, F f) 2085 | { 2086 | return set(name, to_class_setter_function(f)); 2087 | } 2088 | #endif 2089 | 2090 | public: 2091 | #if !LUAAA_WITHOUT_CPP_STDLIB 2092 | template 2093 | inline LuaClass& fun(const std::string& name, F f) 2094 | { 2095 | return fun(name.c_str(), f); 2096 | } 2097 | 2098 | template 2099 | inline LuaClass& def(const std::string& name, const V& val) 2100 | { 2101 | return def(name.c_str(), val); 2102 | } 2103 | 2104 | template 2105 | inline LuaClass& get(const std::string& name, F f) 2106 | { 2107 | return get(name.c_str(), f); 2108 | } 2109 | 2110 | template 2111 | inline LuaClass& set(const std::string& name, F f) 2112 | { 2113 | return set(name.c_str(), f); 2114 | } 2115 | #endif 2116 | 2117 | private: 2118 | lua_State * m_state; 2119 | 2120 | private: 2121 | static char * klassName; 2122 | }; 2123 | 2124 | template char * LuaClass::klassName = nullptr; 2125 | 2126 | 2127 | // ----------------------------------- 2128 | // export module 2129 | // ----------------------------------- 2130 | struct LuaModule 2131 | { 2132 | public: 2133 | LuaModule(lua_State * state, const char * name = "_G") 2134 | : m_state(state) 2135 | { 2136 | size_t strBufLen = strlen(name) + 1; 2137 | m_moduleName = new char[strBufLen]; 2138 | memcpy(m_moduleName, name, strBufLen); 2139 | def("__name", m_moduleName); 2140 | } 2141 | 2142 | #if !LUAAA_WITHOUT_CPP_STDLIB 2143 | LuaModule(lua_State * state, const std::string& name) 2144 | : LuaModule(state, name.empty() ? "_G" : name.c_str()) 2145 | {} 2146 | #endif 2147 | 2148 | ~LuaModule() 2149 | { 2150 | if (m_moduleName) { 2151 | delete[] m_moduleName; 2152 | m_moduleName = nullptr; 2153 | } 2154 | } 2155 | 2156 | private: 2157 | void _initMetaTable(lua_State * state, int idx) { 2158 | struct HelperClass { 2159 | #if LUAAA_FEATURE_PROPERTY 2160 | static int f_internal_index(lua_State* state) 2161 | { 2162 | const char* key = luaL_checkstring(state, 2); 2163 | if (!key) 2164 | { 2165 | lua_pushnil(state); 2166 | return 1; 2167 | } 2168 | // lookup module first 2169 | lua_pushstring(state, key); 2170 | lua_rawget(state, 1); 2171 | if (!lua_isnil(state, -1)) 2172 | { 2173 | return 1; 2174 | } 2175 | 2176 | lua_pop(state, 1); 2177 | 2178 | // then lookup registered property 2179 | char internal_name[256]; 2180 | snprintf(internal_name, sizeof(internal_name), "<%s", key); 2181 | 2182 | lua_getmetatable(state, 1); 2183 | lua_pushstring(state, internal_name); 2184 | lua_rawget(state, -2); 2185 | if (lua_isfunction(state, -1)) 2186 | { 2187 | lua_insert(state, 1); 2188 | lua_pcall(state, lua_gettop(state) - 1, 1, 0); 2189 | } 2190 | else 2191 | { 2192 | // check if user defined __index method 2193 | lua_pop(state, 3); 2194 | lua_pushstring(state, "__index"); 2195 | lua_rawget(state, 1); 2196 | if (lua_isfunction(state, -1)) 2197 | { 2198 | lua_insert(state, 1); 2199 | lua_pcall(state, lua_gettop(state) - 1, 1, 0); 2200 | } 2201 | else if (lua_istable(state, -1)) 2202 | { 2203 | lua_replace(state, 1); 2204 | lua_rawget(state, 1); 2205 | } 2206 | else 2207 | { 2208 | // no custom __index 2209 | lua_getmetatable(state, 1); 2210 | snprintf(internal_name, sizeof(internal_name), ">%s", key); 2211 | lua_pushstring(state, internal_name); 2212 | lua_rawget(state, -2); 2213 | if (lua_isfunction(state, -1)) 2214 | { 2215 | lua_pushstring(state, "__name"); 2216 | lua_rawget(state, -3); 2217 | luaL_error(state, "attempt to read Write-Only property '%s' of '%s'", luaL_optstring(state, -1, "?")); 2218 | } 2219 | else 2220 | { 2221 | // do nothing here. nil will be return. 2222 | // luaL_error(state, "attempt to access Non-existing property '%s' of '%s'", key, LuaClass::klassName); 2223 | } 2224 | } 2225 | } 2226 | return 1; 2227 | } 2228 | 2229 | static int f_internal_newindex(lua_State* state) 2230 | { 2231 | const char* key = luaL_checkstring(state, 2); 2232 | if (!key) 2233 | { 2234 | lua_pushnil(state); 2235 | return 1; 2236 | } 2237 | 2238 | char internal_name[256]; 2239 | snprintf(internal_name, sizeof(internal_name), ">%s", key); 2240 | 2241 | lua_getmetatable(state, 1); 2242 | lua_pushstring(state, internal_name); 2243 | lua_rawget(state, -2); 2244 | if (lua_isfunction(state, -1)) 2245 | { 2246 | lua_insert(state, 1); 2247 | lua_pcall(state, lua_gettop(state) - 1, 0, 0); 2248 | } 2249 | else 2250 | { 2251 | lua_pop(state, 1); 2252 | snprintf(internal_name, sizeof(internal_name), "<%s", key); 2253 | lua_pushstring(state, internal_name); 2254 | lua_rawget(state, -2); 2255 | if (lua_isfunction(state, -1)) 2256 | { 2257 | luaL_error(state, "attempt to write Read-Only property '%s' of '?'", key); 2258 | } 2259 | else 2260 | { 2261 | lua_pop(state, 2); 2262 | // no associated property, lookup current module 2263 | if (lua_istable(state, 1)) 2264 | { 2265 | // check if user defined __newindex 2266 | lua_pushstring(state, "__newindex"); 2267 | lua_rawget(state, 1); 2268 | if (lua_isfunction(state, -1)) 2269 | { 2270 | lua_insert(state, 1); 2271 | lua_pcall(state, lua_gettop(state) - 1, 0, 0); 2272 | } 2273 | else if (lua_istable(state, -1)) 2274 | { 2275 | lua_replace(state, 1); 2276 | lua_rawset(state, 1); 2277 | } 2278 | else 2279 | { 2280 | // no custom __newindex 2281 | lua_pop(state, 1); 2282 | lua_rawset(state, 1); 2283 | } 2284 | } 2285 | } 2286 | } 2287 | return 0; 2288 | } 2289 | #endif 2290 | }; 2291 | 2292 | luaL_newmetatable(state, m_moduleName); 2293 | luaL_Reg objfunc[] = { 2294 | #if LUAAA_FEATURE_PROPERTY 2295 | { "__index", HelperClass::f_internal_index }, 2296 | { "__newindex", HelperClass::f_internal_newindex }, 2297 | #endif 2298 | { nullptr, nullptr } 2299 | }; 2300 | luaL_setfuncs(state, objfunc, 0); 2301 | lua_setmetatable(state, -2); 2302 | } 2303 | 2304 | template 2305 | inline LuaModule& _registerModuleFunction(const char* name, lua_CFunction caller, F f) { 2306 | #if USE_NEW_MODULE_REGISTRY 2307 | lua_getglobal(m_state, m_moduleName); 2308 | if (lua_isnil(m_state, -1)) 2309 | { 2310 | lua_pop(m_state, 1); 2311 | lua_newtable(m_state); 2312 | _initMetaTable(m_state, -1); 2313 | } 2314 | 2315 | F* funPtr = (F*)lua_newuserdata(m_state, sizeof(F)); 2316 | # if LUAAA_WITHOUT_CPP_STDLIB 2317 | luaL_argcheck(m_state, funPtr != nullptr, 1, "faild to alloc mem to store function of module"); 2318 | # else 2319 | luaL_argcheck(m_state, funPtr != nullptr, 1, (std::string("faild to alloc mem to store function `") + name + "`").c_str()); 2320 | # endif 2321 | if (!funPtr) 2322 | { 2323 | lua_pop(m_state, 2); 2324 | return (*this); 2325 | } 2326 | 2327 | memset(funPtr, 0, sizeof(F)); 2328 | *funPtr = f; 2329 | 2330 | lua_pushvalue(m_state, -1); 2331 | lua_pushcclosure(m_state, caller, 1); 2332 | lua_pushstring(m_state, name); 2333 | lua_insert(m_state, -2); 2334 | lua_rawset(m_state, -4); 2335 | lua_pop(m_state, 1); 2336 | lua_setglobal(m_state, m_moduleName); 2337 | #else 2338 | luaL_Reg regtab[] = { { name, caller },{ nullptr, nullptr } }; 2339 | F* funPtr = (F*)lua_newuserdata(m_state, sizeof(F)); 2340 | # if LUAAA_WITHOUT_CPP_STDLIB 2341 | luaL_argcheck(m_state, funPtr != nullptr, 1, "faild to alloc mem to store function of module"); 2342 | # else 2343 | luaL_argcheck(m_state, funPtr != nullptr, 1, (std::string("faild to alloc mem to store function `") + name + "`").c_str()); 2344 | # endif 2345 | if (funPtr) 2346 | { 2347 | memset(funPtr, 0, sizeof(F)); 2348 | *funPtr = f; 2349 | luaL_openlib(m_state, m_moduleName, regtab, 1); 2350 | } 2351 | #endif 2352 | return (*this); 2353 | } 2354 | 2355 | template 2356 | inline LuaModule& _funImpl(const char * name, F f) 2357 | { 2358 | return _registerModuleFunction(name, NonMemberFunctionCaller(f), f); 2359 | } 2360 | 2361 | public: 2362 | template 2363 | inline LuaModule& fun(const char * name, FRET(*f)(FARGS...)) 2364 | { 2365 | return _funImpl(name, f); 2366 | } 2367 | 2368 | template 2369 | inline LuaModule& fun(const char * name, void(*f)(FARGS...)) 2370 | { 2371 | return _funImpl(name, f); 2372 | } 2373 | 2374 | #if !LUAAA_WITHOUT_CPP_STDLIB 2375 | template 2376 | inline LuaModule& fun(const char * name, const std::function& f) 2377 | { 2378 | return _funImpl>(name, f); 2379 | } 2380 | 2381 | template 2382 | inline LuaModule& fun(const char * name, const std::function& f) 2383 | { 2384 | return _funImpl>(name, f); 2385 | } 2386 | 2387 | template 2388 | inline LuaModule& fun(const char * name, F f) 2389 | { 2390 | return fun(name, to_function(f)); 2391 | } 2392 | #endif 2393 | 2394 | inline LuaModule& fun(const char * name, lua_CFunction f) 2395 | { 2396 | 2397 | #if USE_NEW_MODULE_REGISTRY 2398 | lua_getglobal(m_state, m_moduleName); 2399 | if (lua_isnil(m_state, -1)) 2400 | { 2401 | lua_pop(m_state, 1); 2402 | lua_newtable(m_state); 2403 | _initMetaTable(m_state, -1); 2404 | } 2405 | lua_pushcclosure(m_state, f, 0); 2406 | lua_pushstring(m_state, name); 2407 | lua_insert(m_state, -2); 2408 | lua_rawset(m_state, -3); 2409 | lua_setglobal(m_state, m_moduleName); 2410 | #else 2411 | luaL_Reg regtab[] = { { name, f },{ nullptr, nullptr } }; 2412 | luaL_openlib(m_state, m_moduleName, regtab, 0); 2413 | #endif 2414 | return (*this); 2415 | } 2416 | 2417 | template 2418 | inline LuaModule& def(const char * name, const V& val) 2419 | { 2420 | #if USE_NEW_MODULE_REGISTRY 2421 | lua_getglobal(m_state, m_moduleName); 2422 | if (lua_isnil(m_state, -1)) 2423 | { 2424 | lua_pop(m_state, 1); 2425 | lua_newtable(m_state); 2426 | _initMetaTable(m_state, -1); 2427 | } 2428 | LuaStack::put(m_state, val); 2429 | lua_pushstring(m_state, name); 2430 | lua_insert(m_state, -2); 2431 | lua_rawset(m_state, -3); 2432 | lua_setglobal(m_state, m_moduleName); 2433 | #else 2434 | luaL_Reg regtab = { nullptr, nullptr }; 2435 | luaL_openlib(m_state, m_moduleName, ®tab, 0); 2436 | LuaStack::put(m_state, val); 2437 | lua_pushstring(m_state, name); 2438 | lua_insert(m_state, -2); 2439 | lua_rawset(m_state, -3); 2440 | #endif 2441 | return (*this); 2442 | } 2443 | 2444 | template 2445 | inline LuaModule& def(const char* name, const luaaa::LuaClass&, const TCLASS* obj = nullptr, void(*deleter)(TCLASS*) = nullptr) 2446 | { 2447 | typename LuaClass::UserDataDetail userData{}; 2448 | if (obj) 2449 | { 2450 | userData.obj = const_cast(obj); 2451 | if (deleter) 2452 | { 2453 | struct HelperClass 2454 | { 2455 | static int f_dtor(typename LuaClass::UserDataDetail* uData) { 2456 | typedef decltype(deleter) DELETERFTYPE; 2457 | if (uData && uData->obj && uData->free_func) 2458 | { 2459 | ((DELETERFTYPE)(uData->free_func))(uData->obj); 2460 | uData->obj = nullptr; 2461 | } 2462 | return 0; 2463 | } 2464 | }; 2465 | 2466 | userData.dtor = HelperClass::f_dtor; 2467 | userData.free_func = (void*)(deleter); 2468 | } 2469 | else 2470 | { 2471 | userData.dtor = nullptr; 2472 | userData.free_func = nullptr; 2473 | } 2474 | } 2475 | else 2476 | { 2477 | struct HelperClass 2478 | { 2479 | static int f_dtor(typename LuaClass::UserDataDetail* uData) 2480 | { 2481 | if (uData && uData->obj) 2482 | { 2483 | delete uData->obj; 2484 | uData->obj = nullptr; 2485 | } 2486 | return 0; 2487 | } 2488 | }; 2489 | userData.obj = new TCLASS; 2490 | userData.dtor = HelperClass::f_dtor; 2491 | userData.free_func = nullptr; 2492 | } 2493 | 2494 | #if USE_NEW_MODULE_REGISTRY 2495 | lua_getglobal(m_state, m_moduleName); 2496 | if (lua_isnil(m_state, -1)) 2497 | { 2498 | lua_pop(m_state, 1); 2499 | lua_newtable(m_state); 2500 | _initMetaTable(m_state, -1); 2501 | } 2502 | auto uData = (typename LuaClass::UserDataDetail*)lua_newuserdata(m_state, sizeof(typename LuaClass::UserDataDetail)); 2503 | #if LUAAA_WITHOUT_CPP_STDLIB 2504 | luaL_argcheck(m_state, uData != nullptr, 1, "faild to alloc mem to store object"); 2505 | #else 2506 | luaL_argcheck(m_state, uData != nullptr, 1, (std::string("faild to alloc mem to store object `") + name + "`").c_str()); 2507 | #endif 2508 | if (uData) 2509 | { 2510 | uData->obj = userData.obj; 2511 | uData->dtor = userData.dtor; 2512 | uData->free_func = userData.free_func; 2513 | luaL_setmetatable(m_state, (LuaClass::klassName)); 2514 | lua_pushstring(m_state, name); 2515 | lua_insert(m_state, -2); 2516 | lua_rawset(m_state, -3); 2517 | lua_setglobal(m_state, m_moduleName); 2518 | } 2519 | else 2520 | { 2521 | lua_pop(m_state, 2); 2522 | } 2523 | #else 2524 | luaL_Reg regtab = { nullptr, nullptr }; 2525 | luaL_openlib(m_state, m_moduleName, ®tab, 0); 2526 | auto uData = (typename LuaClass::UserDataDetail*)lua_newuserdata(m_state, sizeof(typename LuaClass::UserDataDetail)); 2527 | if (uData) 2528 | { 2529 | uData->obj = userData.obj; 2530 | uData->dtor = userData.dtor; 2531 | uData->free_func = userData.free_func; 2532 | luaL_setmetatable(m_state, (LuaClass::klassName)); 2533 | lua_pushstring(m_state, name); 2534 | lua_insert(m_state, -2); 2535 | lua_rawset(m_state, -3); 2536 | } 2537 | else 2538 | { 2539 | lua_pop(m_state, 1); 2540 | } 2541 | #endif 2542 | return (*this); 2543 | } 2544 | 2545 | template 2546 | inline LuaModule& def(const char * name, const V val[], size_t length) 2547 | { 2548 | #if USE_NEW_MODULE_REGISTRY 2549 | lua_getglobal(m_state, m_moduleName); 2550 | if (lua_isnil(m_state, -1)) 2551 | { 2552 | lua_pop(m_state, 1); 2553 | lua_newtable(m_state); 2554 | _initMetaTable(m_state, -1); 2555 | } 2556 | lua_newtable(m_state); 2557 | for (size_t idx = 0; idx < length; ++idx) 2558 | { 2559 | LuaStack::put(m_state, val[idx]); 2560 | lua_rawseti(m_state, -2, idx + 1); 2561 | } 2562 | lua_pushstring(m_state, name); 2563 | lua_insert(m_state, -2); 2564 | lua_rawset(m_state, -3); 2565 | lua_setglobal(m_state, m_moduleName); 2566 | #else 2567 | luaL_Reg regtab = { nullptr, nullptr }; 2568 | luaL_openlib(m_state, m_moduleName, ®tab, 0); 2569 | lua_newtable(m_state); 2570 | for (size_t idx = 0; idx < length; ++idx) 2571 | { 2572 | LuaStack::put(m_state, val[idx]); 2573 | lua_rawseti(m_state, -2, idx + 1); 2574 | } 2575 | lua_pushstring(m_state, name); 2576 | lua_insert(m_state, -2); 2577 | lua_rawset(m_state, -3); 2578 | #endif 2579 | return (*this); 2580 | } 2581 | 2582 | // disable the cast from "const char [#]" to "char (*)[#]" 2583 | inline LuaModule& def(const char * name, const char * str) 2584 | { 2585 | #if USE_NEW_MODULE_REGISTRY 2586 | lua_getglobal(m_state, m_moduleName); 2587 | if (lua_isnil(m_state, -1)) 2588 | { 2589 | lua_pop(m_state, 1); 2590 | lua_newtable(m_state); 2591 | _initMetaTable(m_state, -1); 2592 | } 2593 | LuaStack::put(m_state, str); 2594 | lua_pushstring(m_state, name); 2595 | lua_insert(m_state, -2); 2596 | lua_rawset(m_state, -3); 2597 | lua_setglobal(m_state, m_moduleName); 2598 | #else 2599 | luaL_Reg regtab = { nullptr, nullptr }; 2600 | luaL_openlib(m_state, m_moduleName, ®tab, 0); 2601 | LuaStack::put(m_state, str); 2602 | lua_pushstring(m_state, name); 2603 | lua_insert(m_state, -2); 2604 | lua_rawset(m_state, -3); 2605 | #endif 2606 | return (*this); 2607 | } 2608 | 2609 | #if !LUAAA_WITHOUT_CPP_STDLIB 2610 | template 2611 | inline LuaModule& fun(const std::string& name, F f) 2612 | { 2613 | return fun(name.c_str(), f); 2614 | } 2615 | 2616 | template 2617 | inline LuaModule& def(const std::string& name, const V& val) 2618 | { 2619 | return def(name.c_str(), val); 2620 | } 2621 | #endif 2622 | 2623 | private: 2624 | template 2625 | inline LuaModule& _getterImpl(const char* name, lua_CFunction invoker, F f) 2626 | { 2627 | #if LUAAA_FEATURE_PROPERTY 2628 | char internal_name[256]; 2629 | snprintf(internal_name, sizeof(internal_name), "<%s", name); 2630 | return _registerModuleFunction(internal_name, invoker, f); 2631 | #else 2632 | return *this; 2633 | #endif 2634 | } 2635 | 2636 | template 2637 | inline LuaModule& _setterImpl(const char* name, lua_CFunction invoker, F f) 2638 | { 2639 | #if LUAAA_FEATURE_PROPERTY 2640 | char internal_name[256]; 2641 | snprintf(internal_name, sizeof(internal_name), ">%s", name); 2642 | return _registerModuleFunction(internal_name, invoker, f); 2643 | #else 2644 | return *this; 2645 | #endif 2646 | } 2647 | 2648 | public: 2649 | template 2650 | inline LuaModule& get(const char* name, P(*f)()) 2651 | { 2652 | static_assert(!std::is_void

::value, "Error: getter function must return a value."); 2653 | struct HelperClass { 2654 | static inline int Invoke(lua_State* state) { 2655 | typedef decltype(f) FTYPE; 2656 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2657 | if (calleePtr) 2658 | { 2659 | LuaStackReturn

(state, (*(FTYPE*)(calleePtr))()); 2660 | } 2661 | else 2662 | { 2663 | lua_pushnil(state); 2664 | } 2665 | return 1; 2666 | } 2667 | }; 2668 | return _getterImpl(name, HelperClass::Invoke, f); 2669 | } 2670 | 2671 | template 2672 | inline LuaModule& set(const char* name, TRET(*f)(P)) 2673 | { 2674 | struct HelperClass { 2675 | static inline int Invoke(lua_State* state) { 2676 | typedef decltype(f) FTYPE; 2677 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2678 | if (calleePtr) 2679 | { 2680 | (*(FTYPE*)(calleePtr))(LuaStack

::get(state, 3)); 2681 | } 2682 | return 0; 2683 | } 2684 | }; 2685 | return _setterImpl(name, HelperClass::Invoke, f); 2686 | } 2687 | 2688 | public: 2689 | #if !LUAAA_WITHOUT_CPP_STDLIB 2690 | // access prop from lambdas 2691 | template 2692 | inline LuaModule& get(const char* name, std::function f) 2693 | { 2694 | static_assert(!std::is_void

::value, "Error: getter function must return a value."); 2695 | struct HelperClass { 2696 | static inline int Invoke(lua_State* state) { 2697 | typedef decltype(f) FTYPE; 2698 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2699 | if (calleePtr) 2700 | { 2701 | LuaStackReturn

(state, (*(FTYPE*)(calleePtr))()); 2702 | } 2703 | else 2704 | { 2705 | lua_pushnil(state); 2706 | } 2707 | return 1; 2708 | } 2709 | }; 2710 | return _getterImpl(name, HelperClass::Invoke, f); 2711 | } 2712 | 2713 | // template 2714 | // inline LuaModule& get(const char* name, std::function f) 2715 | // { 2716 | // //static_assert(false, "Error: invalid signature of getter function"); 2717 | // assert(!"Error: invalid signature of getter function"); 2718 | // return (*this); 2719 | // } 2720 | 2721 | template 2722 | inline LuaModule& get(const char* name, F f) 2723 | { 2724 | return get(name, to_module_getter_function(f)); 2725 | } 2726 | 2727 | template 2728 | inline LuaModule& set(const char* name, std::function f) 2729 | { 2730 | struct HelperClass { 2731 | static inline int Invoke(lua_State* state) { 2732 | typedef decltype(f) FTYPE; 2733 | void* calleePtr = lua_touserdata(state, lua_upvalueindex(1)); 2734 | if (calleePtr) 2735 | { 2736 | (*(FTYPE*)(calleePtr))(LuaStack

::get(state, 3)); 2737 | } 2738 | return 0; 2739 | } 2740 | }; 2741 | return _setterImpl(name, HelperClass::Invoke, f); 2742 | } 2743 | 2744 | // template 2745 | // inline LuaModule& set(const char* name, std::function f) 2746 | // { 2747 | // //static_assert(std::false_type::value, "Error: invalid signature of setter function"); 2748 | // //assert(!"Error: invalid signature of setter function"); 2749 | // return (*this); 2750 | // } 2751 | 2752 | template 2753 | inline LuaModule& set(const char* name, F f) 2754 | { 2755 | return set(name, to_module_setter_function(f)); 2756 | } 2757 | 2758 | template 2759 | inline LuaModule& get(const std::string& name, F f) 2760 | { 2761 | return get(name.c_str(), f); 2762 | } 2763 | 2764 | template 2765 | inline LuaModule& set(const std::string& name, F f) 2766 | { 2767 | return set(name.c_str(), f); 2768 | } 2769 | #endif 2770 | 2771 | private: 2772 | lua_State * m_state; 2773 | char * m_moduleName; 2774 | }; 2775 | 2776 | } 2777 | 2778 | 2779 | 2780 | #if !LUAAA_WITHOUT_CPP_STDLIB 2781 | 2782 | #include 2783 | #include 2784 | #include 2785 | #include 2786 | #include 2787 | #include 2788 | #include 2789 | #include 2790 | #include 2791 | #include 2792 | 2793 | namespace LUAAA_NS 2794 | { 2795 | // array 2796 | template 2797 | struct LuaStack> 2798 | { 2799 | typedef std::array Container; 2800 | inline static Container get(lua_State * L, int idx) 2801 | { 2802 | Container result; 2803 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 2804 | if (lua_istable(L, idx)) 2805 | { 2806 | int index = 0; 2807 | lua_pushnil(L); 2808 | while (0 != lua_next(L, idx) && index < N) 2809 | { 2810 | result[index++] = LuaStack::get(L, lua_gettop(L)); 2811 | lua_pop(L, 1); 2812 | } 2813 | } 2814 | return result; 2815 | } 2816 | inline static void put(lua_State * L, const Container& s) 2817 | { 2818 | lua_newtable(L); 2819 | int index = 1; 2820 | for (auto it = s.begin(); it != s.end(); ++it) 2821 | { 2822 | LuaStack::put(L, *it); 2823 | lua_rawseti(L, -2, index++); 2824 | } 2825 | } 2826 | }; 2827 | 2828 | // vector 2829 | template 2830 | struct LuaStack> 2831 | { 2832 | typedef std::vector Container; 2833 | inline static Container get(lua_State * L, int idx) 2834 | { 2835 | Container result; 2836 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 2837 | if (lua_istable(L, idx)) 2838 | { 2839 | lua_pushnil(L); 2840 | while (0 != lua_next(L, idx)) 2841 | { 2842 | result.push_back(LuaStack::get(L, lua_gettop(L))); 2843 | lua_pop(L, 1); 2844 | } 2845 | } 2846 | return result; 2847 | } 2848 | inline static void put(lua_State * L, const Container& s) 2849 | { 2850 | lua_newtable(L); 2851 | int index = 1; 2852 | for (auto it = s.begin(); it != s.end(); ++it) 2853 | { 2854 | LuaStack::put(L, *it); 2855 | lua_rawseti(L, -2, index++); 2856 | } 2857 | } 2858 | }; 2859 | 2860 | // deque 2861 | template 2862 | struct LuaStack> 2863 | { 2864 | typedef std::deque Container; 2865 | inline static Container get(lua_State * L, int idx) 2866 | { 2867 | Container result; 2868 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 2869 | if (lua_istable(L, idx)) 2870 | { 2871 | lua_pushnil(L); 2872 | while (0 != lua_next(L, idx)) 2873 | { 2874 | result.push_back(LuaStack::get(L, lua_gettop(L))); 2875 | lua_pop(L, 1); 2876 | } 2877 | } 2878 | return result; 2879 | } 2880 | inline static void put(lua_State * L, const Container& s) 2881 | { 2882 | lua_newtable(L); 2883 | int index = 1; 2884 | for (auto it = s.begin(); it != s.end(); ++it) 2885 | { 2886 | LuaStack::put(L, *it); 2887 | lua_rawseti(L, -2, index++); 2888 | } 2889 | } 2890 | }; 2891 | 2892 | // list 2893 | template 2894 | struct LuaStack> 2895 | { 2896 | typedef std::list Container; 2897 | inline static Container get(lua_State * L, int idx) 2898 | { 2899 | Container result; 2900 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 2901 | if (lua_istable(L, idx)) 2902 | { 2903 | lua_pushnil(L); 2904 | while (0 != lua_next(L, idx)) 2905 | { 2906 | result.push_back(LuaStack::get(L, lua_gettop(L))); 2907 | lua_pop(L, 1); 2908 | } 2909 | } 2910 | return result; 2911 | } 2912 | inline static void put(lua_State * L, const Container& s) 2913 | { 2914 | lua_newtable(L); 2915 | int index = 1; 2916 | for (auto it = s.begin(); it != s.end(); ++it) 2917 | { 2918 | LuaStack::put(L, *it); 2919 | lua_rawseti(L, -2, index++); 2920 | } 2921 | } 2922 | }; 2923 | 2924 | // forward_list 2925 | template 2926 | struct LuaStack> 2927 | { 2928 | typedef std::forward_list Container; 2929 | inline static Container get(lua_State * L, int idx) 2930 | { 2931 | Container result; 2932 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 2933 | if (lua_istable(L, idx)) 2934 | { 2935 | lua_pushnil(L); 2936 | while (0 != lua_next(L, idx)) 2937 | { 2938 | result.push_back(LuaStack::get(L, lua_gettop(L))); 2939 | lua_pop(L, 1); 2940 | } 2941 | } 2942 | return result; 2943 | } 2944 | inline static void put(lua_State * L, const Container& s) 2945 | { 2946 | lua_newtable(L); 2947 | int index = 1; 2948 | for (auto it = s.begin(); it != s.end(); ++it) 2949 | { 2950 | LuaStack::put(L, *it); 2951 | lua_rawseti(L, -2, index++); 2952 | } 2953 | } 2954 | }; 2955 | 2956 | // set 2957 | template 2958 | struct LuaStack> 2959 | { 2960 | typedef std::set Container; 2961 | inline static Container get(lua_State * L, int idx) 2962 | { 2963 | Container result; 2964 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 2965 | if (lua_istable(L, idx)) 2966 | { 2967 | lua_pushnil(L); 2968 | while (0 != lua_next(L, idx)) 2969 | { 2970 | result.insert(LuaStack::get(L, lua_gettop(L))); 2971 | lua_pop(L, 1); 2972 | } 2973 | } 2974 | return result; 2975 | } 2976 | inline static void put(lua_State * L, const Container& s) 2977 | { 2978 | lua_newtable(L); 2979 | int index = 1; 2980 | for (auto it = s.begin(); it != s.end(); ++it) 2981 | { 2982 | LuaStack::put(L, *it); 2983 | lua_rawseti(L, -2, index++); 2984 | } 2985 | } 2986 | }; 2987 | 2988 | // multiset 2989 | template 2990 | struct LuaStack> 2991 | { 2992 | typedef std::multiset Container; 2993 | inline static Container get(lua_State * L, int idx) 2994 | { 2995 | Container result; 2996 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 2997 | if (lua_istable(L, idx)) 2998 | { 2999 | lua_pushnil(L); 3000 | while (0 != lua_next(L, idx)) 3001 | { 3002 | result.insert(LuaStack::get(L, lua_gettop(L))); 3003 | lua_pop(L, 1); 3004 | } 3005 | } 3006 | return result; 3007 | } 3008 | inline static void put(lua_State * L, const Container& s) 3009 | { 3010 | lua_newtable(L); 3011 | int index = 1; 3012 | for (auto it = s.begin(); it != s.end(); ++it) 3013 | { 3014 | LuaStack::put(L, *it); 3015 | lua_rawseti(L, -2, index++); 3016 | } 3017 | } 3018 | }; 3019 | 3020 | // unordered_set 3021 | template 3022 | struct LuaStack> 3023 | { 3024 | typedef std::unordered_set Container; 3025 | inline static Container get(lua_State * L, int idx) 3026 | { 3027 | Container result; 3028 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3029 | if (lua_istable(L, idx)) 3030 | { 3031 | lua_pushnil(L); 3032 | while (0 != lua_next(L, idx)) 3033 | { 3034 | result.insert(LuaStack::get(L, lua_gettop(L))); 3035 | lua_pop(L, 1); 3036 | } 3037 | } 3038 | return result; 3039 | } 3040 | 3041 | inline static void put(lua_State * L, const Container& s) 3042 | { 3043 | lua_newtable(L); 3044 | int index = 1; 3045 | for (auto it = s.begin(); it != s.end(); ++it) 3046 | { 3047 | LuaStack::put(L, *it); 3048 | lua_rawseti(L, -2, index++); 3049 | } 3050 | } 3051 | }; 3052 | 3053 | // unordered_multiset 3054 | template 3055 | struct LuaStack> 3056 | { 3057 | typedef std::unordered_multiset Container; 3058 | inline static Container get(lua_State * L, int idx) 3059 | { 3060 | Container result; 3061 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3062 | if (lua_istable(L, idx)) 3063 | { 3064 | lua_pushnil(L); 3065 | while (0 != lua_next(L, idx)) 3066 | { 3067 | result.insert(LuaStack::get(L, lua_gettop(L))); 3068 | lua_pop(L, 1); 3069 | } 3070 | } 3071 | return result; 3072 | } 3073 | 3074 | inline static void put(lua_State * L, const Container& s) 3075 | { 3076 | lua_newtable(L); 3077 | int index = 1; 3078 | for (auto it = s.begin(); it != s.end(); ++it) 3079 | { 3080 | LuaStack::put(L, *it); 3081 | lua_rawseti(L, -2, index++); 3082 | } 3083 | } 3084 | }; 3085 | 3086 | // map 3087 | template 3088 | struct LuaStack> 3089 | { 3090 | typedef std::map Container; 3091 | inline static Container get(lua_State * L, int idx) 3092 | { 3093 | Container result; 3094 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3095 | if (lua_istable(L, idx)) 3096 | { 3097 | lua_pushnil(L); 3098 | while (0 != lua_next(L, idx)) 3099 | { 3100 | const int top = lua_gettop(L); 3101 | result[LuaStack::get(L, top - 1)] = LuaStack::get(L, top); 3102 | lua_pop(L, 1); 3103 | } 3104 | } 3105 | return result; 3106 | } 3107 | inline static void put(lua_State * L, const Container& s) 3108 | { 3109 | lua_newtable(L); 3110 | for (auto it = s.begin(); it != s.end(); ++it) 3111 | { 3112 | LuaStack::put(L, it->first); 3113 | LuaStack::put(L, it->second); 3114 | lua_rawset(L, -3); 3115 | } 3116 | } 3117 | }; 3118 | 3119 | // multimap 3120 | template 3121 | struct LuaStack> 3122 | { 3123 | typedef std::multimap Container; 3124 | inline static Container get(lua_State * L, int idx) 3125 | { 3126 | Container result; 3127 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3128 | if (lua_istable(L, idx)) 3129 | { 3130 | lua_pushnil(L); 3131 | while (0 != lua_next(L, idx)) 3132 | { 3133 | const int top = lua_gettop(L); 3134 | result[LuaStack::get(L, top - 1)] = LuaStack::get(L, top); 3135 | lua_pop(L, 1); 3136 | } 3137 | } 3138 | return result; 3139 | } 3140 | inline static void put(lua_State * L, const Container& s) 3141 | { 3142 | lua_newtable(L); 3143 | for (auto it = s.begin(); it != s.end(); ++it) 3144 | { 3145 | LuaStack::put(L, it->first); 3146 | LuaStack::put(L, it->second); 3147 | lua_rawset(L, -3); 3148 | } 3149 | } 3150 | }; 3151 | 3152 | // unordered_map 3153 | template 3154 | struct LuaStack> 3155 | { 3156 | typedef std::unordered_map Container; 3157 | inline static Container get(lua_State * L, int idx) 3158 | { 3159 | Container result; 3160 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3161 | if (lua_istable(L, idx)) 3162 | { 3163 | lua_pushnil(L); 3164 | while (0 != lua_next(L, idx)) 3165 | { 3166 | const int top = lua_gettop(L); 3167 | result[LuaStack::get(L, top - 1)] = LuaStack::get(L, top); 3168 | lua_pop(L, 1); 3169 | } 3170 | } 3171 | return result; 3172 | } 3173 | inline static void put(lua_State * L, const Container& s) 3174 | { 3175 | lua_newtable(L); 3176 | for (auto it = s.begin(); it != s.end(); ++it) 3177 | { 3178 | LuaStack::put(L, it->first); 3179 | LuaStack::put(L, it->second); 3180 | lua_rawset(L, -3); 3181 | } 3182 | } 3183 | }; 3184 | 3185 | // unordered_multimap 3186 | template 3187 | struct LuaStack> 3188 | { 3189 | typedef std::unordered_multimap Container; 3190 | inline static Container get(lua_State * L, int idx) 3191 | { 3192 | Container result; 3193 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3194 | if (lua_istable(L, idx)) 3195 | { 3196 | lua_pushnil(L); 3197 | while (0 != lua_next(L, idx)) 3198 | { 3199 | const int top = lua_gettop(L); 3200 | result[LuaStack::get(L, top - 1)] = LuaStack::get(L, top); 3201 | lua_pop(L, 1); 3202 | } 3203 | } 3204 | return result; 3205 | } 3206 | inline static void put(lua_State * L, const Container& s) 3207 | { 3208 | lua_newtable(L); 3209 | for (auto it = s.begin(); it != s.end(); ++it) 3210 | { 3211 | LuaStack::put(L, it->first); 3212 | LuaStack::put(L, it->second); 3213 | lua_rawset(L, -3); 3214 | } 3215 | } 3216 | }; 3217 | 3218 | // std::pair 3219 | template 3220 | struct LuaStack> 3221 | { 3222 | typedef std::pair Container; 3223 | inline static Container get(lua_State * L, int idx) 3224 | { 3225 | Container result; 3226 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3227 | if (lua_istable(L, idx)) 3228 | { 3229 | result.first = LuaStack::get(L, idx + 1); 3230 | result.second = LuaStack::get(L, idx + 2); 3231 | } 3232 | return result; 3233 | } 3234 | 3235 | inline static void put(lua_State * L, const Container& s) 3236 | { 3237 | lua_newtable(L); 3238 | LuaStack::put(L, s.first); 3239 | lua_rawseti(L, -2, 1); 3240 | LuaStack::put(L, s.second); 3241 | lua_rawseti(L, -2, 2); 3242 | } 3243 | }; 3244 | 3245 | // std::tuple 3246 | #if __cplusplus >= 201402 || _MSVC_LANG >= 201402 3247 | template struct is_tuple : std::false_type {}; 3248 | template struct is_tuple> : std::true_type {}; 3249 | 3250 | template::value>::type> 3251 | inline void load_tuple_from_lua_table(lua_State* L, int idx, Tuple& tuple, std::index_sequence) 3252 | { 3253 | luaL_argcheck(L, lua_istable(L, idx), 1, "required table not found on stack."); 3254 | if (lua_istable(L, idx)) 3255 | { 3256 | lua_pushnil(L); 3257 | (void)std::initializer_list{( 3258 | lua_next(L, idx) && (std::get(tuple) = LuaStack(tuple))>::get(L, lua_gettop(L)), 1) && (lua_pop(L, 1), 1), 3259 | 0)...}; 3260 | } 3261 | } 3262 | 3263 | template::value>::type> 3264 | inline void save_tuple_to_lua_table(lua_State* L, const Tuple& tuple, std::index_sequence) 3265 | { 3266 | lua_newtable(L); 3267 | (void)std::initializer_list{( 3268 | LuaStack(tuple))>::put(L, std::get(tuple)), 3269 | lua_rawseti(L, -2, Index + 1), 3270 | 0)...}; 3271 | } 3272 | 3273 | template 3274 | struct LuaStack> 3275 | { 3276 | typedef std::tuple Container; 3277 | inline static Container get(lua_State* L, int idx) 3278 | { 3279 | Container result; 3280 | load_tuple_from_lua_table(L, idx, result, std::make_index_sequence::value>{}); 3281 | return result; 3282 | } 3283 | 3284 | inline static void put(lua_State* L, const Container& s) 3285 | { 3286 | save_tuple_to_lua_table(L, s, std::make_index_sequence::value>{}); 3287 | } 3288 | }; 3289 | #elif __cplusplus 3290 | template 3291 | struct TupleAccessor 3292 | { 3293 | static void get(lua_State* L, int idx, T& tuple) 3294 | { 3295 | TupleAccessor::get(L, idx, tuple); 3296 | if (lua_next(L, idx)) 3297 | { 3298 | const int top = lua_gettop(L); 3299 | std::get(tuple) = LuaStack::type>::get(L, top); 3300 | lua_pop(L, 1); 3301 | } 3302 | } 3303 | 3304 | static void put(lua_State* L, const T& tuple) { 3305 | TupleAccessor::put(L, tuple); 3306 | LuaStack::type>::put(L, std::get(tuple)); 3307 | lua_rawseti(L, -2, N); 3308 | } 3309 | }; 3310 | 3311 | template 3312 | struct TupleAccessor 3313 | { 3314 | static void get(lua_State* L, int idx, T& tuple) 3315 | { 3316 | if (lua_next(L, idx)) 3317 | { 3318 | const int top = lua_gettop(L); 3319 | std::get<0>(tuple) = LuaStack(tuple))>::get(L, top); 3320 | lua_pop(L, 1); 3321 | } 3322 | } 3323 | 3324 | static void put(lua_State* L, const T& tuple) { 3325 | LuaStack::type>::put(L, std::get<0>(tuple)); 3326 | lua_rawseti(L, -2, 1); 3327 | } 3328 | }; 3329 | 3330 | template 3331 | struct TupleAccessor 3332 | { 3333 | static void get(lua_State*, int, T&) {} 3334 | static void put(lua_State*, const T&) {} 3335 | }; 3336 | 3337 | template 3338 | struct LuaStack> 3339 | { 3340 | typedef std::tuple Container; 3341 | inline static Container get(lua_State* L, int idx) 3342 | { 3343 | Container result; 3344 | lua_pushnil(L); 3345 | TupleAccessor::value>::get(L, idx, result); 3346 | return result; 3347 | } 3348 | 3349 | inline static void put(lua_State* L, const Container& s) 3350 | { 3351 | lua_newtable(L); 3352 | TupleAccessor::value>::put(L, s); 3353 | } 3354 | }; 3355 | #endif 3356 | 3357 | } 3358 | 3359 | #endif //#if !LUAAA_WITHOUT_CPP_STDLIB 3360 | 3361 | #endif 3362 | 3363 | --------------------------------------------------------------------------------