1 #ifndef _library__lua_base__hpp__included__
2 #define _library__lua_base__hpp__included__
9 #include <unordered_map>
17 #include "lua-version.hpp"
33 const static unsigned trampoline_upvals
= 2;
34 //Auxillary type for store-tag.
35 template<typename T
> struct _store_tag
39 _store_tag(T
& a
, T v
) : addr(a
), val(v
) {}
41 //Auxillary type for vararg-tag.
44 std::list
<std::string
> args
;
45 vararg_tag(std::list
<std::string
>& _args
) : args(_args
) {}
46 int pushargs(state
& L
);
49 //Auxillary type for numeric-tag.
50 template<typename T
> struct _numeric_tag
53 _numeric_tag(T v
) : val(v
) {}
56 //Auxillary type for fnptr-tag.
57 template<typename T
> struct _fnptr_tag
59 int(*fn
)(state
& L
, T v
);
61 _fnptr_tag(int (*f
)(state
& L
, T v
), T v
) : fn(f
), val(v
) {}
64 //Auxillary type for fn-tag.
65 template<typename T
> struct _fn_tag
68 _fn_tag(T f
) : fn(f
) {}
72 * Callback parameter: Don't pass any real parameter, but instead store specified value in specified
75 * Parameter a: The location to store value to.
76 * Parameter v: The value to store.
77 * Returns: The parameter structure.
79 template<typename T
> static struct _store_tag
<T
> store_tag(T
& a
, T v
) { return _store_tag
<T
>(a
, v
); }
81 * Callback parameter: Pass numeric value.
83 * Parameter v: The value to pass.
84 * Returns: The parameter structure.
86 template<typename T
> static struct _numeric_tag
<T
> numeric_tag(T v
) { return _numeric_tag
<T
>(v
); }
89 * Callback parameter: Execute function to push more parameters.
91 * Parameter f: The function to execute. The return value is number of additional parameters pushed.
92 * Parameter v: The value to pass to function.
93 * Returns: The parameter structure.
95 template<typename T
> static struct _fnptr_tag
<T
> fnptr_tag(int (*f
)(state
& L
, T v
), T v
)
97 return _fnptr_tag
<T
>(f
, v
);
101 * Callback parameter: Execute function to push more parameters.
103 * Parameter v: The functor to execute. Passed reference to the Lua state. The return value is number of
104 * additional parameters pushed.
105 * Returns: The parameter structure.
107 template<typename T
> static struct _fn_tag
<T
> fn_tag(T v
) { return _fn_tag
<T
>(v
); }
110 * Callback parameter: Pass boolean argument.
112 * Parameter v: The boolean value to pass.
114 struct boolean_tag
{ bool val
; boolean_tag(bool v
) : val(v
) {}};
117 * Callback parameter: Pass string argument.
119 * Parameter v: The string value to pass.
121 struct string_tag
{ std::string val
; string_tag(const std::string
& v
) : val(v
) {}};
124 * Callback parameter: Pass nil argument.
126 struct nil_tag
{ nil_tag() {}};
128 template<typename U
, typename
... T
> void _callback(int argc
, _store_tag
<U
> tag
, T
... args
)
131 _callback(argc
, args
...);
135 template<typename
... T
> void _callback(int argc
, vararg_tag tag
, T
... args
)
137 int e
= tag
.pushargs(*this);
138 _callback(argc
+ e
, args
...);
141 template<typename
... T
> void _callback(int argc
, nil_tag tag
, T
... args
)
144 _callback(argc
+ 1, args
...);
147 template<typename
... T
> void _callback(int argc
, boolean_tag tag
, T
... args
)
149 pushboolean(tag
.val
);
150 _callback(argc
+ 1, args
...);
153 template<typename
... T
> void _callback(int argc
, string_tag tag
, T
... args
)
155 pushlstring(tag
.val
);
156 _callback(argc
+ 1, args
...);
159 template<typename U
, typename
... T
> void _callback(int argc
, _numeric_tag
<U
> tag
, T
... args
)
162 _callback(argc
+ 1, args
...);
165 template<typename U
, typename
... T
> void _callback(int argc
, _fnptr_tag
<U
> tag
, T
... args
)
167 int extra
= tag
.fn(*this, tag
.val
);
168 _callback(argc
+ extra
, args
...);
171 template<typename U
, typename
... T
> void _callback(int argc
, _fn_tag
<U
> tag
, T
... args
)
173 int extra
= tag
.fn(*this);
174 _callback(argc
+ extra
, args
...);
177 void _callback(int argc
)
179 int r
= pcall(argc
, 0, 0);
180 if(r
== LUA_ERRRUN
) {
181 (stringfmt() << "Error running Lua callback: " << tostring(-1)).throwex();
184 if(r
== LUA_ERRMEM
) {
185 (stringfmt() << "Error running Lua callback: Out of memory").throwex();
188 if(r
== LUA_ERRERR
) {
189 (stringfmt() << "Error running Lua callback: Double Fault???").throwex();
195 * Create a new state.
199 * Create a new state with specified master state.
201 state(state
& _master
, lua_State
* L
);
207 * Get the internal state object.
209 * Return value: Internal state.
211 lua_State
* handle() { return lua_handle
; }
213 * Get the master state.
215 state
& get_master() { return master
? master
->get_master() : *this; }
217 * Set the internal state object.
219 void handle(lua_State
* l
) { lua_handle
= l
; }
223 void set_oom_handler(void (*oom
)()) { oom_handler
= oom
? oom
: builtin_oom
; }
225 * Set soft OOM handler.
227 void set_soft_oom_handler(void (*oom
)(int status
)) { soft_oom_handler
= oom
? oom
: builtin_soft_oom
; }
229 * Set memory use change handler.
231 void set_memory_change_handler(std::function
<void(ssize_t change
)> cb
)
242 void deinit() throw();
244 * Create a trampoline.
246 * Parameter fn The function to execute.
247 * Parameter n_upvals The number of extra upvalues besides the 2 used by trampoline itself. Popped from stack.
249 void push_trampoline(int(*fn
)(state
& L
), unsigned n_upvals
);
251 * Get specified trampoline upvalue index.
253 int trampoline_upval(int val
) { return lua_upvalueindex(trampoline_upvals
+ val
); }
255 * Set value of interruptable flag.
257 * Parameter flag: The flag.
259 void set_interruptable_flag(bool flag
)
261 if(master
) master
->set_interruptable_flag(flag
); else interruptable
= flag
;
264 * Get interruptable flag.
266 bool get_interruptable_flag()
268 if(master
) return master
->get_interruptable_flag(); else return interruptable
;
273 void set_memory_limit(size_t limit
)
275 if(master
) master
->set_memory_limit(limit
); else memory_limit
= limit
;
280 size_t get_memory_limit()
282 if(master
) return master
->get_memory_limit(); else return memory_limit
;
287 size_t get_memory_use()
289 if(master
) return master
->get_memory_use(); else return memory_use
;
292 * Charge against memory limit.
294 bool charge_memory(size_t amount
, bool release
);
296 * Execute function in interruptable mode.
298 * Parameter fn: The function to execute
299 * Parameter in: Number of slots to copy in.
300 * Parameter out: Number of slots to copy out.
302 void run_interruptable(std::function
<void()> fn
, unsigned in
, unsigned out
);
304 * Get a string argument.
306 * Parameter argindex: The stack index.
307 * Parameter fname: The name of function to use in error messages.
308 * Returns: The string.
309 * Throws std::runtime_error: The specified argument is not a string.
311 std::string
get_string(int argindex
, const std::string
& fname
)
314 (stringfmt() << "argument #" << argindex
<< " to " << fname
<< " must be string").throwex();
316 const char* f
= lua_tolstring(lua_handle
, argindex
, &len
);
318 (stringfmt() << "argument #" << argindex
<< " to " << fname
<< " must be string").throwex();
319 return std::string(f
, f
+ len
);
322 * Read slot as string.
324 * Parameter argindex: The stack index.
325 * Returns: The string.
327 std::string
as_string(int argindex
)
329 if(isnone(argindex
)) return "(none)";
331 const char* f
= lua_tolstring(lua_handle
, argindex
, &len
);
332 if(!f
) return "(null)";
333 return std::string(f
, f
+ len
);
336 * Get a boolean argument.
338 * Parameter argindex: The stack index.
339 * Parameter fname: The name of function to use in error messages.
340 * Returns: The string.
341 * Throws std::runtime_error: The specified argument is not a boolean.
343 bool get_bool(int argindex
, const std::string
& fname
)
345 if(isnone(argindex
) || !isboolean(argindex
))
346 (stringfmt() << "argument #" << argindex
<< " to " << fname
<< " must be boolean").throwex();
347 return (lua_toboolean(lua_handle
, argindex
) != 0);
350 * Get a mandatory numeric argument.
352 * Parameter argindex: The stack index.
353 * Parameter fname: The name of function to use in error messages.
354 * Returns: The parsed number.
355 * Throws std::runtime_error: Bad type.
358 T
get_numeric_argument(int argindex
, const std::string
& fname
)
360 if(std::numeric_limits
<T
>::is_integer
) {
361 if(isnone(argindex
) || !isinteger(argindex
))
362 (stringfmt() << "Argument #" << argindex
<< " to " << fname
363 << " must be integer").throwex();
364 return static_cast<T
>(lua_tointeger(lua_handle
, argindex
));
366 if(isnone(argindex
) || !isnumber(argindex
))
367 (stringfmt() << "Argument #" << argindex
<< " to " << fname
368 << " must be numeric").throwex();
369 return static_cast<T
>(lua_tonumber(lua_handle
, argindex
));
373 * Get a optional numeric argument.
375 * Parameter argindex: The stack index.
376 * Parameter value: The place to store the value.
377 * Parameter fname: The name of function to use in error messages.
378 * Throws std::runtime_error: Bad type.
381 void get_numeric_argument(unsigned argindex
, T
& value
, const std::string
& fname
)
383 if(isnoneornil(argindex
))
385 if(std::numeric_limits
<T
>::is_integer
) {
386 if(isnone(argindex
) || !isinteger(argindex
))
387 (stringfmt() << "Argument #" << argindex
<< " to " << fname
<< " must be integer if "
388 "present").throwex();
389 value
= static_cast<T
>(lua_tointeger(lua_handle
, argindex
));
391 if(isnone(argindex
) || !isnumber(argindex
))
392 (stringfmt() << "Argument #" << argindex
<< " to " << fname
<< " must be numeric if "
393 "present").throwex();
394 value
= static_cast<T
>(lua_tonumber(lua_handle
, argindex
));
400 * Parameter name: The name of the callback.
401 * Parameter args: Arguments to pass to the callback.
403 template<typename
... T
>
404 bool callback(const std::string
& name
, T
... args
)
406 getglobal(name
.c_str());
408 if(t
!= LUA_TFUNCTION
) {
412 _callback(0, args
...);
418 * Parameter cblist: List of environment keys to do callbacks.
419 * Parameter args: Arguments to pass to the callback.
421 template<typename
... T
>
422 bool callback(std::list
<char>& cblist
, const char*& r_cb
, bool& r_cb_f
, T
... args
)
425 for(auto i
= cblist
.begin(); i
!= cblist
.end();) {
426 pushlightuserdata(const_cast<char*>(&*i
));
427 rawget(LUA_REGISTRYINDEX
);
429 if(t
!= LUA_TFUNCTION
) {
432 //Note the currently running CB so that unregister treats it specially if it is
435 _callback(0, args
...);
439 //Currently iterated function may be erased. The memory has to be freed in that case.
450 * Add a group of functions.
452 void add_function_group(function_group
& group
);
454 * Add a group of classes.
456 void add_class_group(class_group
& group
);
460 void function_callback(const std::string
& name
, function
* func
);
464 void class_callback(const std::string
& name
, class_base
* func
);
466 * Do something just once per VM.
468 * Parameter key: The do-once key value.
469 * Returns: True if called the first time for given key on given VM, false otherwise.
471 bool do_once(void* key
);
478 callback_list(state
& L
, const std::string
& name
, const std::string
& fn_cbname
= "");
480 void _register(state
& L
); //Reads callback from top of lua stack.
481 void _unregister(state
& L
); //Reads callback from top of lua stack.
482 template<typename
... T
> bool callback(T
... args
) {
483 bool any
= L
.callback(callbacks
, running_cb
, running_cb_f
, args
...);
484 if(fn_cbname
!= "" && L
.callback(fn_cbname
, args
...))
488 const std::string
& get_name() { return name
; }
489 void clear() { callbacks
.clear(); }
491 callback_list(const callback_list
&);
492 callback_list
& operator=(const callback_list
&);
493 std::list
<char> callbacks
;
494 const char* running_cb
;
498 std::string fn_cbname
;
501 * Enumerate all callbacks.
503 std::list
<callback_list
*> get_callbacks();
505 * Register/Unregister a callback list.
507 void do_register(const std::string
& name
, callback_list
& callback
);
508 void do_unregister(const std::string
& name
, callback_list
& callback
);
510 //All kinds of Lua API functions.
511 void pop(int n
) { lua_pop(lua_handle
, n
); }
512 void* newuserdata(size_t size
) { return lua_newuserdata(lua_handle
, size
); }
513 int setmetatable(int index
) { return lua_setmetatable(lua_handle
, index
); }
514 int type(int index
) { return lua_type(lua_handle
, index
); }
515 void replace(int index
) { lua_replace(lua_handle
, index
); }
516 int getmetatable(int index
) { return lua_getmetatable(lua_handle
, index
); }
517 int rawequal(int index1
, int index2
) { return lua_rawequal(lua_handle
, index1
, index2
); }
518 void* touserdata(int index
) { return lua_touserdata(lua_handle
, index
); }
519 const void* topointer(int index
) { return lua_topointer(lua_handle
, index
); }
520 int gettop() { return lua_gettop(lua_handle
); }
521 void pushvalue(int index
) { lua_pushvalue(lua_handle
, index
); }
522 void pushlightuserdata(void* p
) { lua_pushlightuserdata(lua_handle
, p
); }
523 void rawset(int index
) { lua_rawset(lua_handle
, index
); }
524 void pushnil() { lua_pushnil(lua_handle
); }
525 void pushstring(const char* s
) { lua_pushstring(lua_handle
, s
); }
526 void rawget(int index
) { lua_rawget(lua_handle
, index
); }
527 int isnil(int index
) { return lua_isnil(lua_handle
, index
); }
528 void newtable() { lua_newtable(lua_handle
); }
529 void pushcclosure(lua_CFunction fn
, int n
) { lua_pushcclosure(lua_handle
, fn
, n
); }
530 void pushcfunction(lua_CFunction fn
) { lua_pushcfunction(lua_handle
, fn
); }
531 void setfield(int index
, const char* k
) { lua_setfield(lua_handle
, index
, k
); }
532 void getfield(int index
, const char* k
) { lua_getfield(lua_handle
, index
, k
); }
533 void getglobal(const char* name
) { lua_getglobal(lua_handle
, name
); }
534 void setglobal(const char* name
) { lua_setglobal(lua_handle
, name
); }
535 void insert(int index
) { lua_insert(lua_handle
, index
); }
536 void settable(int index
) { lua_settable(lua_handle
, index
); }
537 int isnone(int index
) { return lua_isnone(lua_handle
, index
); }
538 int isnumber(int index
) { return lua_isnumber(lua_handle
, index
); }
539 int isinteger(int index
) { return LUA_INTEGER_POSTFIX(lua_is
) (lua_handle
, index
); }
540 int isboolean(int index
) { return lua_isboolean(lua_handle
, index
); }
541 int toboolean(int index
) { return lua_toboolean(lua_handle
, index
); }
542 const char* tolstring(int index
, size_t *len
) { return lua_tolstring(lua_handle
, index
, len
); }
543 lua_Number
tonumber(int index
) { return lua_tonumber(lua_handle
, index
); }
544 int64_t tointeger(int index
) { return LUA_INTEGER_POSTFIX(lua_to
) (lua_handle
, index
); }
545 void gettable(int index
) { lua_gettable(lua_handle
, index
); }
546 int load(lua_Reader reader
, void* data
, const char* chunkname
, const char* mode
) {
548 return lua_load(lua_handle
, reader
, data
, chunkname
LUA_LOADMODE_ARG(mode
) );
550 const char* tostring(int index
) { return lua_tostring(lua_handle
, index
); }
551 const char* tolstring(int index
, size_t& len
) { return lua_tolstring(lua_handle
, index
, &len
); }
552 void pushlstring(const char* s
, size_t len
) { lua_pushlstring(lua_handle
, s
, len
); }
553 void pushlstring(const std::string
& s
) { lua_pushlstring(lua_handle
, s
.c_str(), s
.length()); }
554 void pushlstring(const char32_t
* s
, size_t len
) { pushlstring(utf8::to8(std::u32string(s
, len
))); }
555 int pcall(int nargs
, int nresults
, int errfunc
)
557 state
* master_state
= this;
558 while(master_state
->master
) master_state
= master_state
->master
;
559 //Upon entry to protected mode, interruptable mode is always set, and it is restored on exit
560 //from protected mode.
561 bool old_interruptable
= master_state
->interruptable
;
562 master_state
->interruptable
= true;
563 auto ret
= lua_pcall(lua_handle
, nargs
, nresults
, errfunc
);
564 master_state
->interruptable
= old_interruptable
;
567 int next(int index
) { return lua_next(lua_handle
, index
); }
568 int isnoneornil(int index
) { return lua_isnoneornil(lua_handle
, index
); }
569 void rawgeti(int index
, int n
) { lua_rawgeti(lua_handle
, index
, n
); }
570 template<typename T
> void pushnumber(T val
)
572 if(std::numeric_limits
<T
>::is_integer
|| is_ss_int24
<T
>::flag
)
573 return LUA_INTEGER_POSTFIX(lua_push
) (lua_handle
, val
);
575 return lua_pushnumber(lua_handle
, val
);
577 void pushboolean(bool b
) { lua_pushboolean(lua_handle
, b
); }
578 void pushglobals() { LUA_LOADGLOBALS
}
580 static void builtin_oom();
581 static void builtin_soft_oom(int status
);
582 static void* builtin_alloc(void* user
, void* old
, size_t olds
, size_t news
);
583 void (*oom_handler
)();
584 void (*soft_oom_handler
)(int status
);
585 std::function
<void(ssize_t change
)> memory_change
;
590 lua_State
* lua_handle
;
592 state
& operator=(state
&);