Lua: Memory usage limit
[lsnes.git] / include / library / lua-base.hpp
blobdf4b405a2916d3c525ff334f6235555715627bb1
1 #ifndef _library__lua_base__hpp__included__
2 #define _library__lua_base__hpp__included__
4 #include <string>
5 #include <stdexcept>
6 #include <typeinfo>
7 #include <typeindex>
8 #include <map>
9 #include <unordered_map>
10 #include <set>
11 #include <list>
12 #include <cassert>
13 #include "string.hpp"
14 #include "utf8.hpp"
15 #include "lua-version.hpp"
17 namespace lua
19 class state;
20 class function;
21 class function_group;
22 class class_group;
23 class class_base;
25 /**
26 * Lua state object.
28 class state
30 public:
31 const static unsigned trampoline_upvals = 2;
32 //Auxillary type for store-tag.
33 template<typename T> struct _store_tag
35 T& addr;
36 T val;
37 _store_tag(T& a, T v) : addr(a), val(v) {}
39 //Auxillary type for vararg-tag.
40 struct vararg_tag
42 std::list<std::string> args;
43 vararg_tag(std::list<std::string>& _args) : args(_args) {}
44 int pushargs(state& L);
47 //Auxillary type for numeric-tag.
48 template<typename T> struct _numeric_tag
50 T val;
51 _numeric_tag(T v) : val(v) {}
54 //Auxillary type for fnptr-tag.
55 template<typename T> struct _fnptr_tag
57 int(*fn)(state& L, T v);
58 T val;
59 _fnptr_tag(int (*f)(state& L, T v), T v) : fn(f), val(v) {}
62 //Auxillary type for fn-tag.
63 template<typename T> struct _fn_tag
65 T fn;
66 _fn_tag(T f) : fn(f) {}
69 /**
70 * Callback parameter: Don't pass any real parameter, but instead store specified value in specified
71 * location.
73 * Parameter a: The location to store value to.
74 * Parameter v: The value to store.
75 * Returns: The parameter structure.
77 template<typename T> static struct _store_tag<T> store_tag(T& a, T v) { return _store_tag<T>(a, v); }
78 /**
79 * Callback parameter: Pass numeric value.
81 * Parameter v: The value to pass.
82 * Returns: The parameter structure.
84 template<typename T> static struct _numeric_tag<T> numeric_tag(T v) { return _numeric_tag<T>(v); }
86 /**
87 * Callback parameter: Execute function to push more parameters.
89 * Parameter f: The function to execute. The return value is number of additional parameters pushed.
90 * Parameter v: The value to pass to function.
91 * Returns: The parameter structure.
93 template<typename T> static struct _fnptr_tag<T> fnptr_tag(int (*f)(state& L, T v), T v)
95 return _fnptr_tag<T>(f, v);
98 /**
99 * Callback parameter: Execute function to push more parameters.
101 * Parameter v: The functor to execute. Passed reference to the Lua state. The return value is number of
102 * additional parameters pushed.
103 * Returns: The parameter structure.
105 template<typename T> static struct _fn_tag<T> fn_tag(T v) { return _fn_tag<T>(v); }
108 * Callback parameter: Pass boolean argument.
110 * Parameter v: The boolean value to pass.
112 struct boolean_tag { bool val; boolean_tag(bool v) : val(v) {}};
115 * Callback parameter: Pass string argument.
117 * Parameter v: The string value to pass.
119 struct string_tag { std::string val; string_tag(const std::string& v) : val(v) {}};
122 * Callback parameter: Pass nil argument.
124 struct nil_tag { nil_tag() {}};
125 private:
126 template<typename U, typename... T> void _callback(int argc, _store_tag<U> tag, T... args)
128 tag.addr = tag.val;
129 _callback(argc, args...);
130 tag.addr = NULL;
133 template<typename... T> void _callback(int argc, vararg_tag tag, T... args)
135 int e = tag.pushargs(*this);
136 _callback(argc + e, args...);
139 template<typename... T> void _callback(int argc, nil_tag tag, T... args)
141 pushnil();
142 _callback(argc + 1, args...);
145 template<typename... T> void _callback(int argc, boolean_tag tag, T... args)
147 pushboolean(tag.val);
148 _callback(argc + 1, args...);
151 template<typename... T> void _callback(int argc, string_tag tag, T... args)
153 pushlstring(tag.val);
154 _callback(argc + 1, args...);
157 template<typename U, typename... T> void _callback(int argc, _numeric_tag<U> tag, T... args)
159 pushnumber(tag.val);
160 _callback(argc + 1, args...);
163 template<typename U, typename... T> void _callback(int argc, _fnptr_tag<U> tag, T... args)
165 int extra = tag.fn(*this, tag.val);
166 _callback(argc + extra, args...);
169 template<typename U, typename... T> void _callback(int argc, _fn_tag<U> tag, T... args)
171 int extra = tag.fn(*this);
172 _callback(argc + extra, args...);
175 void _callback(int argc)
177 int r = pcall(argc, 0, 0);
178 if(r == LUA_ERRRUN) {
179 (stringfmt() << "Error running Lua callback: " << tostring(-1)).throwex();
180 pop(1);
182 if(r == LUA_ERRMEM) {
183 (stringfmt() << "Error running Lua callback: Out of memory").throwex();
184 pop(1);
186 if(r == LUA_ERRERR) {
187 (stringfmt() << "Error running Lua callback: Double Fault???").throwex();
188 pop(1);
191 public:
193 * Create a new state.
195 state() throw(std::bad_alloc);
197 * Create a new state with specified master state.
199 state(state& _master, lua_State* L);
201 * Destroy a state.
203 ~state() throw();
205 * Get the internal state object.
207 * Return value: Internal state.
209 lua_State* handle() { return lua_handle; }
211 * Get the master state.
213 state& get_master() { return master ? master->get_master() : *this; }
215 * Set the internal state object.
217 void handle(lua_State* l) { lua_handle = l; }
219 * Set OOM handler.
221 void set_oom_handler(void (*oom)()) { oom_handler = oom ? oom : builtin_oom; }
223 * Set soft OOM handler.
225 void set_soft_oom_handler(void (*oom)(int status)) { soft_oom_handler = oom ? oom : builtin_soft_oom; }
227 * Reset the state.
229 void reset() throw(std::runtime_error, std::bad_alloc);
231 * Deinit the state.
233 void deinit() throw();
235 * Create a trampoline.
237 * Parameter fn The function to execute.
238 * Parameter n_upvals The number of extra upvalues besides the 2 used by trampoline itself. Popped from stack.
240 void push_trampoline(int(*fn)(state& L), unsigned n_upvals);
242 * Get specified trampoline upvalue index.
244 int trampoline_upval(int val) { return lua_upvalueindex(trampoline_upvals + val); }
246 * Set value of interruptable flag.
248 * Parameter flag: The flag.
250 void set_interruptable_flag(bool flag)
252 if(master) master->set_interruptable_flag(flag); else interruptable = flag;
255 * Get interruptable flag.
257 bool get_interruptable_flag()
259 if(master) return master->get_interruptable_flag(); else return interruptable;
262 * Set memory limit.
264 void set_memory_limit(size_t limit)
266 if(master) master->set_memory_limit(limit); else memory_limit = limit;
269 * Get memory limit.
271 size_t get_memory_limit()
273 if(master) return master->get_memory_limit(); else return memory_limit;
276 * Get memory use.
278 size_t get_memory_use()
280 if(master) return master->get_memory_use(); else return memory_use;
283 * Charge against memory limit.
285 bool charge_memory(size_t amount, bool release);
287 * Execute function in interruptable mode.
289 * Parameter fn: The function to execute
290 * Parameter in: Number of slots to copy in.
291 * Parameter out: Number of slots to copy out.
293 void run_interruptable(std::function<void()> fn, unsigned in, unsigned out);
295 * Get a string argument.
297 * Parameter argindex: The stack index.
298 * Parameter fname: The name of function to use in error messages.
299 * Returns: The string.
300 * Throws std::runtime_error: The specified argument is not a string.
302 std::string get_string(int argindex, const std::string& fname) throw(std::runtime_error, std::bad_alloc)
304 if(isnone(argindex))
305 (stringfmt() << "argument #" << argindex << " to " << fname << " must be string").throwex();
306 size_t len;
307 const char* f = lua_tolstring(lua_handle, argindex, &len);
308 if(!f)
309 (stringfmt() << "argument #" << argindex << " to " << fname << " must be string").throwex();
310 return std::string(f, f + len);
313 * Get a boolean argument.
315 * Parameter argindex: The stack index.
316 * Parameter fname: The name of function to use in error messages.
317 * Returns: The string.
318 * Throws std::runtime_error: The specified argument is not a boolean.
320 bool get_bool(int argindex, const std::string& fname) throw(std::runtime_error, std::bad_alloc)
322 if(isnone(argindex) || !isboolean(argindex))
323 (stringfmt() << "argument #" << argindex << " to " << fname << " must be boolean").throwex();
324 return (lua_toboolean(lua_handle, argindex) != 0);
327 * Get a mandatory numeric argument.
329 * Parameter argindex: The stack index.
330 * Parameter fname: The name of function to use in error messages.
331 * Returns: The parsed number.
332 * Throws std::runtime_error: Bad type.
334 template<typename T>
335 T get_numeric_argument(int argindex, const std::string& fname)
337 if(std::numeric_limits<T>::is_integer) {
338 if(isnone(argindex) || !isinteger(argindex))
339 (stringfmt() << "Argument #" << argindex << " to " << fname
340 << " must be integer").throwex();
341 return static_cast<T>(lua_tointeger(lua_handle, argindex));
342 } else {
343 if(isnone(argindex) || !isnumber(argindex))
344 (stringfmt() << "Argument #" << argindex << " to " << fname
345 << " must be numeric").throwex();
346 return static_cast<T>(lua_tonumber(lua_handle, argindex));
350 * Get a optional numeric argument.
352 * Parameter argindex: The stack index.
353 * Parameter value: The place to store the value.
354 * Parameter fname: The name of function to use in error messages.
355 * Throws std::runtime_error: Bad type.
357 template<typename T>
358 void get_numeric_argument(unsigned argindex, T& value, const std::string& fname)
360 if(isnoneornil(argindex))
361 return;
362 if(std::numeric_limits<T>::is_integer) {
363 if(isnone(argindex) || !isinteger(argindex))
364 (stringfmt() << "Argument #" << argindex << " to " << fname << " must be integer if "
365 "present").throwex();
366 value = static_cast<T>(lua_tointeger(lua_handle, argindex));
367 } else {
368 if(isnone(argindex) || !isnumber(argindex))
369 (stringfmt() << "Argument #" << argindex << " to " << fname << " must be numeric if "
370 "present").throwex();
371 value = static_cast<T>(lua_tonumber(lua_handle, argindex));
375 * Do a callback.
377 * Parameter name: The name of the callback.
378 * Parameter args: Arguments to pass to the callback.
380 template<typename... T>
381 bool callback(const std::string& name, T... args)
383 getglobal(name.c_str());
384 int t = type(-1);
385 if(t != LUA_TFUNCTION) {
386 pop(1);
387 return false;
389 _callback(0, args...);
390 return true;
393 * Do a callback.
395 * Parameter cblist: List of environment keys to do callbacks.
396 * Parameter args: Arguments to pass to the callback.
398 template<typename... T>
399 bool callback(const std::list<char>& cblist, T... args)
401 bool any = false;
402 for(auto& i : cblist) {
403 pushlightuserdata(const_cast<char*>(&i));
404 rawget(LUA_REGISTRYINDEX);
405 int t = type(-1);
406 if(t != LUA_TFUNCTION) {
407 pop(1);
408 } else {
409 _callback(0, args...);
410 any = true;
413 return any;
416 * Add a group of functions.
418 void add_function_group(function_group& group);
420 * Add a group of classes.
422 void add_class_group(class_group& group);
424 * Function callback.
426 void function_callback(const std::string& name, function* func);
428 * Class callback.
430 void class_callback(const std::string& name, class_base* func);
432 * Do something just once per VM.
434 * Parameter key: The do-once key value.
435 * Returns: True if called the first time for given key on given VM, false otherwise.
437 bool do_once(void* key);
439 * Callback list.
441 class callback_list
443 public:
444 callback_list(state& L, const std::string& name, const std::string& fn_cbname = "");
445 ~callback_list();
446 void _register(state& L); //Reads callback from top of lua stack.
447 void _unregister(state& L); //Reads callback from top of lua stack.
448 template<typename... T> bool callback(T... args) {
449 bool any = L.callback(callbacks, args...);
450 if(fn_cbname != "" && L.callback(fn_cbname, args...))
451 any = true;
452 return any;
454 const std::string& get_name() { return name; }
455 void clear() { callbacks.clear(); }
456 private:
457 callback_list(const callback_list&);
458 callback_list& operator=(const callback_list&);
459 std::list<char> callbacks;
460 state& L;
461 std::string name;
462 std::string fn_cbname;
465 * Enumerate all callbacks.
467 std::list<callback_list*> get_callbacks();
469 * Register/Unregister a callback list.
471 void do_register(const std::string& name, callback_list& callback);
472 void do_unregister(const std::string& name, callback_list& callback);
474 //All kinds of Lua API functions.
475 void pop(int n) { lua_pop(lua_handle, n); }
476 void* newuserdata(size_t size) { return lua_newuserdata(lua_handle, size); }
477 int setmetatable(int index) { return lua_setmetatable(lua_handle, index); }
478 int type(int index) { return lua_type(lua_handle, index); }
479 void replace(int index) { lua_replace(lua_handle, index); }
480 int getmetatable(int index) { return lua_getmetatable(lua_handle, index); }
481 int rawequal(int index1, int index2) { return lua_rawequal(lua_handle, index1, index2); }
482 void* touserdata(int index) { return lua_touserdata(lua_handle, index); }
483 const void* topointer(int index) { return lua_topointer(lua_handle, index); }
484 int gettop() { return lua_gettop(lua_handle); }
485 void pushvalue(int index) { lua_pushvalue(lua_handle, index); }
486 void pushlightuserdata(void* p) { lua_pushlightuserdata(lua_handle, p); }
487 void rawset(int index) { lua_rawset(lua_handle, index); }
488 void pushnil() { lua_pushnil(lua_handle); }
489 void pushstring(const char* s) { lua_pushstring(lua_handle, s); }
490 void rawget(int index) { lua_rawget(lua_handle, index); }
491 int isnil(int index) { return lua_isnil(lua_handle, index); }
492 void newtable() { lua_newtable(lua_handle); }
493 void pushcclosure(lua_CFunction fn, int n) { lua_pushcclosure(lua_handle, fn, n); }
494 void pushcfunction(lua_CFunction fn) { lua_pushcfunction(lua_handle, fn); }
495 void setfield(int index, const char* k) { lua_setfield(lua_handle, index, k); }
496 void getfield(int index, const char* k) { lua_getfield(lua_handle, index, k); }
497 void getglobal(const char* name) { lua_getglobal(lua_handle, name); }
498 void setglobal(const char* name) { lua_setglobal(lua_handle, name); }
499 void insert(int index) { lua_insert(lua_handle, index); }
500 void settable(int index) { lua_settable(lua_handle, index); }
501 int isnone(int index) { return lua_isnone(lua_handle, index); }
502 int isnumber(int index) { return lua_isnumber(lua_handle, index); }
503 int isinteger(int index) { return LUA_INTEGER_POSTFIX(lua_is) (lua_handle, index); }
504 int isboolean(int index) { return lua_isboolean(lua_handle, index); }
505 int toboolean(int index) { return lua_toboolean(lua_handle, index); }
506 const char* tolstring(int index, size_t *len) { return lua_tolstring(lua_handle, index, len); }
507 lua_Number tonumber(int index) { return lua_tonumber(lua_handle, index); }
508 uint64_t tointeger(int index) { return LUA_INTEGER_POSTFIX(lua_to) (lua_handle, index); }
509 void gettable(int index) { lua_gettable(lua_handle, index); }
510 int load(lua_Reader reader, void* data, const char* chunkname, const char* mode) {
511 (void)mode;
512 return lua_load(lua_handle, reader, data, chunkname LUA_LOADMODE_ARG(mode) );
514 const char* tostring(int index) { return lua_tostring(lua_handle, index); }
515 const char* tolstring(int index, size_t& len) { return lua_tolstring(lua_handle, index, &len); }
516 void pushlstring(const char* s, size_t len) { lua_pushlstring(lua_handle, s, len); }
517 void pushlstring(const std::string& s) { lua_pushlstring(lua_handle, s.c_str(), s.length()); }
518 void pushlstring(const char32_t* s, size_t len) { pushlstring(utf8::to8(std::u32string(s, len))); }
519 int pcall(int nargs, int nresults, int errfunc)
521 state* master_state = this;
522 while(master_state->master) master_state = master_state->master;
523 //Upon entry to protected mode, interruptable mode is always set, and it is restored on exit
524 //from protected mode.
525 bool old_interruptable = master_state->interruptable;
526 master_state->interruptable = true;
527 auto ret = lua_pcall(lua_handle, nargs, nresults, errfunc);
528 master_state->interruptable = old_interruptable;
529 return ret;
531 int next(int index) { return lua_next(lua_handle, index); }
532 int isnoneornil(int index) { return lua_isnoneornil(lua_handle, index); }
533 void rawgeti(int index, int n) { lua_rawgeti(lua_handle, index, n); }
534 template<typename T> void pushnumber(T val)
536 if(std::numeric_limits<T>::is_integer)
537 _pushinteger(val);
538 else
539 _pushnumber(val);
541 void pushboolean(bool b) { lua_pushboolean(lua_handle, b); }
542 void pushglobals() { LUA_LOADGLOBALS }
543 private:
544 void _pushnumber(lua_Number n) { return lua_pushnumber(lua_handle, n); }
545 void _pushinteger(uint64_t n) { return LUA_INTEGER_POSTFIX(lua_push) (lua_handle, n); }
546 static void builtin_oom();
547 static void builtin_soft_oom(int status);
548 static void* builtin_alloc(void* user, void* old, size_t olds, size_t news);
549 void (*oom_handler)();
550 void (*soft_oom_handler)(int status);
551 state* master;
552 bool interruptable;
553 size_t memory_limit;
554 size_t memory_use;
555 lua_State* lua_handle;
556 state(state&);
557 state& operator=(state&);
562 #endif