Skip to content

Commit

Permalink
Merge pull request #111 from AnonymousProgrammerLandau/lessen_use_of_…
Browse files Browse the repository at this point in the history
…std_function

Lessen use of std function
  • Loading branch information
jeremyong committed Oct 28, 2015
2 parents bd7a3f1 + d3a0854 commit ab633b1
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 122 deletions.
30 changes: 29 additions & 1 deletion include/selene/LuaRef.h
@@ -1,6 +1,8 @@
#pragma once

#include <memory>
#include "primitives.h"
#include "ResourceHandler.h"

extern "C" {
#include <lua.h>
Expand Down Expand Up @@ -28,8 +30,34 @@ class LuaRef {
LuaRef(lua_State *state, int ref)
: _ref(new int{ref}, detail::LuaRefDeleter{state}) {}

void Push(lua_State *state) {
void Push(lua_State *state) const {
lua_rawgeti(state, LUA_REGISTRYINDEX, *_ref);
}
};

template <typename T>
LuaRef make_Ref(lua_State * state, T&& t) {
detail::_push(state, std::forward<T>(t));
return LuaRef(state, luaL_ref(state, LUA_REGISTRYINDEX));
}

namespace detail {
void append_ref_recursive(lua_State *, std::vector<LuaRef> &) {}

template <typename Head, typename... Tail>
void append_ref_recursive(lua_State * state, std::vector<LuaRef> & refs, Head&& head, Tail&&... tail) {
refs.push_back(make_Ref(state, std::forward<Head>(head)));

append_ref_recursive(state, refs, std::forward<Tail>(tail)...);
}
}

template <typename... Args>
std::vector<LuaRef> make_Refs(lua_State * state, Args&&... args) {
std::vector<LuaRef> refs;
refs.reserve(sizeof...(Args));

detail::append_ref_recursive(state, refs, std::forward<Args>(args)...);
return refs;
}
}
34 changes: 21 additions & 13 deletions include/selene/ResourceHandler.h
Expand Up @@ -2,26 +2,34 @@

namespace sel {

template<typename Signature>
class CallOnce;
class MovingFlag {
bool flag = false;

template<typename... Args>
class CallOnce<void(Args...)> {
std::function<void(Args...)> _f;
public:
CallOnce() = default;
MovingFlag() = default;

CallOnce(std::function<void(Args...)> f) : _f(std::move(f)) {}
MovingFlag(MovingFlag const &) = default;

void operator()(Args... args) {
if (_f) {
auto consume_f = std::move(_f);
consume_f(std::forward<Args>(args)...);
}
MovingFlag & operator=(MovingFlag const &) = default;

MovingFlag(MovingFlag && that) noexcept
: flag(that.flag) {
that = false;
}

MovingFlag & operator=(MovingFlag && that) noexcept {
this->flag = that.flag;
that = false;
return *this;
}

operator bool() const {
return static_cast<bool>(_f);
return flag;
}

MovingFlag & operator=(bool x) {
flag = x;
return *this;
}
};

Expand Down
193 changes: 85 additions & 108 deletions include/selene/Selector.h
Expand Up @@ -3,6 +3,7 @@
#include "exception.h"
#include "exotics.h"
#include <functional>
#include "LuaRef.h"
#include "Registry.h"
#include "ResourceHandler.h"
#include <string>
Expand Down Expand Up @@ -45,38 +46,46 @@ class Selector {
Registry *_registry;
ExceptionHandler *_exception_handler;
std::string _name;
using Fun = std::function<void()>;
using PFun = std::function<void(Fun)>;

// Traverses the structure up to this element
std::vector<Fun> _traversal;
std::vector<LuaRef> _traversal;

// Pushes this element to the stack
Fun _get;
// Sets this element from a function that pushes a value to the
// stack.
PFun _put;
// Key of the value to act upon.
LuaRef _key;

// Functor is stored when the () operator is invoked. The argument
// is used to indicate how many return values are expected
mutable CallOnce<void(int)> _functor;
std::vector<LuaRef> _functor_arguments;

// Functor is activated when the () operator is invoked.
mutable MovingFlag _functor_active;

Selector(lua_State *s, Registry &r, ExceptionHandler &eh, const std::string &name,
std::vector<Fun> traversal, Fun get, PFun put)
std::vector<LuaRef> traversal, LuaRef key)
: _state(s), _registry(&r), _exception_handler(&eh), _name(name), _traversal(traversal),
_get(get), _put(put) {}
_key(key) {}

Selector(lua_State *s, Registry &r, ExceptionHandler &eh, const std::string& name)
: _state(s), _registry(&r), _exception_handler(&eh), _name(name) {
const auto state = _state; // gcc-5.1 doesn't support implicit member capturing
// `name' is passed by value because lambda's lifetime may be longer than lifetime of `name'
_get = [state, name]() {
lua_getglobal(state, name.c_str());
};
_put = [state, name](Fun fun) {
fun();
lua_setglobal(state, name.c_str());
};
: _state(s), _registry(&r), _exception_handler(&eh), _name(name),
_key(make_Ref(s, name)) {}

void _get(LuaRef r) const {
r.Push(_state);
lua_gettable(_state, -2);
lua_remove(_state, lua_absindex(_state, -2));
}

// Pushes this element to the stack
void _get() const {
_get(_key);
}

// Sets this element from a function that pushes a value to the
// stack.
template<typename PushFunction>
void _put(PushFunction fun) const {
_key.Push(_state);
fun();
lua_settable(_state, -3);
lua_pop(_state, 1);
}

void _check_create_table() const {
Expand All @@ -88,26 +97,60 @@ class Selector {
auto put = [this]() {
lua_newtable(_state);
};
_traverse();
_put(put);
}
}

void _traverse() const {
for (auto &fun : _traversal) {
fun();
lua_pushglobaltable(_state);
for (auto &key : _traversal) {
_get(key);
}
}

void _evaluate_store(Fun push) const {
template <typename Fun>
void _evaluate_store(Fun&& push) const {
ResetStackOnScopeExit save(_state);
_traverse();
_put(std::move(push));
_put(std::forward<Fun>(push));
}

void _evaluate_retrieve(int num_results) const {
_traverse();
_get();
_functor(num_results);
_evaluate_function_call(num_results);
}

void _evaluate_function_call(int num_ret) const {
if(!_functor_active) return;
_functor_active = false;
// install handler, and swap(handler, function) on lua stack
int handler_index = SetErrorHandler(_state);
int func_index = handler_index - 1;
#if LUA_VERSION_NUM >= 502
lua_pushvalue(_state, func_index);
lua_copy(_state, handler_index, func_index);
lua_replace(_state, handler_index);
#else
lua_pushvalue(_state, func_index);
lua_push_value(_state, handler_index);
lua_replace(_state, func_index);
lua_replace(_state, handler_index);
#endif
// call lua function with error handler
for(auto const & arg : _functor_arguments) {
arg.Push(_state);
}
auto const statusCode =
lua_pcall(_state, _functor_arguments.size(), num_ret, handler_index - 1);

// remove error handler
lua_remove(_state, handler_index - 1);

if (statusCode != LUA_OK) {
_exception_handler->Handle_top_of_stack(statusCode, _state);
}
}
public:

Expand All @@ -118,20 +161,20 @@ class Selector {

~Selector() noexcept(false) {
// If there is a functor is not empty, execute it and collect no args
if (_functor) {
if (_functor_active) {
ResetStackOnScopeExit save(_state);
_traverse();
_get();
if (std::uncaught_exception())
{
try {
_functor(0);
_evaluate_function_call(0);
} catch (...) {
// We are already unwinding, ignore further exceptions.
// As of C++17 consider std::uncaught_exceptions()
}
} else {
_functor(0);
_evaluate_function_call(0);
}
}
}
Expand All @@ -140,38 +183,12 @@ class Selector {
bool operator==(Selector &other) = delete;

template <typename... Args>
const Selector operator()(Args... args) const {
auto tuple_args = std::make_tuple(std::forward<Args>(args)...);
constexpr int num_args = sizeof...(Args);
const Selector operator()(Args&&... args) const {
Selector copy{*this};
const auto state = _state; // gcc-5.1 doesn't support implicit member capturing
const auto eh = _exception_handler;
copy._functor = CallOnce<void(int)>{[state, eh, tuple_args, num_args](int num_ret) {
// install handler, and swap(handler, function) on lua stack
int handler_index = SetErrorHandler(state);
int func_index = handler_index - 1;
#if LUA_VERSION_NUM >= 502
lua_pushvalue(state, func_index);
lua_copy(state, handler_index, func_index);
lua_replace(state, handler_index);
#else
lua_pushvalue(state, func_index);
lua_push_value(state, handler_index);
lua_replace(state, func_index);
lua_replace(state, handler_index);
#endif
// call lua function with error handler
detail::_push(state, tuple_args);
auto const statusCode =
lua_pcall(state, num_args, num_ret, handler_index - 1);

// remove error handler
lua_remove(state, handler_index - 1);

if (statusCode != LUA_OK) {
eh->Handle_top_of_stack(statusCode, state);
}
}};
copy._functor_arguments = make_Refs(_state, std::forward<Args>(args)...);
copy._functor_active = true;
return copy;
}

Expand Down Expand Up @@ -321,17 +338,8 @@ class Selector {
Selector&& operator[](const std::string& name) && {
_name += std::string(".") + name;
_check_create_table();
_traversal.push_back(_get);
const auto state = _state; // gcc-5.1 doesn't support implicit member capturing
// `name' is passed by value because lambda lifetime may be longer than `name'
_get = [state, name]() {
lua_getfield(state, -1, name.c_str());
};
_put = [state, name](Fun fun) {
fun();
lua_setfield(state, -2, name.c_str());
lua_pop(state, 1);
};
_traversal.push_back(_key);
_key = make_Ref(_state, name);
return std::move(*this);
}
Selector&& operator[](const char* name) && {
Expand All @@ -340,37 +348,17 @@ class Selector {
Selector&& operator[](const int index) && {
_name += std::string(".") + std::to_string(index);
_check_create_table();
_traversal.push_back(_get);
const auto state = _state; // gcc-5.1 doesn't support implicit member capturing
_get = [state, index]() {
lua_pushinteger(state, index);
lua_gettable(state, -2);
};
_put = [state, index](Fun fun) {
lua_pushinteger(state, index);
fun();
lua_settable(state, -3);
lua_pop(state, 1);
};
_traversal.push_back(_key);
_key = make_Ref(_state, index);
return std::move(*this);
}
#endif // HAS_REF_QUALIFIERS
Selector operator[](const std::string& name) const REF_QUAL_LVALUE {
auto n = _name + "." + name;
_check_create_table();
auto traversal = _traversal;
traversal.push_back(_get);
const auto state = _state; // gcc-5.1 doesn't support implicit member capturing
// `name' is passed by value because lambda lifetime may be longer than `name'
Fun get = [state, name]() {
lua_getfield(state, -1, name.c_str());
};
PFun put = [state, name](Fun fun) {
fun();
lua_setfield(state, -2, name.c_str());
lua_pop(state, 1);
};
return Selector{_state, *_registry, *_exception_handler, n, traversal, get, put};
traversal.push_back(_key);
return Selector{_state, *_registry, *_exception_handler, n, traversal, make_Ref(_state, name)};
}
Selector operator[](const char* name) const REF_QUAL_LVALUE {
return (*this)[std::string{name}];
Expand All @@ -379,19 +367,8 @@ class Selector {
auto name = _name + "." + std::to_string(index);
_check_create_table();
auto traversal = _traversal;
traversal.push_back(_get);
const auto state = _state; // gcc-5.1 doesn't support implicit member capturing
Fun get = [state, index]() {
lua_pushinteger(state, index);
lua_gettable(state, -2);
};
PFun put = [state, index](Fun fun) {
lua_pushinteger(state, index);
fun();
lua_settable(state, -3);
lua_pop(state, 1);
};
return Selector{_state, *_registry, *_exception_handler, name, traversal, get, put};
traversal.push_back(_key);
return Selector{_state, *_registry, *_exception_handler, name, traversal, make_Ref(_state, index)};
}

friend bool operator==(const Selector &, const char *);
Expand Down

0 comments on commit ab633b1

Please sign in to comment.