1 #ifndef _library__lua_class__hpp__included__
2 #define _library__lua_class__hpp__included__
5 #include "lua-base.hpp"
28 * Add a class to group.
30 void do_register(const std::string
& name
, class_base
& fun
);
32 * Drop a class from group.
34 void do_unregister(const std::string
& name
, class_base
& fun
);
36 * Request callbacks on all currently registered functions.
38 void request_callback(std::function
<void(std::string
, class_base
*)> cb
);
42 * Callbacks for all registered functions are immediately called.
44 int add_callback(std::function
<void(std::string
, class_base
*)> cb
,
45 std::function
<void(class_group
*)> dcb
);
49 void drop_callback(int handle
);
56 bool (*is
)(state
& _state
, int index
);
57 const std::string
& (*name
)();
58 std::string (*print
)(state
& _state
, int index
);
61 std::list
<class_ops
>& userdata_recogn_fns();
62 std::string
try_recognize_userdata(state
& _state
, int index
);
63 std::string
try_print_userdata(state
& _state
, int index
);
64 std::unordered_map
<std::type_index
, void*>& class_types();
67 * Helper class containing binding data for Lua class call.
69 template<class T
> struct class_binding
72 * The pointer to call.
74 int (T::*fn
)(state
& lstate
, lua::parameters
& P
);
76 * The state to call it in.
80 * The name of the method to pass.
86 * Helper class containing binding data for Lua static class call.
91 * The pointer to call.
93 int (*fn
)(state
& lstate
, parameters
& P
);
95 * The state to call it in.
99 * The name of the method to pass.
104 template<class T
> class _class
;
107 * Function to obtain class object for given Lua class.
109 template<class T
> _class
<T
>& objclass()
111 auto& type
= typeid(T
);
112 if(!class_types().count(type
))
113 throw std::runtime_error("Internal error: Lua class not found!");
114 return *reinterpret_cast<_class
<T
>*>(class_types()[type
]);
120 template<class T
> struct class_method
129 int (T::*fn
)(state
& LS
, lua::parameters
& P
);
133 * A static class method.
144 int (*fn
)(state
& LS
, parameters
& P
);
148 * Virtual base of Lua classes
154 * Create a new Lua class.
156 * Parameter _group: The group the class will be in.
157 * Parameter _name: The name of the class.
159 class_base(class_group
& _group
, const std::string
& _name
);
163 virtual ~class_base() throw();
165 * Lookup by name in given Lua state.
167 * Parameter _L: The Lua state to look in.
168 * Parameter _name: The name of the class.
169 * Returns: The class instance, or NULL if no match.
171 static class_base
* lookup(state
& L
, const std::string
& _name
);
173 * Push class table to stack.
175 static bool lookup_and_push(state
& L
, const std::string
& _name
);
177 * Get set of all classes.
179 static std::set
<std::string
> all_classes(state
& L
);
181 * Register in given Lua state.
183 virtual void register_state(state
& L
) = 0;
185 * Lookup static methods in class.
187 virtual std::list
<static_method
> static_methods() = 0;
189 * Lookup class methods in class.
191 virtual std::set
<std::string
> class_methods() = 0;
195 const std::string
& get_name() { return name
; }
197 void delayed_register();
198 void register_static(state
& L
);
205 static const size_t overcommit_std_align
= 32;
208 * Align a overcommit pointer.
210 template<typename T
, typename U
> U
* align_overcommit(T
* th
)
212 size_t ptr
= reinterpret_cast<size_t>(th
) + sizeof(T
);
213 return reinterpret_cast<U
*>(ptr
+ (overcommit_std_align
- ptr
% overcommit_std_align
) % overcommit_std_align
);
217 * The type of Lua classes.
219 template<class T
> class _class
: public class_base
221 template<typename
... U
> T
* _create(state
& _state
, U
... args
)
223 size_t overcommit
= T::overcommit(args
...);
226 _state
.run_interruptable([st
, overcommit
, &obj
]() {
227 obj
= st
->newuserdata(sizeof(T
) + overcommit
);
229 load_metatable(_state
);
230 _state
.setmetatable(-2);
231 T
* _obj
= reinterpret_cast<T
*>(obj
);
233 new(_obj
) T(_state
, args
...);
235 //CTOR FAILED. Get rid of the dtor (since it would error) and then dump the object.
237 _state
.setmetatable(-2);
244 static int class_bind_trampoline(state
& L
)
246 class_binding
<T
>* b
= (class_binding
<T
>*)L
.touserdata(L
.trampoline_upval(1));
247 T
* p
= _class
<T
>::get(L
, 1, b
->fname
);
248 lua::parameters
P(L
, b
->fname
);
249 return (p
->*(b
->fn
))(L
, P
);
252 T
* _get(state
& _state
, int arg
, const std::string
& fname
, bool optional
= false)
254 if(_state
.type(arg
) == LUA_TNONE
|| _state
.type(arg
) == LUA_TNIL
) {
260 load_metatable(_state
);
261 if(!_state
.getmetatable(arg
))
263 if(!_state
.rawequal(-1, -2))
266 return reinterpret_cast<T
*>(_state
.touserdata(arg
));
268 (stringfmt() << "argument #" << arg
<< " to " << fname
<< " must be " << name
).throwex();
269 return NULL
; //Never reached.
272 bool _is(state
& _state
, int arg
)
274 if(_state
.type(arg
) != LUA_TUSERDATA
)
276 load_metatable(_state
);
277 if(!_state
.getmetatable(arg
)) {
281 bool ret
= _state
.rawequal(-1, -2);
286 objpin
<T
> _pin(state
& _state
, int arg
, const std::string
& fname
)
288 T
* obj
= get(_state
, arg
, fname
);
289 _state
.pushvalue(arg
);
290 objpin
<T
> t(_state
, obj
);
295 void bind(state
& _state
, const char* keyname
, int (T::*fn
)(state
& LS
, lua::parameters
& P
))
297 load_metatable(_state
);
298 _state
.pushstring(keyname
);
299 std::string fname
= name
+ std::string("::") + keyname
;
300 void* ptr
= _state
.newuserdata(sizeof(class_binding
<T
>) + fname
.length() + 1);
301 class_binding
<T
>* bdata
= reinterpret_cast<class_binding
<T
>*>(ptr
);
303 bdata
->_state
= &_state
.get_master();
304 std::copy(fname
.begin(), fname
.end(), bdata
->fname
);
305 bdata
->fname
[fname
.length()] = 0;
306 _state
.push_trampoline(class_bind_trampoline
, 1);
311 void register_state(state
& L
)
313 static char once_key
;
315 if(L
.do_once(&once_key
))
316 for(auto i
: cmethods
)
317 bind(L
, i
.name
, i
.fn
);
321 * Create a new Lua class.
323 * Parameter _group: The group the class will be in.
324 * Parameter _name: The name of the class.
325 * Parameter _smethods: Static methods of the class.
326 * Parameter _cmethods: Class methods of the class.
327 * Parameter _print: The print method.
329 _class(class_group
& _group
, const std::string
& _name
, std::initializer_list
<static_method
> _smethods
,
330 std::initializer_list
<class_method
<T
>> _cmethods
= {}, std::string (T::*_print
)() = NULL
)
331 : class_base(_group
, _name
), smethods(_smethods
), cmethods(_cmethods
)
336 m
.is
= _class
<T
>::is
;
337 m
.name
= _class
<T
>::get_name
;
338 m
.print
= _class
<T
>::print
;
339 userdata_recogn_fns().push_back(m
);
340 auto& type
= typeid(T
);
341 class_types()[type
] = this;
349 auto& type
= typeid(T
);
350 class_types().erase(type
);
351 auto& fns
= userdata_recogn_fns();
352 for(auto i
= fns
.begin(); i
!= fns
.end(); i
++) {
353 if(i
->is
== _class
<T
>::is
) {
360 * Create a new instance of object.
362 * Parameter _state: The Lua state to create the object in.
363 * Parameter args: The arguments to pass to class constructor.
365 template<typename
... U
> static T
* create(state
& _state
, U
... args
)
367 return objclass
<T
>()._create(_state
, args
...);
371 * Get a pointer to the object.
373 * Parameter _state: The Lua state.
374 * Parameter arg: Argument index.
375 * Parameter fname: The name of function for error messages.
376 * Parameter optional: If true and argument is NIL or none, return NULL.
377 * Throws std::runtime_error: Wrong type.
379 static T
* get(state
& _state
, int arg
, const std::string
& fname
, bool optional
= false)
381 return objclass
<T
>()._get(_state
, arg
, fname
, optional
);
385 * Identify if object is of this type.
387 * Parameter _state: The Lua state.
388 * Parameter arg: Argument index.
389 * Returns: True if object is of specified type, false if not.
391 static bool is(state
& _state
, int arg
) throw()
394 return objclass
<T
>()._is(_state
, arg
);
402 static const std::string
& get_name()
405 return objclass
<T
>().name
;
407 static std::string foo
= "???";
412 * Format instance of this class as string.
414 static std::string
print(state
& _state
, int index
)
416 T
* obj
= get(_state
, index
, "__internal_print");
418 auto pmeth
= objclass
<T
>().printmeth
;
420 return (obj
->*pmeth
)();
428 * Get a pin of object against Lua GC.
430 * Parameter _state: The Lua state.
431 * Parameter arg: Argument index.
432 * Parameter fname: Name of function for error message purposes.
433 * Throws std::runtime_error: Wrong type.
435 static objpin
<T
> pin(state
& _state
, int arg
, const std::string
& fname
)
437 return objclass
<T
>()._pin(_state
, arg
, fname
);
440 * Lookup static methods.
442 std::list
<static_method
> static_methods()
447 * Lookup class methods.
449 std::set
<std::string
> class_methods()
451 std::set
<std::string
> r
;
452 for(auto& i
: cmethods
)
457 static int dogc(state
& L
)
459 T
* obj
= reinterpret_cast<T
*>(L
.touserdata(1));
464 static int newindex(state
& L
)
466 throw std::runtime_error("Writing metatables of classes is not allowed");
469 static int index(state
& L
)
474 if(L
.type(-1) == LUA_TNIL
) {
475 std::string err
= std::string("Class '") + L
.tostring(L
.trampoline_upval(1)) +
476 "' does not have class method '" + L
.tostring(2) + "'";
477 throw std::runtime_error(err
);
482 void load_metatable(state
& _state
)
485 _state
.pushlightuserdata(this);
486 _state
.rawget(LUA_REGISTRYINDEX
);
487 if(_state
.type(-1) == LUA_TNIL
) {
489 _state
.pushlightuserdata(this);
491 _state
.pushvalue(-1);
492 _state
.setmetatable(-2);
493 _state
.pushstring("__gc");
494 _state
.push_trampoline(&_class
<T
>::dogc
, 0);
496 _state
.pushstring("__newindex");
497 _state
.push_trampoline(&_class
<T
>::newindex
, 0);
499 _state
.pushstring("__index");
500 _state
.pushlstring(name
);
501 _state
.push_trampoline(&_class
<T
>::index
, 1);
503 _state
.rawset(LUA_REGISTRYINDEX
);
508 std::list
<static_method
> smethods
;
509 std::list
<class_method
<T
>> cmethods
;
510 std::string (T::*printmeth
)();
511 _class(const _class
<T
>&);
512 _class
& operator=(const _class
<T
>&);