| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /* Luwra
- * Minimal-overhead Lua wrapper for C++
- *
- * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
- */
- #ifndef LUWRA_STACK_H_
- #define LUWRA_STACK_H_
- #include "common.hpp"
- #include "types.hpp"
- #include <cassert>
- #include <utility>
- #include <functional>
- #include <string>
- LUWRA_NS_BEGIN
- namespace internal {
- template <typename T>
- struct Layout {
- static_assert(
- sizeof(T) == -1,
- "Parameter to Layout is not a function signature"
- );
- };
- template <typename R>
- struct Layout<R()> {
- template <typename F, typename... A> static inline
- R direct(State*, int, F hook, A&&... args) {
- return hook(
- std::forward<A>(args)...
- );
- }
- };
- template <typename R, typename T>
- struct Layout<R(T)> {
- template <typename F, typename... A> static inline
- R direct(State* state, int n, F hook, A&&... args) {
- return hook(
- std::forward<A>(args)...,
- Value<T>::read(state, n)
- );
- }
- };
- template <typename R, typename T1, typename... TR>
- struct Layout<R(T1, TR...)> {
- template <typename F, typename... A> static inline
- R direct(State* state, int n, F hook, A&&... args) {
- return Layout<R(TR...)>::direct(
- state,
- n + 1,
- hook,
- std::forward<A>(args)...,
- Value<T1>::read(state, n)
- );
- }
- };
- template <typename K, typename V, typename... R>
- struct EntryPusher {
- static inline
- void push(State* state, int index, K&& key, V&& value, R&&... rest) {
- EntryPusher<K, V>::push(state, index, std::forward<K>(key), std::forward<V>(value));
- EntryPusher<R...>::push(state, index, std::forward<R>(rest)...);
- }
- };
- template <typename K, typename V>
- struct EntryPusher<K, V> {
- static inline
- void push(State* state, int index, K&& key, V&& value) {
- assert(1 == luwra::push(state, key));
- assert(1 == luwra::push(state, value));
- lua_rawset(state, index < 0 ? index - 2 : index);
- }
- };
- }
- /**
- * Assuming a stack layout as follows (where A = A0, A1 ... An):
- *
- * Position | Parameter
- * ----------+-----------
- * pos + n | An xn
- * ... | ...
- * pos + 1 | A1 x1
- * pos + 0 | A0 x0
- * ... | ...
- *
- * Given a function `R f(A0, A1, ... An)` you are able to map over
- * the values on the stack on the stack like so:
- *
- * R my_result = apply(lua_state, pos, f);
- *
- * which is equivalent to
- *
- * R my_result = f(x0, x1, ... xn);
- *
- * where x0, x1, ... xn are the values on the stack.
- */
- template <typename R, typename... A> static inline
- R apply(State* state, int pos, R (*function_pointer)(A...)) {
- return internal::Layout<R(A...)>::direct(state, pos, function_pointer);
- }
- /**
- * Same as `apply(state, 1, function_pointer)`.
- */
- template <typename R, typename... A> static inline
- R apply(State* state, R (*function_pointer)(A...)) {
- return apply(state, 1, function_pointer);
- }
- /**
- * Specialization of `apply` which works for `std::function`.
- */
- template <typename R, typename... A> static inline
- R apply(State* state, int pos, const std::function<R(A...)>& function_object) {
- return internal::Layout<R(A...)>::direct(state, pos, function_object);
- }
- /**
- * Same as `apply(state, 1, function_object)`.
- */
- template <typename R, typename... A> static inline
- R apply(State* state, const std::function<R(A...)>& function_object) {
- return apply(state, 1, function_object);
- }
- /**
- * Check if two values are equal.
- */
- static inline
- bool equal(State* state, int index1, int index2) {
- #if LUA_VERSION_NUM <= 501
- return lua_equal(state, index1, index2);
- #else
- return lua_compare(state, index1, index2, LUA_OPEQ);
- #endif
- }
- /**
- * Register a value as a global.
- */
- template <typename V> static inline
- void setGlobal(State* state, const std::string& name, V value) {
- assert(1 == push(state, value));
- lua_setglobal(state, name.c_str());
- }
- /**
- * Retrieve a global value.
- */
- template <typename V> static inline
- V getGlobal(State* state, const std::string& name) {
- lua_getglobal(state, name.c_str());
- V instance = read<V>(state, -1);
- lua_pop(state, 1);
- return instance;
- }
- /**
- * Set multiple fields at once. Allows you to provide multiple key-value pairs.
- */
- template <typename... R> static inline
- void setFields(State* state, int index, R&&... args) {
- static_assert(sizeof...(R) % 2 == 0, "Field parameters must appear in pairs");
- internal::EntryPusher<R...>::push(state, index, std::forward<R>(args)...);
- }
- /**
- * Create a new table and set its fields.
- */
- template <typename... R> static inline
- void newTable(State* state, R&&... args) {
- lua_newtable(state);
- setFields(state, lua_gettop(state), std::forward<R>(args)...);
- }
- LUWRA_NS_END
- #endif
|