1 #ifndef _library__lua_class__hpp__included__
2 #define _library__lua_class__hpp__included__
4 #include "lua-base.hpp"
27 * Add a class to group.
29 void do_register(const std::string
& name
, class_base
& fun
);
31 * Drop a class from group.
33 void do_unregister(const std::string
& name
, class_base
& fun
);
35 * Request callbacks on all currently registered functions.
37 void request_callback(std::function
<void(std::string
, class_base
*)> cb
);
41 * Callbacks for all registered functions are immediately called.
43 int add_callback(std::function
<void(std::string
, class_base
*)> cb
,
44 std::function
<void(class_group
*)> dcb
);
48 void drop_callback(int handle
);
55 bool (*is
)(state
& _state
, int index
);
56 const std::string
& (*name
)();
57 std::string (*print
)(state
& _state
, int index
);
60 std::list
<class_ops
>& userdata_recogn_fns();
61 std::string
try_recognize_userdata(state
& _state
, int index
);
62 std::string
try_print_userdata(state
& _state
, int index
);
63 std::unordered_map
<std::type_index
, void*>& class_types();
66 * Helper class containing binding data for Lua class call.
68 template<class T
> struct class_binding
71 * The pointer to call.
73 int (T::*fn
)(state
& lstate
, lua::parameters
& P
);
75 * The state to call it in.
79 * The name of the method to pass.
85 * Helper class containing binding data for Lua static class call.
90 * The pointer to call.
92 int (*fn
)(state
& lstate
, parameters
& P
);
94 * The state to call it in.
98 * The name of the method to pass.
103 template<class T
> class _class
;
106 * Function to obtain class object for given Lua class.
108 template<class T
> _class
<T
>& objclass()
110 auto& type
= typeid(T
);
111 if(!class_types().count(type
))
112 throw std::runtime_error("Internal error: Lua class not found!");
113 return *reinterpret_cast<_class
<T
>*>(class_types()[type
]);
119 template<class T
> struct class_method
128 int (T::*fn
)(state
& LS
, lua::parameters
& P
);
132 * A static class method.
143 int (*fn
)(state
& LS
, parameters
& P
);
147 * Virtual base of Lua classes
153 * Create a new Lua class.
155 * Parameter _group: The group the class will be in.
156 * Parameter _name: The name of the class.
158 class_base(class_group
& _group
, const std::string
& _name
);
162 virtual ~class_base() throw();
164 * Lookup by name in given Lua state.
166 * Parameter _L: The Lua state to look in.
167 * Parameter _name: The name of the class.
168 * Returns: The class instance, or NULL if no match.
170 static class_base
* lookup(state
& L
, const std::string
& _name
);
172 * Push class table to stack.
174 static bool lookup_and_push(state
& L
, const std::string
& _name
);
176 * Get set of all classes.
178 static std::set
<std::string
> all_classes(state
& L
);
180 * Register in given Lua state.
182 virtual void register_state(state
& L
) = 0;
184 * Lookup static methods in class.
186 virtual std::list
<static_method
> static_methods() = 0;
188 * Lookup class methods in class.
190 virtual std::set
<std::string
> class_methods() = 0;
194 const std::string
& get_name() { return name
; }
196 void delayed_register();
197 void register_static(state
& L
);
204 static const size_t overcommit_std_align
= 32;
207 * Align a overcommit pointer.
209 template<typename T
, typename U
> U
* align_overcommit(T
* th
)
211 size_t ptr
= reinterpret_cast<size_t>(th
) + sizeof(T
);
212 return reinterpret_cast<U
*>(ptr
+ (overcommit_std_align
- ptr
% overcommit_std_align
) % overcommit_std_align
);
216 * The type of Lua classes.
218 template<class T
> class _class
: public class_base
220 template<typename
... U
> T
* _create(state
& _state
, U
... args
)
222 size_t overcommit
= T::overcommit(args
...);
225 _state
.run_interruptable([st
, overcommit
, &obj
]() {
226 obj
= st
->newuserdata(sizeof(T
) + overcommit
);
228 load_metatable(_state
);
229 _state
.setmetatable(-2);
230 T
* _obj
= reinterpret_cast<T
*>(obj
);
232 new(_obj
) T(_state
, args
...);
234 //CTOR FAILED. Get rid of the dtor (since it would error) and then dump the object.
236 _state
.setmetatable(-2);
243 static int class_bind_trampoline(state
& L
)
245 class_binding
<T
>* b
= (class_binding
<T
>*)L
.touserdata(L
.trampoline_upval(1));
246 T
* p
= _class
<T
>::get(L
, 1, b
->fname
);
247 lua::parameters
P(L
, b
->fname
);
248 return (p
->*(b
->fn
))(L
, P
);
251 T
* _get(state
& _state
, int arg
, const std::string
& fname
, bool optional
= false)
253 if(_state
.type(arg
) == LUA_TNONE
|| _state
.type(arg
) == LUA_TNIL
) {
259 load_metatable(_state
);
260 if(!_state
.getmetatable(arg
))
262 if(!_state
.rawequal(-1, -2))
265 return reinterpret_cast<T
*>(_state
.touserdata(arg
));
267 (stringfmt() << "argument #" << arg
<< " to " << fname
<< " must be " << name
).throwex();
268 return NULL
; //Never reached.
271 bool _is(state
& _state
, int arg
)
273 if(_state
.type(arg
) != LUA_TUSERDATA
)
275 load_metatable(_state
);
276 if(!_state
.getmetatable(arg
)) {
280 bool ret
= _state
.rawequal(-1, -2);
285 objpin
<T
> _pin(state
& _state
, int arg
, const std::string
& fname
)
287 T
* obj
= get(_state
, arg
, fname
);
288 _state
.pushvalue(arg
);
289 objpin
<T
> t(_state
, obj
);
294 void bind(state
& _state
, const char* keyname
, int (T::*fn
)(state
& LS
, lua::parameters
& P
))
296 load_metatable(_state
);
297 _state
.pushstring(keyname
);
298 std::string fname
= name
+ std::string("::") + keyname
;
299 void* ptr
= _state
.newuserdata(sizeof(class_binding
<T
>) + fname
.length() + 1);
300 class_binding
<T
>* bdata
= reinterpret_cast<class_binding
<T
>*>(ptr
);
302 bdata
->_state
= &_state
.get_master();
303 std::copy(fname
.begin(), fname
.end(), bdata
->fname
);
304 bdata
->fname
[fname
.length()] = 0;
305 _state
.push_trampoline(class_bind_trampoline
, 1);
310 void register_state(state
& L
)
312 static char once_key
;
314 if(L
.do_once(&once_key
))
315 for(auto i
: cmethods
)
316 bind(L
, i
.name
, i
.fn
);
320 * Create a new Lua class.
322 * Parameter _group: The group the class will be in.
323 * Parameter _name: The name of the class.
324 * Parameter _smethods: Static methods of the class.
325 * Parameter _cmethods: Class methods of the class.
326 * Parameter _print: The print method.
328 _class(class_group
& _group
, const std::string
& _name
, std::initializer_list
<static_method
> _smethods
,
329 std::initializer_list
<class_method
<T
>> _cmethods
= {}, std::string (T::*_print
)() = NULL
)
330 : class_base(_group
, _name
), smethods(_smethods
), cmethods(_cmethods
)
335 m
.is
= _class
<T
>::is
;
336 m
.name
= _class
<T
>::get_name
;
337 m
.print
= _class
<T
>::print
;
338 userdata_recogn_fns().push_back(m
);
339 auto& type
= typeid(T
);
340 class_types()[type
] = this;
348 auto& type
= typeid(T
);
349 class_types().erase(type
);
350 auto& fns
= userdata_recogn_fns();
351 for(auto i
= fns
.begin(); i
!= fns
.end(); i
++) {
352 if(i
->is
== _class
<T
>::is
) {
359 * Create a new instance of object.
361 * Parameter _state: The Lua state to create the object in.
362 * Parameter args: The arguments to pass to class constructor.
364 template<typename
... U
> static T
* create(state
& _state
, U
... args
)
366 return objclass
<T
>()._create(_state
, args
...);
370 * Get a pointer to the object.
372 * Parameter _state: The Lua state.
373 * Parameter arg: Argument index.
374 * Parameter fname: The name of function for error messages.
375 * Parameter optional: If true and argument is NIL or none, return NULL.
376 * Throws std::runtime_error: Wrong type.
378 static T
* get(state
& _state
, int arg
, const std::string
& fname
, bool optional
= false)
379 throw(std::bad_alloc
, std::runtime_error
)
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
) throw(std::bad_alloc
,
438 return objclass
<T
>()._pin(_state
, arg
, fname
);
441 * Lookup static methods.
443 std::list
<static_method
> static_methods()
448 * Lookup class methods.
450 std::set
<std::string
> class_methods()
452 std::set
<std::string
> r
;
453 for(auto& i
: cmethods
)
458 static int dogc(state
& L
)
460 T
* obj
= reinterpret_cast<T
*>(L
.touserdata(1));
465 static int newindex(state
& L
)
467 throw std::runtime_error("Writing metatables of classes is not allowed");
470 static int index(state
& L
)
475 if(L
.type(-1) == LUA_TNIL
) {
476 std::string err
= std::string("Class '") + L
.tostring(L
.trampoline_upval(1)) +
477 "' does not have class method '" + L
.tostring(2) + "'";
478 throw std::runtime_error(err
);
483 void load_metatable(state
& _state
)
486 _state
.pushlightuserdata(this);
487 _state
.rawget(LUA_REGISTRYINDEX
);
488 if(_state
.type(-1) == LUA_TNIL
) {
490 _state
.pushlightuserdata(this);
492 _state
.pushvalue(-1);
493 _state
.setmetatable(-2);
494 _state
.pushstring("__gc");
495 _state
.push_trampoline(&_class
<T
>::dogc
, 0);
497 _state
.pushstring("__newindex");
498 _state
.push_trampoline(&_class
<T
>::newindex
, 0);
500 _state
.pushstring("__index");
501 _state
.pushlstring(name
);
502 _state
.push_trampoline(&_class
<T
>::index
, 1);
504 _state
.rawset(LUA_REGISTRYINDEX
);
509 std::list
<static_method
> smethods
;
510 std::list
<class_method
<T
>> cmethods
;
511 std::string (T::*printmeth
)();
512 _class(const _class
<T
>&);
513 _class
& operator=(const _class
<T
>&);