Skip to content

Commit

Permalink
Add support for C++ object registration.
Browse files Browse the repository at this point in the history
In addition, this adds partial specializations for Fun and ClassFun
to permit calling of functions that do not return values.
  • Loading branch information
jeremyong committed Jan 21, 2014
1 parent 5abf516 commit c2b9a43
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 76 deletions.
42 changes: 42 additions & 0 deletions include/BaseFun.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <functional>
#include <tuple>
#include "util.h"

namespace sel {
struct BaseFun {
virtual ~BaseFun() {}
virtual int Apply(lua_State *l) = 0;
};

namespace detail {

int _lua_dispatcher(lua_State *l);

template <typename Ret, typename... Args, std::size_t... N>
Ret _lift(std::function<Ret(Args...)> fun,
std::tuple<Args...> args,
_indices<N...>) {
return fun(std::get<N>(args)...);
}

template <typename Ret, typename... Args>
Ret _lift(std::function<Ret(Args...)> fun,
std::tuple<Args...> args) {
return _lift(fun, args, typename _indices_builder<sizeof...(Args)>::type());
}


template <typename... T, std::size_t... N>
std::tuple<T...> _get_args(lua_State *l, _indices<N...>) {
return std::make_tuple(_check_get<T>(l, N + 1)...);
}

template <typename... T>
std::tuple<T...> _get_args(lua_State *l) {
constexpr std::size_t num_args = sizeof...(T);
return _get_args<T...>(l, typename _indices_builder<num_args>::type());
}
}
}
55 changes: 55 additions & 0 deletions include/Class.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include "ClassFun.h"
#include <functional>
#include "LuaName.h"
#include <memory>
#include "State.h"
#include <string>
#include "util.h"
#include <utility>
#include <vector>

namespace sel {
struct BaseClass {
virtual ~BaseClass() {}
};
template <typename T, typename... Funs>
class Class : public BaseClass {
private:
LuaName _name;
std::vector<std::unique_ptr<BaseFun>> _funs;

template <typename Ret, typename... Args>
void _register_fun(lua_State *state,
T *t,
const char *fun_name,
Ret(T::*fun)(Args...)) {
std::function<Ret(Args...)> lambda = [t, fun](Args... args) {
return (t->*fun)(args...);
};
constexpr int arity = detail::_arity<Ret>::value;
_funs.emplace_back(
new ClassFun<arity, Ret, Args...>
{state, std::string(fun_name), lambda});
}

void _register_funs(lua_State *state, T *t) {}

template <typename F, typename... Fs>
void _register_funs(lua_State *state, T *t,
std::pair<const char *, F> fun,
std::pair<const char *, Fs>... funs) {
_register_fun(state, t, fun.first, fun.second);
_register_funs(state, t, funs...);
}
public:
Class(lua_State *&state, T *t, const std::string &name,
std::pair<const char *, Funs>... funs)
: _name(state, name) {
lua_createtable(state, 0, sizeof...(Funs));
_register_funs(state, t, funs...);
_name.Register();
}
};
}
69 changes: 69 additions & 0 deletions include/ClassFun.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#pragma once

#include "BaseFun.h"
#include "LuaName.h"
#include <string>

namespace sel {

template <int N, typename Ret, typename... Args>
class ClassFun : public BaseFun {
private:
using _return_type = Ret;
using _fun_type = std::function<Ret(Args...)>;
_fun_type _fun;

public:
ClassFun(lua_State *l,
const std::string &name,
_return_type(*fun)(Args...))
: ClassFun(l, name, _fun_type{fun}) {}

ClassFun(lua_State *l,
const std::string &name,
_fun_type fun) : _fun(fun) {
lua_pushlightuserdata(l, (void *)static_cast<BaseFun *>(this));
lua_pushcclosure(l, &detail::_lua_dispatcher, 1);
lua_setfield(l, -2, name.c_str());
}

// Each application of a function receives a new Lua context so
// this argument is necessary.
int Apply(lua_State *l) {
std::tuple<Args...> args = detail::_get_args<Args...>(l);
_return_type value = detail::_lift(_fun, args);
detail::_push(l, std::forward<_return_type>(value));
return N;
}
};

template <typename Ret, typename... Args>
class ClassFun<0, Ret, Args...> : public BaseFun {
private:
using _return_type = Ret;
using _fun_type = std::function<Ret(Args...)>;
_fun_type _fun;

public:
ClassFun(lua_State *l,
const std::string &name,
_return_type(*fun)(Args...))
: ClassFun(l, name, _fun_type{fun}) {}

ClassFun(lua_State *l,
const std::string &name,
_fun_type fun) : _fun(fun) {
lua_pushlightuserdata(l, (void *)static_cast<BaseFun *>(this));
lua_pushcclosure(l, &detail::_lua_dispatcher, 1);
lua_setfield(l, -2, name.c_str());
}

// Each application of a function receives a new Lua context so
// this argument is necessary.
int Apply(lua_State *l) {
std::tuple<Args...> args = detail::_get_args<Args...>(l);
detail::_lift(_fun, args);
return 0;
}
};
}
81 changes: 34 additions & 47 deletions include/Fun.h
Original file line number Diff line number Diff line change
@@ -1,59 +1,17 @@
#pragma once

#include <functional>
#include "LuaGlobal.h"
#include "BaseFun.h"
#include "LuaName.h"
#include <string>
#include <tuple>
#include "util.h"

extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}

namespace sel {
namespace detail {
template <typename Ret, typename... Args, std::size_t... N>
Ret _lift(std::function<Ret(Args...)> fun,
std::tuple<Args...> args,
_indices<N...>) {
return fun(std::get<N>(args)...);
}

template <typename Ret, typename... Args>
Ret _lift(std::function<Ret(Args...)> fun,
std::tuple<Args...> args) {
return _lift(fun, args, typename _indices_builder<sizeof...(Args)>::type());
}


template <typename... T, std::size_t... N>
std::tuple<T...> _get_args(lua_State *l, _indices<N...>) {
return std::make_tuple(_check_get<T>(l, N + 1)...);
}

template <typename... T>
std::tuple<T...> _get_args(lua_State *l) {
constexpr std::size_t num_args = sizeof...(T);
return _get_args<T...>(l, typename _indices_builder<num_args>::type());
}

int _lua_dispatcher(lua_State *l);
}

struct BaseFun {
virtual ~BaseFun() {}
virtual int Apply(lua_State *l) = 0;
};

template <int N, typename Ret, typename... Args>
class Fun : public BaseFun {
private:
using _return_type = Ret;
using _fun_type = std::function<Ret(Args...)>;
_fun_type _fun;
LuaGlobal _global;
LuaName _name;

public:
Fun(lua_State *&l,
Expand All @@ -63,10 +21,10 @@ class Fun : public BaseFun {

Fun(lua_State *&l,
const std::string &name,
_fun_type fun) : _fun(fun), _global(l, name) {
_fun_type fun) : _fun(fun), _name(l, name) {
lua_pushlightuserdata(l, (void *)static_cast<BaseFun *>(this));
lua_pushcclosure(l, &detail::_lua_dispatcher, 1);
_global.Register();
_name.Register();
}

// Each application of a function receives a new Lua context so
Expand All @@ -78,5 +36,34 @@ class Fun : public BaseFun {
return N;
}
};
template <typename Ret, typename... Args>
class Fun<0, Ret, Args...> : public BaseFun {
private:
using _return_type = Ret;
using _fun_type = std::function<Ret(Args...)>;
_fun_type _fun;
LuaName _name;

public:
Fun(lua_State *&l,
const std::string &name,
_return_type(*fun)(Args...))
: Fun(l, name, _fun_type{fun}) {}

Fun(lua_State *&l,
const std::string &name,
_fun_type fun) : _fun(fun), _name(l, name) {
lua_pushlightuserdata(l, (void *)static_cast<BaseFun *>(this));
lua_pushcclosure(l, &detail::_lua_dispatcher, 1);
_name.Register();
}

// Each application of a function receives a new Lua context so
// this argument is necessary.
int Apply(lua_State *l) {
std::tuple<Args...> args = detail::_get_args<Args...>(l);
detail::_lift(_fun, args);
return 0;
}
};
}
13 changes: 8 additions & 5 deletions include/LuaGlobal.h → include/LuaName.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ namespace sel {
* context in which it was registered still exists before doing so.
* Prevents copying but permits moving.
*/
class LuaGlobal {
class LuaName {
private:
lua_State **_l;
std::string _name;

public:
LuaGlobal(lua_State *&l, const std::string &name) : _l(&l), _name(name) {}
LuaGlobal(const LuaGlobal &other) = delete;
LuaGlobal(LuaGlobal &&other)
LuaName(lua_State *&l, const std::string &name) : _l(&l), _name(name) {}
LuaName(const LuaName &other) = delete;
LuaName(LuaName &&other)
: _l(other._l),
_name(other._name) {
*other._l = nullptr;
}
~LuaGlobal() {
~LuaName() {
if (_l != nullptr && *_l != nullptr) {
lua_pushnil(*_l);
lua_setglobal(*_l, _name.c_str());
Expand All @@ -38,5 +38,8 @@ class LuaGlobal {
lua_setglobal(*_l, _name.c_str());
}
}

std::string GetName() const {return _name;}
lua_State *GetState() {return *_l;}
};
}
Loading

0 comments on commit c2b9a43

Please sign in to comment.