Too much stuff

* Implemented lua using kaguya, only for config files for now
* Moved color struct to its own header
* statically link glew instead of including the source in the project
* Other stuff that I don't remember
This commit is contained in:
Adrian Hedqvist 2017-10-18 12:22:28 +02:00
parent 2acbef3893
commit ec131d8bda
62 changed files with 12505 additions and 56777 deletions

View file

@ -6,12 +6,30 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Za")
endif(MSVC)
project(dungeon)
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(Lua REQUIRED)
find_package(SDL2 REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} "libs/glm")
link_libraries(${OPENGL_LIBRARIES} ${SDL2_LIBRARY})
include_directories(
${OPENGL_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
${GLEW_INCLUDE_DIRS}
${LUA_INCLUDE_DIR}
"libs/glm"
"libs/kaguya-1.3.2/include"
)
link_libraries(
${OPENGL_LIBRARIES}
${SDL2_LIBRARY}
${GLEW_LIBRARIES}
${LUA_LIBRARIES}
)
file(GLOB SOURCES "src/*.cpp" "src/*.c" "src/*.h")
add_executable(dungeon ${SOURCES})

View file

@ -1,7 +1,8 @@
@echo off
:: Set your paths here
set SDL2_PATH="E:\Programmering\C++\_libs\SDL2-2.0.5"
set SDL2_PATH="..\_libs\SDL2-2.0.5"
set LUA_DIR="E:\Programmering\C++\_libs\lua-5.3.4"
mkdir build
cd build

10
build_msys.bat Normal file
View file

@ -0,0 +1,10 @@
@echo off
:: Set your paths here
set SDL2_PATH="/e/Programmering/C++/_libs/SDL2-2.0.5/msys/x86_64-w64-mingw32"
set LUA_DIR="/e/Programmering/C++/_libs/lua-5.3.4"
mkdir build
cd build
cmake build -D LUA_DIR:STRING=%LUA_DIR% -D SDL2_PATH:STRING=%SDL2_PATH% ..
cd ..

81
cmake/FindLua53.cmake Normal file
View file

@ -0,0 +1,81 @@
# Locate Lua library
# This module defines
# LUA53_FOUND, if false, do not try to link to Lua
# LUA53_LIBRARIES
# LUA53_INCLUDE_DIR, where to find lua.h
# LUA53_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
#
# Note that the expected include convention is
# #include "lua.h"
# and not
# #include <lua/lua.h>
# This is because, the lua location is not standardized and may exist
# in locations other than lua/
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
FIND_PATH(LUA53_INCLUDE_DIR lua.h
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES include/lua53 include/lua5.3 include/lua include
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
FIND_LIBRARY(LUA53_LIBRARY
NAMES liblua53 lua53 lua5.3 lua-5.3 liblua lua
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw
/opt/local
/opt/csw
/opt
)
IF(LUA53_LIBRARY)
# include the math library for Unix
IF(UNIX AND NOT APPLE)
FIND_LIBRARY(LUA53_MATH_LIBRARY m)
SET( LUA53_LIBRARIES "${LUA53_LIBRARY};${LUA53_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
# For Windows and Mac, don't need to explicitly include the math library
ELSE(UNIX AND NOT APPLE)
SET( LUA53_LIBRARIES "${LUA53_LIBRARY}" CACHE STRING "Lua Libraries")
ENDIF(UNIX AND NOT APPLE)
ENDIF(LUA53_LIBRARY)
IF(LUA53_INCLUDE_DIR AND EXISTS "${LUA53_INCLUDE_DIR}/lua.h")
FILE(STRINGS "${LUA53_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA53_VERSION_STRING "${lua_version_str}")
UNSET(lua_version_str)
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LUA52_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua53
REQUIRED_VARS LUA53_LIBRARIES LUA53_INCLUDE_DIR
VERSION_VAR LUA53_VERSION_STRING)
MARK_AS_ADVANCED(LUA53_INCLUDE_DIR LUA53_LIBRARIES LUA53_LIBRARY LUA53_MATH_LIBRARY)

7
config.lua Normal file
View file

@ -0,0 +1,7 @@
function dungeon.config(cfg)
cfg.window.fullscreen = false
cfg.window.width = 792
cfg.window.height = 300
cfg.gfx.vsync = false
cfg.gfx.wireframes = false
end

View file

@ -0,0 +1,277 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include "kaguya/kaguya.hpp"
/// @addtogroup another_binding_api
/// @brief Boost.python like binding API.(experimental)
/// this api is not multi-thread-safe.
/// @{
#if defined(KAGUYA_DYNAMIC_LIB)
#if defined(_WIN32) || defined(_WIN64)
#define KAGUYA_EXPORT extern "C" __declspec(dllexport)
#else
#define KAGUYA_EXPORT extern "C" __attribute__((visibility("default")))
#endif
#else
#define KAGUYA_EXPORT
#endif
/// @brief start define binding
#define KAGUYA_BINDINGS(MODULE_NAME) \
\
void KAGUYA_PP_CAT(kaguya_bind_internal_, MODULE_NAME)(); \
\
KAGUYA_EXPORT int \
KAGUYA_PP_CAT(luaopen_, MODULE_NAME)(lua_State * L) { \
return kaguya::detail::bind_internal( \
L, &KAGUYA_PP_CAT(kaguya_bind_internal_, MODULE_NAME)); \
} \
\
void KAGUYA_PP_CAT(kaguya_bind_internal_, MODULE_NAME)()
namespace kaguya {
namespace detail {
struct scope_stack {
LuaTable current_scope() {
return !stack.empty() ? stack.back() : LuaTable();
}
static scope_stack &instance() {
static scope_stack instance_;
return instance_;
}
void push(const LuaTable &table) { stack.push_back(table); }
void pop() { stack.pop_back(); }
private:
scope_stack() {}
scope_stack(const scope_stack &);
scope_stack &operator=(const scope_stack &);
std::vector<LuaTable> stack;
};
}
/// @ingroup another_binding_api
/// @brief binding scope
struct scope {
scope(const std::string &name) : pushed_(true) {
detail::scope_stack &stack = detail::scope_stack::instance();
LuaTable current = stack.current_scope();
if (!current[name]) {
current[name] = NewTable();
}
scope_table_ = current[name];
stack.push(scope_table_);
}
scope(const LuaTable &t) : pushed_(true) {
scope_table_ = t;
detail::scope_stack::instance().push(scope_table_);
}
scope() : pushed_(false) {
detail::scope_stack &stack = detail::scope_stack::instance();
scope_table_ = stack.current_scope();
}
TableKeyReferenceProxy<std::string> attr(const std::string &name) {
return scope_table_.operator[]<std::string>(name);
}
LuaTable table() { return scope_table_; }
~scope() {
if (pushed_) {
detail::scope_stack::instance().pop();
}
}
private:
LuaTable scope_table_;
bool pushed_;
};
namespace detail {
inline int bind_internal(lua_State *L, void (*bindfn)()) {
int count = lua_gettop(L);
kaguya::State state(L);
LuaTable l = state.newTable();
l.push();
scope scope(l);
bindfn();
return lua_gettop(L) - count;
}
}
/// @ingroup another_binding_api
/// @brief define class binding
template <typename ClassType, typename BaseType = void>
struct class_ : private UserdataMetatable<ClassType, BaseType> {
class_(const std::string &name) : name_(name) {}
~class_() {
LuaTable scope = detail::scope_stack::instance().current_scope();
if (scope) {
scope[name_].setClass(*this);
}
}
#if KAGUYA_USE_CPP11
template <typename... Args> class_ &constructor() {
this->template setConstructors<ClassType(Args...)>();
return *this;
}
template <typename... Constructors> class_ &constructors() {
this->template setConstructors<Constructors...>();
return *this;
}
#else
class_ &constructor() {
this->template setConstructors<ClassType()>();
return *this;
}
#define KAGUYA_ADD_CON_FN_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> class_ &constructor() { \
this->template setConstructors<ClassType( \
KAGUYA_PP_TEMPLATE_ARG_REPEAT(N))>(); \
return *this; \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_ADD_CON_FN_DEF)
#undef KAGUYA_ADD_CON_FN_DEF
class_ &constructors() {
this->template setConstructors<ClassType()>();
return *this;
}
#define KAGUYA_ADD_CONS_FN_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> class_ &constructors() { \
this->template setConstructors<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>(); \
return *this; \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_ADD_CONS_FN_DEF)
#undef KAGUYA_ADD_CONS_FN_DEF
#endif
/// @ingroup another_binding_api
/// @brief function binding
template <typename F> class_ &function(const char *name, F f) {
this->addFunction(name, f);
return *this;
}
template <typename F>
class_ &function(const char *name, FunctionInvokerType<F> f) {
this->addStaticField(name, f);
return *this;
}
/// @ingroup another_binding_api
/// @brief property binding
template <typename F> class_ &property(const char *name, F f) {
this->addProperty(name, f);
return *this;
}
/// @ingroup another_binding_api
/// @brief property binding with getter and sette function
template <typename Getter, typename Setter>
class_ &property(const char *name, Getter getter, Setter setter) {
this->addProperty(name, getter, setter);
return *this;
}
/// @brief class function binding
template <typename F> class_ &class_function(const char *name, F f) {
this->addStaticFunction(name, f);
return *this;
}
template <typename F>
class_ &class_function(const char *name, FunctionInvokerType<F> f) {
this->addStaticField(name, f);
return *this;
}
/// @ingroup another_binding_api
/// @brief function binding
template <typename F> class_ &def(const char *name, F f) {
this->addFunction(name, f);
return *this;
}
/// @ingroup another_binding_api
/// @brief property binding with getter and sette function
template <typename Getter, typename Setter>
class_ &add_property(const char *name, Getter getter, Setter setter) {
property(name, getter, setter);
return *this;
}
/// @ingroup another_binding_api
/// @brief property binding
template <typename F> class_ &add_property(const char *name, F f) {
property(name, f);
return *this;
}
/// @ingroup another_binding_api
/// @brief static property binding
template <typename Data>
class_ &add_static_property(const char *name, Data data) {
this->addStaticField(name, data);
return *this;
}
private:
std::string name_;
};
template <typename EnumType> struct enum_ {
enum_(const std::string &name) : enum_scope_table_(scope(name).table()) {}
enum_ &value(const char *name, EnumType data) {
enum_scope_table_[name] = data;
return *this;
}
private:
LuaTable enum_scope_table_;
};
/// @ingroup another_binding_api
/// @brief function binding
template <typename F> void function(const char *name, F f) {
LuaTable scope = detail::scope_stack::instance().current_scope();
if (scope) {
scope[name] = kaguya::function(f);
}
}
template <typename F>
void function(const char *name, FunctionInvokerType<F> f) {
LuaTable scope = detail::scope_stack::instance().current_scope();
if (scope) {
scope[name] = f;
}
}
/// @ingroup another_binding_api
/// @brief function binding
template <typename F> void def(const char *name, F f) {
kaguya::function(name, f);
}
/// @ingroup another_binding_api
/// @brief function binding
template <typename T> void constant(const char *name, T v) {
LuaTable scope = detail::scope_stack::instance().current_scope();
if (scope) {
scope[name] = v;
}
}
}
/// @}

View file

@ -0,0 +1,123 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include "kaguya/config.hpp"
namespace kaguya {
// for lua version compatibility
namespace compat {
#if LUA_VERSION_NUM >= 503
inline int lua_rawgetp_rtype(lua_State *L, int idx, const void *ptr) {
return lua_rawgetp(L, idx, ptr);
}
inline int lua_getfield_rtype(lua_State *L, int idx, const char *k) {
return lua_getfield(L, idx, k);
}
inline int lua_gettable_rtype(lua_State *L, int idx) {
return lua_gettable(L, idx);
}
#elif LUA_VERSION_NUM == 502
inline int lua_rawgetp_rtype(lua_State *L, int idx, const void *ptr) {
lua_rawgetp(L, idx, ptr);
return lua_type(L, -1);
}
#elif LUA_VERSION_NUM < 502
enum LUA_OPEQ { LUA_OPEQ, LUA_OPLT, LUA_OPLE };
inline int lua_compare(lua_State *L, int index1, int index2, int op) {
switch (op) {
case LUA_OPEQ:
return lua_equal(L, index1, index2);
case LUA_OPLT:
return lua_lessthan(L, index1, index2);
case LUA_OPLE:
return lua_equal(L, index1, index2) || lua_lessthan(L, index1, index2);
default:
return 0;
}
}
inline void lua_pushglobaltable(lua_State *L) {
lua_pushvalue(L, LUA_GLOBALSINDEX);
}
inline size_t lua_rawlen(lua_State *L, int index) {
int type = lua_type(L, index);
if (type != LUA_TSTRING && type != LUA_TTABLE && type != LUA_TUSERDATA &&
type != LUA_TLIGHTUSERDATA) {
return 0;
}
return lua_objlen(L, index);
}
inline int lua_resume(lua_State *L, lua_State *from, int nargs) {
KAGUYA_UNUSED(from);
return ::lua_resume(L, nargs);
}
inline int lua_absindex(lua_State *L, int idx) {
return (idx > 0 || (idx <= LUA_REGISTRYINDEX)) ? idx
: lua_gettop(L) + 1 + idx;
}
inline int lua_rawgetp_rtype(lua_State *L, int idx, const void *ptr) {
int absidx = lua_absindex(L, idx);
lua_pushlightuserdata(L, (void *)ptr);
lua_rawget(L, absidx);
return lua_type(L, -1);
}
inline void lua_rawsetp(lua_State *L, int idx, const void *ptr) {
int absidx = lua_absindex(L, idx);
lua_pushvalue(L, -1);
lua_pushlightuserdata(L, (void *)ptr);
lua_replace(L, -3);
lua_rawset(L, absidx);
}
inline void luaL_requiref(lua_State *L, const char *modname,
lua_CFunction openf, int glb) {
lua_pushcfunction(L, openf);
lua_pushstring(L, modname);
lua_call(L, 1, 1);
if (glb) {
lua_pushvalue(L, -1);
lua_setglobal(L, modname);
}
}
inline lua_Number lua_tonumberx(lua_State *L, int index, int *isnum) {
if (isnum) {
*isnum = lua_isnumber(L, index);
}
return lua_tonumber(L, index);
}
#endif
#if LUA_VERSION_NUM < 503
inline void lua_seti(lua_State *L, int index, lua_Integer n) {
int absidx = lua_absindex(L, index);
lua_pushvalue(L, -1);
lua_pushinteger(L, n);
lua_replace(L, -3);
lua_rawset(L, absidx);
}
inline int lua_geti(lua_State *L, int index, lua_Integer i) {
int absidx = lua_absindex(L, index);
lua_pushinteger(L, i);
lua_rawget(L, absidx);
return lua_type(L, -1);
}
inline int lua_getfield_rtype(lua_State *L, int idx, const char *k) {
lua_getfield(L, idx, k);
return lua_type(L, -1);
}
inline int lua_gettable_rtype(lua_State *L, int idx) {
lua_gettable(L, idx);
return lua_type(L, -1);
}
#endif
#if LUA_VERSION_NUM < 501
void lua_createtable(lua_State *L, int narr, int nrec) { lua_newtable(L); }
#endif
}
using namespace compat;
}

View file

@ -0,0 +1,144 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#ifndef KAGUYA_USE_CPP11
#if defined(__cpp_decltype) || __cplusplus >= 201103L || \
(defined(_MSC_VER) && _MSC_VER >= 1800)
#define KAGUYA_USE_CPP11 1
#else
#define KAGUYA_USE_CPP11 0
#endif
#endif
#if KAGUYA_USE_CPP11
#include <functional>
#include <tuple>
#include <memory>
#include <utility>
#include <type_traits>
#include <initializer_list>
#include <array>
#else
#include <boost/function.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/utility/result_of.hpp>
#endif
#ifndef KAGUYA_NO_USERDATA_TYPE_CHECK
#define KAGUYA_NO_USERDATA_TYPE_CHECK 0
#endif
#ifndef KAGUYA_USE_RVALUE_REFERENCE
#if KAGUYA_USE_CPP11
#define KAGUYA_USE_RVALUE_REFERENCE 1
#else
#define KAGUYA_USE_RVALUE_REFERENCE 0
#endif
#endif
#ifdef KAGUYA_NO_VECTOR_AND_MAP_TO_TABLE
#define KAGUYA_NO_STD_VECTOR_TO_TABLE
#define KAGUYA_NO_STD_MAP_TO_TABLE
#endif
#if !KAGUYA_USE_CPP11
#ifndef KAGUYA_FUNCTION_MAX_ARGS
///! max argumeent number for binding function. this define used C++03 only.
#define KAGUYA_FUNCTION_MAX_ARGS 9
#endif
#ifndef KAGUYA_FUNCTION_MAX_TUPLE_SIZE
///! this define used C++03 only.
#define KAGUYA_FUNCTION_MAX_TUPLE_SIZE 9
#endif
#ifndef KAGUYA_FUNCTION_MAX_OVERLOADS
#define KAGUYA_FUNCTION_MAX_OVERLOADS 9
#endif
#endif
#ifndef KAGUYA_CLASS_MAX_BASE_CLASSES
#define KAGUYA_CLASS_MAX_BASE_CLASSES 9
#endif
#ifndef KAGUYA_USE_CXX_ABI_DEMANGLE
#if defined(__GNUC__) || defined(__clang__)
#define KAGUYA_USE_CXX_ABI_DEMANGLE 1
#else
#define KAGUYA_USE_CXX_ABI_DEMANGLE 0
#endif
#endif
#ifndef KAGUYA_USE_SHARED_LUAREF
#define KAGUYA_USE_SHARED_LUAREF 0
#endif
#ifndef KAGUYA_NOEXCEPT
#if KAGUYA_USE_CPP11 && (!defined(_MSC_VER) || _MSC_VER >= 1900)
#define KAGUYA_NOEXCEPT noexcept
#else
#define KAGUYA_NOEXCEPT throw()
#endif
#endif
#ifndef KAGUYA_DEPRECATED_FEATURE
#if __cplusplus >= 201402L && defined(__has_cpp_attribute)
#if __has_cpp_attribute(deprecated)
// C++ standard depecated
#define KAGUYA_DEPRECATED_FEATURE(MSG) [[deprecated(MSG)]]
#endif
#endif
#endif
#ifndef KAGUYA_DEPRECATED_FEATURE
#if defined(_MSC_VER)
// MSVC depecated
#define KAGUYA_DEPRECATED_FEATURE(MSG) __declspec(deprecated(MSG))
#elif defined(__GNUC__) || defined(__clang__)
#define KAGUYA_DEPRECATED_FEATURE(MSG) __attribute__((deprecated))
#else
#define KAGUYA_DEPRECATED_FEATURE(MSG)
#endif
#endif
#define KAGUYA_UNUSED(V) (void)(V)
namespace kaguya {
#if defined(_MSC_VER) && _MSC_VER <= 1500
typedef unsigned char uint8_t;
typedef int int32_t;
typedef long long int64_t;
#endif
namespace standard {
#if KAGUYA_USE_CPP11
using namespace std;
#define KAGUYA_STATIC_ASSERT static_assert
#else
using namespace boost;
#define KAGUYA_STATIC_ASSERT BOOST_STATIC_ASSERT_MSG
#endif
}
#if LUA_VERSION_NUM > 502
typedef lua_Integer luaInt;
#else
typedef int32_t luaInt;
#endif
}

View file

@ -0,0 +1,295 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <map>
#include <cassert>
#include <algorithm>
#include <ostream>
#include "kaguya/config.hpp"
#include "kaguya/error_handler.hpp"
#include "kaguya/type.hpp"
#include "kaguya/utility.hpp"
namespace kaguya {
class LuaTable;
class LuaFunction;
class FunctionResults;
/**
* status of coroutine
*/
enum coroutine_status {
COSTAT_RUNNING, //!< coroutine is running
COSTAT_SUSPENDED, //!< coroutine is suspended
COSTAT_NORMAL, //!<
COSTAT_DEAD //!< coroutine is dead
};
namespace detail {
class FunctionResultProxy {
public:
template <typename RetType>
static RetType ReturnValue(lua_State *state, int restatus, int retindex,
types::typetag<RetType> tag);
static FunctionResults ReturnValue(lua_State *state, int restatus,
int retindex,
types::typetag<FunctionResults> tag);
static void ReturnValue(lua_State *state, int restatus, int retindex,
types::typetag<void> tag);
};
template <typename Derived> class LuaFunctionImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
int push_(lua_State *state) const {
return static_cast<const Derived *>(this)->push(state);
}
public:
/**
* set function environment table
*/
bool setFunctionEnv(const LuaTable &env);
/**
* set function environment to new table
*/
bool setFunctionEnv(NewTable env);
/**
* get function environment table
*/
LuaTable getFunctionEnv() const;
#if KAGUYA_USE_CPP11
template <class Result, class... Args> Result call(Args &&... args) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "nil");
return Result();
}
int argstart = lua_gettop(state) + 1;
push_(state);
int argnum = util::push_args(state, std::forward<Args>(args)...);
int result = lua_pcall_wrap(state, argnum, LUA_MULTRET);
except::checkErrorAndThrow(result, state);
return detail::FunctionResultProxy::ReturnValue(state, result, argstart,
types::typetag<Result>());
}
template <class... Args> FunctionResults operator()(Args &&... args);
#else
#define KAGUYA_CALL_DEF(N) \
template <class Result KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
Result call(KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
lua_State *state = state_(); \
if (!state) { \
except::typeMismatchError(state, "attempt to call nil value"); \
return Result(); \
} \
int argstart = lua_gettop(state) + 1; \
push_(state); \
int argnum = util::push_args(state KAGUYA_PP_ARG_REPEAT_CONCAT(N)); \
int result = lua_pcall_wrap(state, argnum, LUA_MULTRET); \
except::checkErrorAndThrow(result, state); \
return detail::FunctionResultProxy::ReturnValue(state, result, argstart, \
types::typetag<Result>()); \
}
KAGUYA_CALL_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_CALL_DEF)
#undef KAGUYA_RESUME_DEF
inline FunctionResults operator()();
#define KAGUYA_OP_FN_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
inline FunctionResults operator()(KAGUYA_PP_ARG_CR_DEF_REPEAT(N));
#define KAGUYA_FUNCTION_ARGS_DEF(N)
#define KAGUYA_CALL_ARGS(N) KAGUYA_PP_ARG_REPEAT(N)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF)
#undef KAGUYA_OP_FN_DEF
#undef KAGUYA_CALL_ARGS
#undef KAGUYA_FUNCTION_ARGS_DEF
#undef KAGUYA_CALL_DEF
#endif
};
template <typename Derived> class LuaThreadImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
public:
#if KAGUYA_USE_CPP11
template <class Result, class... Args> Result resume(Args &&... args) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "attempt to call nil value");
return Result();
}
util::ScopedSavedStack save(state);
int corStackIndex = pushStackIndex_(state);
lua_State *thread = lua_tothread(state, corStackIndex);
if (!thread) {
except::typeMismatchError(state, "not thread");
return Result();
}
int argstart = 1; // exist function in stack at first resume.
if (lua_status(thread) == LUA_YIELD) {
argstart = 0;
}
util::push_args(thread, std::forward<Args>(args)...);
int argnum = lua_gettop(thread) - argstart;
if (argnum < 0) {
argnum = 0;
}
int result = lua_resume(thread, state, argnum);
except::checkErrorAndThrow(result, thread);
return detail::FunctionResultProxy::ReturnValue(thread, result, 1,
types::typetag<Result>());
}
template <class... Args> FunctionResults operator()(Args &&... args);
#else
#define KAGUYA_RESUME_DEF(N) \
template <class Result KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
Result resume(KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
lua_State *state = state_(); \
if (!state) { \
except::typeMismatchError(state, "attempt to call nil value"); \
return Result(); \
} \
util::ScopedSavedStack save(state); \
int corStackIndex = pushStackIndex_(state); \
lua_State *thread = lua_tothread(state, corStackIndex); \
if (!thread) { \
except::typeMismatchError(state, "not thread"); \
return Result(); \
} \
int argstart = 1; \
if (lua_status(thread) == LUA_YIELD) { \
argstart = 0; \
} \
util::push_args(thread KAGUYA_PP_ARG_REPEAT_CONCAT(N)); \
int argnum = lua_gettop(thread) - argstart; \
if (argnum < 0) { \
argnum = 0; \
} \
int result = lua_resume(thread, state, argnum); \
except::checkErrorAndThrow(result, thread); \
return detail::FunctionResultProxy::ReturnValue(thread, result, 1, \
types::typetag<Result>()); \
}
KAGUYA_RESUME_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_RESUME_DEF)
#undef KAGUYA_RESUME_DEF
inline FunctionResults operator()();
#define KAGUYA_OP_FN_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
inline FunctionResults operator()(KAGUYA_PP_ARG_CR_DEF_REPEAT(N));
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF)
#undef KAGUYA_OP_FN_DEF
#endif
//!
//! @return state status
//!
int threadStatus() const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "attempt to call nil value");
return LUA_ERRRUN;
}
util::ScopedSavedStack save(state);
int corStackIndex = pushStackIndex_(state);
lua_State *thread = lua_tothread(state, corStackIndex);
if (!thread) {
except::typeMismatchError(state, "not thread");
return LUA_ERRRUN;
}
return lua_status(thread);
}
//! deprecate
int thread_status() const { return threadStatus(); }
//!
//! @return coroutine status
//!
coroutine_status costatus(lua_State *l = 0) const {
lua_State *state = state_();
if (!state) {
return COSTAT_DEAD;
}
util::ScopedSavedStack save(state);
int corStackIndex = pushStackIndex_(state);
lua_State *thread = lua_tothread(state, corStackIndex);
if (!thread) {
except::typeMismatchError(state, "not thread");
return COSTAT_DEAD;
} else if (thread == l) {
return COSTAT_RUNNING;
} else {
switch (lua_status(thread)) {
case LUA_YIELD:
return COSTAT_SUSPENDED;
case 0: // LUA_OK
{
if (lua_gettop(thread) == 0) {
return COSTAT_DEAD;
} else {
return COSTAT_SUSPENDED;
}
}
default:
break;
}
}
return COSTAT_DEAD;
}
//!
//! @return if coroutine status is dead, return true. Otherwise return false
//!
bool isThreadDead() const { return costatus() == COSTAT_DEAD; }
/// @brief set function for thread running.
void setFunction(const LuaFunction &f);
/// @brief get lua thread
lua_State *getthread() {
lua_State *state = state_();
util::ScopedSavedStack save(state);
int corStackIndex = pushStackIndex_(state);
return lua_tothread(state, corStackIndex);
}
};
}
}

View file

@ -0,0 +1,318 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <map>
#include <cassert>
#include <algorithm>
#include <ostream>
#include "kaguya/config.hpp"
#include "kaguya/error_handler.hpp"
#include "kaguya/type.hpp"
#include "kaguya/utility.hpp"
namespace kaguya {
/// @brief StackTop tag type
struct StackTop {};
namespace Ref {
/// @brief NoMainCheck tag type
struct NoMainCheck {};
/// @brief reference to Lua stack value
class StackRef {
protected:
lua_State *state_;
int stack_index_;
mutable bool pop_;
#if KAGUYA_USE_CPP11
StackRef(StackRef &&src)
: state_(src.state_), stack_index_(src.stack_index_), pop_(src.pop_) {
src.pop_ = false;
}
StackRef &operator=(StackRef &&src) {
state_ = src.state_;
stack_index_ = src.stack_index_;
pop_ = src.pop_;
src.pop_ = false;
return *this;
}
StackRef(const StackRef &src) = delete;
StackRef &operator=(const StackRef &src) = delete;
#else
StackRef(const StackRef &src)
: state_(src.state_), stack_index_(src.stack_index_), pop_(src.pop_) {
src.pop_ = false;
}
StackRef &operator=(const StackRef &src) {
if (this != &src) {
state_ = src.state_;
stack_index_ = src.stack_index_;
pop_ = src.pop_;
src.pop_ = false;
}
return *this;
}
#endif
StackRef(lua_State *s, int index)
: state_(s), stack_index_(lua_absindex(s, index)), pop_(true) {}
StackRef(lua_State *s, int index, bool pop)
: state_(s), stack_index_(lua_absindex(s, index)), pop_(pop) {}
StackRef() : state_(0), stack_index_(0), pop_(false) {}
~StackRef() {
if (state_ && pop_) {
if (lua_gettop(state_) >= stack_index_) {
lua_settop(state_, stack_index_ - 1);
}
}
}
public:
bool isNilref() const {
return state_ == 0 || lua_type(state_, stack_index_) == LUA_TNIL;
}
int push() const {
lua_pushvalue(state_, stack_index_);
return 1;
}
int push(lua_State *state) const {
lua_pushvalue(state_, stack_index_);
if (state_ != state) {
lua_pushvalue(state_, stack_index_);
lua_xmove(state_, state, 1);
}
return 1;
}
int pushStackIndex(lua_State *state) const {
if (state_ != state) {
lua_pushvalue(state_, stack_index_);
lua_xmove(state_, state, 1);
return lua_gettop(state);
} else {
return stack_index_;
}
}
lua_State *state() const { return state_; }
};
/// @brief Reference to Lua value. Retain reference by LUA_REGISTRYINDEX
class RegistoryRef {
public:
#if KAGUYA_USE_SHARED_LUAREF
struct RefHolder {
struct RefDeleter {
RefDeleter(lua_State *L) : state_(L) {}
void operator()(int *ref) {
luaL_unref(state_, LUA_REGISTRYINDEX, *ref);
delete ref;
}
lua_State *state_;
};
RefHolder(lua_State *L, int ref)
: state_(L), ref_(new int(ref), RefDeleter(L)) {}
RefHolder(const RefHolder &src) : state_(src.state_), ref_(src.ref_) {}
RefHolder &operator=(const RefHolder &src) {
state_ = src.state_;
ref_ = src.ref_;
return *this;
}
#if KAGUYA_USE_RVALUE_REFERENCE
RefHolder(RefHolder &&src) : state_(0), ref_() { swap(src); }
RefHolder &operator=(RefHolder &&src) throw() {
swap(src);
return *this;
}
#endif
void swap(RefHolder &other) throw() {
std::swap(state_, other.state_);
std::swap(ref_, other.ref_);
}
int ref() const {
if (state_ && ref_) {
return *ref_;
}
return LUA_REFNIL;
}
void reset() { ref_.reset(); }
lua_State *state() const { return state_; }
private:
lua_State *state_;
standard::shared_ptr<int> ref_;
};
#else
struct RefHolder {
RefHolder(lua_State *L, int ref) : state_(L), ref_(ref) {}
RefHolder(const RefHolder &src) : state_(src.state_), ref_(LUA_REFNIL) {
if (state_) {
lua_rawgeti(state_, LUA_REGISTRYINDEX, src.ref_);
ref_ = luaL_ref(state_, LUA_REGISTRYINDEX);
}
}
RefHolder &operator=(const RefHolder &src) {
reset();
state_ = src.state_;
if (state_) {
lua_rawgeti(state_, LUA_REGISTRYINDEX, src.ref_);
ref_ = luaL_ref(state_, LUA_REGISTRYINDEX);
} else {
ref_ = LUA_REFNIL;
}
return *this;
}
#if KAGUYA_USE_RVALUE_REFERENCE
RefHolder(RefHolder &&src) throw() : state_(src.state_), ref_(src.ref_) {
src.ref_ = LUA_REFNIL;
}
RefHolder &operator=(RefHolder &&src) throw() {
swap(src);
return *this;
}
#endif
void swap(RefHolder &other) throw() {
std::swap(state_, other.state_);
std::swap(ref_, other.ref_);
}
int ref() const {
if (state_) {
return ref_;
}
return LUA_REFNIL;
}
void reset() {
if (ref_ != LUA_REFNIL && state_) {
luaL_unref(state_, LUA_REGISTRYINDEX, ref_);
ref_ = LUA_REFNIL;
}
}
~RefHolder() { reset(); }
lua_State *state() const { return state_; }
private:
lua_State *state_;
int ref_;
};
#endif
RegistoryRef(const RegistoryRef &src) : ref_(src.ref_) {}
RegistoryRef &operator=(const RegistoryRef &src) {
if (this != &src) {
ref_ = src.ref_;
}
return *this;
}
static int ref_from_stacktop(lua_State *state) {
if (state) {
return luaL_ref(state, LUA_REGISTRYINDEX);
} else {
return LUA_REFNIL;
}
}
#if KAGUYA_USE_RVALUE_REFERENCE
RegistoryRef(RegistoryRef &&src) throw() : ref_(0, LUA_REFNIL) { swap(src); }
RegistoryRef &operator=(RegistoryRef &&src) throw() {
swap(src);
return *this;
}
#endif
RegistoryRef() : ref_(0, LUA_REFNIL) {}
RegistoryRef(lua_State *state) : ref_(state, LUA_REFNIL) {}
RegistoryRef(lua_State *state, StackTop, NoMainCheck)
: ref_(state, ref_from_stacktop(state)) {}
RegistoryRef(lua_State *state, StackTop)
: ref_(util::toMainThread(state), ref_from_stacktop(state)) {}
void swap(RegistoryRef &other) throw() { ref_.swap(other.ref_); }
template <typename T>
RegistoryRef(lua_State *state, const T &v, NoMainCheck)
: ref_(0, LUA_REFNIL) {
if (!state) {
return;
}
util::ScopedSavedStack save(state);
util::one_push(state, v);
ref_ = RefHolder(state, ref_from_stacktop(state));
}
template <typename T>
RegistoryRef(lua_State *state, const T &v) : ref_(0, LUA_REFNIL) {
if (!state) {
return;
}
util::ScopedSavedStack save(state);
util::one_push(state, v);
ref_ = RefHolder(util::toMainThread(state), ref_from_stacktop(state));
}
#if KAGUYA_USE_CPP11
template <typename T>
RegistoryRef(lua_State *state, T &&v, NoMainCheck) : ref_(0, LUA_REFNIL) {
if (!state) {
return;
}
util::ScopedSavedStack save(state);
util::one_push(state, standard::forward<T>(v));
ref_ = RefHolder(state, ref_from_stacktop(state));
}
template <typename T>
RegistoryRef(lua_State *state, T &&v) : ref_(0, LUA_REFNIL) {
if (!state) {
return;
}
util::ScopedSavedStack save(state);
util::one_push(state, standard::forward<T>(v));
ref_ = RefHolder(util::toMainThread(state), ref_from_stacktop(state));
}
#endif
~RegistoryRef() {
try {
unref();
} catch (...) {
} // can't throw at Destructor
}
/// @brief push to Lua stack
int push() const { return push(ref_.state()); }
/// @brief push to Lua stack
int push(lua_State *state) const {
if (isNilref()) {
lua_pushnil(state);
return 1;
}
#if LUA_VERSION_NUM >= 502
if (state != ref_.state()) { // state check
assert(util::toMainThread(state) == util::toMainThread(ref_.state()));
}
#endif
lua_rawgeti(state, LUA_REGISTRYINDEX, ref_.ref());
return 1;
}
int pushStackIndex(lua_State *state) const {
push(state);
return lua_gettop(state);
}
lua_State *state() const { return ref_.state(); }
bool isNilref() const { return ref_.ref() == LUA_REFNIL; }
void unref() { ref_.reset(); }
private:
RefHolder ref_;
};
}
}

View file

@ -0,0 +1,466 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <map>
#include <algorithm>
#include "kaguya/config.hpp"
#include "kaguya/error_handler.hpp"
#include "kaguya/type.hpp"
#include "kaguya/utility.hpp"
namespace kaguya {
class LuaRef;
class LuaStackRef;
class LuaTable;
template <typename KEY> class TableKeyReferenceProxy;
class MemberFunctionBinder;
namespace detail {
struct table_proxy {
#if KAGUYA_USE_CPP11
template <typename V, typename KEY>
static void set(lua_State *state, int table_index, KEY &&key, V &&value) {
util::one_push(state, std::forward<KEY>(key));
util::one_push(state, std::forward<V>(value));
lua_settable(state, table_index);
}
template <typename V>
static void set(lua_State *state, int table_index, const char *key,
V &&value) {
util::one_push(state, std::forward<V>(value));
lua_setfield(state, table_index, key);
}
template <typename V>
static void set(lua_State *state, int table_index, const std::string &key,
V &&value) {
set(state, table_index, key.c_str(), std::forward<V>(value));
}
template <typename V>
static void set(lua_State *state, int table_index, luaInt key, V &&value) {
util::one_push(state, std::forward<V>(value));
lua_seti(state, table_index, key);
}
template <typename V, typename KEY>
static void rawset(lua_State *state, int table_index, KEY &&key, V &&value) {
util::one_push(state, std::forward<KEY>(key));
util::one_push(state, std::forward<V>(value));
lua_rawset(state, table_index);
}
template <typename V>
static void rawset(lua_State *state, int table_index, luaInt key, V &&value) {
util::one_push(state, std::forward<V>(value));
lua_rawseti(state, table_index, key);
}
#else
template <typename V, typename KEY>
static void set(lua_State *state, int table_index, const KEY &key,
const V &value) {
util::one_push(state, key);
util::one_push(state, value);
lua_settable(state, table_index);
}
template <typename V>
static void set(lua_State *state, int table_index, const char *key,
const V &value) {
util::one_push(state, value);
lua_setfield(state, table_index, key);
}
template <typename V>
static void set(lua_State *state, int table_index, const std::string &key,
const V &value) {
util::one_push(state, value);
lua_setfield(state, table_index, key.c_str());
}
template <typename V>
static void set(lua_State *state, int table_index, luaInt key,
const V &value) {
util::one_push(state, value);
lua_seti(state, table_index, key);
}
template <typename V, typename KEY>
static void rawset(lua_State *state, int table_index, const KEY &key,
const V &value) {
util::one_push(state, key);
util::one_push(state, value);
lua_rawset(state, table_index);
}
template <typename V>
static void rawset(lua_State *state, int table_index, luaInt key,
const V &value) {
util::one_push(state, value);
lua_rawseti(state, table_index, key);
}
#endif
#if KAGUYA_USE_CPP11
template <typename KEY>
static void get(lua_State *state, int table_index, KEY &&key) {
util::one_push(state, std::forward<KEY>(key));
lua_gettable(state, table_index);
}
#endif
template <typename KEY>
static void get(lua_State *state, int table_index, const KEY &key) {
util::one_push(state, key);
lua_gettable(state, table_index);
}
static void get(lua_State *state, int table_index, const char *key) {
lua_getfield(state, table_index, key);
}
static void get(lua_State *state, int table_index, const std::string &key) {
lua_getfield(state, table_index, key.c_str());
}
static void get(lua_State *state, int table_index, luaInt key) {
lua_geti(state, table_index, key);
}
#if KAGUYA_USE_CPP11
template <typename KEY>
static void rawget(lua_State *state, int table_index, KEY &&key) {
util::one_push(state, std::forward<KEY>(key));
lua_rawget(state, table_index);
}
#endif
template <typename KEY>
static void rawget(lua_State *state, int table_index, const KEY &key) {
util::one_push(state, key);
lua_rawget(state, table_index);
}
static void rawget(lua_State *state, int table_index, luaInt key) {
lua_rawgeti(state, table_index, key);
}
};
template <typename Derived> class LuaTableOrUserDataImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
int push_(lua_State *state) const {
return static_cast<const Derived *>(this)->push(state);
}
public:
/// @brief set metatable
/// @param table metatable
bool setMetatable(const LuaTable &table);
/// @brief get metatable
LuaTable getMetatable() const;
/// @brief table->*"function_name"() in c++ and table:function_name(); in lua
/// is same
/// @param function_name function_name in table
MemberFunctionBinder operator->*(const char *function_name);
/// @brief value = table[key];
/// @param key key of table
/// @return reference of field value
template <typename T, typename KEY>
typename lua_type_traits<T>::get_type getField(const KEY &key) const {
lua_State *state = state_();
typedef typename lua_type_traits<T>::get_type get_type;
if (!state) {
except::typeMismatchError(state, "is nil");
return get_type();
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::get(state, stackIndex, key);
return lua_type_traits<T>::get(state, -1);
}
/// @brief value = table[key];
/// @param key key of table
/// @return reference of field value
template <typename KEY> LuaStackRef getField(const KEY &key) const;
#if KAGUYA_USE_CPP11
/// @brief table[key] = value;
template <typename K, typename V> bool setField(K &&key, V &&value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::set(state, stackIndex, std::forward<K>(key),
std::forward<V>(value));
return true;
}
#else
/// @brief table[key] = value;
template <typename K, typename V>
bool setField(const K &key, const V &value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::set(state, stackIndex, key, value);
return true;
}
#endif
/// @brief value = table[key];
/// @param key key of table
/// @return reference of field value
template <typename K> LuaStackRef operator[](K key) const;
/// @brief value = table[key];or table[key] = value;
/// @param key key of table
/// @return reference of field value
template <typename K> TableKeyReferenceProxy<K> operator[](K key);
};
template <typename Derived> class LuaTableImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
int push_(lua_State *state) const {
return static_cast<const Derived *>(this)->push(state);
}
template <typename K, typename A> struct gettablekey {
typedef K key_type;
typedef void value_type;
std::vector<K, A> &v_;
gettablekey(std::vector<K, A> &v) : v_(v) {}
void operator()(K key, const void *) { v_.push_back(key); }
};
template <typename V, typename A> struct gettablevalue {
typedef void key_type;
typedef V value_type;
std::vector<V, A> &v_;
gettablevalue(std::vector<V, A> &v) : v_(v) {}
void operator()(const void *, V value) { v_.push_back(value); }
};
template <typename K, typename V, typename C, typename A> struct gettablemap {
typedef K key_type;
typedef V value_type;
std::map<K, V, C, A> &m_;
gettablemap(std::map<K, V, C, A> &m) : m_(m) {}
void operator()(K key, V value) { m_[key] = value; }
};
public:
#if KAGUYA_USE_CPP11
/// @brief rawset(table,key,value)
template <typename K, typename V> bool setRawField(K &&key, V &&value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::rawset(state, stackIndex, std::forward<K>(key),
std::forward<V>(value));
return true;
}
#else
/// @brief rawset(table,key,value)
template <typename K, typename V>
bool setRawField(const K &key, const V &value) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::rawset(state, stackIndex, key, value);
return true;
}
#endif
/// @brief value = rawget(table,key);
/// @param key key of table
/// @return reference of field value
template <typename T, typename KEY>
typename lua_type_traits<T>::get_type getRawField(const KEY &key) const {
lua_State *state = state_();
typedef typename lua_type_traits<T>::get_type get_type;
if (!state) {
except::typeMismatchError(state, "is nil");
return get_type();
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
table_proxy::rawget(state, stackIndex, key);
return lua_type_traits<T>::get(state, -1);
}
/// @brief value = rawget(table,key);
/// @param key key of table
/// @return reference of field value
template <typename KEY> LuaStackRef getRawField(const KEY &key) const;
/// @brief foreach table fields
template <class K, class V, class Fun> void foreach_table(Fun f) const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
lua_pushnil(state);
while (lua_next(state, stackIndex) != 0) {
// backup key
lua_pushvalue(state, -2);
f(lua_type_traits<K>::get(state, -1), lua_type_traits<V>::get(state, -2));
lua_pop(state, 2); // pop key and value
}
}
/// @brief foreach table fields
template <class K, class V, class Fun>
void foreach_table_breakable(Fun f) const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
lua_pushnil(state);
while (lua_next(state, stackIndex) != 0) {
lua_pushvalue(state, -2); // backup key
bool cont = f(lua_type_traits<K>::get(state, -1),
lua_type_traits<V>::get(state, -2));
lua_pop(state, 2); // pop key and value
if (!cont) {
break;
}
}
}
/// @brief If type is table or userdata, return keys.
/// @return field keys
template <typename K, typename A> std::vector<K, A> keys() const {
std::vector<K, A> res;
util::ScopedSavedStack save(state_());
int stackIndex = pushStackIndex_(state_());
size_t size = lua_rawlen(state_(), stackIndex);
res.reserve(size);
foreach_table<K, void>(gettablekey<K, A>(res));
return res;
}
/// @brief If type is table or userdata, return keys.
/// @return field keys
template <typename K> std::vector<K> keys() const {
return keys<K, std::allocator<K> >();
}
std::vector<LuaRef> keys() const;
/// @brief If type is table or userdata, return values.
/// @return field value
template <typename V, typename A> std::vector<V, A> values() const {
std::vector<V, A> res;
util::ScopedSavedStack save(state_());
int stackIndex = pushStackIndex_(state_());
size_t size = lua_rawlen(state_(), stackIndex);
res.reserve(size);
foreach_table<void, V>(gettablevalue<V, A>(res));
return res;
}
/// @brief If type is table or userdata, return values.
/// @return field value
template <typename V> std::vector<V> values() const {
return values<V, std::allocator<V> >();
}
std::vector<LuaRef> values() const;
/// @brief If type is table or userdata, return key value pair.
/// @return key value pair
template <typename K, typename V, typename C, typename A>
std::map<K, V, C, A> map() const {
std::map<K, V, C, A> res;
foreach_table<K, V>(gettablemap<K, V, C, A>(res));
return res;
}
/// @brief If type is table or userdata, return key value pair.
/// @return key value pair
template <typename K, typename V, typename C> std::map<K, V, C> map() const {
return map<K, V, C, std::allocator<std::pair<const K, V> > >();
}
/// @brief If type is table or userdata, return key value pair.
/// @return key value pair
template <typename K, typename V> std::map<K, V> map() const {
return map<K, V, std::less<K> >();
}
std::map<LuaRef, LuaRef> map() const;
};
template <typename Derived> class LuaUserDataImpl {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
int push_(lua_State *state) const {
return static_cast<const Derived *>(this)->push(state);
}
public:
/// @brief is type test
template <typename T> bool isType() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::strictCheckType(state, pushStackIndex_(state));
}
template <typename T> bool isConvertible() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::checkType(state, pushStackIndex_(state));
}
template <typename T> bool typeTest() const { return isType<T>(); }
template <typename T> bool weakTypeTest() const { return isConvertible<T>(); }
template <typename T> typename lua_type_traits<T>::get_type get() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::get(state, state ? pushStackIndex_(state) : 0);
}
template <typename T> operator T() const { return get<T>(); }
};
}
}

View file

@ -0,0 +1,104 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include "kaguya/detail/lua_function_def.hpp"
#include "kaguya/detail/lua_table_def.hpp"
namespace kaguya {
class LuaRef;
class LuaTable;
template <typename KEY> class TableKeyReferenceProxy;
class MemberFunctionBinder;
namespace detail {
template <typename Derived>
class LuaVariantImpl : public LuaTableImpl<Derived>,
public LuaTableOrUserDataImpl<Derived>,
public detail::LuaFunctionImpl<Derived>,
public detail::LuaThreadImpl<Derived>,
public LuaBasicTypeFunctions<Derived> {
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
public:
using LuaBasicTypeFunctions<Derived>::type;
using LuaBasicTypeFunctions<Derived>::typeName;
/// @brief deprecated, use isType instead.
template <typename T> bool typeTest() const { return isType<T>(); }
/// @brief deprecated, use isConvertible instead.
template <typename T> bool weakTypeTest() const { return isConvertible<T>(); }
/// @brief is type test
template <typename T> bool isType() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::strictCheckType(state, pushStackIndex_(state));
}
template <typename T> bool isConvertible() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::checkType(state, pushStackIndex_(state));
}
template <typename T> typename lua_type_traits<T>::get_type get() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<T>::get(state, state ? pushStackIndex_(state) : 0);
}
template <typename T, typename U>
typename lua_type_traits<T>::get_type value_or(U v) const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
return lua_type_traits<optional<T> >::get(
state, state ? pushStackIndex_(state) : 0)
.value_or(v);
}
// deprecated. use get<kaguya::optional<T> >() instead;
template <typename T>
typename lua_type_traits<T>::get_type
get(bool &was_valid, bool allow_convertible = true) const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
int stackindex = pushStackIndex_(state);
if (allow_convertible) {
was_valid = lua_type_traits<T>::checkType(state, stackindex);
} else {
was_valid = lua_type_traits<T>::strictCheckType(state, stackindex);
}
if (was_valid) {
return lua_type_traits<T>::get(state, stackindex);
} else {
return T();
}
}
template <typename T> operator T() const { return get<T>(); }
#if KAGUYA_USE_CPP11
template <class... Args> FunctionResults operator()(Args &&... args);
#else
inline FunctionResults operator()();
#define KAGUYA_OP_FN_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
inline FunctionResults operator()(KAGUYA_PP_ARG_CR_DEF_REPEAT(N));
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF)
#undef KAGUYA_OP_FN_DEF
#endif
};
}
}

View file

@ -0,0 +1,174 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include "kaguya/config.hpp"
#include "kaguya/type.hpp"
namespace kaguya {
inline const char *get_error_message(lua_State *state) {
if (lua_type(state, -1) == LUA_TSTRING) {
const char *message = lua_tostring(state, -1);
return message ? message : "unknown error";
} else {
return "unknown error";
}
}
inline int lua_pcall_wrap(lua_State *state, int argnum, int retnum) {
int result = lua_pcall(state, argnum, retnum, 0);
return result;
}
struct ErrorHandler {
typedef standard::function<void(int, const char *)> function_type;
static bool handle(const char *message, lua_State *state) {
function_type handler = getHandler(state);
if (handler) {
handler(0, message);
return true;
}
return false;
}
static bool handle(int status_code, const char *message, lua_State *state) {
function_type handler = getHandler(state);
if (handler) {
handler(status_code, message);
return true;
}
return false;
}
static bool handle(int status_code, lua_State *state) {
function_type handler = getHandler(state);
if (handler) {
handler(status_code, get_error_message(state));
return true;
}
return false;
}
static function_type getHandler(lua_State *state) {
function_type *funptr = getFunctionPointer(state);
if (funptr) {
return *funptr;
}
return function_type();
}
static void unregisterHandler(lua_State *state) {
if (state) {
function_type *funptr = getFunctionPointer(state);
if (funptr) {
*funptr = function_type();
}
}
}
static void registerHandler(lua_State *state, function_type f) {
if (state) {
function_type *funptr = getFunctionPointer(state);
if (!funptr) {
util::ScopedSavedStack save(state);
lua_pushlightuserdata(state, handlerRegistryKey());
void *ptr = lua_newuserdata(
state, sizeof(function_type)); // dummy data for gc call
funptr = new (ptr) function_type();
// create function_type metatable
lua_newtable(state);
lua_pushcclosure(state, &error_handler_cleanner, 0);
lua_setfield(state, -2, "__gc");
lua_pushvalue(state, -1);
lua_setfield(state, -1, "__index");
lua_setmetatable(state, -2);
lua_rawset(state, LUA_REGISTRYINDEX);
}
*funptr = f;
}
}
static void throwDefaultError(int status, const char *message = 0) {
switch (status) {
case LUA_ERRSYNTAX:
throw LuaSyntaxError(status, message ? std::string(message)
: "unknown syntax error");
case LUA_ERRRUN:
throw LuaRuntimeError(status, message ? std::string(message)
: "unknown runtime error");
case LUA_ERRMEM:
throw LuaMemoryError(status, message ? std::string(message)
: "lua memory allocation error");
case LUA_ERRERR:
throw LuaErrorRunningError(status, message
? std::string(message)
: "unknown error running error");
#if LUA_VERSION_NUM >= 502
case LUA_ERRGCMM:
throw LuaGCError(status,
message ? std::string(message) : "unknown gc error");
#endif
default:
throw LuaUnknownError(status, message ? std::string(message)
: "lua unknown error");
}
}
private:
static void *handlerRegistryKey() {
static void *key;
return key;
}
static function_type *getFunctionPointer(lua_State *state) {
if (state) {
util::ScopedSavedStack save(state);
lua_pushlightuserdata(state, handlerRegistryKey());
lua_rawget(state, LUA_REGISTRYINDEX);
function_type *ptr = (function_type *)lua_touserdata(state, -1);
return ptr;
}
return 0;
}
ErrorHandler() {}
ErrorHandler(const ErrorHandler &);
ErrorHandler &operator=(const ErrorHandler &);
static int error_handler_cleanner(lua_State *state) {
function_type *ptr = (function_type *)lua_touserdata(state, 1);
ptr->~function_type();
return 0;
}
};
namespace except {
inline void OtherError(lua_State *state, const std::string &message) {
if (ErrorHandler::handle(message.c_str(), state)) {
return;
}
}
inline void typeMismatchError(lua_State *state, const std::string &message) {
if (ErrorHandler::handle(message.c_str(), state)) {
return;
}
}
inline void memoryError(lua_State *state, const char *message) {
if (ErrorHandler::handle(message, state)) {
return;
}
}
inline bool checkErrorAndThrow(int status, lua_State *state) {
if (status != 0 && status != LUA_YIELD) {
ErrorHandler::handle(status, state);
return false;
}
return true;
}
}
}

View file

@ -0,0 +1,92 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <exception>
#include <stdexcept>
namespace kaguya {
class LuaException : public std::exception {
int status_;
std::string what_;
const char *what_c_;
public:
LuaException(int status, const char *what) throw()
: status_(status), what_c_(what) {}
LuaException(int status, const std::string &what)
: status_(status), what_(what), what_c_(0) {}
int status() const throw() { return status_; }
const char *what() const throw() { return what_c_ ? what_c_ : what_.c_str(); }
~LuaException() throw() {}
};
class KaguyaException : public std::exception {
std::string what_;
const char *what_c_;
public:
KaguyaException(const char *what) throw() : what_c_(what) {}
KaguyaException(const std::string &what) : what_(what), what_c_(0) {}
const char *what() const throw() { return what_c_ ? what_c_ : what_.c_str(); }
~KaguyaException() throw() {}
};
class LuaTypeMismatch : public LuaException {
public:
LuaTypeMismatch() throw() : LuaException(0, "type mismatch!!") {}
LuaTypeMismatch(const char *what) throw() : LuaException(0, what) {}
LuaTypeMismatch(const std::string &what) : LuaException(0, what) {}
};
class LuaMemoryError : public LuaException {
public:
LuaMemoryError(int status, const char *what) throw()
: LuaException(status, what) {}
LuaMemoryError(int status, const std::string &what)
: LuaException(status, what) {}
};
class LuaRuntimeError : public LuaException {
public:
LuaRuntimeError(int status, const char *what) throw()
: LuaException(status, what) {}
LuaRuntimeError(int status, const std::string &what)
: LuaException(status, what) {}
};
class LuaErrorRunningError : public LuaException {
public:
LuaErrorRunningError(int status, const char *what) throw()
: LuaException(status, what) {}
LuaErrorRunningError(int status, const std::string &what)
: LuaException(status, what) {}
};
class LuaGCError : public LuaException {
public:
LuaGCError(int status, const char *what) throw()
: LuaException(status, what) {}
LuaGCError(int status, const std::string &what)
: LuaException(status, what) {}
};
class LuaUnknownError : public LuaException {
public:
LuaUnknownError(int status, const char *what) throw()
: LuaException(status, what) {}
LuaUnknownError(int status, const std::string &what)
: LuaException(status, what) {}
};
class LuaSyntaxError : public LuaException {
public:
LuaSyntaxError(int status, const std::string &what)
: LuaException(status, what) {}
};
namespace except {
void OtherError(lua_State *state, const std::string &message);
void typeMismatchError(lua_State *state, const std::string &message);
void memoryError(lua_State *state, const char *message);
bool checkErrorAndThrow(int status, lua_State *state);
}
}

View file

@ -0,0 +1,104 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include "kaguya/config.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/preprocess.hpp"
namespace kaguya {
namespace fntuple {
#if KAGUYA_USE_CPP11 && !defined(KAGUYA_FUNCTION_MAX_OVERLOADS)
// In Clang with libstdc++.
// std::tuple elements is limited to 16 for template depth limit
using std::tuple;
using std::get;
using std::tuple_element;
using std::tuple_size;
#else
using util::null_type;
// boost::tuple is max
#define KAGUYA_PP_STRUCT_TDEF_REP(N) KAGUYA_PP_CAT(typename A, N) = null_type
#define KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_STRUCT_TDEF_REP)
template <KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(
KAGUYA_PP_INC(KAGUYA_FUNCTION_MAX_OVERLOADS))>
struct tuple {};
#undef KAGUYA_PP_STRUCT_TDEF_REP
#undef KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT
#define KAGUYA_FUNCTION_TUPLE_ELEMENT(N) \
KAGUYA_PP_CAT(A, N) KAGUYA_PP_CAT(elem, N);
#define KAGUYA_FUNCTION_TUPLE_ELEMENT_INIT(N) \
KAGUYA_PP_CAT(elem, N)(KAGUYA_PP_CAT(a, N))
#define KAGUYA_FUNCTION_TUPLE_IMPL_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
struct tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> { \
KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_TUPLE_ELEMENT) \
tuple(KAGUYA_PP_ARG_DEF_REPEAT(N)) \
: KAGUYA_PP_REPEAT_ARG(N, KAGUYA_FUNCTION_TUPLE_ELEMENT_INIT) {} \
};
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS,
KAGUYA_FUNCTION_TUPLE_IMPL_DEF)
template <typename Tuple> struct tuple_size;
#define KAGUYA_TUPLE_SIZE_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
struct tuple_size<tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > { \
static const size_t value = N; \
};
KAGUYA_TUPLE_SIZE_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_SIZE_DEF)
#undef KAGUYA_TUPLE_SIZE_DEF
template <std::size_t remain, class result, bool flag = remain <= 0>
struct tuple_element {};
#define KAGUYA_TUPLE_ELEMENT_DEF(N) \
template <std::size_t remain, \
class arg KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct tuple_element< \
remain, tuple<arg KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)>, true> { \
typedef arg type; \
}; \
template <std::size_t remain, \
class arg KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct tuple_element< \
remain, tuple<arg KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)>, false> \
: tuple_element<remain - 1, tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > { \
};
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_ELEMENT_DEF)
#undef KAGUYA_TUPLE_SIZE_DEF
template <size_t S, typename T> struct tuple_get_helper;
#define KAGUYA_TUPLE_GET_DEF(N) \
template <typename T> struct tuple_get_helper<N, T> { \
static typename tuple_element<N - 1, T>::type &get(T &t) { \
return t.KAGUYA_PP_CAT(elem, N); \
} \
static const typename tuple_element<N - 1, T>::type &cget(const T &t) { \
return t.KAGUYA_PP_CAT(elem, N); \
} \
};
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_GET_DEF)
template <size_t S, typename T> typename tuple_element<S, T>::type &get(T &t) {
return tuple_get_helper<S + 1, T>::get(t);
}
template <size_t S, typename T>
const typename tuple_element<S, T>::type &get(const T &t) {
return tuple_get_helper<S + 1, T>::cget(t);
}
#endif
}
}

View file

@ -0,0 +1,14 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include "kaguya/config.hpp"
#include "kaguya/lua_ref.hpp"
#include "kaguya/native_function.hpp"
#include "kaguya/state.hpp"
#include "kaguya/lua_ref_table.hpp"
#include "kaguya/lua_ref_function.hpp"
#include "kaguya/ref_tuple.hpp"

View file

@ -0,0 +1,585 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <map>
#include <cassert>
#include <algorithm>
#include <ostream>
#include <istream>
#include "kaguya/config.hpp"
#include "kaguya/error_handler.hpp"
#include "kaguya/type.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/detail/lua_ref_impl.hpp"
#include "kaguya/detail/lua_variant_def.hpp"
namespace kaguya {
namespace util {
template <class Result>
inline Result get_result_impl(lua_State *l, int startindex,
types::typetag<Result>) {
return lua_type_traits<Result>::get(l, startindex);
}
#if KAGUYA_USE_CPP11
inline standard::tuple<>
get_result_tuple_impl(lua_State *, int, types::typetag<standard::tuple<> >) {
return standard::tuple<>();
}
template <typename T, typename... TYPES>
inline standard::tuple<T, TYPES...>
get_result_tuple_impl(lua_State *l, int index,
types::typetag<standard::tuple<T, TYPES...> >) {
return standard::tuple_cat(
standard::tuple<T>(lua_type_traits<T>::get(l, index)),
get_result_tuple_impl(l, index + 1,
types::typetag<standard::tuple<TYPES...> >()));
}
template <typename... TYPES>
inline standard::tuple<TYPES...>
get_result_impl(lua_State *l, int startindex,
types::typetag<standard::tuple<TYPES...> > tag) {
return get_result_tuple_impl<TYPES...>(l, startindex, tag);
}
#else
inline standard::tuple<> get_result_impl(lua_State *l, int startindex,
types::typetag<standard::tuple<> >) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(startindex);
return standard::tuple<>();
}
#define KAGUYA_GET_DEF(N) \
lua_type_traits<KAGUYA_PP_CAT(A, N)>::get(l, N + startindex - 1)
#define KAGUYA_GET_TUPLE_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
inline standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> get_result_impl( \
lua_State *l, int startindex, \
types::typetag<standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> >) { \
return standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>( \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_GET_DEF)); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_TUPLE_SIZE, KAGUYA_GET_TUPLE_DEF)
#undef KAGUYA_GET_DEF
#undef KAGUYA_GET_TUPLE_DEF
#endif
template <class Result> inline Result get_result(lua_State *l, int startindex) {
return get_result_impl(l, startindex, types::typetag<Result>());
}
template <> inline void get_result<void>(lua_State *, int) {}
}
/// @addtogroup Lua_reference_types
/// @ingroup Lua_reference_types
/// @brief Reference to any Lua data.
class LuaRef : public Ref::RegistoryRef, public detail::LuaVariantImpl<LuaRef> {
private:
static lua_State *toMainThread(lua_State *state) {
#if LUA_VERSION_NUM >= 502
if (state) {
lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
lua_State *mainthread = lua_tothread(state, -1);
lua_pop(state, 1);
if (mainthread) {
return mainthread;
}
}
#endif
return state;
}
public:
LuaRef(const Ref::RegistoryRef &src) : Ref::RegistoryRef(src) {}
LuaRef(const LuaRef &src) : Ref::RegistoryRef(src) {}
LuaRef &operator=(const LuaRef &src) {
static_cast<RegistoryRef &>(*this) = src;
return *this;
}
#if KAGUYA_USE_CPP11
LuaRef(LuaRef &&src) : Ref::RegistoryRef(std::move(src)) {}
LuaRef &operator=(LuaRef &&src) throw() {
swap(src);
return *this;
}
LuaRef(RegistoryRef &&src) throw() : Ref::RegistoryRef(std::move(src)) {}
template <typename T>
LuaRef(lua_State *state, T &&v, Ref::NoMainCheck)
: Ref::RegistoryRef(state, std::move(v), Ref::NoMainCheck()) {}
template <typename T>
LuaRef(lua_State *state, T &&v) : Ref::RegistoryRef(state, std::move(v)) {}
#endif
LuaRef() {}
LuaRef(lua_State *state) : Ref::RegistoryRef(state) {}
LuaRef(lua_State *state, StackTop, Ref::NoMainCheck)
: Ref::RegistoryRef(state, StackTop(), Ref::NoMainCheck()) {}
LuaRef(lua_State *state, StackTop) : Ref::RegistoryRef(state, StackTop()) {}
template <typename T>
LuaRef(lua_State *state, const T &v, Ref::NoMainCheck)
: Ref::RegistoryRef(state, v, Ref::NoMainCheck()) {}
template <typename T>
LuaRef(lua_State *state, const T &v) : Ref::RegistoryRef(state, v) {}
const void *native_pointer() const {
util::ScopedSavedStack save(state());
push(state());
return lua_topointer(state(), -1);
}
static void putindent(std::ostream &os, int indent) {
while (indent-- > 0) {
os << " ";
}
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaRef
template <> struct lua_type_traits<LuaRef> {
typedef LuaRef get_type;
typedef const LuaRef &push_type;
static bool checkType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return true;
}
static bool strictCheckType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return false;
}
static get_type get(lua_State *l, int index) {
lua_pushvalue(l, index);
return LuaRef(l, StackTop());
}
static int push(lua_State *l, push_type v) { return v.push(l); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaRef
template <> struct lua_type_traits<const LuaRef &> : lua_type_traits<LuaRef> {};
class LuaStackRef : public Ref::StackRef,
public detail::LuaVariantImpl<LuaStackRef> {
public:
LuaStackRef() : Ref::StackRef() {}
LuaStackRef(lua_State *s, int index) : Ref::StackRef(s, index, false) {}
LuaStackRef(lua_State *s, int index, bool popAtDestruct)
: Ref::StackRef(s, index, popAtDestruct) {}
#if KAGUYA_USE_CPP11
LuaStackRef(LuaStackRef &&src) : Ref::StackRef(std::move(src)) {
src.pop_ = false;
}
LuaStackRef &operator=(LuaStackRef &&src) {
if (this != &src) {
Ref::StackRef::operator=(std::move(src));
src.pop_ = false;
}
return *this;
}
LuaStackRef(const LuaStackRef &src) = delete;
#else
LuaStackRef(const LuaStackRef &src) : Ref::StackRef(src) { src.pop_ = false; }
LuaStackRef &operator=(const LuaStackRef &src) {
if (this != &src) {
Ref::StackRef::operator=(src);
src.pop_ = false;
}
return *this;
}
#endif
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaStackRef
template <> struct lua_type_traits<LuaStackRef> {
typedef LuaStackRef get_type;
typedef const LuaStackRef &push_type;
static bool checkType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return true;
}
static bool strictCheckType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return false;
}
static get_type get(lua_State *l, int index) { return LuaStackRef(l, index); }
static int push(lua_State *l, push_type v) { return v.push(l); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaStackRef
template <>
struct lua_type_traits<const LuaStackRef &> : lua_type_traits<LuaStackRef> {};
/// @ingroup Lua_reference_types
/// @brief Reference to Lua userdata.
class LuaUserData : public Ref::RegistoryRef,
public detail::LuaUserDataImpl<LuaUserData>,
public detail::LuaTableOrUserDataImpl<LuaUserData>,
public detail::LuaBasicTypeFunctions<LuaUserData> {
void typecheck() {
int t = type();
if (t != TYPE_USERDATA && t != TYPE_LIGHTUSERDATA && t != TYPE_NIL &&
t != TYPE_NONE) {
except::typeMismatchError(state(), "not user data");
unref();
}
}
public:
operator LuaRef() {
push(state());
return LuaRef(state(), StackTop());
}
LuaUserData(lua_State *state, StackTop)
: Ref::RegistoryRef(state, StackTop()) {
typecheck();
}
template <typename TYPE>
LuaUserData(lua_State *state, const TYPE &table)
: Ref::RegistoryRef(state, table) {
typecheck();
}
explicit LuaUserData(lua_State *state)
: Ref::RegistoryRef(state, NilValue()) {
typecheck();
}
LuaUserData() { typecheck(); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaUserData
template <> struct lua_type_traits<LuaUserData> {
typedef LuaUserData get_type;
typedef LuaUserData push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TUSERDATA;
}
static bool checkType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TUSERDATA || lua_isnil(l, index);
}
static LuaUserData get(lua_State *l, int index) {
lua_pushvalue(l, index);
return LuaUserData(l, StackTop());
}
static int push(lua_State *l, const LuaUserData &ref) { return ref.push(l); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaUserData
template <>
struct lua_type_traits<const LuaUserData &> : lua_type_traits<LuaUserData> {};
/// @ingroup Lua_reference_types
/// @brief Reference to Lua table.
class LuaTable : public Ref::RegistoryRef,
public detail::LuaTableImpl<LuaTable>,
public detail::LuaTableOrUserDataImpl<LuaTable>,
public detail::LuaBasicTypeFunctions<LuaTable> {
void typecheck() {
int t = type();
if (t != TYPE_TABLE && t != TYPE_NIL && t != TYPE_NONE) {
except::typeMismatchError(state(), "not table");
unref();
}
}
public:
operator LuaRef() {
push(state());
return LuaRef(state(), StackTop());
}
LuaTable(lua_State *state, StackTop) : Ref::RegistoryRef(state, StackTop()) {
typecheck();
}
LuaTable(lua_State *state, const NewTable &table)
: Ref::RegistoryRef(state, table) {
typecheck();
}
explicit LuaTable(lua_State *state) : Ref::RegistoryRef(state, NewTable()) {
typecheck();
}
LuaTable() { typecheck(); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaTable
template <> struct lua_type_traits<LuaTable> {
typedef LuaTable get_type;
typedef LuaTable push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_istable(l, index);
}
static bool checkType(lua_State *l, int index) {
return lua_istable(l, index) || lua_isnil(l, index);
}
static LuaTable get(lua_State *l, int index) {
lua_pushvalue(l, index);
return LuaTable(l, StackTop());
}
static int push(lua_State *l, const LuaTable &ref) { return ref.push(l); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaTable
template <>
struct lua_type_traits<const LuaTable &> : lua_type_traits<LuaTable> {};
/// @ingroup Lua_reference_types
/// @brief Reference to Lua function.
class LuaFunction : public Ref::RegistoryRef,
public detail::LuaFunctionImpl<LuaFunction>,
public detail::LuaBasicTypeFunctions<LuaFunction> {
void typecheck() {
int t = type();
if (t != TYPE_FUNCTION && t != TYPE_NIL && t != TYPE_NONE) {
except::typeMismatchError(state(), "not function");
RegistoryRef::unref();
}
}
struct LuaLoadStreamWrapper {
LuaLoadStreamWrapper(std::istream &stream)
: preloaded_(false), stream_(stream) {
buffer_.reserve(512);
skipComment();
preloaded_ = !buffer_.empty();
}
void skipComment() {
// skip bom
const char *bom = "\xEF\xBB\xBF";
const char *bomseq = bom;
char c;
while (stream_.get(c)) {
if (c != *bomseq) // not bom sequence
{
buffer_.assign(bom, bomseq);
buffer_.push_back(c);
break;
}
bomseq++;
if ('\0' == *bomseq) {
return;
}
}
// skip comment
if (!buffer_.empty() && buffer_.front() == '#') {
buffer_.clear();
std::string comment;
std::getline(stream_, comment);
}
}
static const char *getdata(lua_State *, void *ud, size_t *size) {
LuaLoadStreamWrapper *loader = static_cast<LuaLoadStreamWrapper *>(ud);
if (loader->preloaded_) {
loader->preloaded_ = false;
} else {
loader->buffer_.clear();
}
char c = 0;
while (loader->buffer_.size() < loader->buffer_.capacity() &&
loader->stream_.get(c)) {
loader->buffer_.push_back(c);
}
*size = loader->buffer_.size();
return loader->buffer_.empty() ? 0 : &loader->buffer_[0];
}
private:
bool preloaded_;
std::vector<char> buffer_;
std::istream &stream_;
};
public:
/// @brief construct with state and function .
/// @param state pointer to lua_State
/// @param f execute function for lua thread. e.g.
/// kaguya::function(function_ptr),kaguya::overload(function_ptr)
template <typename F>
LuaFunction(lua_State *state, F f) : Ref::RegistoryRef(state, f) {
typecheck();
}
/// @brief construct with stack top value.
/// @param state pointer to lua_State
LuaFunction(lua_State *state, StackTop)
: Ref::RegistoryRef(state, StackTop()) {
typecheck();
}
/// @brief construct with nil reference.
LuaFunction() {}
/// @brief load lua code .
/// @param state pointer to lua_State
/// @param luacode string
static LuaFunction loadstring(lua_State *state, const std::string &luacode) {
return loadstring(state, luacode.c_str());
}
/// @brief load lua code .
/// @param state pointer to lua_State
/// @param luacode string
static LuaFunction loadstring(lua_State *state, const char *luacode) {
util::ScopedSavedStack save(state);
int status = luaL_loadstring(state, luacode);
if (status) {
ErrorHandler::handle(status, state);
lua_pushnil(state);
}
return LuaFunction(state, StackTop());
}
/// @brief If there are no errors,compiled file as a Lua function and return.
/// Otherwise send error message to error handler and return nil reference
/// @param state pointer to lua_State
/// @param file file path of lua script
/// @return reference of lua function
static LuaFunction loadfile(lua_State *state, const std::string &file) {
return loadfile(state, file.c_str());
}
/// @brief If there are no errors,compiled file as a Lua function and return.
/// Otherwise send error message to error handler and return nil reference
/// @param state pointer to lua_State
/// @param file file path of lua script
/// @return reference of lua function
static LuaFunction loadfile(lua_State *state, const char *file) {
util::ScopedSavedStack save(state);
int status = luaL_loadfile(state, file);
if (status) {
ErrorHandler::handle(status, state);
lua_pushnil(state);
}
return LuaFunction(state, StackTop());
}
/// @brief If there are no errors,compiled stream as a Lua function and
/// return.
/// Otherwise send error message to error handler and return nil reference
/// @param state pointer to lua_State
/// @param stream stream of lua script data
/// @param chunkname use for error message.
/// @return reference of lua function
static LuaStackRef loadstreamtostack(lua_State *state, std::istream &stream,
const char *chunkname = 0) {
LuaLoadStreamWrapper wrapper(stream);
#if LUA_VERSION_NUM >= 502
int status =
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname, 0);
#else
int status =
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname);
#endif
if (status) {
ErrorHandler::handle(status, state);
lua_pushnil(state);
}
return LuaStackRef(state, -1, true);
}
/// @brief If there are no errors,compiled stream as a Lua function and
/// return.
/// Otherwise send error message to error handler and return nil reference
/// @param state pointer to lua_State
/// @param stream stream of lua script data
/// @param chunkname use for error message.
/// @return reference of lua function
static LuaFunction loadstream(lua_State *state, std::istream &stream,
const char *chunkname = 0) {
util::ScopedSavedStack save(state);
LuaLoadStreamWrapper wrapper(stream);
#if LUA_VERSION_NUM >= 502
int status =
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname, 0);
#else
int status =
lua_load(state, &LuaLoadStreamWrapper::getdata, &wrapper, chunkname);
#endif
if (status) {
ErrorHandler::handle(status, state);
lua_pushnil(state);
}
return LuaFunction(state, StackTop());
}
};
/// @ingroup Lua_reference_types
/// @brief Reference to Lua thread(coroutine).
class LuaThread : public Ref::RegistoryRef,
public detail::LuaThreadImpl<LuaThread>,
public detail::LuaBasicTypeFunctions<LuaThread> {
void typecheck() {
int t = type();
if (t != TYPE_THREAD && t != TYPE_NIL && t != TYPE_NONE) {
except::typeMismatchError(state(), "not lua thread");
RegistoryRef::unref();
}
}
public:
/// @brief construct with stack top value.
LuaThread(lua_State *state, StackTop) : Ref::RegistoryRef(state, StackTop()) {
typecheck();
}
/// @brief construct with new thread.
LuaThread(lua_State *state, const NewThread &t)
: Ref::RegistoryRef(state, t) {}
/// @brief construct with nil reference.
LuaThread(lua_State *state) : Ref::RegistoryRef(state, NewThread()) {}
/// @brief construct with nil reference.
LuaThread() {}
/// @brief get lua thread
operator lua_State *() { return getthread(); }
};
}
#if KAGUYA_USE_CPP11
#else
namespace std {
template <> inline void swap(kaguya::LuaUserData &a, kaguya::LuaUserData &b) {
a.swap(b);
}
template <> inline void swap(kaguya::LuaTable &a, kaguya::LuaTable &b) {
a.swap(b);
}
template <> inline void swap(kaguya::LuaFunction &a, kaguya::LuaFunction &b) {
a.swap(b);
}
template <> inline void swap(kaguya::LuaThread &a, kaguya::LuaThread &b) {
a.swap(b);
}
template <> inline void swap(kaguya::LuaRef &a, kaguya::LuaRef &b) {
a.swap(b);
}
}
#endif

View file

@ -0,0 +1,407 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <map>
#include <cassert>
#include "kaguya/config.hpp"
#include "kaguya/lua_ref.hpp"
#include "kaguya/exception.hpp"
#include "kaguya/type.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/detail/lua_function_def.hpp"
#include "kaguya/detail/lua_variant_def.hpp"
namespace kaguya {
/// @brief function result value proxy class.
/// don't direct use.
class FunctionResults : public Ref::StackRef,
public detail::LuaVariantImpl<FunctionResults> {
FunctionResults(lua_State *state, int return_status, int startIndex)
: Ref::StackRef(state, startIndex, true), state_(state),
resultStatus_(return_status),
resultCount_(lua_gettop(state) + 1 - startIndex) {}
FunctionResults(lua_State *state, int return_status, int startIndex,
int endIndex)
: Ref::StackRef(state, startIndex, true), state_(state),
resultStatus_(return_status), resultCount_(endIndex - startIndex) {}
friend class detail::FunctionResultProxy;
public:
FunctionResults()
: Ref::StackRef(), state_(0), resultStatus_(0), resultCount_(0) {}
FunctionResults(lua_State *state)
: Ref::StackRef(state, 0, true), state_(state), resultStatus_(0),
resultCount_(0) {}
#if KAGUYA_USE_CPP11
FunctionResults(FunctionResults &&src)
: Ref::StackRef(std::move(src)), state_(src.state_),
resultStatus_(src.resultStatus_), resultCount_(src.resultCount_) {
src.state_ = 0;
}
#else
FunctionResults(const FunctionResults &src)
: Ref::StackRef(src), state_(src.state_),
resultStatus_(src.resultStatus_), resultCount_(src.resultCount_) {
src.state_ = 0;
}
#endif
~FunctionResults() {}
struct reference : public Ref::StackRef,
public detail::LuaVariantImpl<reference> {
reference(lua_State *s, int index) : Ref::StackRef(s, index, false) {}
reference *operator->() { return this; }
const reference *operator->() const { return this; }
};
template <typename T> struct iterator_base {
iterator_base(lua_State *s, int i) : state(s), stack_index(i) {}
template <typename U>
iterator_base(const iterator_base<U> &other)
: state(other.state), stack_index(other.stack_index) {}
T operator*() const { return reference(state, stack_index); }
T operator->() const { return reference(state, stack_index); }
const iterator_base &operator++() {
stack_index++;
return *this;
}
iterator_base operator++(int) {
return iterator_base(state, stack_index++);
}
iterator_base operator+=(int n) {
stack_index += n;
return iterator_base(state, stack_index);
}
/**
* @name relational operators
* @brief
*/
//@{
bool operator==(const iterator_base &other) const {
return state == other.state && stack_index == other.stack_index;
}
bool operator!=(const iterator_base &other) const {
return !(*this == other);
}
//@}
int index() const { return stack_index; }
private:
template <typename U> friend struct iterator_base;
lua_State *state;
int stack_index;
};
typedef iterator_base<reference> iterator;
typedef iterator_base<const reference> const_iterator;
typedef reference const_reference;
iterator begin() { return iterator(state_, stack_index_); }
iterator end() { return iterator(state_, stack_index_ + resultCount_); }
const_iterator begin() const { return const_iterator(state_, stack_index_); }
const_iterator end() const {
return const_iterator(state_, stack_index_ + resultCount_);
}
const_iterator cbegin() const { return const_iterator(state_, stack_index_); }
const_iterator cend() const {
return const_iterator(state_, stack_index_ + resultCount_);
}
template <class Result>
Result get_result(types::typetag<Result> = types::typetag<Result>()) const {
return util::get_result<Result>(state_, stack_index_);
}
LuaStackRef get_result(types::typetag<LuaStackRef>) const {
pop_ = 0;
return LuaStackRef(state_, stack_index_, true);
}
lua_State *state() const { return state_; }
template <typename T>
typename lua_type_traits<T>::get_type result_at(size_t index) const {
if (index >= result_size()) {
throw std::out_of_range("function result out of range");
}
return lua_type_traits<T>::get(state_,
stack_index_ + static_cast<int>(index));
}
reference result_at(size_t index) const {
if (index >= result_size()) {
throw std::out_of_range("function result out of range");
}
return reference(state_, stack_index_ + static_cast<int>(index));
}
size_t result_size() const { return resultCount_; }
size_t resultStatus() const { return resultStatus_; }
operator LuaStackRef() {
pop_ = 0;
return LuaStackRef(state_, stack_index_, true);
}
private:
mutable lua_State *state_;
int resultStatus_;
int resultCount_;
};
namespace detail {
template <typename RetType>
inline RetType FunctionResultProxy::ReturnValue(lua_State *state,
int return_status, int retindex,
types::typetag<RetType>) {
return FunctionResults(state, return_status, retindex)
.get_result(types::typetag<RetType>());
}
inline FunctionResults
FunctionResultProxy::ReturnValue(lua_State *state, int return_status,
int retindex,
types::typetag<FunctionResults>) {
return FunctionResults(state, return_status, retindex);
}
inline void FunctionResultProxy::ReturnValue(lua_State *state,
int return_status, int retindex,
types::typetag<void>) {
KAGUYA_UNUSED(return_status);
lua_settop(state, retindex - 1);
}
#if KAGUYA_USE_CPP11
template <typename Derived>
template <class... Args>
FunctionResults LuaFunctionImpl<Derived>::operator()(Args &&... args) {
return this->template call<FunctionResults>(std::forward<Args>(args)...);
}
template <typename Derived>
template <class... Args>
FunctionResults LuaThreadImpl<Derived>::operator()(Args &&... args) {
return this->template resume<FunctionResults>(std::forward<Args>(args)...);
}
template <typename Derived>
template <class... Args>
FunctionResults LuaVariantImpl<Derived>::operator()(Args &&... args) {
int t = type();
if (t == LUA_TTHREAD) {
return this->template resume<FunctionResults>(std::forward<Args>(args)...);
} else if (t == LUA_TFUNCTION) {
return this->template call<FunctionResults>(std::forward<Args>(args)...);
} else {
except::typeMismatchError(state_(), " is not function or thread");
return FunctionResults(state_());
}
}
#else
#define KAGUYA_TEMPLATE_PARAMETER(N) template <typename Derived>
#define KAGUYA_FUNCTION_ARGS_DEF(N)
#define KAGUYA_CALL_ARGS(N)
#define KAGUYA_OP_FN_DEF(N) \
KAGUYA_TEMPLATE_PARAMETER(N) \
inline FunctionResults LuaFunctionImpl<Derived>::operator()( \
KAGUYA_FUNCTION_ARGS_DEF(N)) { \
return this->template call<FunctionResults>(KAGUYA_CALL_ARGS(N)); \
} \
KAGUYA_TEMPLATE_PARAMETER(N) \
inline FunctionResults LuaThreadImpl<Derived>::operator()( \
KAGUYA_FUNCTION_ARGS_DEF(N)) { \
return this->template resume<FunctionResults>(KAGUYA_CALL_ARGS(N)); \
} \
KAGUYA_TEMPLATE_PARAMETER(N) \
inline FunctionResults LuaVariantImpl<Derived>::operator()( \
KAGUYA_FUNCTION_ARGS_DEF(N)) { \
int t = type(); \
if (t == LUA_TTHREAD) { \
return this->template resume<FunctionResults>(KAGUYA_CALL_ARGS(N)); \
} else if (t == LUA_TFUNCTION) { \
return this->template call<FunctionResults>(KAGUYA_CALL_ARGS(N)); \
} else { \
except::typeMismatchError(state_(), " is not function or thread"); \
return FunctionResults(state_()); \
} \
}
KAGUYA_OP_FN_DEF(0)
#undef KAGUYA_TEMPLATE_PARAMETER
#undef KAGUYA_FUNCTION_ARGS_DEF
#undef KAGUYA_CALL_ARGS
#define KAGUYA_TEMPLATE_PARAMETER(N) \
template <typename Derived> template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)>
#define KAGUYA_FUNCTION_ARGS_DEF(N) KAGUYA_PP_ARG_CR_DEF_REPEAT(N)
#define KAGUYA_CALL_ARGS(N) KAGUYA_PP_ARG_REPEAT(N)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF)
#undef KAGUYA_OP_FN_DEF
#undef KAGUYA_TEMPLATE_PARAMETER
#undef KAGUYA_CALL_ARGS
#undef KAGUYA_FUNCTION_ARGS_DEF
#undef KAGUYA_CALL_DEF
#undef KAGUYA_OP_FN_DEF
#endif
}
inline std::ostream &operator<<(std::ostream &os, const FunctionResults &res) {
for (FunctionResults::const_iterator it = res.begin(); it != res.end();
++it) {
if (it != res.begin()) {
os << ",";
}
util::stackValueDump(os, res.state(), it.index());
}
return os;
}
/// @ingroup lua_type_traits
/// @brief lua_type_traits for FunctionResults
template <> struct lua_type_traits<FunctionResults> {
static int push(lua_State *l, const FunctionResults &ref) {
int size = 0;
for (FunctionResults::const_iterator it = ref.cbegin(); it != ref.cend();
++it) {
size += it->push(l);
}
return size;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for FunctionResults::reference
template <> struct lua_type_traits<FunctionResults::reference> {
static int push(lua_State *l, const FunctionResults::reference &ref) {
return ref.push(l);
}
};
template <unsigned int I>
FunctionResults::reference get(const FunctionResults &res) {
return res.result_at(I);
}
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaFunction
template <> struct lua_type_traits<LuaFunction> {
typedef LuaFunction get_type;
typedef LuaFunction push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_isfunction(l, index);
}
static bool checkType(lua_State *l, int index) {
return lua_isfunction(l, index) || lua_isnil(l, index);
}
static LuaFunction get(lua_State *l, int index) {
lua_pushvalue(l, index);
return LuaFunction(l, StackTop());
}
static int push(lua_State *l, const LuaFunction &ref) { return ref.push(l); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaFunction
template <>
struct lua_type_traits<const LuaFunction &> : lua_type_traits<LuaFunction> {};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaThread
template <> struct lua_type_traits<LuaThread> {
typedef LuaThread get_type;
typedef LuaThread push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_isthread(l, index);
}
static bool checkType(lua_State *l, int index) {
return lua_isthread(l, index) || lua_isnil(l, index);
}
static LuaThread get(lua_State *l, int index) {
lua_pushvalue(l, index);
return LuaThread(l, StackTop());
}
static int push(lua_State *l, const LuaThread &ref) { return ref.push(l); }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaThread
template <>
struct lua_type_traits<const LuaThread &> : lua_type_traits<LuaThread> {};
/**
* @brief table and function binder.
* state["table"]->*"fun"() is table:fun() in Lua
* @param arg... function args
*/
class MemberFunctionBinder {
public:
template <class T>
MemberFunctionBinder(LuaRef self, T key)
: self_(self), fun_(self_.getField(key)) {}
#define KAGUYA_DELEGATE_LUAREF fun_
#define KAGUYA_DELEGATE_FIRST_ARG self_
#define KAGUYA_DELEGATE_FIRST_ARG_C KAGUYA_DELEGATE_FIRST_ARG,
#if KAGUYA_USE_CPP11
template <class... Args> FunctionResults operator()(Args &&... args) {
return KAGUYA_DELEGATE_LUAREF(
KAGUYA_DELEGATE_FIRST_ARG_C std::forward<Args>(args)...);
}
template <class Result, class... Args> Result call(Args &&... args) {
return KAGUYA_DELEGATE_LUAREF.call<Result>(
KAGUYA_DELEGATE_FIRST_ARG_C std::forward<Args>(args)...);
}
#else
#define KAGUYA_OP_FN_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
FunctionResults operator()(KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
return KAGUYA_DELEGATE_LUAREF( \
KAGUYA_DELEGATE_FIRST_ARG_C KAGUYA_PP_ARG_REPEAT(N)); \
}
/**
* @brief If type is function, call lua function.
* If type is lua thread,start or resume lua thread.
* Otherwise send error message to error handler
*/
FunctionResults operator()() {
return KAGUYA_DELEGATE_LUAREF(KAGUYA_DELEGATE_FIRST_ARG);
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF)
#undef KAGUYA_OP_FN_DEF
#define KAGUYA_CALL_DEF(N) \
template <class Result, KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
Result call(KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
return KAGUYA_DELEGATE_LUAREF.call<Result>( \
KAGUYA_DELEGATE_FIRST_ARG_C KAGUYA_PP_ARG_REPEAT(N)); \
}
template <class Result> Result call() {
return KAGUYA_DELEGATE_LUAREF.call<Result>(KAGUYA_DELEGATE_FIRST_ARG);
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_CALL_DEF)
#undef KAGUYA_CALL_DEF
#endif
#undef KAGUYA_DELEGATE_FIRST_ARG_C
#undef KAGUYA_DELEGATE_FIRST_ARG
#undef KAGUYA_DELEGATE_LUAREF
private:
LuaRef self_; // Table or Userdata
LuaFunction fun_;
};
typedef MemberFunctionBinder mem_fun_binder; // for backward conpatible
}

View file

@ -0,0 +1,588 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <vector>
#include <map>
#include "kaguya/config.hpp"
#include "kaguya/lua_ref.hpp"
#include "kaguya/push_any.hpp"
#include "kaguya/detail/lua_ref_impl.hpp"
#include "kaguya/detail/lua_table_def.hpp"
namespace kaguya {
class State;
/**
* This class is the type returned by members of non-const LuaRef(Table) when
* directly accessing its elements.
*/
template <typename KEY>
class TableKeyReferenceProxy
: public detail::LuaVariantImpl<TableKeyReferenceProxy<KEY> > {
public:
int pushStackIndex(lua_State *state) const {
push(state);
return lua_gettop(state);
}
lua_State *state() const { return state_; }
friend class LuaRef;
friend class State;
//! this is not copy.same assign from referenced value.
TableKeyReferenceProxy &operator=(const TableKeyReferenceProxy &src) {
detail::table_proxy::set(state_, table_index_, key_, src);
return *this;
}
//! assign from T
template <typename T> TableKeyReferenceProxy &operator=(const T &src) {
detail::table_proxy::set(state_, table_index_, key_, src);
return *this;
}
#if KAGUYA_USE_CPP11
template <typename T> TableKeyReferenceProxy &operator=(T &&src) {
detail::table_proxy::set(state_, table_index_, key_, std::forward<T>(src));
return *this;
}
#endif
bool isNilref() const {
if (!state_) {
return false;
}
util::ScopedSavedStack save(state_);
push(state_);
return lua_isnoneornil(state_, -1);
}
//! register class metatable to lua and set to table
template <typename T, typename P>
void setClass(const UserdataMetatable<T, P> &reg) {
set_class(reg);
}
//! set function
template <typename T> void setFunction(T f) {
detail::table_proxy::set(state_, table_index_, key_, kaguya::function(f));
}
int push(lua_State *state) const {
int type = lua_type(state_, table_index_);
if (type != LUA_TTABLE && type != LUA_TUSERDATA) {
lua_pushnil(state);
return 1;
}
detail::table_proxy::get(state_, table_index_, key_);
if (state_ != state) {
lua_xmove(state_, state, 1);
}
return 1;
}
int push() const { return push(state_); }
int type() const {
util::ScopedSavedStack save(state_);
push();
return lua_type(state_, -1);
}
~TableKeyReferenceProxy() {
if (state_) {
lua_settop(state_, stack_top_);
}
}
///!constructs the reference. Accessible only to kaguya::LuaRef itself
TableKeyReferenceProxy(const TableKeyReferenceProxy &src)
: state_(src.state_), stack_top_(src.stack_top_),
table_index_(src.table_index_), key_(src.key_) {
src.state_ = 0;
}
///!constructs the reference. Accessible only to kaguya::LuaRef itself
TableKeyReferenceProxy(lua_State *state, int table_index, KEY key,
int revstacktop)
: state_(state), stack_top_(revstacktop), table_index_(table_index),
key_(key) {}
private:
template <typename T, typename P>
void set_class(const UserdataMetatable<T, P> &reg) {
detail::table_proxy::set(state_, table_index_, key_,
reg.createMatatable(state_));
}
///!constructs the reference. Accessible only to kaguya::LuaRef itself
TableKeyReferenceProxy(lua_State *state, int table_index, const KEY &key,
int revstacktop, const NoTypeCheck &)
: state_(state), stack_top_(revstacktop), table_index_(table_index),
key_(key) {}
TableKeyReferenceProxy(const LuaTable &table, const KEY &key)
: state_(table.state()), stack_top_(lua_gettop(state_)), key_(key) {
util::one_push(state_, table);
table_index_ = stack_top_ + 1;
}
TableKeyReferenceProxy(const LuaRef &table, const KEY &key)
: state_(table.state()), stack_top_(lua_gettop(state_)), key_(key) {
util::one_push(state_, table);
table_index_ = stack_top_ + 1;
int t = lua_type(state_, table_index_);
if (t != LUA_TTABLE) {
except::typeMismatchError(state_, lua_typename(state_, t) +
std::string(" is not table"));
}
}
mutable lua_State *state_; // mutable for RVO unsupported compiler
int stack_top_;
int table_index_;
KEY key_;
};
template <typename KEY>
inline std::ostream &operator<<(std::ostream &os,
const TableKeyReferenceProxy<KEY> &ref) {
lua_State *state = ref.state();
util::ScopedSavedStack save(state);
int stackIndex = ref.pushStackIndex(state);
util::stackValueDump(os, state, stackIndex);
return os;
}
namespace detail {
template <typename T>
inline bool LuaFunctionImpl<T>::setFunctionEnv(const LuaTable &env) {
lua_State *state = state_();
if (!state) {
return false;
}
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
int t = lua_type(state, stackIndex);
if (t != LUA_TFUNCTION) {
except::typeMismatchError(state, lua_typename(state, t) +
std::string(" is not function"));
return false;
}
env.push(state);
#if LUA_VERSION_NUM >= 502
lua_setupvalue(state, stackIndex, 1);
#else
lua_setfenv(state, stackIndex);
#endif
return true;
}
template <typename T> inline bool LuaFunctionImpl<T>::setFunctionEnv(NewTable) {
return setFunctionEnv(LuaTable(state_()));
}
template <typename T>
inline LuaTable LuaFunctionImpl<T>::getFunctionEnv() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
if (!state) {
except::typeMismatchError(state, "is nil");
return LuaTable();
}
int stackIndex = pushStackIndex_(state);
int t = lua_type(state, stackIndex);
if (t != LUA_TFUNCTION) {
except::typeMismatchError(state, lua_typename(state, t) +
std::string(" is not function"));
return LuaTable();
}
#if LUA_VERSION_NUM >= 502
lua_getupvalue(state, stackIndex, 1);
#else
lua_getfenv(state, stackIndex);
#endif
return LuaTable(state, StackTop());
}
template <typename T> void LuaThreadImpl<T>::setFunction(const LuaFunction &f) {
lua_State *corstate = getthread();
if (corstate) {
lua_settop(corstate, 0);
f.push(corstate);
}
}
template <typename T>
bool LuaTableOrUserDataImpl<T>::setMetatable(const LuaTable &table) {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return false;
}
util::ScopedSavedStack save(state);
int stackindex = pushStackIndex_(state);
int t = lua_type(state, stackindex);
if (t != LUA_TTABLE && t != LUA_TUSERDATA) {
except::typeMismatchError(state, lua_typename(state, t) +
std::string(" is not table"));
return false;
}
table.push();
return lua_setmetatable(state, stackindex) != 0;
}
template <typename T> LuaTable LuaTableOrUserDataImpl<T>::getMetatable() const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return LuaTable();
}
util::ScopedSavedStack save(state);
int stackindex = pushStackIndex_(state);
int t = lua_type(state, stackindex);
if (t != LUA_TTABLE && t != LUA_TUSERDATA) {
except::typeMismatchError(state, lua_typename(state, t) +
std::string(" is not table"));
return LuaTable();
}
if (!lua_getmetatable(state, stackindex)) {
lua_pushnil(state);
}
return LuaTable(state, StackTop());
}
template <typename T>
MemberFunctionBinder LuaTableOrUserDataImpl<T>::
operator->*(const char *function_name) {
push_(state_());
return MemberFunctionBinder(LuaRef(state_(), StackTop()), function_name);
}
template <typename T>
template <typename KEY>
LuaStackRef LuaTableOrUserDataImpl<T>::getField(const KEY &key) const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return LuaStackRef();
}
push_(state);
detail::table_proxy::get(state, lua_gettop(state), key);
lua_remove(state, -2); // remove table
return LuaStackRef(state, -1, true);
}
template <typename T>
template <typename KEY>
LuaStackRef LuaTableImpl<T>::getRawField(const KEY &key) const {
lua_State *state = state_();
if (!state) {
except::typeMismatchError(state, "is nil");
return LuaStackRef();
}
push_(state);
detail::table_proxy::rawget(state, lua_gettop(state), key);
lua_remove(state, -2); // remove table
return LuaStackRef(state, -1, true);
}
template <typename T>
template <typename KEY>
LuaStackRef LuaTableOrUserDataImpl<T>::operator[](KEY key) const {
return getField(key);
}
template <typename T> std::vector<LuaRef> LuaTableImpl<T>::values() const {
return values<LuaRef>();
}
template <typename T> std::vector<LuaRef> LuaTableImpl<T>::keys() const {
return keys<LuaRef>();
}
template <typename T> std::map<LuaRef, LuaRef> LuaTableImpl<T>::map() const {
return map<LuaRef, LuaRef>();
}
template <typename T>
template <typename K>
TableKeyReferenceProxy<K> LuaTableOrUserDataImpl<T>::operator[](K key) {
lua_State *state = state_();
int stack_top = lua_gettop(state);
int stackindex = pushStackIndex_(state);
return TableKeyReferenceProxy<K>(state, stackindex, key, stack_top);
}
}
/// @ingroup lua_type_traits
/// @brief lua_type_traits for TableKeyReferenceProxy<KEY>
template <typename KEY> struct lua_type_traits<TableKeyReferenceProxy<KEY> > {
static int push(lua_State *l, const TableKeyReferenceProxy<KEY> &ref) {
return ref.push(l);
}
};
#if KAGUYA_USE_CPP11
/// @ingroup lua_type_traits
/// @brief lua_type_traits for std::array<T, A>
template <typename T, size_t S> struct lua_type_traits<std::array<T, S> > {
typedef std::array<T, S> get_type;
typedef const std::array<T, S> &push_type;
static bool checkType(lua_State *l, int index) {
if (lua_type(l, index) != LUA_TTABLE) {
return false;
}
LuaStackRef table(l, index);
if (table.size() != S) {
return false;
} // TODO
bool valid = true;
table.foreach_table_breakable<LuaStackRef, LuaStackRef>(
[&](const LuaStackRef &k, const LuaStackRef &v) {
valid = valid && k.typeTest<size_t>() && v.typeTest<T>();
return valid;
});
return valid;
}
static bool strictCheckType(lua_State *l, int index) {
if (lua_type(l, index) != LUA_TTABLE) {
return false;
}
LuaStackRef table(l, index);
if (table.size() != S) {
return false;
} // TODO
bool valid = true;
table.foreach_table_breakable<LuaStackRef, LuaStackRef>(
[&](const LuaStackRef &k, const LuaStackRef &v) {
valid = valid && k.typeTest<size_t>() && v.typeTest<T>();
return valid;
});
return valid;
}
static get_type get(lua_State *l, int index) {
if (lua_type(l, index) != LUA_TTABLE) {
except::typeMismatchError(l, std::string("type mismatch"));
return get_type();
}
LuaStackRef t(l, index);
if (t.size() != S) // TODO
{
except::typeMismatchError(l, std::string("type mismatch"));
}
get_type res;
t.foreach_table<size_t, const T &>([&](size_t k, const T &v) {
if (k > 0 && k <= S) {
res[k - 1] = v;
}
});
return res;
}
static int push(lua_State *l, push_type v) {
lua_createtable(l, int(S), 0);
for (size_t i = 0; i < S; ++i) {
util::one_push(l, v[i]);
lua_rawseti(l, -2, i + 1);
}
return 1;
}
};
#endif
#ifndef KAGUYA_NO_STD_VECTOR_TO_TABLE
/// @ingroup lua_type_traits
/// @brief lua_type_traits for std::vector<T, A>
template <typename T, typename A> struct lua_type_traits<std::vector<T, A> > {
typedef std::vector<T, A> get_type;
typedef const std::vector<T, A> &push_type;
struct checkTypeForEach {
checkTypeForEach(bool &valid) : valid_(valid) {}
bool &valid_;
bool operator()(const LuaStackRef &k, const LuaStackRef &v) {
valid_ = k.typeTest<size_t>() && v.weakTypeTest<T>();
return valid_;
}
};
struct strictCheckTypeForEach {
strictCheckTypeForEach(bool &valid) : valid_(valid) {}
bool &valid_;
bool operator()(const LuaStackRef &k, const LuaStackRef &v) {
valid_ = k.typeTest<size_t>() && v.typeTest<T>();
return valid_;
}
};
static bool checkType(lua_State *l, int index) {
LuaStackRef table(l, index);
if (table.type() != LuaRef::TYPE_TABLE) {
return false;
}
bool valid = true;
table.foreach_table_breakable<LuaStackRef, LuaStackRef>(
checkTypeForEach(valid));
return valid;
}
static bool strictCheckType(lua_State *l, int index) {
LuaStackRef table(l, index);
if (table.type() != LuaRef::TYPE_TABLE) {
return false;
}
bool valid = true;
table.foreach_table_breakable<LuaStackRef, LuaStackRef>(
strictCheckTypeForEach(valid));
return valid;
}
static get_type get(lua_State *l, int index) {
if (lua_type(l, index) != LUA_TTABLE) {
except::typeMismatchError(l, std::string("type mismatch"));
return get_type();
}
return LuaStackRef(l, index).values<T>();
}
#if KAGUYA_USE_CPP11
typedef std::vector<T, A> &&move_push_type;
static int push(lua_State *l, move_push_type v) {
lua_createtable(l, int(v.size()), 0);
int count = 1; // array is 1 origin in Lua
for (typename std::vector<T, A>::iterator it = v.begin(); it != v.end();
++it) {
util::one_push(l, static_cast<T &&>(*it));
lua_rawseti(l, -2, count++);
}
return 1;
}
#endif
static int push(lua_State *l, push_type v) {
lua_createtable(l, int(v.size()), 0);
int count = 1; // array is 1 origin in Lua
for (typename std::vector<T, A>::const_iterator it = v.begin();
it != v.end(); ++it) {
util::one_push(l, *it);
lua_rawseti(l, -2, count++);
}
return 1;
}
};
#endif
#ifndef KAGUYA_NO_STD_MAP_TO_TABLE
/// @ingroup lua_type_traits
/// @brief lua_type_traits for std::map<K, V, C, A>
template <typename K, typename V, typename C, typename A>
struct lua_type_traits<std::map<K, V, C, A> > {
typedef std::map<K, V, C, A> get_type;
typedef const std::map<K, V, C, A> &push_type;
struct checkTypeForEach {
checkTypeForEach(bool &valid) : valid_(valid) {}
bool &valid_;
bool operator()(const LuaStackRef &k, const LuaStackRef &v) {
valid_ = k.weakTypeTest<K>() && v.weakTypeTest<V>();
return valid_;
}
};
struct strictCheckTypeForEach {
strictCheckTypeForEach(bool &valid) : valid_(valid) {}
bool &valid_;
bool operator()(const LuaStackRef &k, const LuaStackRef &v) {
valid_ = k.typeTest<K>() && v.typeTest<V>();
return valid_;
}
};
static bool checkType(lua_State *l, int index) {
LuaStackRef table(l, index);
if (table.type() != LuaRef::TYPE_TABLE) {
return false;
}
bool valid = true;
table.foreach_table_breakable<LuaStackRef, LuaStackRef>(
checkTypeForEach(valid));
return valid;
}
static bool strictCheckType(lua_State *l, int index) {
LuaStackRef table(l, index);
if (table.type() != LuaRef::TYPE_TABLE) {
return false;
}
bool valid = true;
table.foreach_table_breakable<LuaStackRef, LuaStackRef>(
strictCheckTypeForEach(valid));
return valid;
}
static get_type get(lua_State *l, int index) {
if (lua_type(l, index) != LUA_TTABLE) {
except::typeMismatchError(l, std::string("type mismatch"));
return get_type();
}
return LuaStackRef(l, index).map<K, V>();
}
static int push(lua_State *l, push_type v) {
lua_createtable(l, 0, int(v.size()));
for (typename std::map<K, V, C, A>::const_iterator it = v.begin();
it != v.end(); ++it) {
util::one_push(l, it->first);
util::one_push(l, it->second);
lua_rawset(l, -3);
}
return 1;
}
};
#endif
struct TableDataElement {
typedef std::pair<AnyDataPusher, AnyDataPusher> keyvalue_type;
template <typename Value>
TableDataElement(Value value)
: keyvalue(keyvalue_type(AnyDataPusher(), value)) {}
template <typename Key, typename Value>
TableDataElement(Key key, Value value)
: keyvalue(keyvalue_type(key, value)) {}
std::pair<AnyDataPusher, AnyDataPusher> keyvalue;
};
struct TableData {
typedef std::pair<AnyDataPusher, AnyDataPusher> data_type;
#if KAGUYA_USE_CPP11
TableData(std::initializer_list<TableDataElement> list)
: elements(list.begin(), list.end()) {}
#endif
template <typename IT> TableData(IT beg, IT end) : elements(beg, end) {}
TableData() {}
std::vector<TableDataElement> elements;
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for TableData
template <> struct lua_type_traits<TableData> {
static int push(lua_State *l, const TableData &list) {
lua_createtable(l, int(list.elements.size()), int(list.elements.size()));
int count = 1; // array is 1 origin in Lua
for (std::vector<TableDataElement>::const_iterator it =
list.elements.begin();
it != list.elements.end(); ++it) {
const TableDataElement &v = *it;
if (v.keyvalue.first.empty()) {
util::one_push(l, v.keyvalue.second);
lua_rawseti(l, -2, count++);
} else {
util::one_push(l, v.keyvalue.first);
util::one_push(l, v.keyvalue.second);
lua_rawset(l, -3);
}
}
return 1;
}
};
}

View file

@ -0,0 +1,695 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include <vector>
#include <map>
#include <typeinfo>
#include "kaguya/config.hpp"
#include "kaguya/push_any.hpp"
#include "kaguya/native_function.hpp"
#include "kaguya/lua_ref_function.hpp"
#define KAGUYA_PROPERTY_PREFIX "_prop_"
namespace kaguya {
#define KAGUYA_PP_STRUCT_TDEF_REP(N) KAGUYA_PP_CAT(class A, N) = void
#define KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_STRUCT_TDEF_REP)
template <KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(KAGUYA_CLASS_MAX_BASE_CLASSES)>
struct MultipleBase {};
#undef KAGUYA_PP_STRUCT_TDEF_REP
#undef KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT
}
namespace kaguya {
struct LuaCodeChunk {
LuaCodeChunk(const std::string &src, const std::string &name = "")
: code_(src), chunk_name_(name) {}
LuaCodeChunk(const char *src, const char *name = "")
: code_(src), chunk_name_(name ? name : "") {}
std::string code_;
std::string chunk_name_;
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaCodeChunk
template <> struct lua_type_traits<LuaCodeChunk> {
static int push(lua_State *state, const LuaCodeChunk &ref) {
int status = luaL_loadbuffer(
state, ref.code_.c_str(), ref.code_.size(),
ref.chunk_name_.empty() ? ref.code_.c_str() : ref.chunk_name_.c_str());
if (!except::checkErrorAndThrow(status, state)) {
return 0;
}
return 1;
}
};
struct LuaCodeChunkExecute : LuaCodeChunk {
LuaCodeChunkExecute(const std::string &src, const std::string &name = "")
: LuaCodeChunk(src, name) {}
LuaCodeChunkExecute(const char *src, const char *name = "")
: LuaCodeChunk(src, name) {}
};
typedef LuaCodeChunkExecute LuaCodeChunkResult;
/// @ingroup lua_type_traits
/// @brief lua_type_traits for LuaCodeChunkResult
template <> struct lua_type_traits<LuaCodeChunkExecute> {
static int push(lua_State *state, const LuaCodeChunkExecute &ref) {
int status = luaL_loadbuffer(
state, ref.code_.c_str(), ref.code_.size(),
ref.chunk_name_.empty() ? ref.code_.c_str() : ref.chunk_name_.c_str());
if (!except::checkErrorAndThrow(status, state)) {
return 0;
}
status = lua_pcall_wrap(state, 0, 1);
if (!except::checkErrorAndThrow(status, state)) {
return 0;
}
return 1;
}
};
namespace Metatable {
typedef std::map<std::string, AnyDataPusher> PropMapType;
typedef std::map<std::string, AnyDataPusher> MemberMapType;
inline bool is_property_key(const char *keyname) {
return keyname &&
strncmp(keyname, KAGUYA_PROPERTY_PREFIX,
sizeof(KAGUYA_PROPERTY_PREFIX) - 1) != 0;
}
inline int property_index_function(lua_State *L) {
// Lua
// local arg = {...};local metatable = arg[1];
// return function(table, index)
// if string.find(index,KAGUYA_PROPERTY_PREFIX)~=0 then
// local propfun = metatable[KAGUYA_PROPERTY_PREFIX ..index];
// if propfun then return propfun(table) end
// end
// return metatable[index]
// end
static const int table = 1;
static const int key = 2;
static const int metatable = lua_upvalueindex(1);
const char *strkey = lua_tostring(L, key);
if (lua_type(L, 1) == LUA_TUSERDATA && is_property_key(strkey)) {
int type = lua_getfield_rtype(
L, metatable, (KAGUYA_PROPERTY_PREFIX + std::string(strkey)).c_str());
if (type == LUA_TFUNCTION) {
lua_pushvalue(L, table);
lua_call(L, 1, 1);
return 1;
}
}
lua_pushvalue(L, key);
lua_gettable(L, metatable);
return 1;
}
inline int property_newindex_function(lua_State *L) {
// Lua
// local arg = {...};local metatable = arg[1];
// return function(table, index, value)
// if type(table) == 'userdata' then
// if string.find(index,KAGUYA_PROPERTY_PREFIX)~=0 then
// local propfun = metatable[KAGUYA_PROPERTY_PREFIX..index];
// if propfun then return propfun(table,value) end
// end
// end
// rawset(table,index,value)
// end
static const int table = 1;
static const int key = 2;
static const int value = 3;
static const int metatable = lua_upvalueindex(1);
const char *strkey = lua_tostring(L, 2);
if (lua_type(L, 1) == LUA_TUSERDATA && is_property_key(strkey)) {
int type = lua_getfield_rtype(
L, metatable, (KAGUYA_PROPERTY_PREFIX + std::string(strkey)).c_str());
if (type == LUA_TFUNCTION) {
lua_pushvalue(L, table);
lua_pushvalue(L, value);
lua_call(L, 2, 0);
return 0;
}
}
lua_pushvalue(L, key);
lua_pushvalue(L, value);
lua_rawset(L, table);
return 0;
}
inline int multiple_base_index_function(lua_State *L) {
// Lua
// local arg = {...};local metabases = arg[1];
// return function(t, k)
// for i = 1,#metabases do
// local v = metabases[i][k]
// if v then
// t[k] = v
// return v end
// end
// end
static const int table = 1;
static const int key = 2;
static const int metabases = lua_upvalueindex(1);
lua_pushnil(L);
while (lua_next(L, metabases) != 0) {
if (lua_type(L, -1) == LUA_TTABLE) {
lua_pushvalue(L, key);
int type = lua_gettable_rtype(L, -2);
if (type != LUA_TNIL) {
lua_pushvalue(L, key);
lua_pushvalue(L, -2);
lua_settable(L, table);
return 1;
}
}
lua_settop(L, 3); // pop value
}
return 0;
}
inline int call_constructor_function(lua_State *L) {
// function(t,...) return t.new(...) end
lua_getfield(L, 1, "new");
lua_replace(L, 1);
lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
return lua_gettop(L);
}
inline void get_call_constructor_metatable(lua_State *L) {
static int key = 0;
int ttype = lua_rawgetp_rtype(L, LUA_REGISTRYINDEX, &key);
if (ttype != LUA_TTABLE) {
lua_pop(L, 1);
lua_createtable(L, 0, 1);
lua_pushstring(L, "__call");
lua_pushcfunction(L, &call_constructor_function);
lua_rawset(L, -3);
lua_pushvalue(L, -1);
lua_rawsetp(L, LUA_REGISTRYINDEX, &key);
}
}
inline void setMembers(lua_State *state, int metatable_index,
const MemberMapType &member_map,
const PropMapType &property_map) {
for (MemberMapType::const_iterator it = member_map.begin();
it != member_map.end(); ++it) {
util::one_push(state, it->first);
util::one_push(state, it->second);
lua_rawset(state, metatable_index);
}
for (PropMapType::const_iterator it = property_map.begin();
it != property_map.end(); ++it) {
util::one_push(state, KAGUYA_PROPERTY_PREFIX + it->first);
util::one_push(state, it->second);
lua_rawset(state, metatable_index);
}
}
inline void setPropertyIndexMetamethod(lua_State *state, int metatable_index) {
lua_pushstring(state, "__index");
lua_pushvalue(state, metatable_index);
lua_pushcclosure(state, &property_index_function, 1);
lua_rawset(state, metatable_index);
}
inline void setPropertyNewIndexMetamethod(lua_State *state,
int metatable_index) {
lua_pushstring(state, "__newindex");
lua_pushvalue(state, metatable_index);
lua_pushcclosure(state, &property_newindex_function, 1);
lua_rawset(state, metatable_index);
}
inline void setMultipleBase(lua_State *state, int metatable_index,
int metabase_array_index) {
lua_createtable(state, 0, 1);
int newmetaindex = lua_gettop(state);
lua_pushstring(state, "__index");
lua_pushvalue(state, metabase_array_index); // bind metabase_array to
// multiple_base_index_function
lua_pushcclosure(state, &multiple_base_index_function, 1);
lua_rawset(state,
newmetaindex); // newmeta["__index"] = multiple_base_index_function
lua_setmetatable(state, metatable_index); // metatable.setMetatable(newmeta);
}
}
/// class binding interface.
template <typename class_type, typename base_class_type = void>
class UserdataMetatable {
public:
UserdataMetatable() {
addStaticFunction("__gc", &class_userdata::destructor<ObjectWrapperBase>);
KAGUYA_STATIC_ASSERT(is_registerable<class_type>::value ||
!traits::is_std_vector<class_type>::value,
"std::vector is binding to lua-table by default.If "
"you wants register for std::vector yourself,"
"please define KAGUYA_NO_STD_VECTOR_TO_TABLE");
KAGUYA_STATIC_ASSERT(is_registerable<class_type>::value ||
!traits::is_std_map<class_type>::value,
"std::map is binding to lua-table by default.If you "
"wants register for std::map yourself,"
"please define KAGUYA_NO_STD_MAP_TO_TABLE");
// can not register push specialized class
KAGUYA_STATIC_ASSERT(is_registerable<class_type>::value,
"Can not register specialized of type conversion "
"class. e.g. std::tuple");
}
LuaTable createMatatable(lua_State *state) const {
util::ScopedSavedStack save(state);
if (!class_userdata::newmetatable<class_type>(state)) {
except::OtherError(state, typeid(class_type *).name() +
std::string(" is already registered"));
return LuaTable();
}
int metatable_index = lua_gettop(state);
Metatable::setMembers(state, metatable_index, member_map_, property_map_);
if (!traits::is_same<base_class_type, void>::value ||
!property_map_.empty()) // if base class has property and derived class
// hasnt property. need property access
// metamethod
{
if (member_map_.count("__index") == 0) {
Metatable::setPropertyIndexMetamethod(state, metatable_index);
}
if (member_map_.count("__newindex") == 0) {
Metatable::setPropertyNewIndexMetamethod(state, metatable_index);
}
} else {
if (member_map_.count("__index") == 0) {
lua_pushstring(state, "__index");
lua_pushvalue(state, metatable_index);
lua_rawset(state, metatable_index);
}
}
set_base_metatable(state, metatable_index,
types::typetag<base_class_type>());
if (lua_getmetatable(state, metatable_index)) // get base_metatable
{
lua_pushstring(state, "__call");
lua_pushcfunction(state, &Metatable::call_constructor_function);
lua_rawset(state, -3); // base_metatable["__call"] =
// Metatable::call_constructor_function
} else {
Metatable::get_call_constructor_metatable(state);
lua_setmetatable(state, metatable_index);
}
return LuaStackRef(state, metatable_index);
}
#if KAGUYA_USE_CPP11
template <typename... ArgTypes> UserdataMetatable &setConstructors() {
addOverloadedFunctions(
"new", typename ConstructorFunction<class_type, ArgTypes>::type()...);
return *this;
}
#else
#define KAGUYA_SET_CON_TYPE_DEF(N) \
typename ConstructorFunction<class_type, KAGUYA_PP_CAT(A, N)>::type()
#define KAGUYA_SET_CON_FN_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
inline UserdataMetatable &setConstructors() { \
addOverloadedFunctions("new", \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_SET_CON_TYPE_DEF)); \
return *this; \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_SET_CON_FN_DEF)
#undef KAGUYA_SET_CON_FN_DEF
#undef KAGUYA_SET_CON_TYPE_DEF
#endif
/// @brief add member property with getter function.(experimental)
/// @param name function name for lua
/// @param mem bind member data
template <typename Ret>
UserdataMetatable &addProperty(const char *name, Ret class_type::*mem) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(kaguya::function(mem));
return *this;
}
/// @brief add member property with getter function.(experimental)
/// @param name function name for lua
/// @param getter getter function
template <typename GetType>
UserdataMetatable &addProperty(const char *name,
GetType (class_type::*getter)() const) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(kaguya::function(getter));
return *this;
}
/// @brief add member property with setter, getter functions.(experimental)
/// @param name function name for lua
/// @param getter getter function
/// @param setter setter function
template <typename GetType>
UserdataMetatable &addProperty(const char *name,
GetType (*getter)(const class_type *)) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(function(getter));
return *this;
}
/// @brief add member property with setter, getter functions.(experimental)
/// @param name function name for lua
/// @param getter getter function
/// @param setter setter function
template <typename GetType>
UserdataMetatable &addProperty(const char *name,
GetType (*getter)(const class_type &)) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(function(getter));
return *this;
}
/// @brief add member property with setter, getter functions.(experimental)
/// @param name function name for lua
/// @param getter getter function
/// @param setter setter function
template <typename GetType, typename SetType>
UserdataMetatable &addProperty(const char *name,
GetType (class_type::*getter)() const,
void (class_type::*setter)(SetType)) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(overload(getter, setter));
return *this;
}
/// @brief add member property with external setter, getter
/// functions.(experimental)
/// @param name function name for lua
/// @param getter getter function
/// @param setter setter function
template <typename GetType, typename SetType>
UserdataMetatable &addProperty(const char *name,
GetType (*getter)(const class_type *),
void (*setter)(class_type *, SetType)) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(overload(getter, setter));
return *this;
}
/// @brief add member property with external setter, getter
/// functions.(experimental)
/// @param name function name for lua
/// @param getter getter function
/// @param setter setter function
template <typename GetType, typename SetType>
UserdataMetatable &addProperty(const char *name,
GetType (*getter)(const class_type &),
void (*setter)(class_type &, SetType)) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(overload(getter, setter));
return *this;
}
/// @brief add member property with getter function.(experimental)
/// @param name function name for lua
/// @param getter getter function
template <typename GetterType>
UserdataMetatable &addPropertyAny(const char *name, GetterType getter) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(function(getter));
return *this;
}
/// @brief add member property with setter, getter functions.(experimental)
/// @param name function name for lua
/// @param getter getter function
/// @param setter setter function
template <typename GetterType, typename SetterType>
UserdataMetatable &addPropertyAny(const char *name, GetterType getter,
SetterType setter) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
property_map_[name] = AnyDataPusher(overload(getter, setter));
return *this;
}
/// @brief add non member function
/// @param name function name for lua
/// @param f function
template <typename Fun>
UserdataMetatable &addStaticFunction(const char *name, Fun f) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
member_map_[name] = AnyDataPusher(kaguya::function(f));
return *this;
}
#if KAGUYA_USE_CPP11
/// @brief assign overloaded from functions.
/// @param name name for lua
/// @param f functions
template <typename... Funcs>
UserdataMetatable &addOverloadedFunctions(const char *name, Funcs... f) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
member_map_[name] = AnyDataPusher(overload(f...));
return *this;
}
/// @brief assign data by argument value.
/// @param name name for lua
/// @param d data
template <typename Data>
UserdataMetatable &addStaticField(const char *name, Data &&d) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
member_map_[name] = AnyDataPusher(std::forward<Data>(d));
return *this;
}
#else
#define KAGUYA_ADD_OVERLOAD_FUNCTION_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
inline UserdataMetatable &addOverloadedFunctions( \
const char *name, KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
if (has_key(name)) { \
throw KaguyaException(std::string(name) + " is already registered."); \
return *this; \
} \
member_map_[name] = \
AnyDataPusher(kaguya::overload(KAGUYA_PP_ARG_REPEAT(N))); \
return *this; \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS,
KAGUYA_ADD_OVERLOAD_FUNCTION_DEF)
#undef KAGUYA_ADD_OVERLOAD_FUNCTION_DEF
/// @brief assign data by argument value.
/// @param name name for lua
/// @param d data
template <typename Data>
UserdataMetatable &addStaticField(const char *name, const Data &d) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered.");
return *this;
}
member_map_[name] = AnyDataPusher(d);
return *this;
}
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1800
// can not write Ret class_type::* f on MSC++2013
template <typename Fun>
UserdataMetatable &addFunction(const char *name, Fun f) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered. To "
"overload a function, use "
"addOverloadedFunctions");
return *this;
}
member_map_[name] = AnyDataPusher(kaguya::function(f));
return *this;
}
#else
/// @brief assign function
/// @param name name for lua
/// @param f pointer to member function.
template <typename Ret>
UserdataMetatable &addFunction(const char *name, Ret class_type::*f) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered. To "
"overload a function, use "
"addOverloadedFunctions");
return *this;
}
member_map_[name] = AnyDataPusher(kaguya::function(f));
return *this;
}
#endif
/// @brief assign function
/// @param name name for lua
/// @param f member function object.
UserdataMetatable &addFunction(const char *name, PolymorphicMemberInvoker f) {
if (has_key(name)) {
throw KaguyaException(std::string(name) + " is already registered. To "
"overload a function, use "
"addOverloadedFunctions");
return *this;
}
member_map_[name] = AnyDataPusher(kaguya::function(f));
return *this;
}
private:
void set_base_metatable(lua_State *, int, types::typetag<void>) const {}
template <class Base>
void set_base_metatable(lua_State *state, int metatable_index,
types::typetag<Base>) const {
class_userdata::get_metatable<Base>(state);
lua_setmetatable(state,
metatable_index); // metatable.setMetatable(newmeta);
PointerConverter &pconverter = PointerConverter::get(state);
pconverter.add_type_conversion<Base, class_type>();
}
#if KAGUYA_USE_CPP11
template <typename Base>
void metatables(lua_State *state, int metabase_array_index,
PointerConverter &pvtreg,
types::typetag<MultipleBase<Base> >) const {
class_userdata::get_metatable<Base>(state);
lua_rawseti(state, metabase_array_index,
lua_rawlen(state, metabase_array_index) + 1);
pvtreg.add_type_conversion<Base, class_type>();
}
template <typename Base, typename... Remain>
void metatables(lua_State *state, int metabase_array_index,
PointerConverter &pvtreg,
types::typetag<MultipleBase<Base, Remain...> >) const {
class_userdata::get_metatable<Base>(state);
lua_rawseti(state, metabase_array_index,
lua_rawlen(state, metabase_array_index) + 1);
pvtreg.add_type_conversion<Base, class_type>();
metatables(state, metabase_array_index, pvtreg,
types::typetag<MultipleBase<Remain...> >());
}
template <typename... Bases>
void
set_base_metatable(lua_State *state, int metatable_index,
types::typetag<MultipleBase<Bases...> > metatypes) const {
PointerConverter &pconverter = PointerConverter::get(state);
lua_createtable(state, sizeof...(Bases), 0);
int metabase_array_index = lua_gettop(state);
metatables(state, metabase_array_index, pconverter, metatypes);
Metatable::setMultipleBase(state, metatable_index, metabase_array_index);
}
#else
#define KAGUYA_GET_BASE_METATABLE(N) \
class_userdata::get_metatable<KAGUYA_PP_CAT(A, N)>(state); \
lua_rawseti(state, metabase_array_index, \
lua_rawlen(state, metabase_array_index) + 1); \
pconverter.add_type_conversion<KAGUYA_PP_CAT(A, N), class_type>();
#define KAGUYA_MULTIPLE_INHERITANCE_SETBASE_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
void set_base_metatable( \
lua_State *state, int metatable_index, \
types::typetag<MultipleBase<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> >) const { \
PointerConverter &pconverter = PointerConverter::get(state); \
lua_createtable(state, N, 0); \
int metabase_array_index = lua_gettop(state); \
KAGUYA_PP_REPEAT(N, KAGUYA_GET_BASE_METATABLE); \
Metatable::setMultipleBase(state, metatable_index, metabase_array_index); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_CLASS_MAX_BASE_CLASSES,
KAGUYA_MULTIPLE_INHERITANCE_SETBASE_DEF)
#undef KAGUYA_MULTIPLE_INHERITANCE_SETBASE_DEF
#undef KAGUYA_GET_BASE_METATABLE
#endif
bool has_key(const std::string &key) {
if (member_map_.count(key) > 0) {
return true;
}
if (property_map_.count(key) > 0) {
return true;
}
std::string propkey = KAGUYA_PROPERTY_PREFIX + key;
if (member_map_.count(propkey) > 0) //_prop_keyname is reserved for property
{
return true;
}
return false;
}
Metatable::PropMapType property_map_;
Metatable::MemberMapType member_map_;
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for UserdataMetatable
template <typename T, typename Base>
struct lua_type_traits<UserdataMetatable<T, Base> > {
typedef const UserdataMetatable<T, Base> &push_type;
static int push(lua_State *l, push_type ref) {
return ref.createMatatable(l).push(l);
}
};
}

View file

@ -0,0 +1,967 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include <vector>
#include <iterator>
#include "kaguya/config.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/type.hpp"
#include "kaguya/lua_ref.hpp"
#if KAGUYA_USE_CPP11
#include "kaguya/native_function_cxx11.hpp"
#else
#include "kaguya/native_function_cxx03.hpp"
#endif
#include "kaguya/function_tuple_def.hpp"
namespace kaguya {
struct FunctionImpl {
virtual int invoke(lua_State *state) = 0;
virtual std::string argTypesName() const = 0;
virtual bool checkArgTypes(lua_State *state) const = 0;
virtual bool strictCheckArgTypes(lua_State *state) const = 0;
virtual int minArgCount() const = 0;
virtual int maxArgCount() const = 0;
virtual ~FunctionImpl() {}
};
struct PolymorphicInvoker {
typedef standard::shared_ptr<FunctionImpl> holder_type;
PolymorphicInvoker(const holder_type &fptr) : fnc(fptr) {}
int invoke(lua_State *state) const { return fnc->invoke(state); }
std::string argTypesName() const { return fnc->argTypesName(); }
bool checkArgTypes(lua_State *state) const {
return fnc->checkArgTypes(state);
}
bool strictCheckArgTypes(lua_State *state) const {
return fnc->strictCheckArgTypes(state);
}
int minArgCount() const { return fnc->minArgCount(); }
int maxArgCount() const { return fnc->maxArgCount(); }
~PolymorphicInvoker() {}
private:
holder_type fnc;
};
struct PolymorphicMemberInvoker : PolymorphicInvoker {
PolymorphicMemberInvoker(const holder_type &fptr)
: PolymorphicInvoker(fptr) {}
};
namespace nativefunction {
template <size_t INDEX, typename F>
typename lua_type_traits<typename util::ArgumentType<INDEX, F>::type>::get_type
getArgument(lua_State *state) {
return lua_type_traits<typename util::ArgumentType<INDEX, F>::type>::get(
state, INDEX + 1);
}
template <typename T, typename Enable = void>
struct is_callable
: traits::integral_constant<
bool, !traits::is_same<
void, typename util::FunctionSignature<T>::type>::value> {};
template <class MemType, class T>
struct is_callable<MemType T::*> : traits::integral_constant<bool, true> {};
template <typename T>
struct is_callable<ConstructorFunctor<T> >
: traits::integral_constant<bool, true> {};
// for constructors
template <class T> int call(lua_State *state, ConstructorFunctor<T> &con) {
return con(state);
}
template <class T>
int call(lua_State *state, const ConstructorFunctor<T> &con) {
return con(state);
}
template <class T>
bool checkArgTypes(lua_State *state, const ConstructorFunctor<T> &con,
int opt_count = 0) {
return con.checkArgTypes(state, opt_count);
}
template <class T>
bool strictCheckArgTypes(lua_State *state, const ConstructorFunctor<T> &con,
int opt_count = 0) {
return con.strictCheckArgTypes(state, opt_count);
}
template <class T> std::string argTypesName(const ConstructorFunctor<T> &con) {
return con.argTypesName();
}
template <class T> int minArgCount(const ConstructorFunctor<T> &) {
return ConstructorFunctor<T>::signature_type::argument_count;
}
template <class T> int maxArgCount(const ConstructorFunctor<T> &) {
return ConstructorFunctor<T>::signature_type::argument_count;
}
// for data member
// using is_member_function_pointer in MSVC2010 : fatal error LNK1179: invalid
// or corrupt file: duplicate COMDAT
// '?value@?$result_@P8ABC@test_02_classreg@@AE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ@?$is_mem_fun_pointer_select@$0A@@detail@boost@@2_NB'
template <class MemType, class T>
typename traits::enable_if<traits::is_object<MemType>::value, int>::type
call(lua_State *state, MemType T::*mptr) {
T *this_ = lua_type_traits<T *>::get(state, 1);
if (lua_gettop(state) == 1) {
if (!this_) {
const T &this_ = lua_type_traits<const T &>::get(state, 1);
if (is_usertype<MemType>::value && !traits::is_pointer<MemType>::value) {
return util::push_args(
state, standard::reference_wrapper<const MemType>(this_.*mptr));
} else {
return util::push_args(state, this_.*mptr);
}
} else {
if (is_usertype<MemType>::value && !traits::is_pointer<MemType>::value) {
return util::push_args(
state, standard::reference_wrapper<MemType>(this_->*mptr));
} else {
return util::push_args(state, this_->*mptr);
}
}
} else {
if (!this_) {
throw LuaTypeMismatch();
}
this_->*mptr = lua_type_traits<MemType>::get(state, 2);
return 0;
}
}
template <class MemType, class T>
typename traits::enable_if<traits::is_object<MemType>::value, bool>::type
checkArgTypes(lua_State *state, MemType T::*, int opt_count = 0) {
KAGUYA_UNUSED(opt_count);
if (lua_gettop(state) >= 2) {
// setter typecheck
return lua_type_traits<MemType>::checkType(state, 2) &&
lua_type_traits<T>::checkType(state, 1);
}
// getter typecheck
return lua_type_traits<T>::checkType(state, 1);
}
template <class MemType, class T>
typename traits::enable_if<traits::is_object<MemType>::value, bool>::type
strictCheckArgTypes(lua_State *state, MemType T::*, int opt_count = 0) {
KAGUYA_UNUSED(opt_count);
if (lua_gettop(state) == 2) {
// setter typecheck
return lua_type_traits<MemType>::strictCheckType(state, 2) &&
lua_type_traits<T>::strictCheckType(state, 1);
}
// getter typecheck
return lua_type_traits<T>::strictCheckType(state, 1);
}
template <class MemType, class T>
typename traits::enable_if<traits::is_object<MemType>::value, std::string>::type
argTypesName(MemType T::*) {
return util::pretty_name(typeid(T *)) + ",[OPT] " +
util::pretty_name(typeid(MemType));
}
template <class MemType, class T>
typename traits::enable_if<traits::is_object<MemType>::value, int>::type
minArgCount(MemType T::*) {
return 1;
}
template <class MemType, class T>
typename traits::enable_if<traits::is_object<MemType>::value, int>::type
maxArgCount(MemType T::*) {
return 2;
}
inline int call(lua_State *state, const PolymorphicInvoker &f) {
return f.invoke(state);
}
inline int call(lua_State *state, PolymorphicInvoker &f) {
return f.invoke(state);
}
inline bool checkArgTypes(lua_State *state, const PolymorphicInvoker &f) {
return f.checkArgTypes(state);
}
inline bool strictCheckArgTypes(lua_State *state, const PolymorphicInvoker &f) {
return f.strictCheckArgTypes(state);
}
inline std::string argTypesName(const PolymorphicInvoker &f) {
return f.argTypesName();
}
inline int minArgCount(const PolymorphicInvoker &f) { return f.minArgCount(); }
inline int maxArgCount(const PolymorphicInvoker &f) { return f.maxArgCount(); }
template <>
struct is_callable<PolymorphicInvoker> : traits::integral_constant<bool, true> {
};
inline int call(lua_State *state, const PolymorphicMemberInvoker &f) {
return f.invoke(state);
}
inline int call(lua_State *state, PolymorphicMemberInvoker &f) {
return f.invoke(state);
}
inline bool checkArgTypes(lua_State *state, const PolymorphicMemberInvoker &f) {
return f.checkArgTypes(state);
}
inline bool strictCheckArgTypes(lua_State *state,
const PolymorphicMemberInvoker &f) {
return f.strictCheckArgTypes(state);
}
inline std::string argTypesName(const PolymorphicMemberInvoker &f) {
return f.argTypesName();
}
inline int minArgCount(const PolymorphicMemberInvoker &f) {
return f.minArgCount();
}
inline int maxArgCount(const PolymorphicMemberInvoker &f) {
return f.maxArgCount();
}
template <>
struct is_callable<PolymorphicMemberInvoker>
: traits::integral_constant<bool, true> {};
}
class VariadicArgType {
public:
VariadicArgType(lua_State *state, int startIndex)
: state_(state), startIndex_(startIndex),
endIndex_(lua_gettop(state) + 1) {
if (startIndex_ > endIndex_) {
endIndex_ = startIndex_;
}
}
template <typename T> operator std::vector<T>() const {
if (startIndex_ >= endIndex_) {
return std::vector<T>();
}
std::vector<T> result;
result.reserve(endIndex_ - startIndex_);
for (int index = startIndex_; index < endIndex_; ++index) {
result.push_back(lua_type_traits<T>::get(state_, index));
}
return result;
}
struct reference : public Ref::StackRef,
public detail::LuaVariantImpl<reference> {
reference(lua_State *s, int index) : Ref::StackRef(s, index, false) {}
const reference *operator->() const { return this; }
};
struct iterator {
typedef std::random_access_iterator_tag iterator_category;
typedef VariadicArgType::reference reference;
typedef int difference_type;
typedef reference value_type;
typedef reference *pointer;
iterator() : state_(0), stack_index_(0) {}
iterator(lua_State *state, int index)
: state_(state), stack_index_(index) {}
reference operator*() const { return reference(state_, stack_index_); }
reference operator->() const { return reference(state_, stack_index_); }
iterator &operator++() {
stack_index_++;
return *this;
}
iterator operator++(int) { return iterator(state_, stack_index_++); }
iterator &operator+=(int n) {
stack_index_ += n;
return *this;
}
iterator operator+(int n) const {
return iterator(state_, stack_index_ + n);
}
iterator &operator--() {
stack_index_--;
return *this;
}
iterator operator--(int) { return iterator(state_, stack_index_--); }
iterator &operator-=(int n) {
stack_index_ -= n;
return *this;
}
iterator operator-(int n) const {
return iterator(state_, stack_index_ - n);
}
difference_type operator-(const iterator &n) {
return stack_index_ - n.stack_index_;
}
reference operator[](difference_type offset) const {
return reference(state_, stack_index_ + offset);
}
/**
* @name relational operators
* @brief
*/
//@{
bool operator==(const iterator &other) const {
return state_ == other.state_ && stack_index_ == other.stack_index_;
}
bool operator!=(const iterator &other) const { return !(*this == other); }
bool operator<(const iterator &other) const {
return stack_index_ < other.stack_index_;
}
bool operator>(const iterator &other) const { return other < *this; }
bool operator<=(const iterator &other) const { return other >= *this; }
bool operator>=(const iterator &other) const { return !(*this < other); }
//@}
private:
lua_State *state_;
int stack_index_;
};
typedef iterator const_iterator;
typedef reference const_reference;
typedef reference value_type;
iterator begin() { return iterator(state_, startIndex_); }
iterator end() { return iterator(state_, endIndex_); }
const_iterator cbegin() { return const_iterator(state_, startIndex_); }
const_iterator cend() { return const_iterator(state_, endIndex_); }
template <typename T>
typename lua_type_traits<T>::get_type at(size_t index) const {
if (index >= size()) {
throw std::out_of_range("variadic arguments out of range");
}
return lua_type_traits<T>::get(state_,
startIndex_ + static_cast<int>(index));
}
reference at(size_t index) const {
if (index >= size()) {
throw std::out_of_range("variadic arguments out of range");
}
return reference(state_, startIndex_ + static_cast<int>(index));
}
reference operator[](size_t index) const {
return reference(state_, startIndex_ + static_cast<int>(index));
}
size_t size() const { return endIndex_ - startIndex_; }
size_t empty() const { return endIndex_ == startIndex_; }
private:
lua_State *state_;
int startIndex_;
int endIndex_;
};
inline VariadicArgType::iterator operator+(int n,
const VariadicArgType::iterator &i) {
return i + n;
}
/// @ingroup lua_type_traits
/// @brief lua_type_traits for VariadicArgType
template <> struct lua_type_traits<VariadicArgType> {
typedef VariadicArgType get_type;
static bool strictCheckType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return true;
}
static bool checkType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return true;
}
static get_type get(lua_State *l, int index) {
return VariadicArgType(l, index);
}
};
namespace nativefunction {
static const int MAX_OVERLOAD_SCORE = 255;
template <typename Fn>
uint8_t compute_function_matching_score(lua_State *state, const Fn &fn) {
int argcount = lua_gettop(state);
if (strictCheckArgTypes(state, fn)) {
const int minargcount = minArgCount(fn);
const int maxargcount = maxArgCount(fn);
if (minargcount <= argcount && maxargcount >= argcount) {
return MAX_OVERLOAD_SCORE;
} else {
int diff = std::min(std::abs(argcount - minargcount),
std::abs(argcount - maxargcount));
return std::max(100 - diff, 51);
}
} else if (checkArgTypes(state, fn)) {
const int minargcount = minArgCount(fn);
const int maxargcount = maxArgCount(fn);
if (minargcount <= argcount && maxargcount >= argcount) {
return 200;
} else {
int diff = std::min(std::abs(argcount - minargcount),
std::abs(argcount - maxargcount));
return std::max(50 - diff, 1);
}
} else {
return 0;
}
}
inline int pushArgmentTypeNames(lua_State *state, int top) {
for (int i = 1; i <= top; i++) {
if (i != 1) {
lua_pushliteral(state, ",");
}
int type = lua_type(state, i);
if (type == LUA_TUSERDATA) {
int nametype = luaL_getmetafield(state, i, "__name");
if (nametype != LUA_TSTRING) {
lua_pop(state, 1);
lua_pushstring(state, lua_typename(state, type));
}
} else {
lua_pushstring(state, lua_typename(state, type));
}
}
return lua_gettop(state) - top;
}
}
#if KAGUYA_USE_CPP11
namespace detail {
template <typename Fn, typename... Functions>
void function_match_scoring(lua_State *state, uint8_t *score_array,
int current_index, const Fn &fn) {
score_array[current_index] =
nativefunction::compute_function_matching_score(state, fn);
}
template <typename Fn, typename... Functions>
void function_match_scoring(lua_State *state, uint8_t *score_array,
int current_index, const Fn &fn,
const Functions &... fns) {
score_array[current_index] =
nativefunction::compute_function_matching_score(state, fn);
if (score_array[current_index] < nativefunction::MAX_OVERLOAD_SCORE) {
function_match_scoring(state, score_array, current_index + 1, fns...);
}
}
template <typename... Functions>
int best_function_index(lua_State *state, const Functions &... fns) {
static const int fncount = sizeof...(fns);
uint8_t score[fncount] = {};
function_match_scoring(state, score, 0, fns...);
uint8_t best_score = 0;
int best_score_index = -1;
for (int i = 0; i < fncount; ++i) {
if (best_score < score[i]) {
best_score = score[i];
best_score_index = i;
if (best_score == nativefunction::MAX_OVERLOAD_SCORE) {
break;
}
}
}
return best_score_index;
}
template <typename Fn>
int invoke_index(lua_State *state, int index, int current_index, Fn &&fn) {
KAGUYA_UNUSED(index);
KAGUYA_UNUSED(current_index);
return nativefunction::call(state, fn);
}
template <typename Fn, typename... Functions>
int invoke_index(lua_State *state, int index, int current_index, Fn &&fn,
Functions &&... fns) {
if (index == current_index) {
return nativefunction::call(state, fn);
} else {
return invoke_index(state, index, current_index + 1, fns...);
}
}
template <typename Fun> int best_match_invoke(lua_State *state, Fun &&fn) {
return nativefunction::call(state, fn);
}
template <typename Fun, typename... Functions>
int best_match_invoke(lua_State *state, Fun &&fn, Functions &&... fns) {
int index = best_function_index(state, fn, fns...);
if (index >= 0) {
assert(size_t(index) <= sizeof...(fns));
return invoke_index(state, index, 0, fn, fns...);
} else {
throw LuaTypeMismatch();
}
return 0;
}
template <typename TupleType, std::size_t... S>
int invoke_tuple_impl(lua_State *state, TupleType &&tuple,
nativefunction::index_tuple<S...>) {
return best_match_invoke(state, fntuple::get<S>(tuple)...);
}
template <typename TupleType>
int invoke_tuple(lua_State *state, TupleType &&tuple) {
typedef typename std::decay<TupleType>::type ttype;
typedef typename nativefunction::index_range<
0, fntuple::tuple_size<ttype>::value>::type indexrange;
return invoke_tuple_impl(state, tuple, indexrange());
}
template <typename Fun>
void push_arg_typename(lua_State *state, const Fun &fn) {
lua_pushliteral(state, "\t\t");
lua_pushstring(state, nativefunction::argTypesName(fn).c_str());
lua_pushliteral(state, "\n");
}
template <typename Fun, typename... Functions>
void push_arg_typename(lua_State *state, const Fun &fn,
const Functions &... fns) {
lua_pushliteral(state, "\t\t");
lua_pushstring(state, nativefunction::argTypesName(fn).c_str());
lua_pushliteral(state, "\n");
push_arg_typename(state, fns...);
}
template <typename TupleType, std::size_t... S>
void push_arg_typename_tuple_impl(lua_State *state, TupleType &&tuple,
nativefunction::index_tuple<S...>) {
return push_arg_typename(state, fntuple::get<S>(tuple)...);
}
template <typename TupleType>
void push_arg_typename_tuple(lua_State *state, TupleType &&tuple) {
typedef typename std::decay<TupleType>::type ttype;
typedef typename nativefunction::index_range<
0, fntuple::tuple_size<ttype>::value>::type indexrange;
return push_arg_typename_tuple_impl(state, tuple, indexrange());
}
}
#else
namespace detail {
#define KAGUYA_FUNCTION_SCOREING(N) \
if (currentbestscore < nativefunction::MAX_OVERLOAD_SCORE) { \
int score = nativefunction::compute_function_matching_score( \
state, fntuple::get<N - 1>(tuple)); \
if (currentbestscore < score) { \
currentbestscore = score; \
currentbestindex = N; \
} \
}
#define KAGUYA_FUNCTION_INVOKE(N) \
if (currentbestindex == N) { \
return nativefunction::call(state, fntuple::get<N - 1>(tuple)); \
}
#define KAGUYA_ARG_PUSH_TYPENAMES(N) \
lua_pushliteral(state, "\t\t"); \
lua_pushstring( \
state, \
nativefunction::argTypesName(fntuple::get<N - 1>(tuple)).c_str()); \
lua_pushliteral(state, "\n");
#define KAGUYA_TEMPLATE_PARAMETER(N) template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)>
#define KAGUYA_TUPLE_INVOKE_DEF(N) \
KAGUYA_TEMPLATE_PARAMETER(N) \
int invoke_tuple(lua_State *state, \
fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> &tuple) { \
if (N == 1) { \
return nativefunction::call(state, fntuple::get<0>(tuple)); \
} \
int32_t currentbestscore = 0; \
int32_t currentbestindex = -1; \
KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_SCOREING); \
KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_INVOKE); \
throw LuaTypeMismatch(); \
} \
KAGUYA_TEMPLATE_PARAMETER(N) \
void push_arg_typename_tuple( \
lua_State *state, \
fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> &tuple) { \
KAGUYA_PP_REPEAT(N, KAGUYA_ARG_PUSH_TYPENAMES); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_INVOKE_DEF)
#undef KAGUYA_TEMPLATE_PARAMETER
#undef KAGUYA_TUPLE_INVOKE_DEF
#undef KAGUYA_ARG_TYPENAMES
#undef KAGUYA_FUNCTION_INVOKE
#undef KAGUYA_FUNCTION_SCOREING
template <typename TupleType>
int invoke_tuple(lua_State *state, TupleType &tuple) {
KAGUYA_UNUSED(state);
KAGUYA_UNUSED(tuple);
return 0;
}
}
#endif
template <typename FunctionTuple> struct FunctionInvokerType {
FunctionTuple functions;
FunctionInvokerType(const FunctionTuple &t) : functions(t) {}
};
template <typename T>
inline FunctionInvokerType<fntuple::tuple<T> > function(T f) {
KAGUYA_STATIC_ASSERT(
nativefunction::is_callable<typename traits::decay<T>::type>::value,
"argument need callable");
return FunctionInvokerType<fntuple::tuple<T> >(fntuple::tuple<T>(f));
}
template <typename FTYPE, typename T>
inline FunctionInvokerType<fntuple::tuple<standard::function<FTYPE> > >
function(T f) {
return FunctionInvokerType<fntuple::tuple<standard::function<FTYPE> > >(
fntuple::tuple<standard::function<FTYPE> >(standard::function<FTYPE>(f)));
}
#if KAGUYA_USE_CPP11
template <typename... Functions>
FunctionInvokerType<fntuple::tuple<Functions...> > overload(Functions... fns) {
return FunctionInvokerType<fntuple::tuple<Functions...> >(
fntuple::tuple<Functions...>(fns...));
}
#else
#define KAGUYA_FOVERLOAD_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
FunctionInvokerType<fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > \
overload(KAGUYA_PP_ARG_DEF_REPEAT(N)) { \
typedef typename fntuple::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> ttype; \
return FunctionInvokerType<ttype>(ttype(KAGUYA_PP_ARG_REPEAT(N))); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_FOVERLOAD_DEF)
#undef KAGUYA_FOVERLOAD_DEF
#endif
struct luacfunction {
lua_CFunction ptr;
luacfunction(lua_CFunction f) : ptr(f) {}
operator lua_CFunction() { return ptr; }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for FunctionInvokerType
template <typename FunctionTuple>
struct lua_type_traits<FunctionInvokerType<FunctionTuple> > {
typedef FunctionInvokerType<FunctionTuple> userdatatype;
typedef const FunctionInvokerType<FunctionTuple> &push_type;
static const char *build_arg_error_message(lua_State *state, const char *msg,
FunctionTuple *tuple) {
int stack_top = lua_gettop(state);
if (msg) {
lua_pushstring(state, msg);
}
lua_pushliteral(state, "Argument mismatch:");
nativefunction::pushArgmentTypeNames(state, stack_top);
lua_pushliteral(state, "\t candidate is:\n");
detail::push_arg_typename_tuple(state, *tuple);
lua_concat(state, lua_gettop(state) - stack_top);
return lua_tostring(state, -1);
}
static int invoke(lua_State *state) {
FunctionTuple *t = static_cast<FunctionTuple *>(
lua_touserdata(state, lua_upvalueindex(1)));
if (t) {
try {
return detail::invoke_tuple(state, *t);
} catch (LuaTypeMismatch &e) {
if (strcmp(e.what(), "type mismatch!!") == 0) {
util::traceBack(state, build_arg_error_message(state, "maybe...", t));
} else {
util::traceBack(state, e.what());
}
} catch (std::exception &e) {
util::traceBack(state, e.what());
} catch (...) {
util::traceBack(state, "Unknown exception");
}
}
return lua_error(state);
}
inline static int tuple_destructor(lua_State *state) {
FunctionTuple *f = static_cast<FunctionTuple *>(lua_touserdata(state, 1));
if (f) {
f->~FunctionTuple();
}
return 0;
}
static int push(lua_State *state, push_type fns) {
void *ptr = lua_newuserdata(state, sizeof(FunctionTuple));
new (ptr) FunctionTuple(fns.functions);
lua_createtable(state, 0, 2);
lua_pushcclosure(state, &tuple_destructor, 0);
lua_setfield(state, -2, "__gc");
lua_pushvalue(state, -1);
lua_setfield(state, -1, "__index");
lua_setmetatable(state, -2);
lua_pushcclosure(state, &invoke, 1);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for c function
template <typename T>
struct lua_type_traits<
T, typename traits::enable_if<traits::is_function<
typename traits::remove_pointer<T>::type>::value>::type> {
static int push(lua_State *l, T f) {
return util::one_push(l, kaguya::function(f));
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for luacfunction
template <> struct lua_type_traits<luacfunction> {
typedef luacfunction push_type;
typedef luacfunction get_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_iscfunction(l, index) != 0;
}
static bool checkType(lua_State *l, int index) {
return lua_iscfunction(l, index) != 0;
}
static get_type get(lua_State *l, int index) {
return lua_tocfunction(l, index);
}
static int push(lua_State *l, push_type f) {
lua_pushcfunction(l, f);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for std::function or boost::function
template <typename T> struct lua_type_traits<standard::function<T> > {
typedef const standard::function<T> &push_type;
typedef standard::function<T> get_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TFUNCTION;
}
static bool checkType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TFUNCTION;
}
static get_type get(lua_State *l, int index) {
if (!l || lua_type(l, index) != LUA_TFUNCTION) {
return get_type();
}
lua_pushvalue(l, index);
return get_type(LuaFunction(l, StackTop()));
}
static int push(lua_State *l, push_type v) {
return util::one_push(l, kaguya::function(v));
}
};
template <typename F,
typename Ret = typename util::FunctionSignature<F>::type::result_type>
struct OverloadFunctionImpl : kaguya::FunctionImpl {
typedef Ret result_type;
typedef typename util::FunctionSignature<F>::type::c_function_type
c_function_type;
virtual result_type invoke_type(lua_State *state) = 0;
virtual int invoke(lua_State *state) {
return util::push_args(state, invoke_type(state));
}
virtual std::string argTypesName() const {
return nativefunction::argTypesName(c_function_type(0),
maxArgCount() - minArgCount());
}
virtual bool checkArgTypes(lua_State *state) const {
return kaguya::nativefunction::checkArgTypes(state, c_function_type(0),
maxArgCount() - minArgCount());
}
virtual bool strictCheckArgTypes(lua_State *state) const {
return kaguya::nativefunction::strictCheckArgTypes(
state, c_function_type(0), maxArgCount() - minArgCount());
}
};
template <typename F>
struct OverloadFunctionImpl<F, void> : kaguya::FunctionImpl {
typedef void result_type;
typedef typename util::FunctionSignature<F>::type::c_function_type
c_function_type;
virtual result_type invoke_type(lua_State *state) = 0;
virtual int invoke(lua_State *state) {
invoke_type(state);
return 0;
}
virtual std::string argTypesName() const {
return nativefunction::argTypesName(c_function_type(0),
maxArgCount() - minArgCount());
}
virtual bool checkArgTypes(lua_State *state) const {
return kaguya::nativefunction::checkArgTypes(state, c_function_type(0),
maxArgCount() - minArgCount());
}
virtual bool strictCheckArgTypes(lua_State *state) const {
return kaguya::nativefunction::strictCheckArgTypes(
state, c_function_type(0), maxArgCount() - minArgCount());
}
};
}
#define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REP(N) \
getArgument<N - 1, F>(state)
#define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REP)
#define KAGUYA_INTERNAL_OVERLOAD_FUNCTION_INVOKE(N, FNAME, MINARG, MAXARG) \
if (argcount == KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N))) { \
return FNAME(KAGUYA_INTERNAL_OVERLOAD_FUNCTION_GET_REPEAT( \
KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N)))); \
}
#define KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, \
MAXARG, CREATE_FN) \
\
struct GENERATE_NAME \
{ \
template <typename F> struct Function : kaguya::OverloadFunctionImpl<F> { \
typedef \
typename kaguya::OverloadFunctionImpl<F>::result_type result_type; \
virtual result_type invoke_type(lua_State *state) { \
using namespace kaguya::nativefunction; \
int argcount = lua_gettop(state); \
KAGUYA_PP_REPEAT_DEF_VA_ARG( \
KAGUYA_PP_INC(KAGUYA_PP_SUB(MAXARG, MINARG)), \
KAGUYA_INTERNAL_OVERLOAD_FUNCTION_INVOKE, FNAME, MINARG, MAXARG) \
throw kaguya::LuaTypeMismatch("argument count mismatch"); \
} \
virtual int minArgCount() const { return MINARG; } \
virtual int maxArgCount() const { return MAXARG; } \
}; \
template <typename F> kaguya::PolymorphicInvoker::holder_type create(F) { \
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
return kaguya::PolymorphicInvoker::holder_type(ptr); \
} \
template <typename F> kaguya::PolymorphicInvoker::holder_type create() { \
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
return kaguya::PolymorphicInvoker::holder_type(ptr); \
} \
kaguya::PolymorphicInvoker operator()() { return CREATE_FN; } \
\
} \
GENERATE_NAME;
#define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REP(N) \
getArgument<N, F>(state)
#define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REP)
#define KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_INVOKE(N, FNAME, MINARG, \
MAXARG) \
if (argcount == 1 + KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N))) { \
return (getArgument<0, F>(state)) \
.FNAME(KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_GET_REPEAT( \
KAGUYA_PP_ADD(MINARG, KAGUYA_PP_DEC(N)))); \
}
#define KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, CLASS, FNAME, \
MINARG, MAXARG, CREATE_FN) \
\
struct GENERATE_NAME \
{ \
template <typename F> struct Function : kaguya::OverloadFunctionImpl<F> { \
typedef \
typename kaguya::OverloadFunctionImpl<F>::result_type result_type; \
virtual result_type invoke_type(lua_State *state) { \
using namespace kaguya::nativefunction; \
int argcount = lua_gettop(state); \
KAGUYA_PP_REPEAT_DEF_VA_ARG( \
KAGUYA_PP_INC(KAGUYA_PP_SUB(MAXARG, MINARG)), \
KAGUYA_INTERNAL_OVERLOAD_MEMBER_FUNCTION_INVOKE, FNAME, MINARG, \
MAXARG) \
throw kaguya::LuaTypeMismatch("argument count mismatch"); \
} \
virtual int minArgCount() const { return MINARG + 1; } \
virtual int maxArgCount() const { return MAXARG + 1; } \
}; \
template <typename F> \
kaguya::PolymorphicMemberInvoker::holder_type create(F f) { \
KAGUYA_UNUSED(f); \
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
return kaguya::PolymorphicMemberInvoker::holder_type(ptr); \
} \
template <typename F> \
kaguya::PolymorphicMemberInvoker::holder_type create() { \
kaguya::OverloadFunctionImpl<F> *ptr = new Function<F>(); \
return kaguya::PolymorphicMemberInvoker::holder_type(ptr); \
} \
kaguya::PolymorphicMemberInvoker operator()() { return CREATE_FN; } \
\
} \
GENERATE_NAME;
/// @brief Generate wrapper function object for count based overloads with
/// nonvoid return function. Include default arguments parameter function
/// @param GENERATE_NAME generate function object name
/// @param FNAME target function name
/// @param MINARG minimum arguments count
/// @param MAXARG maximum arguments count
#define KAGUYA_FUNCTION_OVERLOADS(GENERATE_NAME, FNAME, MINARG, MAXARG) \
KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, MAXARG, \
create(FNAME))
/// @brief Generate wrapper function object for count based overloads with
/// nonvoid return function. Include default arguments parameter function
/// @param GENERATE_NAME generate function object name
/// @param FNAME target function name
/// @param MINARG minimum arguments count
/// @param MAXARG maximum arguments count
/// @param SIGNATURE function signature. e,g, int(int)
#define KAGUYA_FUNCTION_OVERLOADS_WITH_SIGNATURE(GENERATE_NAME, FNAME, MINARG, \
MAXARG, SIGNATURE) \
KAGUYA_FUNCTION_OVERLOADS_INTERNAL(GENERATE_NAME, FNAME, MINARG, MAXARG, \
create<SIGNATURE>())
/// @brief Generate wrapper function object for count based overloads with
/// nonvoid return function. Include default arguments parameter function
/// @param GENERATE_NAME generate function object name
/// @param CLASS target class name
/// @param FNAME target function name
/// @param MINARG minimum arguments count
/// @param MAXARG maximum arguments count
#define KAGUYA_MEMBER_FUNCTION_OVERLOADS(GENERATE_NAME, CLASS, FNAME, MINARG, \
MAXARG) \
KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL( \
GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, create(&CLASS::FNAME))
/// @brief Generate wrapper function object for count based overloads with
/// nonvoid return function. Include default arguments parameter function
/// @param GENERATE_NAME generate function object name
/// @param CLASS target class name
/// @param FNAME target function name
/// @param MINARG minimum arguments count
/// @param MAXARG maximum arguments count
/// @param SIGNATURE function signature. e,g, int(Test::*)(int)
#define KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE( \
GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, SIGNATURE) \
KAGUYA_MEMBER_FUNCTION_OVERLOADS_INTERNAL( \
GENERATE_NAME, CLASS, FNAME, MINARG, MAXARG, create<SIGNATURE>())

View file

@ -0,0 +1,189 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include "kaguya/config.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/object.hpp"
namespace kaguya {
namespace nativefunction {
#define KAGUYA_INVOKE_SIG_TARG_DEF_CONCAT_REP(N) \
, typename util::ArgumentType<N - 1, F>::type
#define KAGUYA_INVOKE_SIG_TARG_DEF_REPEAT_CONCAT(N) \
KAGUYA_PP_REPEAT(N, KAGUYA_INVOKE_SIG_TARG_DEF_CONCAT_REP)
#define KAGUYA_GET_REP(N) , lua_type_traits<KAGUYA_PP_CAT(A, N)>::get(state, N)
#define KAGUYA_FUNC_DEF(N) \
const util::FunctionSignatureType<Ret KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT( \
N)> &fsig
#define KAGUYA_TYPENAME_REP(N) \
+((MAX_ARG - opt_count < N) ? "[OPT]" : "") + \
util::pretty_name(typeid(KAGUYA_PP_CAT(A, N))) + ","
#define KAGUYA_TYPECHECK_REP(N) \
&&(((MAX_ARG - opt_count < N) && lua_isnoneornil(state, N)) || \
lua_type_traits<KAGUYA_PP_CAT(A, N)>::checkType(state, N))
#define KAGUYA_STRICT_TYPECHECK_REP(N) \
&&(((MAX_ARG - opt_count < N) && lua_isnoneornil(state, N)) || \
lua_type_traits<KAGUYA_PP_CAT(A, N)>::strictCheckType(state, N))
#define KAGUYA_CALL_FN_DEF(N) \
template <typename F, typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
inline typename traits::enable_if<!traits::is_same<void, Ret>::value, \
int>::type \
_call_apply(lua_State *state, F &f, KAGUYA_FUNC_DEF(N)) { \
KAGUYA_UNUSED(fsig); \
return util::push_args( \
state, util::invoke<F KAGUYA_INVOKE_SIG_TARG_DEF_REPEAT_CONCAT(N)>( \
f KAGUYA_PP_REPEAT(N, KAGUYA_GET_REP))); \
} \
template <typename F, typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
inline \
typename traits::enable_if<traits::is_same<void, Ret>::value, int>::type \
_call_apply(lua_State *state, F &f, KAGUYA_FUNC_DEF(N)) { \
KAGUYA_UNUSED(state); \
KAGUYA_UNUSED(fsig); \
util::invoke<F KAGUYA_INVOKE_SIG_TARG_DEF_REPEAT_CONCAT(N)>( \
f KAGUYA_PP_REPEAT(N, KAGUYA_GET_REP)); \
return 0; \
} \
template <typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
bool _ctype_apply(lua_State *state, KAGUYA_FUNC_DEF(N), int opt_count = 0) { \
KAGUYA_UNUSED(state); \
KAGUYA_UNUSED(opt_count); \
KAGUYA_UNUSED(fsig); \
const int MAX_ARG = N; \
(void)MAX_ARG; \
return true KAGUYA_PP_REVERSE_REPEAT(N, KAGUYA_TYPECHECK_REP); \
} \
template <typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
bool _sctype_apply(lua_State *state, KAGUYA_FUNC_DEF(N), \
int opt_count = 0) { \
KAGUYA_UNUSED(state); \
KAGUYA_UNUSED(opt_count); \
KAGUYA_UNUSED(fsig); \
const int MAX_ARG = N; \
(void)MAX_ARG; \
return true KAGUYA_PP_REVERSE_REPEAT(N, KAGUYA_STRICT_TYPECHECK_REP); \
} \
template <typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
std::string _type_name_apply(KAGUYA_FUNC_DEF(N), int opt_count) { \
KAGUYA_UNUSED(fsig); \
KAGUYA_UNUSED(opt_count); \
const int MAX_ARG = N; \
(void)MAX_ARG; \
return std::string() KAGUYA_PP_REPEAT(N, KAGUYA_TYPENAME_REP); \
}
KAGUYA_CALL_FN_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_CALL_FN_DEF)
#undef KAGUYA_CALL_FN_DEF
#undef KAGUYA_CALL_FN_DEF
#undef KAGUYA_FUNC_DEF
template <class F> int call(lua_State *state, F f) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return _call_apply(state, f, fsigtype());
}
template <class F>
bool checkArgTypes(lua_State *state, const F &, int opt_count = 0) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return _ctype_apply(state, fsigtype(), opt_count);
}
template <class F>
bool strictCheckArgTypes(lua_State *state, const F &, int opt_count = 0) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return _sctype_apply(state, fsigtype(), opt_count);
}
template <class F> std::string argTypesName(const F &f, int opt_count = 0) {
KAGUYA_UNUSED(f);
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return _type_name_apply(fsigtype(), opt_count);
}
template <class F> int minArgCount(const F &f) {
KAGUYA_UNUSED(f);
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return fsigtype::argument_count;
}
template <class F> int maxArgCount(const F &f) {
KAGUYA_UNUSED(f);
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return fsigtype::argument_count;
}
///! for constructor
template <typename T> struct ConstructorFunctor;
#define KAGUYA_CONSTRUCTOR_GET_REP(N) \
lua_type_traits<KAGUYA_PP_CAT(A, N)>::get(L, N)
#define KAGUYA_CONSTRUCTOR_CALL_FN_DEF(N) \
template <typename ClassType KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct ConstructorFunctor<util::FunctionSignatureType< \
ClassType KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> > { \
typedef util::FunctionSignatureType< \
ClassType KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> \
signature_type; \
int operator()(lua_State *L) const { \
typedef ObjectWrapper<ClassType> wrapper_type; \
void *storage = lua_newuserdata(L, sizeof(wrapper_type)); \
try { \
new (storage) \
wrapper_type(KAGUYA_PP_REPEAT_ARG(N, KAGUYA_CONSTRUCTOR_GET_REP)); \
} catch (...) { \
lua_pop(L, 1); \
throw; \
} \
class_userdata::setmetatable<ClassType>(L); \
return 1; \
} \
bool checkArgTypes(lua_State *L, int opt_count = 0) const { \
return _ctype_apply(L, signature_type(), opt_count); \
} \
bool strictCheckArgTypes(lua_State *L, int opt_count = 0) const { \
return _sctype_apply(L, signature_type(), opt_count); \
} \
std::string argTypesName(int opt_count = 0) const { \
KAGUYA_UNUSED(opt_count); \
return _type_name_apply(signature_type(), 0); \
} \
};
KAGUYA_CONSTRUCTOR_CALL_FN_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_CONSTRUCTOR_CALL_FN_DEF)
#undef KAGUYA_CONSTRUCTOR_CALL_FN_DEF
template <class ClassType, class FunType = void> struct ConstructorFunction;
#define KAGUYA_F_TO_CONSIG_TYPE_DEF(N) \
ConstructorFunctor<util::FunctionSignatureType< \
ClassType KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> >
#define KAGUYA_F_TO_CONSIG_DEF(N) \
template <typename ClassType KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct ConstructorFunction<ClassType(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N))> { \
typedef KAGUYA_F_TO_CONSIG_TYPE_DEF(N) type; \
}; \
template <typename ClassType, \
typename RetType KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct ConstructorFunction<ClassType, \
RetType(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N))> { \
typedef KAGUYA_F_TO_CONSIG_TYPE_DEF(N) type; \
};
KAGUYA_F_TO_CONSIG_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_F_TO_CONSIG_DEF)
#undef KAGUYA_F_TO_CONSIG_DEF
}
using nativefunction::ConstructorFunction;
}

View file

@ -0,0 +1,207 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include "kaguya/config.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/object.hpp"
namespace kaguya {
namespace nativefunction {
template <std::size_t... indexes> struct index_tuple {};
template <std::size_t first, std::size_t last, class result = index_tuple<>,
bool flag = first >= last>
struct index_range {
using type = result;
};
template <std::size_t step, std::size_t last, std::size_t... indexes>
struct index_range<step, last, index_tuple<indexes...>, false>
: index_range<step + 1, last, index_tuple<indexes..., step> > {};
template <class F, class Ret, class... Args, size_t... Indexes>
int _call_apply(lua_State *state, F &&f, index_tuple<Indexes...>,
util::FunctionSignatureType<Ret, Args...>) {
return util::push_args(
state, util::invoke(f, lua_type_traits<Args>::get(state, Indexes)...));
}
template <class F, class... Args, size_t... Indexes>
int _call_apply(lua_State *state, F &&f, index_tuple<Indexes...>,
util::FunctionSignatureType<void, Args...>) {
KAGUYA_UNUSED(state);
util::invoke(f, lua_type_traits<Args>::get(state, Indexes)...);
return 0;
}
inline bool all_true() { return true; }
template <class Arg, class... Args>
bool all_true(Arg f, Args... args) { // check from backward and lazy evaluation
return all_true(args...) && bool(f);
}
inline void join(std::string &, const char *) {}
template <class Arg, class... Args>
void join(std::string &result, const char *delim, const Arg &str,
const Args &... args) {
result += str;
result += delim;
join(result, delim, args...);
}
template <typename T> struct _wcheckeval {
_wcheckeval(lua_State *s, int i, bool opt)
: state(s), index(i), opt_arg(opt) {}
lua_State *state;
int index;
bool opt_arg;
operator bool() {
return (opt_arg && lua_isnoneornil(state, index)) ||
lua_type_traits<T>::checkType(state, index);
}
};
template <typename T> struct _scheckeval {
_scheckeval(lua_State *s, int i, bool opt)
: state(s), index(i), opt_arg(opt) {}
lua_State *state;
int index;
bool opt_arg;
operator bool() {
return (opt_arg && lua_isnoneornil(state, index)) ||
lua_type_traits<T>::strictCheckType(state, index);
}
};
template <class... Args, size_t... Indexes>
bool _ctype_apply(lua_State *state, index_tuple<Indexes...>,
util::TypeTuple<Args...>, int opt_count) {
KAGUYA_UNUSED(state);
KAGUYA_UNUSED(opt_count);
return all_true(_wcheckeval<Args>(
state, Indexes, sizeof...(Indexes) - opt_count < Indexes)...);
}
template <class... Args, size_t... Indexes>
bool _sctype_apply(lua_State *state, index_tuple<Indexes...>,
util::TypeTuple<Args...>, int opt_count) {
KAGUYA_UNUSED(state);
KAGUYA_UNUSED(opt_count);
return all_true(_scheckeval<Args>(
state, Indexes, sizeof...(Indexes) - opt_count < Indexes)...);
}
template <class... Args, size_t... Indexes>
std::string _type_name_apply(index_tuple<Indexes...>, util::TypeTuple<Args...>,
int opt_count) {
KAGUYA_UNUSED(opt_count);
std::string result;
const int max_arg = sizeof...(Args);
join(result, ",",
(((max_arg - opt_count < int(Indexes)) ? std::string("[OPT]")
: std::string("")) +
util::pretty_name(typeid(Args)))...);
return result;
}
template <class F> int call(lua_State *state, F &&f) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
typedef typename index_range<1, fsigtype::argument_count + 1>::type index;
return _call_apply(state, f, index(), fsigtype());
}
template <class F>
bool checkArgTypes(lua_State *state, const F &, int opt_count = 0) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
typedef typename index_range<1, fsigtype::argument_count + 1>::type index;
typedef typename fsigtype::argument_type_tuple argument_type_tuple;
return _ctype_apply(state, index(), argument_type_tuple(), opt_count);
}
template <class F>
bool strictCheckArgTypes(lua_State *state, const F &, int opt_count = 0) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
typedef typename index_range<1, fsigtype::argument_count + 1>::type index;
typedef typename fsigtype::argument_type_tuple argument_type_tuple;
return _sctype_apply(state, index(), argument_type_tuple(), opt_count);
}
template <class F> std::string argTypesName(const F &, int opt_count = 0) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
typedef typename index_range<1, fsigtype::argument_count + 1>::type index;
typedef typename fsigtype::argument_type_tuple argument_type_tuple;
return _type_name_apply(index(), argument_type_tuple(), opt_count);
}
template <class F> int minArgCount(const F &) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return fsigtype::argument_count;
}
template <class F> int maxArgCount(const F &) {
typedef typename traits::decay<F>::type ftype;
typedef typename util::FunctionSignature<ftype>::type fsigtype;
return fsigtype::argument_count;
}
// for constructor
template <typename T> struct ConstructorFunctor;
template <typename ClassType, typename... Args>
struct ConstructorFunctor<util::FunctionSignatureType<ClassType, Args...> > {
typedef util::FunctionSignatureType<ClassType, Args...> signature_type;
typedef typename index_range<1, sizeof...(Args) + 1>::type get_index;
template <size_t... Indexes>
int invoke(lua_State *L, index_tuple<Indexes...>) const {
typedef ObjectWrapper<ClassType> wrapper_type;
void *storage = lua_newuserdata(L, sizeof(wrapper_type));
try {
new (storage) wrapper_type(lua_type_traits<Args>::get(L, Indexes)...);
} catch (...) {
lua_pop(L, 1);
throw;
}
class_userdata::setmetatable<ClassType>(L);
return 1;
}
int operator()(lua_State *L) const { return invoke(L, get_index()); }
bool checkArgTypes(lua_State *L, int opt_count = 0) const {
return _ctype_apply(L, get_index(),
typename signature_type::argument_type_tuple(),
opt_count);
}
bool strictCheckArgTypes(lua_State *L, int opt_count = 0) const {
return _sctype_apply(L, get_index(),
typename signature_type::argument_type_tuple(),
opt_count);
}
std::string argTypesName(int opt_count = 0) const {
return _type_name_apply(
get_index(), typename signature_type::argument_type_tuple(), opt_count);
}
};
template <typename ClassType, typename... Args> struct ConstructorFunction;
template <typename ClassType, typename... Args>
struct ConstructorFunction<ClassType(Args...)> {
typedef ConstructorFunctor<util::FunctionSignatureType<ClassType, Args...> >
type;
};
template <typename ClassType, typename RetType, typename... Args>
struct ConstructorFunction<ClassType,
RetType(Args...)> // class type check version
{
typedef ConstructorFunctor<util::FunctionSignatureType<ClassType, Args...> >
type;
};
}
using nativefunction::ConstructorFunction;
}

View file

@ -0,0 +1,807 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include <cstring>
#include <typeinfo>
#include <algorithm>
#include "kaguya/config.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/traits.hpp"
#include "kaguya/exception.hpp"
namespace kaguya {
namespace types {
template <typename T> struct typetag {};
}
inline void *metatable_name_key() {
static int key;
return &key;
}
inline void *metatable_type_table_key() {
static int key;
return &key;
}
template <typename T> const std::type_info &metatableType() {
return typeid(typename traits::decay<T>::type);
}
template <typename T> inline std::string metatableName() {
return util::pretty_name(metatableType<T>());
}
struct ObjectWrapperBase {
virtual const void *cget() = 0;
virtual void *get() = 0;
virtual const std::type_info &type() = 0;
virtual const std::type_info &native_type() { return type(); }
virtual void *native_get() { return get(); }
ObjectWrapperBase() {}
virtual ~ObjectWrapperBase() {}
private:
// noncopyable
ObjectWrapperBase(const ObjectWrapperBase &);
ObjectWrapperBase &operator=(const ObjectWrapperBase &);
};
template <class T> struct ObjectWrapper : ObjectWrapperBase {
#if KAGUYA_USE_CPP11
template <class... Args>
ObjectWrapper(Args &&... args) : object_(std::forward<Args>(args)...) {}
#else
ObjectWrapper() : object_() {}
#define KAGUYA_OBJECT_WRAPPER_CONSTRUCTOR_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
ObjectWrapper(KAGUYA_PP_ARG_DEF_REPEAT(N)) \
: object_(KAGUYA_PP_ARG_REPEAT(N)) {}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_OBJECT_WRAPPER_CONSTRUCTOR_DEF)
#undef KAGUYA_OBJECT_WRAPPER_CONSTRUCTOR_DEF
#endif
virtual const std::type_info &type() { return metatableType<T>(); }
virtual void *get() { return &object_; }
virtual const void *cget() { return &object_; }
private:
T object_;
};
struct ObjectSharedPointerWrapper : ObjectWrapperBase {
template <typename T>
ObjectSharedPointerWrapper(const standard::shared_ptr<T> &sptr)
: object_(standard::const_pointer_cast<
typename standard::remove_const<T>::type>(sptr)),
type_(metatableType<T>()),
shared_ptr_type_(
metatableType<
standard::shared_ptr<typename traits::decay<T>::type> >()),
const_value_(traits::is_const<T>::value) {}
#if KAGUYA_USE_RVALUE_REFERENCE
template <typename T>
ObjectSharedPointerWrapper(standard::shared_ptr<T> &&sptr)
: object_(std::move(standard::const_pointer_cast<
typename standard::remove_const<T>::type>(sptr))),
type_(metatableType<T>()),
shared_ptr_type_(
metatableType<
standard::shared_ptr<typename traits::decay<T>::type> >()),
const_value_(traits::is_const<T>::value) {}
#endif
virtual const std::type_info &type() { return type_; }
virtual void *get() { return const_value_ ? 0 : object_.get(); }
virtual const void *cget() { return object_.get(); }
standard::shared_ptr<void> object() const {
return const_value_ ? standard::shared_ptr<void>() : object_;
}
standard::shared_ptr<const void> const_object() const { return object_; }
const std::type_info &shared_ptr_type() const { return shared_ptr_type_; }
virtual const std::type_info &native_type() {
return metatableType<standard::shared_ptr<void> >();
}
virtual void *native_get() { return &object_; }
private:
standard::shared_ptr<void> object_;
const std::type_info &type_;
const std::type_info &shared_ptr_type_;
bool const_value_;
};
template <typename T, typename ElementType = typename T::element_type>
struct ObjectSmartPointerWrapper : ObjectWrapperBase {
ObjectSmartPointerWrapper(const T &sptr) : object_(sptr) {}
#if KAGUYA_USE_RVALUE_REFERENCE
ObjectSmartPointerWrapper(T &&sptr) : object_(std::move(sptr)) {}
#endif
virtual const std::type_info &type() { return metatableType<ElementType>(); }
virtual void *get() { return object_ ? &(*object_) : 0; }
virtual const void *cget() { return object_ ? &(*object_) : 0; }
virtual const std::type_info &native_type() { return metatableType<T>(); }
virtual void *native_get() { return &object_; }
private:
T object_;
};
template <class T> struct ObjectPointerWrapper : ObjectWrapperBase {
ObjectPointerWrapper(T *ptr) : object_(ptr) {}
virtual const std::type_info &type() { return metatableType<T>(); }
virtual void *get() {
if (traits::is_const<T>::value) {
return 0;
}
return const_cast<void *>(static_cast<const void *>(object_));
}
virtual const void *cget() { return object_; }
~ObjectPointerWrapper() {}
protected:
T *object_;
};
// Customizable for ObjectPointerWrapper
template <class T, class Enable = void> struct ObjectPointerWrapperType {
typedef ObjectPointerWrapper<T> type;
};
// for internal use
struct PointerConverter {
template <typename T, typename F> static void *base_pointer_cast(void *from) {
return static_cast<T *>(static_cast<F *>(from));
}
template <typename T, typename F>
static standard::shared_ptr<void>
base_shared_pointer_cast(const standard::shared_ptr<void> &from) {
return standard::shared_ptr<T>(standard::static_pointer_cast<F>(from));
}
typedef void *(*convert_function_type)(void *);
typedef standard::shared_ptr<void> (*shared_ptr_convert_function_type)(
const standard::shared_ptr<void> &);
typedef std::pair<std::string, std::string> convert_map_key;
template <typename ToType, typename FromType> void add_type_conversion() {
add_function(metatableType<ToType>(), metatableType<FromType>(),
&base_pointer_cast<ToType, FromType>);
add_function(metatableType<standard::shared_ptr<ToType> >(),
metatableType<standard::shared_ptr<FromType> >(),
&base_shared_pointer_cast<ToType, FromType>);
}
template <typename TO> TO *get_pointer(ObjectWrapperBase *from) const {
const std::type_info &to_type = metatableType<TO>();
// unreachable
// if (to_type == from->type())
//{
// return static_cast<TO*>(from->get());
//}
std::map<convert_map_key,
std::vector<convert_function_type> >::const_iterator match =
function_map_.find(
convert_map_key(to_type.name(), from->type().name()));
if (match != function_map_.end()) {
return static_cast<TO *>(pcvt_list_apply(from->get(), match->second));
}
return 0;
}
template <typename TO>
const TO *get_const_pointer(ObjectWrapperBase *from) const {
const std::type_info &to_type = metatableType<TO>();
// unreachable
// if (to_type == from->type())
//{
// return static_cast<const TO*>(from->cget());
//}
std::map<convert_map_key,
std::vector<convert_function_type> >::const_iterator match =
function_map_.find(
convert_map_key(to_type.name(), from->type().name()));
if (match != function_map_.end()) {
return static_cast<const TO *>(
pcvt_list_apply(const_cast<void *>(from->cget()), match->second));
}
return 0;
}
template <typename TO>
standard::shared_ptr<TO>
get_shared_pointer(ObjectSharedPointerWrapper *from) const {
const std::type_info &to_type = metatableType<
standard::shared_ptr<typename traits::decay<TO>::type> >();
// unreachable
// if (to_type == from->type())
// {
// return
//standard::static_pointer_cast<TO>(from->object());
// }
const std::type_info &from_type = from->shared_ptr_type();
std::map<convert_map_key,
std::vector<shared_ptr_convert_function_type> >::const_iterator
match = shared_ptr_function_map_.find(
convert_map_key(to_type.name(), from_type.name()));
if (match != shared_ptr_function_map_.end()) {
standard::shared_ptr<void> sptr = from->object();
if (!sptr && standard::is_const<TO>::value) {
sptr = standard::const_pointer_cast<void>(from->const_object());
}
return standard::static_pointer_cast<TO>(
pcvt_list_apply(sptr, match->second));
}
return standard::shared_ptr<TO>();
}
template <class T>
T *get_pointer(ObjectWrapperBase *from, types::typetag<T>) {
return get_pointer<T>(from);
}
template <class T>
standard::shared_ptr<T>
get_pointer(ObjectWrapperBase *from,
types::typetag<standard::shared_ptr<T> >) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(from);
if (ptr) {
return get_shared_pointer<T>(ptr);
}
return standard::shared_ptr<T>();
}
static int deleter(lua_State *state) {
PointerConverter *ptr = (PointerConverter *)lua_touserdata(state, 1);
ptr->~PointerConverter();
return 0;
}
static PointerConverter &get(lua_State *state) {
static char kaguya_ptrcvt_key_ptr;
util::ScopedSavedStack save(state);
lua_pushlightuserdata(state, &kaguya_ptrcvt_key_ptr);
lua_rawget(state, LUA_REGISTRYINDEX);
if (lua_isuserdata(state, -1)) {
return *static_cast<PointerConverter *>(lua_touserdata(state, -1));
} else {
void *ptr = lua_newuserdata(
state, sizeof(PointerConverter)); // dummy data for gc call
PointerConverter *converter = new (ptr) PointerConverter();
lua_createtable(state, 0, 2);
lua_pushcclosure(state, &deleter, 0);
lua_setfield(state, -2, "__gc");
lua_pushvalue(state, -1);
lua_setfield(state, -2, "__index");
lua_setmetatable(state, -2); // set to userdata
lua_pushlightuserdata(state, &kaguya_ptrcvt_key_ptr);
lua_pushvalue(state, -2);
lua_rawset(state, LUA_REGISTRYINDEX);
return *converter;
}
}
private:
void add_function(const std::type_info &to_type,
const std::type_info &from_type, convert_function_type f) {
std::map<convert_map_key, std::vector<convert_function_type> > add_map;
for (std::map<convert_map_key,
std::vector<convert_function_type> >::iterator it =
function_map_.begin();
it != function_map_.end(); ++it) {
if (it->first.second == to_type.name()) {
std::vector<convert_function_type> newlist;
newlist.push_back(f);
newlist.insert(newlist.end(), it->second.begin(), it->second.end());
add_map[convert_map_key(it->first.first, from_type.name())] = newlist;
}
}
function_map_.insert(add_map.begin(), add_map.end());
std::vector<convert_function_type> flist;
flist.push_back(f);
function_map_[convert_map_key(to_type.name(), from_type.name())] = flist;
}
void add_function(const std::type_info &to_type,
const std::type_info &from_type,
shared_ptr_convert_function_type f) {
std::map<convert_map_key, std::vector<shared_ptr_convert_function_type> >
add_map;
for (std::map<convert_map_key,
std::vector<shared_ptr_convert_function_type> >::iterator it =
shared_ptr_function_map_.begin();
it != shared_ptr_function_map_.end(); ++it) {
if (it->first.second == to_type.name()) {
std::vector<shared_ptr_convert_function_type> newlist;
newlist.push_back(f);
newlist.insert(newlist.end(), it->second.begin(), it->second.end());
add_map[convert_map_key(it->first.first, from_type.name())] = newlist;
}
}
shared_ptr_function_map_.insert(add_map.begin(), add_map.end());
std::vector<shared_ptr_convert_function_type> flist;
flist.push_back(f);
shared_ptr_function_map_[convert_map_key(to_type.name(),
from_type.name())] = flist;
}
void *pcvt_list_apply(void *ptr,
const std::vector<convert_function_type> &flist) const {
for (std::vector<convert_function_type>::const_iterator i = flist.begin();
i != flist.end(); ++i) {
ptr = (*i)(ptr);
}
return ptr;
}
standard::shared_ptr<void> pcvt_list_apply(
standard::shared_ptr<void> ptr,
const std::vector<shared_ptr_convert_function_type> &flist) const {
for (std::vector<shared_ptr_convert_function_type>::const_iterator i =
flist.begin();
i != flist.end(); ++i) {
#if KAGUYA_USE_CPP11
ptr = (*i)(std::move(ptr));
#else
ptr = (*i)(ptr);
#endif
}
return ptr;
}
PointerConverter() {}
std::map<convert_map_key, std::vector<convert_function_type> > function_map_;
std::map<convert_map_key, std::vector<shared_ptr_convert_function_type> >
shared_ptr_function_map_;
PointerConverter(PointerConverter &);
PointerConverter &operator=(PointerConverter &);
};
namespace detail {
inline bool object_wrapper_type_check(lua_State *l, int index) {
#if KAGUYA_NO_USERDATA_TYPE_CHECK
return lua_isuserdata(l, index) && !lua_islightuserdata(l, index);
#endif
if (lua_getmetatable(l, index)) {
int type = lua_rawgetp_rtype(l, -1, metatable_name_key());
lua_pop(l, 2);
return type == LUA_TSTRING;
}
return false;
}
}
inline ObjectWrapperBase *object_wrapper(lua_State *l, int index) {
if (detail::object_wrapper_type_check(l, index)) {
ObjectWrapperBase *ptr =
static_cast<ObjectWrapperBase *>(lua_touserdata(l, index));
return ptr;
}
return 0;
}
template <typename RequireType>
inline ObjectWrapperBase *
object_wrapper(lua_State *l, int index, bool convert = true,
types::typetag<RequireType> = types::typetag<RequireType>()) {
if (detail::object_wrapper_type_check(l, index)) {
ObjectWrapperBase *ptr =
static_cast<ObjectWrapperBase *>(lua_touserdata(l, index));
if (ptr->type() == metatableType<RequireType>()) {
return ptr;
} else if (convert) {
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_pointer(ptr, types::typetag<RequireType>()) ? ptr : 0;
}
return 0;
}
return 0;
}
template <class T> T *get_pointer(lua_State *l, int index, types::typetag<T>) {
int type = lua_type(l, index);
if (type == LUA_TLIGHTUSERDATA) {
return (T *)lua_topointer(l, index);
} else if (type != LUA_TUSERDATA) {
return 0;
} else {
ObjectWrapperBase *objwrapper = object_wrapper(l, index);
if (objwrapper) {
const std::type_info &to_type = metatableType<T>();
if (objwrapper->type() == to_type) {
return static_cast<T *>(objwrapper->get());
}
if (objwrapper->native_type() == to_type) {
return static_cast<T *>(objwrapper->native_get());
} else {
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_pointer<T>(objwrapper);
}
}
}
return 0;
}
template <class T>
const T *get_const_pointer(lua_State *l, int index, types::typetag<T>) {
int type = lua_type(l, index);
if (type == LUA_TLIGHTUSERDATA) {
return (T *)lua_topointer(l, index);
} else if (type != LUA_TUSERDATA) {
return 0;
} else {
ObjectWrapperBase *objwrapper = object_wrapper(l, index);
if (objwrapper) {
if (objwrapper->type() == metatableType<T>()) {
return static_cast<const T *>(objwrapper->cget());
} else {
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_const_pointer<T>(objwrapper);
}
}
}
return 0;
}
template <class T>
const T *get_pointer(lua_State *l, int index, types::typetag<const T>) {
return get_const_pointer<T>(l, index, types::typetag<T>());
}
template <class T>
standard::shared_ptr<T> get_shared_pointer(lua_State *l, int index,
types::typetag<T>) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(object_wrapper(l, index));
if (ptr) {
const std::type_info &from_type = ptr->shared_ptr_type();
const std::type_info &to_type =
metatableType<standard::shared_ptr<typename traits::decay<T>::type> >();
if (from_type == to_type) {
if (standard::is_const<T>::value) {
return standard::static_pointer_cast<T>(
standard::const_pointer_cast<void>(ptr->const_object()));
} else {
return standard::static_pointer_cast<T>(ptr->object());
}
}
PointerConverter &pcvt = PointerConverter::get(l);
return pcvt.get_shared_pointer<T>(ptr);
}
return standard::shared_ptr<T>();
}
inline standard::shared_ptr<void> get_shared_pointer(lua_State *l, int index,
types::typetag<void>) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(object_wrapper(l, index));
if (ptr) {
return ptr->object();
}
return standard::shared_ptr<void>();
}
inline standard::shared_ptr<const void>
get_shared_pointer(lua_State *l, int index, types::typetag<const void>) {
ObjectSharedPointerWrapper *ptr =
dynamic_cast<ObjectSharedPointerWrapper *>(object_wrapper(l, index));
if (ptr) {
return ptr->const_object();
}
return standard::shared_ptr<const void>();
}
namespace class_userdata {
template <typename T> inline void destructor(T *pointer) {
if (pointer) {
pointer->~T();
}
}
inline bool get_metatable(lua_State *l, const std::type_info &typeinfo) {
int ttype = lua_rawgetp_rtype(
l, LUA_REGISTRYINDEX,
metatable_type_table_key()); // get metatable registry table
if (ttype != LUA_TTABLE) {
lua_newtable(l);
lua_rawsetp(l, LUA_REGISTRYINDEX, metatable_type_table_key());
return false;
}
int type = lua_rawgetp_rtype(l, -1, &typeinfo);
lua_remove(l, -2); // remove metatable registry table
return type != LUA_TNIL;
}
template <typename T> bool get_metatable(lua_State *l) {
return get_metatable(l, metatableType<T>());
}
template <typename T> bool available_metatable(lua_State *l) {
util::ScopedSavedStack save(l);
return get_metatable<T>(l);
}
inline bool newmetatable(lua_State *l, const std::type_info &typeinfo,
const char *name) {
if (get_metatable(l, typeinfo)) // already register
{
return false; //
}
lua_pop(l, 1);
lua_rawgetp_rtype(l, LUA_REGISTRYINDEX,
metatable_type_table_key()); // get metatable registry table
int metaregindex = lua_absindex(l, -1);
lua_createtable(l, 0, 2);
lua_pushstring(l, name);
lua_pushvalue(l, -1);
lua_setfield(l, -3, "__name"); // metatable.__name = name
lua_rawsetp(l, -2, metatable_name_key());
lua_pushvalue(l, -1);
lua_rawsetp(l, metaregindex, &typeinfo);
lua_remove(l, metaregindex); // remove metatable registry table
return true;
}
template <typename T> bool newmetatable(lua_State *l) {
return newmetatable(l, metatableType<T>(), metatableName<T>().c_str());
}
template <typename T> inline int deleter(lua_State *state) {
T *ptr = (T *)lua_touserdata(state, 1);
ptr->~T();
return 0;
}
struct UnknownType {};
inline void setmetatable(lua_State *l, const std::type_info &typeinfo) {
// if not available metatable, set unknown class metatable
if (!get_metatable(l, typeinfo)) {
lua_pop(l, 1);
if (!get_metatable<UnknownType>(l)) {
lua_pop(l, 1);
newmetatable<UnknownType>(l);
lua_pushcclosure(l, &deleter<ObjectWrapperBase>, 0);
lua_setfield(l, -2, "__gc");
}
}
lua_setmetatable(l, -2);
}
template <typename T> void setmetatable(lua_State *l) {
setmetatable(l, metatableType<T>());
}
}
template <typename T>
bool available_metatable(lua_State *l,
types::typetag<T> = types::typetag<T>()) {
return class_userdata::available_metatable<T>(l);
}
namespace util {
template <typename T> inline bool object_checkType(lua_State *l, int index) {
return object_wrapper<T>(l, index) != 0;
}
template <typename T>
inline bool object_strictCheckType(lua_State *l, int index) {
return object_wrapper<T>(l, index, false) != 0;
}
template <typename T>
inline optional<T> object_getopt(lua_State *l, int index) {
const typename traits::remove_reference<T>::type *pointer = get_const_pointer(
l, index, types::typetag<typename traits::remove_reference<T>::type>());
if (!pointer) {
return optional<T>();
}
return *pointer;
}
template <typename T> inline T object_get(lua_State *l, int index) {
const typename traits::remove_reference<T>::type *pointer = get_const_pointer(
l, index, types::typetag<typename traits::remove_reference<T>::type>());
if (!pointer) {
throw LuaTypeMismatch();
}
return *pointer;
}
template <typename To> struct ConvertibleRegisterHelperProxy {
template <typename DataType>
ConvertibleRegisterHelperProxy(DataType v)
: holder_(new DataHolder<DataType>(v)) {}
operator To() { return holder_->get(); }
private:
struct DataHolderBase {
virtual To get() const = 0;
virtual ~DataHolderBase() {}
};
template <typename Type> class DataHolder : public DataHolderBase {
typedef typename traits::decay<Type>::type DataType;
public:
explicit DataHolder(DataType v) : data_(v) {}
virtual To get() const { return To(data_); }
private:
DataType data_;
};
standard::shared_ptr<DataHolderBase> holder_;
};
#if KAGUYA_USE_CPP11
template <typename T> inline int object_push(lua_State *l, T &&v) {
typedef ObjectWrapper<typename traits::remove_const_and_reference<T>::type>
wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(std::forward<T>(v));
class_userdata::setmetatable<T>(l);
return 1;
}
namespace conv_helper_detail {
template <class To> bool checkType(lua_State *, int) { return false; }
template <class To, class From, class... Remain>
bool checkType(lua_State *l, int index) {
return lua_type_traits<From>::checkType(l, index) ||
checkType<To, Remain...>(l, index);
}
template <class To> bool strictCheckType(lua_State *, int) { return false; }
template <class To, class From, class... Remain>
bool strictCheckType(lua_State *l, int index) {
return lua_type_traits<From>::strictCheckType(l, index) ||
strictCheckType<To, Remain...>(l, index);
;
}
template <class To> To get(lua_State *, int) { throw LuaTypeMismatch(); }
template <class To, class From, class... Remain>
To get(lua_State *l, int index) {
typedef optional<typename lua_type_traits<From>::get_type> opt_type;
if (auto opt = lua_type_traits<opt_type>::get(l, index)) {
return *opt;
}
return get<To, Remain...>(l, index);
}
}
template <class To, class... From> struct ConvertibleRegisterHelper {
typedef To get_type;
static bool checkType(lua_State *l, int index) {
if (object_checkType<To>(l, index)) {
return true;
}
return conv_helper_detail::checkType<To, From...>(l, index);
}
static bool strictCheckType(lua_State *l, int index) {
if (object_strictCheckType<To>(l, index)) {
return true;
}
return conv_helper_detail::strictCheckType<To, From...>(l, index);
}
static get_type get(lua_State *l, int index) {
if (auto opt = object_getopt<To>(l, index)) {
return *opt;
}
return conv_helper_detail::get<get_type, From...>(l, index);
}
};
#else
template <typename T> inline int object_push(lua_State *l, T v) {
typedef ObjectWrapper<typename traits::remove_const_and_reference<T>::type>
wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(v);
class_userdata::setmetatable<T>(l);
return 1;
}
namespace conv_helper_detail {
#define KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_REP(N) \
|| lua_type_traits<KAGUYA_PP_CAT(A, N)>::checkType(state, index)
#define KAGUYA_CONVERTIBLE_REG_HELPER_STRICT_CHECK_TYPE_REP(N) \
|| lua_type_traits<KAGUYA_PP_CAT(A, N)>::strictCheckType(state, index)
#define KAGUYA_CONVERTIBLE_REG_HELPER_GET_OPT_TYPEDEF(N) \
typedef optional<typename lua_type_traits<KAGUYA_PP_CAT(A, N)>::get_type> \
KAGUYA_PP_CAT(opt_type, N);
#define KAGUYA_CONVERTIBLE_REG_HELPER_GET_REP(N) \
if (KAGUYA_PP_CAT(opt_type, N) opt = \
lua_type_traits<KAGUYA_PP_CAT(opt_type, N)>::get(state, index)) { \
return *opt; \
} else
template <typename To> bool checkType(lua_State *, int, TypeTuple<>) {
return false;
}
#define KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_DEF(N) \
template <typename To, KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
bool checkType(lua_State *state, int index, \
TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>) { \
return false KAGUYA_PP_REPEAT( \
N, KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_REP); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_DEF)
#undef KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_DEF
template <typename To> bool strictCheckType(lua_State *, int, TypeTuple<>) {
return false;
}
#define KAGUYA_CONVERTIBLE_REG_HELPER_ST_CHECK_TYPE_DEF(N) \
template <typename To, KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
bool strictCheckType(lua_State *state, int index, \
TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>) { \
return false KAGUYA_PP_REPEAT( \
N, KAGUYA_CONVERTIBLE_REG_HELPER_STRICT_CHECK_TYPE_REP); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_CONVERTIBLE_REG_HELPER_ST_CHECK_TYPE_DEF)
#undef KAGUYA_CONVERTIBLE_REG_HELPER_ST_CHECK_TYPE_DEF
#define KAGUYA_CONVERTIBLE_REG_HELPER_GET_DEF(N) \
template <typename To, KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
To get(lua_State *state, int index, \
TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>) { \
KAGUYA_PP_REPEAT(N, KAGUYA_CONVERTIBLE_REG_HELPER_GET_OPT_TYPEDEF) \
KAGUYA_PP_REPEAT(N, KAGUYA_CONVERTIBLE_REG_HELPER_GET_REP) { \
throw LuaTypeMismatch(); \
} \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS,
KAGUYA_CONVERTIBLE_REG_HELPER_GET_DEF)
#undef KAGUYA_CONVERTIBLE_REG_HELPER_GET_DEF
#undef KAGUYA_CONVERTIBLE_REG_HELPER_CHECK_TYPE_REP
#undef KAGUYA_CONVERTIBLE_REG_HELPER_STRICT_CHECK_TYPE_REP
#undef KAGUYA_CONVERTIBLE_REG_HELPER_ST_GET_REP
#undef KAGUYA_CONVERTIBLE_REG_HELPER_GET_REP
}
#define KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REP(N) \
KAGUYA_PP_CAT(typename A, N) = null_type
#define KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REP)
template <typename To,
KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REPEAT(KAGUYA_FUNCTION_MAX_ARGS)>
struct ConvertibleRegisterHelper {
typedef To get_type;
typedef TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(KAGUYA_FUNCTION_MAX_ARGS)>
conv_types;
static bool checkType(lua_State *l, int index) {
if (object_checkType<To>(l, index)) {
return true;
}
return conv_helper_detail::checkType<To>(l, index, conv_types());
}
static bool strictCheckType(lua_State *l, int index) {
if (object_strictCheckType<To>(l, index)) {
return true;
}
return conv_helper_detail::strictCheckType<To>(l, index, conv_types());
}
static get_type get(lua_State *l, int index) {
if (optional<To> opt = object_getopt<To>(l, index)) {
return *opt;
}
return conv_helper_detail::get<get_type>(l, index, conv_types());
}
};
#undef KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REP
#undef KAGUYA_PP_CONVERTIBLE_REG_HELPER_DEF_REPEAT
#endif
}
}

View file

@ -0,0 +1,264 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <cassert>
#include "kaguya/config.hpp"
namespace kaguya {
/// @addtogroup optional
/// @{
struct bad_optional_access : std::exception {};
struct nullopt_t {};
/// @brief self implement for std::optional(C++17 feature).
template <class T> class optional {
typedef void (optional::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
optional() : value_(0){};
optional(nullopt_t) : value_(0){};
optional(const optional &other) : value_(0) {
if (other) {
value_ = new (&storage_) T(other.value());
}
}
optional(const T &value) { value_ = new (&storage_) T(value); }
~optional() { destruct(); }
optional &operator=(nullopt_t) {
destruct();
return *this;
}
optional &operator=(const optional &other) {
if (other) {
*this = other.value();
} else {
destruct();
}
return *this;
}
optional &operator=(const T &value) {
if (value_) {
*value_ = value;
} else {
value_ = new (&storage_) T(value);
}
return *this;
}
#if KAGUYA_USE_CPP11
optional(optional &&other) : value_(0) {
if (other) {
value_ = new (&storage_) T(std::move(other.value()));
}
}
optional(T &&value) { value_ = new (&storage_) T(std::move(value)); }
optional &operator=(optional &&other) {
if (other) {
*this = std::move(other.value());
} else {
destruct();
}
return *this;
}
optional &operator=(T &&value) {
if (value_) {
*value_ = std::move(value);
} else {
value_ = new (&storage_) T(std::move(value));
}
return *this;
}
#endif
operator bool_type() const {
this_type_does_not_support_comparisons();
return value_ != 0 ? &optional::this_type_does_not_support_comparisons : 0;
}
T &value() {
if (value_) {
return *value_;
}
throw bad_optional_access();
}
const T &value() const {
if (value_) {
return *value_;
}
throw bad_optional_access();
}
#if KAGUYA_USE_CPP11
template <class U> T value_or(U &&default_value) const {
if (value_) {
return *value_;
}
return default_value;
}
#else
template <class U> T value_or(const U &default_value) const {
if (value_) {
return *value_;
}
return default_value;
}
#endif
const T *operator->() const {
assert(value_);
return value_;
}
T *operator->() {
assert(value_);
return value_;
}
const T &operator*() const {
assert(value_);
return *value_;
}
T &operator*() {
assert(value_);
return *value_;
}
private:
void destruct() {
if (value_) {
value_->~T();
value_ = 0;
}
}
typename standard::aligned_storage<
sizeof(T), standard::alignment_of<T>::value>::type storage_;
T *value_;
};
/// @brief specialize optional for reference.
/// sizeof(optional<T&>) == sizeof(T*)
template <class T> class optional<T &> {
typedef void (optional::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
optional() : value_(0){};
optional(nullopt_t) : value_(0){};
optional(const optional &other) : value_(other.value_) {}
optional(T &value) : value_(&value) {}
~optional() {}
optional &operator=(nullopt_t) {
value_ = 0;
return *this;
}
optional &operator=(const optional &other) {
value_ = other.value_;
return *this;
}
optional &operator=(T &value) {
value_ = &value;
return *this;
}
operator bool_type() const {
this_type_does_not_support_comparisons();
return value_ != 0 ? &optional::this_type_does_not_support_comparisons : 0;
}
T &value() {
if (value_) {
return *value_;
}
throw bad_optional_access();
}
const T &value() const {
if (value_) {
return *value_;
}
throw bad_optional_access();
}
#if KAGUYA_USE_CPP11
T &value_or(T &default_value) const {
if (value_) {
return *value_;
}
return default_value;
}
#else
T &value_or(T &default_value) const {
if (value_) {
return *value_;
}
return default_value;
}
#endif
const T *operator->() const {
assert(value_);
return value_;
}
T *operator->() {
assert(value_);
return value_;
}
const T &operator*() const {
assert(value_);
return *value_;
}
T &operator*() {
assert(value_);
return *value_;
}
private:
T *value_;
};
/// @name relational operators
/// @brief
///@{
template <class T>
bool operator==(const optional<T> &lhs, const optional<T> &rhs) {
if (bool(lhs) != bool(rhs)) {
return false;
}
if (bool(lhs) == false) {
return true;
}
return lhs.value() == rhs.value();
}
template <class T>
bool operator!=(const optional<T> &lhs, const optional<T> &rhs) {
return !(lhs == rhs);
}
template <class T>
bool operator<(const optional<T> &lhs, const optional<T> &rhs) {
if (!bool(rhs)) {
return false;
}
if (!bool(lhs)) {
return true;
}
return lhs.value() < rhs.value();
}
template <class T>
bool operator<=(const optional<T> &lhs, const optional<T> &rhs) {
return !(rhs < lhs);
}
template <class T>
bool operator>(const optional<T> &lhs, const optional<T> &rhs) {
return rhs < lhs;
}
template <class T>
bool operator>=(const optional<T> &lhs, const optional<T> &rhs) {
return !(lhs < rhs);
}
/// @}
/// @}
}

View file

@ -0,0 +1,54 @@
#pragma once
// for c++03 implement
#define KAGUYA_VA_ARG(...) __VA_ARGS__
#define KAGUYA_PP_CAT(F, B) F##B
#include "kaguya/preprocess_repeate.hpp"
#define KAGUYA_PP_VARIADIC_TARG_CONCAT_REP(N) , KAGUYA_PP_CAT(A, N)
#define KAGUYA_PP_VARIADIC_TARG_REP(N) KAGUYA_PP_CAT(A, N)
#define KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N) \
KAGUYA_PP_REPEAT(N, KAGUYA_PP_VARIADIC_TARG_CONCAT_REP)
#define KAGUYA_PP_TEMPLATE_ARG_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_VARIADIC_TARG_REP)
#define KAGUYA_PP_ARG_DEF_CONCAT_REP(N) \
, KAGUYA_PP_CAT(A, N) KAGUYA_PP_CAT(a, N)
#define KAGUYA_PP_ARG_DEF_REP(N) KAGUYA_PP_CAT(A, N) KAGUYA_PP_CAT(a, N)
#define KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N) \
KAGUYA_PP_REPEAT(N, KAGUYA_PP_ARG_DEF_CONCAT_REP)
#define KAGUYA_PP_ARG_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_ARG_DEF_REP)
#define KAGUYA_PP_ARG_CR_DEF_CONCAT_REP(N) \
, const KAGUYA_PP_CAT(A, N) & KAGUYA_PP_CAT(a, N)
#define KAGUYA_PP_ARG_CR_DEF_REP(N) \
const KAGUYA_PP_CAT(A, N) & KAGUYA_PP_CAT(a, N)
#define KAGUYA_PP_ARG_CR_DEF_REPEAT_CONCAT(N) \
KAGUYA_PP_REPEAT(N, KAGUYA_PP_ARG_CR_DEF_CONCAT_REP)
#define KAGUYA_PP_ARG_CR_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_ARG_CR_DEF_REP)
#define KAGUYA_PP_ARG_CONCAT_REP(N) , KAGUYA_PP_CAT(a, N)
#define KAGUYA_PP_ARG_REP(N) KAGUYA_PP_CAT(a, N)
#define KAGUYA_PP_ARG_REPEAT_CONCAT(N) \
KAGUYA_PP_REPEAT(N, KAGUYA_PP_ARG_CONCAT_REP)
#define KAGUYA_PP_ARG_REPEAT(N) KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_ARG_REP)
#define KAGUYA_PP_VARIADIC_TDEF_CONCAT_REP(N) , KAGUYA_PP_CAT(typename A, N)
#define KAGUYA_PP_VARIADIC_TDEF_REP(N) KAGUYA_PP_CAT(typename A, N)
#define KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N) \
KAGUYA_PP_REPEAT(N, KAGUYA_PP_VARIADIC_TDEF_CONCAT_REP)
#define KAGUYA_PP_TEMPLATE_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_VARIADIC_TDEF_REP)
#define KAGUYA_PP_ADD(X, Y) KAGUYA_PP_WHILE(Y, X, KAGUYA_PP_INC)
#define KAGUYA_PP_SUB(X, Y) KAGUYA_PP_WHILE(Y, X, KAGUYA_PP_DEC)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,91 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <memory>
#include "kaguya/config.hpp"
#include "kaguya/traits.hpp"
#include "kaguya/utility.hpp"
namespace kaguya {
/// @brief any data holder class for push to lua
class AnyDataPusher {
public:
int pushToLua(lua_State *state) const {
if (empty()) {
lua_pushnil(state);
return 1;
} else {
return holder_->pushToLua(state);
}
}
AnyDataPusher() : holder_() {}
template <typename DataType>
AnyDataPusher(const DataType &v) : holder_(new DataHolder<DataType>(v)) {}
#if KAGUYA_USE_CPP11
AnyDataPusher(AnyDataPusher &&other) : holder_(std::move(other.holder_)) {}
AnyDataPusher &operator=(AnyDataPusher &&rhs) {
holder_ = std::move(rhs.holder_);
return *this;
}
template <typename DataType>
AnyDataPusher(DataType &&v)
: holder_(new DataHolder<DataType>(std::move(v))) {}
#endif
AnyDataPusher(const AnyDataPusher &other) : holder_(other.holder_) {}
AnyDataPusher &operator=(const AnyDataPusher &other) {
holder_ = other.holder_;
return *this;
}
bool empty() const { return !holder_.get(); }
private:
struct DataHolderBase {
virtual int pushToLua(lua_State *data) const = 0;
// virtual DataHolderBase * clone(void) = 0;
virtual ~DataHolderBase() {}
};
template <typename Type> class DataHolder : public DataHolderBase {
typedef typename traits::decay<Type>::type DataType;
public:
#if KAGUYA_USE_CPP11
explicit DataHolder(DataType &&v) : data_(std::forward<DataType>(v)) {}
#else
explicit DataHolder(const DataType &v) : data_(v) {}
#endif
virtual int pushToLua(lua_State *state) const {
return util::push_args(state, data_);
}
private:
DataType data_;
};
// specialize for string literal
template <int N> struct DataHolder<const char[N]> : DataHolder<std::string> {
explicit DataHolder(const char *v)
: DataHolder<std::string>(
std::string(v, v[N - 1] != '\0' ? v + N : v + N - 1)) {}
};
template <int N> struct DataHolder<char[N]> : DataHolder<std::string> {
explicit DataHolder(const char *v)
: DataHolder<std::string>(
std::string(v, v[N - 1] != '\0' ? v + N : v + N - 1)) {}
};
standard::shared_ptr<DataHolderBase> holder_;
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for AnyDataPusher
template <> struct lua_type_traits<AnyDataPusher> {
static int push(lua_State *l, const AnyDataPusher &data) {
return data.pushToLua(l);
}
};
}

View file

@ -0,0 +1,53 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include "kaguya/config.hpp"
#include "kaguya/traits.hpp"
namespace kaguya {
#if KAGUYA_USE_CPP11
namespace detail {
template <std::size_t... indexes> struct index_tuple {};
template <std::size_t first, std::size_t last, class result = index_tuple<>,
bool flag = first >= last>
struct index_range {
using type = result;
};
template <std::size_t step, std::size_t last, std::size_t... indexes>
struct index_range<step, last, index_tuple<indexes...>, false>
: index_range<step + 1, last, index_tuple<indexes..., step> > {};
template <std::size_t... Indexes, class... Args>
int push_tuple(lua_State *l, index_tuple<Indexes...>, std::tuple<Args...> &&v) {
return util::push_args(l, std::get<Indexes>(v)...);
}
}
/// @ingroup lua_type_traits
/// @brief lua_type_traits for std::tuple or boost::tuple
template <class... Args> struct lua_type_traits<standard::tuple<Args...> > {
static int push(lua_State *l, std::tuple<Args...> &&v) {
typename detail::index_range<0, sizeof...(Args)>::type index;
return detail::push_tuple(l, index, std::forward<std::tuple<Args...> >(v));
}
};
#else
#define KAGUYA_PP_GET_DATA(N) standard::get<N - 1>(v)
#define KAGUYA_PUSH_TUPLE_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
struct lua_type_traits<standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > { \
static int \
push(lua_State *l, \
const standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> &v) { \
return util::push_args(l, KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_GET_DATA)); \
} \
};
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_TUPLE_SIZE, KAGUYA_PUSH_TUPLE_DEF)
#undef KAGUYA_PP_GET_DATA
#undef KAGUYA_PUSH_TUPLE_DEF
#endif
}

View file

@ -0,0 +1,50 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include "kaguya/config.hpp"
namespace kaguya {
template <typename RefTuple, typename GetTuple> struct ref_tuple {
RefTuple tref;
ref_tuple(const RefTuple &va) : tref(va) {}
void operator=(const FunctionResults &fres) {
tref = fres.get_result(types::typetag<GetTuple>());
}
template <class T> void operator=(const T &fres) { tref = fres; }
};
#if KAGUYA_USE_CPP11
template <class... Args>
ref_tuple<standard::tuple<Args &...>, standard::tuple<Args...> >
tie(Args &... va) {
typedef standard::tuple<Args &...> RefTuple;
typedef standard::tuple<Args...> GetTuple;
return ref_tuple<RefTuple, GetTuple>(RefTuple(va...));
}
#else
#define KAGUYA_VARIADIC_REFARG_REP(N) KAGUYA_PP_CAT(A, N) & KAGUYA_PP_CAT(a, N)
#define KAGUYA_VARIADIC_TREFARG_REP(N) KAGUYA_PP_CAT(A, N) &
#define KAGUYA_TEMPLATE_REFARG_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_VARIADIC_TREFARG_REP)
#define KAGUYA_REF_TUPLE(N) standard::tuple<KAGUYA_TEMPLATE_REFARG_REPEAT(N)>
#define KAGUYA_GET_TUPLE(N) standard::tuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)>
#define KAGUYA_REF_TUPLE_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
ref_tuple<KAGUYA_REF_TUPLE(N), KAGUYA_GET_TUPLE(N)> tie( \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_VARIADIC_REFARG_REP)) { \
return ref_tuple<KAGUYA_REF_TUPLE(N), KAGUYA_GET_TUPLE(N)>( \
KAGUYA_REF_TUPLE(N)(KAGUYA_PP_ARG_REPEAT(N))); \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_TUPLE_SIZE, KAGUYA_REF_TUPLE_DEF)
#undef KAGUYA_VARIADIC_REFARG_REP
#undef KAGUYA_TEMPLATE_REFARG_REPEAT
#undef KAGUYA_REF_TUPLE
#undef KAGUYA_GET_TUPLE
#undef KAGUYA_REF_TUPLE_DEF
#endif
}

View file

@ -0,0 +1,502 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include <iostream>
#include "kaguya/config.hpp"
#include "kaguya/utility.hpp"
#include "kaguya/metatable.hpp"
#include "kaguya/error_handler.hpp"
#include "kaguya/lua_ref_table.hpp"
#include "kaguya/lua_ref_function.hpp"
namespace kaguya {
/// @addtogroup State
/// @{
/// @brief Load library info type @see State::openlibs @see State::State(const
/// LoadLibs &libs)
typedef std::pair<std::string, lua_CFunction> LoadLib;
/// @brief Load libraries info @see State::openlibs @see State::State(const
/// LoadLibs &libs)
typedef std::vector<LoadLib> LoadLibs;
/// @brief return no load library type @see State::State(const LoadLibs &libs)
inline LoadLibs NoLoadLib() { return LoadLibs(); }
/// @brief All load standard libraries type @see State::openlibs
struct AllLoadLibs {};
template <typename Allocator>
void *AllocatorFunction(void *ud, void *ptr, size_t osize, size_t nsize) {
Allocator *allocator = static_cast<Allocator *>(ud);
if (nsize == 0) {
allocator->deallocate(ptr, osize);
} else if (ptr) {
return allocator->reallocate(ptr, nsize);
} else {
return allocator->allocate(nsize);
}
return 0;
}
struct DefaultAllocator {
typedef void *pointer;
typedef size_t size_type;
pointer allocate(size_type n) { return std::malloc(n); }
pointer reallocate(pointer p, size_type n) { return std::realloc(p, n); }
void deallocate(pointer p, size_type n) {
KAGUYA_UNUSED(n);
std::free(p);
}
};
/// lua_State wrap class
class State {
standard::shared_ptr<void> allocator_holder_;
lua_State *state_;
bool created_;
// non copyable
State(const State &);
State &operator=(const State &);
static int initializing_panic(lua_State *L) {
ErrorHandler::throwDefaultError(lua_status(L), lua_tostring(L, -1));
return 0; // return to Lua to abort
}
static int default_panic(lua_State *L) {
if (ErrorHandler::handle(lua_status(L), L)) {
return 0;
}
fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
lua_tostring(L, -1));
fflush(stderr);
return 0; // return to Lua to abort
}
static void stderror_out(int status, const char *message) {
KAGUYA_UNUSED(status);
std::cerr << message << std::endl;
}
template <typename Libs> void init(const Libs &lib) {
if (state_) {
lua_atpanic(state_, &initializing_panic);
try {
if (!ErrorHandler::getHandler(state_)) {
setErrorHandler(&stderror_out);
}
openlibs(lib);
lua_atpanic(state_, &default_panic);
} catch (const LuaException &) {
lua_close(state_);
state_ = 0;
}
}
}
public:
/// @brief create Lua state with lua standard library
State() : allocator_holder_(), state_(luaL_newstate()), created_(true) {
init(AllLoadLibs());
}
/// @brief create Lua state with lua standard library. Can not use this
/// constructor at luajit. error message is 'Must use luaL_newstate() for 64
/// bit target'
/// @param allocator allocator for memory allocation @see DefaultAllocator
template <typename Allocator>
State(standard::shared_ptr<Allocator> allocator)
: allocator_holder_(allocator),
state_(lua_newstate(&AllocatorFunction<Allocator>,
allocator_holder_.get())),
created_(true) {
init(AllLoadLibs());
}
/// @brief create Lua state with (or without) libraries.
/// @param libs load libraries
/// e.g. LoadLibs libs;libs.push_back(LoadLib("libname",libfunction));State
/// state(libs);
/// e.g. State state({{"libname",libfunction}}); for c++ 11
State(const LoadLibs &libs)
: allocator_holder_(), state_(luaL_newstate()), created_(true) {
init(libs);
}
/// @brief create Lua state with (or without) libraries. Can not use this
/// constructor at luajit. error message is 'Must use luaL_newstate() for 64
/// bit target'
/// @param libs load libraries
/// @param allocator allocator for memory allocation @see DefaultAllocator
template <typename Allocator>
State(const LoadLibs &libs, standard::shared_ptr<Allocator> allocator)
: allocator_holder_(allocator),
state_(lua_newstate(&AllocatorFunction<Allocator>,
allocator_holder_.get())),
created_(true) {
init(libs);
}
/// @brief construct using created lua_State.
/// @param lua created lua_State. It is not call lua_close() in this class
State(lua_State *lua) : state_(lua), created_(false) {
if (state_) {
if (!ErrorHandler::getHandler(state_)) {
setErrorHandler(&stderror_out);
}
}
}
~State() {
if (created_ && state_) {
lua_close(state_);
}
}
/// @brief set error handler for lua error.
void
setErrorHandler(standard::function<void(int statuscode, const char *message)>
errorfunction) {
if (!state_) {
return;
}
util::ScopedSavedStack save(state_);
ErrorHandler::registerHandler(state_, errorfunction);
}
/// @brief load all lua standard library
void openlibs(AllLoadLibs = AllLoadLibs()) {
if (!state_) {
return;
}
luaL_openlibs(state_);
}
/// @brief load lua library
LuaStackRef openlib(const LoadLib &lib) {
if (!state_) {
return LuaStackRef();
}
luaL_requiref(state_, lib.first.c_str(), lib.second, 1);
return LuaStackRef(state_, -1, true);
}
/// @brief load lua library
LuaStackRef openlib(std::string name, lua_CFunction f) {
return openlib(LoadLib(name, f));
}
/// @brief load lua libraries
void openlibs(const LoadLibs &libs) {
for (LoadLibs::const_iterator it = libs.begin(); it != libs.end(); ++it) {
openlib(*it);
}
}
/// @brief If there are no errors,compiled file as a Lua function and return.
/// Otherwise send error message to error handler and return nil reference
/// @param file file path of lua script
/// @return reference of lua function
LuaFunction loadfile(const std::string &file) {
return LuaFunction::loadfile(state_, file);
}
/// @brief If there are no errors,compiled file as a Lua function and return.
/// Otherwise send error message to error handler and return nil reference
/// @param file file path of lua script
/// @return reference of lua function
LuaFunction loadfile(const char *file) {
return LuaFunction::loadfile(state_, file);
}
/// @brief If there are no errors,compiled stream as a Lua function and
/// return.
/// Otherwise send error message to error handler and return nil reference
/// @param stream stream of lua script
/// @param chunkname chunkname of lua script
/// @return reference of lua function
LuaFunction loadstream(std::istream &stream, const char *chunkname = 0) {
return LuaFunction::loadstream(state_, stream, chunkname);
}
/// @brief Loads and runs the given stream.
/// @param stream stream of lua script
/// @param chunkname chunkname of lua script
/// @param env execute env table
/// @return If there are no errors, returns true.Otherwise return false
bool dostream(std::istream &stream, const char *chunkname = 0,
const LuaTable &env = LuaTable()) {
util::ScopedSavedStack save(state_);
LuaStackRef f = LuaFunction::loadstreamtostack(state_, stream, chunkname);
if (!f) { // load failed
return false;
}
if (!env.isNilref()) {
f.setFunctionEnv(env);
}
FunctionResults ret = f.call<FunctionResults>();
return !ret.resultStatus();
}
/// @brief If there are no errors,compiled string as a Lua function and
/// return.
/// Otherwise send error message to error handler and return nil reference
/// @param str lua code
/// @return reference of lua function
LuaFunction loadstring(const std::string &str) {
return LuaFunction::loadstring(state_, str);
}
/// @brief If there are no errors,compiled string as a Lua function and
/// return.
/// Otherwise send error message to error handler and return nil reference
/// @param str lua code
/// @return reference of lua function
LuaFunction loadstring(const char *str) {
return LuaFunction::loadstring(state_, str);
}
/// @brief Loads and runs the given file.
/// @param file file path of lua script
/// @param env execute env table
/// @return If there are no errors, returns true.Otherwise return false
bool dofile(const std::string &file, const LuaTable &env = LuaTable()) {
return dofile(file.c_str(), env);
}
/// @brief Loads and runs the given file.
/// @param file file path of lua script
/// @param env execute env table
/// @return If there are no errors, returns true.Otherwise return false
bool dofile(const char *file, const LuaTable &env = LuaTable()) {
util::ScopedSavedStack save(state_);
int status = luaL_loadfile(state_, file);
if (status) {
ErrorHandler::handle(status, state_);
return false;
}
if (!env.isNilref()) { // register _ENV
env.push();
#if LUA_VERSION_NUM >= 502
lua_setupvalue(state_, -2, 1);
#else
lua_setfenv(state_, -2);
#endif
}
status = lua_pcall_wrap(state_, 0, LUA_MULTRET);
if (status) {
ErrorHandler::handle(status, state_);
return false;
}
return true;
}
/// @brief Loads and runs the given string.
/// @param str lua script cpde
/// @param env execute env table
/// @return If there are no errors, returns true.Otherwise return false
bool dostring(const char *str, const LuaTable &env = LuaTable()) {
util::ScopedSavedStack save(state_);
int status = luaL_loadstring(state_, str);
if (status) {
ErrorHandler::handle(status, state_);
return false;
}
if (!env.isNilref()) { // register _ENV
env.push();
#if LUA_VERSION_NUM >= 502
lua_setupvalue(state_, -2, 1);
#else
lua_setfenv(state_, -2);
#endif
}
status = lua_pcall_wrap(state_, 0, LUA_MULTRET);
if (status) {
ErrorHandler::handle(status, state_);
return false;
}
return true;
}
/// @brief Loads and runs the given string.
/// @param str lua script cpde
/// @param env execute env table
/// @return If there are no errors, returns true.Otherwise return false
bool dostring(const std::string &str, const LuaTable &env = LuaTable()) {
return dostring(str.c_str(), env);
}
/// @brief Loads and runs the given string.
/// @param str lua script cpde
/// @return If there are no errors, returns true.Otherwise return false
bool operator()(const std::string &str) { return dostring(str); }
/// @brief Loads and runs the given string.
/// @param str lua script cpde
/// @return If there are no errors, returns true.Otherwise return false
bool operator()(const char *str) { return dostring(str); }
/// @brief return element reference from global table
/// @param str table key
/// @return proxy class for reference to table.
TableKeyReferenceProxy<std::string> operator[](const std::string &str) {
int stack_top = lua_gettop(state_);
util::push_args(state_, GlobalTable());
int table_index = stack_top + 1;
return TableKeyReferenceProxy<std::string>(state_, table_index, str,
stack_top, NoTypeCheck());
}
/// @brief return element reference from global table
/// @param str table key
/// @return proxy class for reference to table.
TableKeyReferenceProxy<const char *> operator[](const char *str) {
int stack_top = lua_gettop(state_);
util::push_args(state_, GlobalTable());
int table_index = stack_top + 1;
return TableKeyReferenceProxy<const char *>(state_, table_index, str,
stack_top, NoTypeCheck());
}
/// @brief return global table
/// @return global table.
LuaTable globalTable() { return newRef(GlobalTable()); }
/// @brief create new Lua reference from argument value
/// @return Lua reference.
template <typename T> LuaRef newRef(const T &value) {
return LuaRef(state_, value);
}
#if KAGUYA_USE_CPP11
/// @brief create new Lua reference from argument value
/// @return Lua reference.
template <typename T> LuaRef newRef(T &&value) {
return LuaRef(state_, std::forward<T>(value));
}
#endif
/// @brief create new Lua table
/// @return Lua table reference.
LuaTable newTable() { return LuaTable(state_); }
/// @brief create new Lua table
/// @param reserve_array reserved array count
/// @param reserve_record reserved record count
/// @return Lua table reference.
LuaTable newTable(int reserve_array, int reserve_record) {
return LuaTable(state_, NewTable(reserve_array, reserve_record));
}
/// @brief create new Lua thread
/// @return Lua thread reference.
LuaThread newThread() { return LuaThread(state_); }
/// @brief create new Lua thread with lua function
/// @param f function
/// @return Lua thread reference.
LuaThread newThread(const LuaFunction &f) {
LuaThread cor(state_);
cor.setFunction(f);
return cor;
}
/// @brief argument value push to stack.
/// @param value value
template <typename T> void pushToStack(T value) {
util::push_args(state_, value);
}
/// @brief pop from stack.
/// @return reference to pop value.
LuaRef popFromStack() { return LuaRef(state_, StackTop()); }
/// @brief Garbage Collection of Lua
struct GCType {
GCType(lua_State *state) : state_(state) {}
/// @brief Performs a full garbage-collection cycle.
void collect() { lua_gc(state_, LUA_GCCOLLECT, 0); }
/// @brief Performs an incremental step of garbage collection.
/// @return If returns true,the step finished a collection cycle.
bool step() { return lua_gc(state_, LUA_GCSTEP, 0) == 1; }
/// @brief Performs an incremental step of garbage collection.
/// @param size the collector will perform as if that amount of memory (in
/// KBytes) had been allocated by Lua.
bool step(int size) { return lua_gc(state_, LUA_GCSTEP, size) == 1; }
/// @brief enable gc
void restart() { enable(); }
/// @brief disable gc
void stop() { disable(); }
/// @brief returns the total memory in use by Lua in Kbytes.
int count() const { return lua_gc(state_, LUA_GCCOUNT, 0); }
/// @brief sets arg as the new value for the pause of the collector. Returns
/// the previous value for pause.
int steppause(int value) { return lua_gc(state_, LUA_GCSETPAUSE, value); }
/// @brief sets arg as the new value for the step multiplier of the
/// collector. Returns the previous value for step.
int setstepmul(int value) {
return lua_gc(state_, LUA_GCSETSTEPMUL, value);
}
/// @brief enable gc
void enable() { lua_gc(state_, LUA_GCRESTART, 0); }
/// @brief disable gc
void disable() { lua_gc(state_, LUA_GCSTOP, 0); }
#if LUA_VERSION_NUM >= 502
/// @brief returns a boolean that tells whether the collector is running
bool isrunning() const { return isenabled(); }
/// @brief returns a boolean that tells whether the collector is running
bool isenabled() const { return lua_gc(state_, LUA_GCISRUNNING, 0) != 0; }
#endif
private:
lua_State *state_;
};
// /@brief return Garbage collection interface.
GCType gc() const { return GCType(state_); }
/// @brief performs a full garbage-collection cycle.
void garbageCollect() { gc().collect(); }
/// @brief returns the current amount of memory (in Kbytes) in use by Lua.
size_t useKBytes() const { return size_t(gc().count()); }
/// @brief create Table and push to stack.
/// using for Lua module
/// @return return Lua Table Reference
LuaTable newLib() {
LuaTable newtable = newTable();
newtable.push(state_);
return newtable;
}
/// @brief return lua_State*.
/// @return lua_State*
lua_State *state() { return state_; };
/// @brief check valid lua_State.
bool isInvalid() const { return !state_; }
};
/// @}
}

View file

@ -0,0 +1,157 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include <vector>
#include <map>
#include "kaguya/config.hpp"
#include "kaguya/optional.hpp"
namespace kaguya {
namespace traits {
using standard::integral_constant;
using standard::true_type;
using standard::false_type;
using standard::remove_reference;
using standard::remove_pointer;
using standard::remove_const;
using standard::remove_volatile;
using standard::remove_cv;
using standard::is_function;
using standard::is_floating_point;
using standard::is_integral;
using standard::is_enum;
using standard::is_convertible;
using standard::is_same;
using standard::is_arithmetic;
using standard::is_union;
using standard::is_class;
using standard::is_pointer;
using standard::is_lvalue_reference;
using standard::is_const;
using standard::is_void;
#if KAGUYA_USE_CPP11
using std::enable_if;
#else
template <bool B, class T = void>
struct enable_if : boost::enable_if_c<B, T> {};
#endif
class Helper {};
/// @brief Check if T_Mem is a member object of a type. That is true if it is
/// not a member function
/// Required as MSVC throws a COMDAT error when using is_member_object_pointer
template <typename T_Mem> struct is_object {
typedef typename standard::is_member_function_pointer<T_Mem Helper::*>::type
NotResult;
enum { value = !NotResult::value };
};
/// @brief Similar to std::decay but also removes const and volatile modifiers
/// if T is neither an array nor a function
template <class T> struct decay {
private:
///@ If T is a reference type, the type referrered to by T. Otherwise, T.
typedef typename standard::remove_reference<T>::type U;
public:
typedef typename standard::conditional<
standard::is_array<U>::value, typename standard::remove_extent<U>::type *,
typename standard::conditional<
is_function<U>::value, typename standard::add_pointer<U>::type,
typename standard::remove_cv<U>::type>::type>::type type;
};
/// @brief Trait class that identifies whether T is a const reference type.
template <class T> struct is_const_reference : false_type {};
template <class T> struct is_const_reference<const T &> : true_type {};
/// @brief Obtains the type T without top-level const and reference.
template <typename T> struct remove_const_and_reference {
/// @brief If T is const or reference, the same type as T but with the const
/// reference removed.Otherwise, T
typedef T type;
};
/// @brief Obtains the type T without top-level const and reference.
template <typename T> struct remove_const_and_reference<T &> {
/// @brief If T is const or reference, the same type as T but with the const
/// reference removed.Otherwise, T
typedef T type;
};
/// @brief Obtains the type T without top-level const and reference.
template <typename T> struct remove_const_and_reference<const T> {
/// @brief If T is const or reference, the same type as T but with the const
/// reference removed.Otherwise, T
typedef T type;
};
/// @brief Obtains the type T without top-level const and reference.
template <typename T> struct remove_const_and_reference<const T &> {
/// @brief If T is const or reference, the same type as T but with the const
/// reference removed.Otherwise, T
typedef T type;
};
/// @brief Obtains the type T without top-level const reference.
template <typename T> struct remove_const_reference {
/// @brief If T is const reference, the same type as T but with the const
/// reference removed.Otherwise, T
typedef T type;
};
/// @brief Obtains the type T without top-level const reference.
template <typename T> struct remove_const_reference<const T &> {
/// @brief If T is const reference, the same type as T but with the const
/// reference removed.Otherwise, T
typedef T type;
};
/// @brief Trait class that identifies whether T is a std::vector type.
template <class T> struct is_std_vector : false_type {};
template <class T, class A>
struct is_std_vector<std::vector<T, A> > : true_type {};
/// @brief Trait class that identifies whether T is a std::map type.
template <class T> struct is_std_map : false_type {};
template <class K, class V, class C, class A>
struct is_std_map<std::map<K, V, C, A> > : true_type {};
}
/// @addtogroup lua_type_traits
/// @ingroup lua_type_traits
/// @brief If you want to customize the conversion to type of lua yourself ,
/// implement specialize of this class
template <typename T, typename Enable = void> struct lua_type_traits {
typedef void Registerable;
typedef typename traits::decay<T>::type NCRT;
typedef const NCRT &get_type;
typedef optional<get_type> opt_type;
typedef const NCRT &push_type;
static bool checkType(lua_State *l, int index);
static bool strictCheckType(lua_State *l, int index);
static get_type get(lua_State *l, int index);
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT;
static int push(lua_State *l, push_type v);
#if KAGUYA_USE_RVALUE_REFERENCE
static int push(lua_State *l, NCRT &&v);
#endif
};
/// @brief Trait class that identifies whether T is a userdata type.
template <typename T, typename Enable = void>
struct is_usertype : traits::false_type {};
template <typename T>
struct is_usertype<T, typename lua_type_traits<T>::Registerable>
: traits::true_type {};
/// @brief Trait class that identifies whether T is a registerable by
/// UserdataMetatable.
template <typename T> struct is_registerable : is_usertype<T> {};
}

View file

@ -0,0 +1,925 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include <cstring>
#include "kaguya/config.hpp"
#include "kaguya/optional.hpp"
#include "kaguya/traits.hpp"
#include "kaguya/object.hpp"
#include "kaguya/exception.hpp"
#include "kaguya/push_tuple.hpp"
namespace kaguya {
// default implements
template <typename T, typename Enable>
bool lua_type_traits<T, Enable>::checkType(lua_State *l, int index) {
return object_wrapper<T>(l, index) != 0;
}
template <typename T, typename Enable>
bool lua_type_traits<T, Enable>::strictCheckType(lua_State *l, int index) {
return object_wrapper<T>(l, index, false) != 0;
}
template <typename T, typename Enable>
typename lua_type_traits<T, Enable>::opt_type
lua_type_traits<T, Enable>::opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
const typename traits::remove_reference<T>::type *pointer = get_const_pointer(
l, index, types::typetag<typename traits::remove_reference<T>::type>());
if (!pointer) {
return opt_type();
}
return *pointer;
}
template <typename T, typename Enable>
typename lua_type_traits<T, Enable>::get_type
lua_type_traits<T, Enable>::get(lua_State *l, int index) {
const typename traits::remove_reference<T>::type *pointer = get_const_pointer(
l, index, types::typetag<typename traits::remove_reference<T>::type>());
if (!pointer) {
throw LuaTypeMismatch();
}
return *pointer;
}
template <typename T, typename Enable>
int lua_type_traits<T, Enable>::push(lua_State *l, push_type v) {
return util::object_push(l, v);
}
#if KAGUYA_USE_RVALUE_REFERENCE
template <typename T, typename Enable>
int lua_type_traits<T, Enable>::push(lua_State *l, NCRT &&v) {
return util::object_push(l, std::forward<NCRT>(v));
}
#endif
/// @ingroup lua_type_traits
/// @brief lua_type_traits for const reference type
template <typename T>
struct lua_type_traits<
T, typename traits::enable_if<traits::is_const_reference<T>::value>::type>
: lua_type_traits<typename traits::remove_const_reference<T>::type> {};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for lvalue reference type
template <typename REF>
struct lua_type_traits<
REF, typename traits::enable_if<
traits::is_lvalue_reference<REF>::value &&
!traits::is_const<
typename traits::remove_reference<REF>::type>::value>::type> {
typedef void Registerable;
typedef REF get_type;
typedef optional<get_type> opt_type;
typedef REF push_type;
typedef typename traits::remove_reference<REF>::type T;
static bool strictCheckType(lua_State *l, int index) {
return object_wrapper<T>(l, index, false) != 0;
}
static bool checkType(lua_State *l, int index) {
if (lua_type(l, index) == LUA_TLIGHTUSERDATA) {
return true;
}
return object_wrapper<T>(l, index) != 0;
}
static get_type get(lua_State *l, int index) {
T *pointer = get_pointer(l, index, types::typetag<T>());
if (!pointer) {
throw LuaTypeMismatch();
}
return *pointer;
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
T *pointer = get_pointer(l, index, types::typetag<T>());
if (!pointer) {
return opt_type();
}
return opt_type(*pointer);
}
static int push(lua_State *l, push_type v) {
if (!available_metatable<T>(l)) {
lua_pushlightuserdata(
l, const_cast<typename traits::remove_const<T>::type *>(&v));
} else {
typedef typename ObjectPointerWrapperType<T>::type wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(&v);
class_userdata::setmetatable<T>(l);
}
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for pointer type
template <typename PTR>
struct lua_type_traits<
PTR, typename traits::enable_if<
traits::is_pointer<
typename traits::remove_const_reference<PTR>::type>::value &&
!traits::is_function<
typename traits::remove_pointer<PTR>::type>::value>::type> {
typedef void Registerable;
typedef PTR get_type;
typedef optional<get_type> opt_type;
typedef PTR push_type;
typedef typename traits::remove_pointer<PTR>::type T;
static bool strictCheckType(lua_State *l, int index) {
return object_wrapper<T>(l, index, false) != 0;
}
static bool checkType(lua_State *l, int index) {
int type = lua_type(l, index);
if (type == LUA_TLIGHTUSERDATA || type == LUA_TNIL || type == LUA_TNONE) {
return true;
}
return object_wrapper<T>(l, index) != 0;
}
static get_type get(lua_State *l, int index) {
int type = lua_type(l, index);
if (type == LUA_TUSERDATA || type == LUA_TLIGHTUSERDATA) {
return get_pointer(l, index, types::typetag<T>());
}
if (type == LUA_TNIL || type == LUA_TNONE) {
return 0;
}
throw LuaTypeMismatch();
return 0;
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
int type = lua_type(l, index);
if (type == LUA_TUSERDATA || type == LUA_TLIGHTUSERDATA) {
return get_pointer(l, index, types::typetag<T>());
}
if (type == LUA_TNIL || type == LUA_TNONE) {
return opt_type(0);
}
return opt_type();
}
static int push(lua_State *l, push_type v) {
if (!v) {
lua_pushnil(l);
} else if (!available_metatable<T>(l)) {
lua_pushlightuserdata(
l, const_cast<typename traits::remove_const<T>::type *>(v));
} else {
typedef typename ObjectPointerWrapperType<T>::type wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(v);
class_userdata::setmetatable<T>(l);
}
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for bool
template <> struct lua_type_traits<bool> {
typedef bool get_type;
typedef optional<get_type> opt_type;
typedef bool push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TBOOLEAN;
}
static bool checkType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return true;
}
static bool get(lua_State *l, int index) {
return l && lua_toboolean(l, index) != 0;
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
if (l) {
return opt_type(lua_toboolean(l, index) != 0);
} else {
return opt_type();
}
}
static int push(lua_State *l, bool s) {
lua_pushboolean(l, s);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for void
template <> struct lua_type_traits<void> {
typedef void *get_type;
typedef void *push_type;
static bool strictCheckType(lua_State *, int) { return true; }
static bool checkType(lua_State *, int) { return true; }
static get_type get(lua_State *, int) { return 0; }
static int push(lua_State *, push_type) { return 0; }
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for reference_wrapper
template <typename T> struct lua_type_traits<standard::reference_wrapper<T> > {
typedef const standard::reference_wrapper<T> &push_type;
static int push(lua_State *l, push_type v) {
return util::push_args(l, &v.get());
}
};
namespace detail {
template <typename T, typename Enable = void>
struct has_optional_get : traits::false_type {};
template <typename T>
struct has_optional_get<
T, typename traits::enable_if<!traits::is_same<
void, typename lua_type_traits<T>::opt_type>::value>::type>
: traits::true_type {};
template <typename T>
typename traits::enable_if<has_optional_get<T>::value, optional<T> >::type
opt_helper(lua_State *state, int index) KAGUYA_NOEXCEPT {
return lua_type_traits<T>::opt(state, index);
}
template <typename T>
typename traits::enable_if<!has_optional_get<T>::value, optional<T> >::type
opt_helper(lua_State *state, int index) {
try {
return lua_type_traits<T>::get(state, index);
} catch (...) {
return optional<T>();
}
}
}
/// @ingroup lua_type_traits
/// @brief lua_type_traits for optional
template <typename T> struct lua_type_traits<optional<T> > {
typedef const optional<T> &push_type;
typedef optional<T> get_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type_traits<T>::strictCheckType(l, index);
}
static bool checkType(lua_State *l, int index) {
KAGUYA_UNUSED(l);
KAGUYA_UNUSED(index);
return true;
}
static get_type get(lua_State *l, int index) KAGUYA_NOEXCEPT {
return detail::opt_helper<T>(l, index);
}
static int push(lua_State *l, push_type v) KAGUYA_NOEXCEPT {
if (v) {
return util::push_args(l, v.value());
} else {
lua_pushnil(l);
}
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for shared_ptr
template <typename T> struct lua_type_traits<standard::shared_ptr<T> > {
typedef const standard::shared_ptr<T> &push_type;
typedef standard::shared_ptr<T> get_type;
static bool strictCheckType(lua_State *l, int index) {
ObjectSharedPointerWrapper *wrapper =
dynamic_cast<ObjectSharedPointerWrapper *>(object_wrapper(l, index));
const std::type_info &type =
metatableType<standard::shared_ptr<typename traits::decay<T>::type> >();
return wrapper && (wrapper->shared_ptr_type() == type);
}
static bool checkType(lua_State *l, int index) {
return get_shared_pointer(l, index, types::typetag<T>()) ||
lua_isnil(l, index);
}
static get_type get(lua_State *l, int index) {
if (lua_isnil(l, index)) {
return get_type();
}
return get_shared_pointer(l, index, types::typetag<T>());
}
static int push(lua_State *l, push_type v) {
if (v) {
typedef ObjectSharedPointerWrapper wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(v);
class_userdata::setmetatable<T>(l);
} else {
lua_pushnil(l);
}
return 1;
}
};
#if KAGUYA_USE_CPP11
/// @ingroup lua_type_traits
/// @brief lua_type_traits for unique_ptr
template <typename T, typename Deleter>
struct lua_type_traits<std::unique_ptr<T, Deleter> > {
typedef std::unique_ptr<T, Deleter> &&push_type;
typedef std::unique_ptr<T, Deleter> &get_type;
typedef std::unique_ptr<T, Deleter> type;
static bool strictCheckType(lua_State *l, int index) {
return object_wrapper<type>(l, index, false) != 0;
}
static bool checkType(lua_State *l, int index) {
return object_wrapper<type>(l, index) != 0 || lua_isnil(l, index);
}
static get_type get(lua_State *l, int index) {
type *pointer = get_pointer(l, index, types::typetag<type>());
if (!pointer) {
throw LuaTypeMismatch();
}
return *pointer;
}
static int push(lua_State *l, push_type v) {
if (v) {
typedef ObjectSmartPointerWrapper<type> wrapper_type;
void *storage = lua_newuserdata(l, sizeof(wrapper_type));
new (storage) wrapper_type(std::forward<push_type>(v));
class_userdata::setmetatable<T>(l);
} else {
lua_pushnil(l);
}
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for nullptr
template <> struct lua_type_traits<std::nullptr_t> {
typedef const std::nullptr_t &push_type;
typedef std::nullptr_t get_type;
typedef optional<get_type> opt_type;
static bool checkType(lua_State *l, int index) {
return lua_isnoneornil(l, index);
}
static bool strictCheckType(lua_State *l, int index) {
return lua_isnil(l, index);
}
static opt_type opt(lua_State *l, int index) {
if (!lua_isnoneornil(l, index)) {
return opt_type();
}
return nullptr;
}
static get_type get(lua_State *l, int index) {
if (!lua_isnoneornil(l, index)) {
throw LuaTypeMismatch();
}
return nullptr;
}
static int push(lua_State *l, const std::nullptr_t &) {
lua_pushnil(l);
return 1;
}
};
#endif
/// @ingroup lua_type_traits
/// @brief lua_type_traits for ObjectWrapperBase*
template <> struct lua_type_traits<ObjectWrapperBase *> {
typedef ObjectWrapperBase *get_type;
typedef ObjectWrapperBase *push_type;
static bool strictCheckType(lua_State *l, int index) {
return object_wrapper(l, index) != 0;
}
static bool checkType(lua_State *l, int index) {
return object_wrapper(l, index) != 0;
}
static get_type get(lua_State *l, int index) {
return object_wrapper(l, index);
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for native type of luathread(lua_State*)
template <> struct lua_type_traits<lua_State *> {
typedef lua_State *get_type;
typedef lua_State *push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_isthread(l, index);
}
static bool checkType(lua_State *l, int index) {
return lua_isthread(l, index);
}
static lua_State *get(lua_State *l, int index) {
return lua_tothread(l, index);
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for floating point number value
template <typename T>
struct lua_type_traits<
T, typename traits::enable_if<traits::is_floating_point<T>::value>::type> {
typedef typename traits::remove_const_reference<T>::type get_type;
typedef optional<get_type> opt_type;
typedef lua_Number push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TNUMBER;
}
static bool checkType(lua_State *l, int index) {
return lua_isnumber(l, index) != 0;
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
int isnum = 0;
get_type num = static_cast<T>(lua_tonumberx(l, index, &isnum));
if (!isnum) {
return opt_type();
}
return num;
}
static get_type get(lua_State *l, int index) {
int isnum = 0;
get_type num = static_cast<T>(lua_tonumberx(l, index, &isnum));
if (!isnum) {
throw LuaTypeMismatch();
}
return num;
}
static int push(lua_State *l, lua_Number s) {
lua_pushnumber(l, s);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for integral number value
template <typename T>
struct lua_type_traits<
T, typename traits::enable_if<traits::is_integral<T>::value>::type> {
typedef typename traits::remove_const_reference<T>::type get_type;
typedef optional<get_type> opt_type;
#if LUA_VERSION_NUM >= 503
typedef lua_Integer push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_isinteger(l, index) != 0;
}
static bool checkType(lua_State *l, int index) {
return lua_isnumber(l, index) != 0;
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
int isnum = 0;
get_type num = static_cast<T>(lua_tointegerx(l, index, &isnum));
if (!isnum) {
return opt_type();
}
return num;
}
static get_type get(lua_State *l, int index) {
int isnum = 0;
get_type num = static_cast<T>(lua_tointegerx(l, index, &isnum));
if (!isnum) {
throw LuaTypeMismatch();
}
return num;
}
static int push(lua_State *l, lua_Integer s) {
lua_pushinteger(l, s);
return 1;
}
#else
typedef typename lua_type_traits<lua_Number>::push_type push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type_traits<lua_Number>::strictCheckType(l, index);
}
static bool checkType(lua_State *l, int index) {
return lua_type_traits<lua_Number>::checkType(l, index);
}
static get_type get(lua_State *l, int index) {
return static_cast<get_type>(lua_type_traits<lua_Number>::get(l, index));
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
lua_type_traits<lua_Number>::opt_type v =
lua_type_traits<lua_Number>::opt(l, index);
if (!v) {
return opt_type();
}
return static_cast<get_type>(*v);
}
static int push(lua_State *l, push_type s) { return util::push_args(l, s); }
#endif
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for enum
template <typename T>
struct lua_type_traits<
T, typename traits::enable_if<traits::is_enum<T>::value>::type> {
typedef typename traits::remove_const_reference<T>::type get_type;
typedef optional<get_type> opt_type;
typedef typename traits::remove_const_reference<T>::type push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type_traits<luaInt>::strictCheckType(l, index);
}
static bool checkType(lua_State *l, int index) {
return lua_type_traits<luaInt>::checkType(l, index);
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
if (lua_type_traits<luaInt>::opt_type t =
lua_type_traits<luaInt>::opt(l, index)) {
return opt_type(static_cast<get_type>(*t));
}
return opt_type();
}
static get_type get(lua_State *l, int index) {
return static_cast<get_type>(lua_type_traits<luaInt>::get(l, index));
}
static int push(lua_State *l, push_type s) {
return util::push_args(
l, static_cast<typename lua_type_traits<int64_t>::push_type>(s));
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for cstring
template <> struct lua_type_traits<const char *> {
typedef const char *get_type;
typedef optional<get_type> opt_type;
typedef const char *push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TSTRING;
}
static bool checkType(lua_State *l, int index) {
return lua_isstring(l, index) != 0;
}
static get_type get(lua_State *l, int index) {
const char *buffer = lua_tostring(l, index);
if (!buffer) {
throw LuaTypeMismatch();
}
return buffer;
}
static opt_type opt(lua_State *l, int index) {
const char *buffer = lua_tostring(l, index);
if (!buffer) {
return opt_type();
}
return buffer;
}
static int push(lua_State *l, const char *s) {
lua_pushstring(l, s);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for cstring
template <int N> struct lua_type_traits<char[N]> {
typedef std::string get_type;
typedef const char *push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TSTRING;
}
static bool checkType(lua_State *l, int index) {
return lua_isstring(l, index) != 0;
}
static const char *get(lua_State *l, int index) {
const char *buffer = lua_tostring(l, index);
if (!buffer) {
throw LuaTypeMismatch();
}
return buffer;
}
static int push(lua_State *l, const char s[N]) {
lua_pushlstring(l, s, s[N - 1] != '\0' ? N : N - 1);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for cstring
template <int N>
struct lua_type_traits<const char[N]> : lua_type_traits<char[N]> {};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for std::string
template <> struct lua_type_traits<std::string> {
typedef std::string get_type;
typedef optional<get_type> opt_type;
typedef const std::string &push_type;
static bool strictCheckType(lua_State *l, int index) {
return lua_type(l, index) == LUA_TSTRING;
}
static bool checkType(lua_State *l, int index) {
return lua_isstring(l, index) != 0;
}
static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT {
size_t size = 0;
const char *buffer = lua_tolstring(l, index, &size);
if (!buffer) {
return opt_type();
}
return std::string(buffer, size);
}
static get_type get(lua_State *l, int index) {
if (opt_type o = opt(l, index)) {
return *o;
}
throw LuaTypeMismatch();
}
static int push(lua_State *l, const std::string &s) {
lua_pushlstring(l, s.c_str(), s.size());
return 1;
}
};
struct NewTable {
NewTable() : reserve_array_(0), reserve_record_(0) {}
NewTable(int reserve_array, int reserve_record_)
: reserve_array_(reserve_array), reserve_record_(reserve_record_) {}
int reserve_array_;
int reserve_record_;
};
struct NewThread {};
struct GlobalTable {};
struct NilValue {};
struct NoTypeCheck {};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for NewTable, push only
template <> struct lua_type_traits<NewTable> {
static int push(lua_State *l, const NewTable &table) {
lua_createtable(l, table.reserve_array_, table.reserve_record_);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for NewThread, push only
template <> struct lua_type_traits<NewThread> {
static int push(lua_State *l, const NewThread &) {
lua_newthread(l);
return 1;
}
};
/// @ingroup lua_type_traits
/// @brief lua_type_traits for NilValue, similar to nullptr_t
/// If you using C++11, recommend use nullptr instead.
template <> struct lua_type_traits<NilValue> {
typedef NilValue get_type;
typedef optional<get_type> opt_type;
typedef NilValue push_type;
static bool checkType(lua_State *l, int index) {
return lua_isnoneornil(l, index);
}
static bool strictCheckType(lua_State *l, int index) {
return lua_isnil(l, index);
}
static opt_type opt(lua_State *l, int index) {
if (!checkType(l, index)) {
return opt_type();
}
return NilValue();
}
static get_type get(lua_State *l, int index) {
if (!checkType(l, index)) {
throw LuaTypeMismatch();
}
return NilValue();
}
static int push(lua_State *l, const NilValue &) {
lua_pushnil(l);
return 1;
}
};
inline std::ostream &operator<<(std::ostream &os, const NilValue &) {
return os << "nil";
}
inline bool operator==(const NilValue &, const NilValue &) { return true; }
inline bool operator!=(const NilValue &, const NilValue &) { return false; }
/// @ingroup lua_type_traits
/// @brief lua_type_traits for GlobalTable, push only
template <> struct lua_type_traits<GlobalTable> {
static int push(lua_State *l, const GlobalTable &) {
lua_pushglobaltable(l);
return 1;
}
};
namespace detail {
template <typename Derived> class LuaBasicTypeFunctions {
template <class Other> friend class LuaBasicTypeFunctions;
typedef void (LuaBasicTypeFunctions::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
enum value_type {
TYPE_NONE = LUA_TNONE, //!< none type
TYPE_NIL = LUA_TNIL, //!< nil type
TYPE_BOOLEAN = LUA_TBOOLEAN, //!< boolean type
TYPE_LIGHTUSERDATA = LUA_TLIGHTUSERDATA, //!< light userdata type
TYPE_NUMBER = LUA_TNUMBER, //!< number type
TYPE_STRING = LUA_TSTRING, //!< string type
TYPE_TABLE = LUA_TTABLE, //!< table type
TYPE_FUNCTION = LUA_TFUNCTION, //!< function type
TYPE_USERDATA = LUA_TUSERDATA, //!< userdata type
TYPE_THREAD = LUA_TTHREAD //!< thread(coroutine) type
};
/// @brief If reference value is none or nil return true. Otherwise false.
bool isNilref_() const {
int t = type();
return t == LUA_TNIL || t == LUA_TNONE;
}
/// @brief Equivalent to `#` operator for strings and tables with no
/// metamethods.
/// Follows Lua's reference manual documentation of `lua_rawlen`, ie. types
/// other
/// than tables, strings or userdatas return 0.
/// @return Size of table, string length or userdata memory block size.
size_t size() const {
lua_State *state = state_();
if (!state) {
return 0;
}
util::ScopedSavedStack save(state);
int index = pushStackIndex_(state);
return lua_rawlen(state, index);
}
// return type
int type() const {
lua_State *state = state_();
if (!state) {
return LUA_TNONE;
}
util::ScopedSavedStack save(state);
return lua_type(state, pushStackIndex_(state));
}
// return type name
const char *typeName() const { return lua_typename(state_(), type()); }
operator bool_type() const {
lua_State *state = state_();
if (!state) {
return 0; // hasn't lua_State
}
util::ScopedSavedStack save(state);
int stackindex = pushStackIndex_(state);
int t = lua_type(state, stackindex);
if (t == LUA_TNONE) {
return 0; // none
}
return lua_toboolean(state, stackindex)
? &LuaBasicTypeFunctions::this_type_does_not_support_comparisons
: 0;
}
/**
* @name relational operators
* @brief
*/
//@{
template <typename OtherDrived>
inline bool operator==(const LuaBasicTypeFunctions<OtherDrived> &rhs) const {
if (isNilref_() || rhs.isNilref_()) {
return !isNilref_() == !rhs.isNilref_();
}
lua_State *state = state_();
util::ScopedSavedStack save(state);
int index = pushStackIndex_(state);
int rhsindex = rhs.pushStackIndex_(state);
return lua_compare(state, index, rhsindex, LUA_OPEQ) != 0;
}
template <typename OtherDrived>
inline bool operator<(const LuaBasicTypeFunctions<OtherDrived> &rhs) const {
if (isNilref_() || rhs.isNilref_()) {
return !isNilref_() != !rhs.isNilref_();
}
lua_State *state = state_();
util::ScopedSavedStack save(state);
int index = pushStackIndex_(state);
int rhsindex = rhs.pushStackIndex_(state);
return lua_compare(state, index, rhsindex, LUA_OPLT) != 0;
}
template <typename OtherDrived>
inline bool operator<=(const LuaBasicTypeFunctions<OtherDrived> &rhs) const {
if (isNilref_() || rhs.isNilref_()) {
return !isNilref_() == !rhs.isNilref_();
}
lua_State *state = state_();
util::ScopedSavedStack save(state);
int index = pushStackIndex_(state);
int rhsindex = rhs.pushStackIndex_(state);
return lua_compare(state, index, rhsindex, LUA_OPLE) != 0;
}
template <typename OtherDrived>
inline bool operator>=(const LuaBasicTypeFunctions<OtherDrived> &rhs) const {
return rhs <= (*this);
}
template <typename OtherDrived>
inline bool operator>(const LuaBasicTypeFunctions<OtherDrived> &rhs) const {
return rhs < (*this);
}
template <typename OtherDrived>
inline bool operator!=(const LuaBasicTypeFunctions<OtherDrived> &rhs) const {
return !this->operator==(rhs);
}
template <typename T>
inline typename traits::enable_if<
!traits::is_convertible<T *, LuaBasicTypeFunctions<T> *>::value,
bool>::type
operator==(const T &rhs) const {
if (optional<typename lua_type_traits<T>::get_type> d = checkGet_<T>()) {
return *d == rhs;
}
return false;
}
template <typename T>
inline typename traits::enable_if<
!traits::is_convertible<T *, LuaBasicTypeFunctions<T> *>::value,
bool>::type
operator!=(const T &rhs) const {
return !((*this) == rhs);
}
//@}
void dump(std::ostream &os) const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
int stackIndex = pushStackIndex_(state);
util::stackValueDump(os, state, stackIndex);
}
private:
lua_State *state_() const {
return static_cast<const Derived *>(this)->state();
}
int pushStackIndex_(lua_State *state) const {
return static_cast<const Derived *>(this)->pushStackIndex(state);
}
template <typename T>
optional<typename lua_type_traits<T>::get_type> checkGet_() const {
lua_State *state = state_();
util::ScopedSavedStack save(state);
int stackindex = pushStackIndex_(state);
return lua_type_traits<
optional<typename lua_type_traits<T>::get_type> >::get(state,
stackindex);
}
};
template <typename D>
inline std::ostream &operator<<(std::ostream &os,
const LuaBasicTypeFunctions<D> &ref) {
ref.dump(os);
return os;
}
/**
* @name relational operators
* @brief
*/
//@{
#define KAGUYA_ENABLE_IF_NOT_LUAREF(RETTYPE) \
typename traits::enable_if< \
!traits::is_convertible<T *, LuaBasicTypeFunctions<T> *>::value, \
RETTYPE>::type
template <typename D, typename T>
inline KAGUYA_ENABLE_IF_NOT_LUAREF(bool)
operator==(const T &lhs, const LuaBasicTypeFunctions<D> &rhs) {
return rhs == lhs;
}
template <typename D, typename T>
inline KAGUYA_ENABLE_IF_NOT_LUAREF(bool)
operator!=(const T &lhs, const LuaBasicTypeFunctions<D> &rhs) {
return !(rhs == lhs);
}
#undef KAGUYA_ENABLE_IF_NOT_LUAREF
//@}
}
}

View file

@ -0,0 +1,232 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <iostream>
#if KAGUYA_USE_CXX_ABI_DEMANGLE
#include <cxxabi.h>
#endif
#include "kaguya/config.hpp"
#include "kaguya/compatibility.hpp"
#include "kaguya/traits.hpp"
#include "kaguya/preprocess.hpp"
#include "kaguya/exception.hpp"
#if KAGUYA_USE_CPP11
#include "kaguya/utility_cxx11.hpp"
#else
#include "kaguya/utility_cxx03.hpp"
#endif
namespace kaguya {
namespace util {
/// @brief save stack count and restore on destructor
class ScopedSavedStack {
lua_State *state_;
int saved_top_index_;
public:
/// @brief save stack count
/// @param state
explicit ScopedSavedStack(lua_State *state)
: state_(state), saved_top_index_(state_ ? lua_gettop(state_) : 0) {}
/// @brief save stack count
/// @param state
/// @param count stack count
explicit ScopedSavedStack(lua_State *state, int count)
: state_(state), saved_top_index_(count) {}
/// @brief restore stack count
~ScopedSavedStack() {
if (state_) {
lua_settop(state_, saved_top_index_);
}
}
private:
ScopedSavedStack(ScopedSavedStack const &);
ScopedSavedStack &operator=(ScopedSavedStack const &);
};
inline void traceBack(lua_State *state, const char *message, int level = 0) {
#if LUA_VERSION_NUM >= 502
luaL_traceback(state, state, message, level);
#else
KAGUYA_UNUSED(level);
lua_pushstring(state, message);
#endif
}
inline void stackDump(lua_State *L) {
int i;
int top = lua_gettop(L);
for (i = 1; i <= top; i++) { /* repeat for each level */
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: /* strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN: /* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* numbers */
printf("%g", lua_tonumber(L, i));
break;
case LUA_TUSERDATA:
if (luaL_getmetafield(L, i, "__name") == LUA_TSTRING) {
printf("userdata:%s", lua_tostring(L, -1));
lua_pop(L, 1);
break;
}
default: /* other values */
printf("%s", lua_typename(L, t));
break;
}
printf(" "); /* put a separator */
}
printf("\n"); /* end the listing */
}
inline void stackValueDump(std::ostream &os, lua_State *state, int stackIndex,
int max_recursive = 2) {
stackIndex = lua_absindex(state, stackIndex);
util::ScopedSavedStack save(state);
int type = lua_type(state, stackIndex);
switch (type) {
case LUA_TNONE:
os << "none";
break;
case LUA_TNIL:
os << "nil";
break;
case LUA_TBOOLEAN:
os << ((lua_toboolean(state, stackIndex) != 0) ? "true" : "false");
break;
case LUA_TNUMBER:
os << lua_tonumber(state, stackIndex);
break;
case LUA_TSTRING:
os << "'" << lua_tostring(state, stackIndex) << "'";
break;
case LUA_TTABLE: {
os << "{";
if (max_recursive <= 1) {
os << "...";
} else {
lua_pushnil(state);
if ((lua_next(state, stackIndex) != 0)) {
stackValueDump(os, state, -2, max_recursive - 1);
os << "=";
stackValueDump(os, state, -1, max_recursive - 1);
lua_pop(state, 1); // pop value
while (lua_next(state, stackIndex) != 0) {
os << ",";
stackValueDump(os, state, -2, max_recursive - 1);
os << "=";
stackValueDump(os, state, -1, max_recursive - 1);
lua_pop(state, 1); // pop value
}
}
}
os << "}";
} break;
case LUA_TUSERDATA:
case LUA_TLIGHTUSERDATA:
case LUA_TTHREAD:
os << lua_typename(state, type) << "(" << lua_topointer(state, stackIndex)
<< ")";
break;
case LUA_TFUNCTION:
os << lua_typename(state, type);
break;
default:
os << "unknown type value";
break;
}
}
inline lua_State *toMainThread(lua_State *state) {
#if LUA_VERSION_NUM >= 502
if (state) {
lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
lua_State *mainthread = lua_tothread(state, -1);
lua_pop(state, 1);
if (mainthread) {
return mainthread;
}
}
#endif
return state;
}
#if KAGUYA_USE_CPP11
inline int push_args(lua_State *) { return 0; }
template <class Arg, class... Args>
inline int push_args(lua_State *l, Arg &&arg, Args &&... args) {
int c = lua_type_traits<typename traits::decay<Arg>::type>::push(
l, std::forward<Arg>(arg));
return c + push_args(l, std::forward<Args>(args)...);
}
template <class Arg, class... Args>
inline int push_args(lua_State *l, const Arg &arg, Args &&... args) {
int c = lua_type_traits<Arg>::push(l, arg);
return c + push_args(l, std::forward<Args>(args)...);
}
#else
inline int push_args(lua_State *) { return 0; }
#define KAGUYA_PUSH_DEF(N) \
c += lua_type_traits<KAGUYA_PP_CAT(A, N)>::push(l, KAGUYA_PP_CAT(a, N));
#define KAGUYA_PUSH_ARG_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
inline int push_args(lua_State *l, KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \
int c = 0; \
KAGUYA_PP_REPEAT(N, KAGUYA_PUSH_DEF) \
return c; \
}
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_PUSH_ARG_DEF)
#undef KAGUYA_PUSH_DEF
#undef KAGUYA_PUSH_ARG_DEF
#endif
#if KAGUYA_USE_CPP11
template <typename T> inline bool one_push(lua_State *state, T &&v) {
int count = util::push_args(state, std::forward<T>(v));
if (count > 1) {
lua_pop(state, count - 1);
}
return count != 0;
}
#else
template <typename T> inline bool one_push(lua_State *state, const T &v) {
int count = util::push_args(state, v);
if (count > 1) {
lua_pop(state, count - 1);
}
return count != 0;
}
#endif
inline std::string pretty_name(const std::type_info &t) {
#if KAGUYA_USE_CXX_ABI_DEMANGLE
int status = 0;
char *demangle_name = abi::__cxa_demangle(t.name(), 0, 0, &status);
struct deleter {
char *data;
deleter(char *d) : data(d) {}
~deleter() { std::free(data); }
} d(demangle_name);
return demangle_name;
#else
return t.name();
#endif
}
}
}

View file

@ -0,0 +1,176 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include "kaguya/config.hpp"
namespace kaguya {
namespace util {
///!
struct null_type {};
#define KAGUYA_PP_STRUCT_TDEF_REP(N) KAGUYA_PP_CAT(typename A, N) = null_type
#define KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(N) \
KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_STRUCT_TDEF_REP)
template <KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(KAGUYA_FUNCTION_MAX_ARGS)>
struct TypeTuple {};
template <typename F> struct TypeTupleSize;
#define KAGUYA_TYPE_TUPLE_SIZE_DEF(N) \
template <KAGUYA_PP_TEMPLATE_DEF_REPEAT(N)> \
struct TypeTupleSize<TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > { \
static const size_t value = N; \
};
KAGUYA_TYPE_TUPLE_SIZE_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_TYPE_TUPLE_SIZE_DEF)
#undef KAGUYA_TYPE_TUPLE_SIZE_DEF
template <typename Ret, typename typetuple> struct CFuntionType;
#define KAGUYA_CFUNCTION_TYPE_DEF(N) \
template <typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct CFuntionType<Ret, TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > { \
typedef Ret (*type)(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)); \
};
KAGUYA_CFUNCTION_TYPE_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_CFUNCTION_TYPE_DEF)
#undef KAGUYA_CFUNCTION_TYPE_DEF
template <typename Ret,
KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(KAGUYA_FUNCTION_MAX_ARGS)>
struct FunctionSignatureType {
typedef Ret result_type;
typedef TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(KAGUYA_FUNCTION_MAX_ARGS)>
argument_type_tuple;
static const size_t argument_count =
TypeTupleSize<argument_type_tuple>::value;
typedef typename CFuntionType<Ret, argument_type_tuple>::type c_function_type;
};
template <typename T, typename Enable = void> struct FunctionSignature;
#define KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF(N) \
template <typename T, typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct FunctionSignature<Ret (T::*)(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N))> { \
typedef FunctionSignatureType<Ret, \
T & KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> \
type; \
}; \
template <typename T, typename Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct FunctionSignature<Ret (T::*)(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)) \
const> { \
typedef FunctionSignatureType< \
Ret, const T & KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> \
type; \
};
#define KAGUYA_FUNCTION_SIGNATURE_DEF(N) \
template <class Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct FunctionSignature<Ret (*)(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N))> { \
typedef FunctionSignatureType<Ret KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> \
type; \
}; \
template <class Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct FunctionSignature<Ret(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N))> { \
typedef FunctionSignatureType<Ret KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> \
type; \
}; \
template <class Ret KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct FunctionSignature< \
standard::function<Ret(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N))> > { \
typedef FunctionSignatureType<Ret KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> \
type; \
};
KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_PP_DEC(KAGUYA_FUNCTION_MAX_ARGS),
KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF)
#undef KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF
KAGUYA_FUNCTION_SIGNATURE_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_FUNCTION_SIGNATURE_DEF)
#undef KAGUYA_FUNCTION_SIGNATURE_DEF
template <typename F> struct FunctionResultType {
typedef typename FunctionSignature<F>::type::result_type type;
};
template <std::size_t remain, class result, bool flag = remain <= 0>
struct TypeIndexGet {};
#define KAGUYA_TYPE_INDEX_GET_DEF(N) \
template <std::size_t remain, \
class arg KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct TypeIndexGet< \
remain, TypeTuple<arg KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)>, true> { \
typedef arg type; \
}; \
template <std::size_t remain, \
class arg KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
struct TypeIndexGet< \
remain, TypeTuple<arg KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)>, false> \
: TypeIndexGet<remain - 1, \
TypeTuple<KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)> > {};
// KAGUYA_TYPE_INDEX_GET_DEF(0);
KAGUYA_PP_REPEAT_DEF(KAGUYA_PP_DEC(KAGUYA_FUNCTION_MAX_ARGS),
KAGUYA_TYPE_INDEX_GET_DEF)
#undef KAGUYA_TYPE_INDEX_GET_DEF
template <std::size_t N, typename F> struct ArgumentType {
typedef typename TypeIndexGet<
N, typename FunctionSignature<F>::type::argument_type_tuple>::type type;
};
namespace detail {
#define KAGUYA_INVOKE_HELPER_DEF(N) \
template <class F, class ThisType KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N), \
typename T> \
typename FunctionResultType<F>::type invoke_helper( \
typename FunctionResultType<F>::type (T::*f)( \
KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)), \
ThisType this_ KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \
return (this_.*f)(KAGUYA_PP_ARG_REPEAT(N)); \
} \
template <class F, class ThisType KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N), \
typename T> \
typename FunctionResultType<F>::type invoke_helper( \
typename FunctionResultType<F>::type (T::*f)( \
KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)) const, \
ThisType this_ KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \
return (this_.*f)(KAGUYA_PP_ARG_REPEAT(N)); \
} \
template <class F KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
typename FunctionResultType<F>::type invoke_helper( \
F f KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \
return f(KAGUYA_PP_ARG_REPEAT(N)); \
}
KAGUYA_INVOKE_HELPER_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_INVOKE_HELPER_DEF)
#undef KAGUYA_INVOKE_HELPER_DEF
}
#define KAGUYA_INVOKE_DEF(N) \
template <class F KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N)> \
typename FunctionResultType<F>::type invoke( \
F f KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \
return detail::invoke_helper<F KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)>( \
f KAGUYA_PP_ARG_REPEAT_CONCAT(N)); \
}
KAGUYA_INVOKE_DEF(0)
KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_INVOKE_DEF)
#undef KAGUYA_INVOKE_DEF
#undef KAGUYA_PP_STRUCT_TDEF_REP
#undef KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT
}
}

View file

@ -0,0 +1,120 @@
// Copyright satoren
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <string>
#include "kaguya/config.hpp"
namespace kaguya {
namespace util {
struct null_type {};
template <class... Args> struct TypeTuple {};
template <class Ret, class... Args> struct FunctionSignatureType {
typedef Ret result_type;
typedef TypeTuple<Args...> argument_type_tuple;
static const size_t argument_count = sizeof...(Args);
typedef Ret (*c_function_type)(Args...);
};
template <typename T> struct FunctorSignature {};
template <typename T, typename Ret, typename... Args>
struct FunctorSignature<Ret (T::*)(Args...) const> {
typedef FunctionSignatureType<Ret, Args...> type;
};
template <typename T, typename Ret, typename... Args>
struct FunctorSignature<Ret (T::*)(Args...)> {
typedef FunctionSignatureType<Ret, Args...> type;
};
#if defined(_MSC_VER) && _MSC_VER < 1900
template <typename T>
struct FunctionSignature : public FunctorSignature<decltype(&T::operator())> {};
#else
template <typename T, typename Enable = void> struct FunctionSignature;
template <typename T, typename = void>
struct has_operator_fn : std::false_type {};
template <typename T>
struct has_operator_fn<T, typename std::enable_if<!std::is_same<
void, decltype(&T::operator())>::value>::type>
: std::true_type {};
template <typename T>
struct FunctionSignature<
T, typename std::enable_if<has_operator_fn<T>::value>::type>
: public FunctorSignature<decltype(&T::operator())> {};
#endif
template <typename T, typename Ret, typename... Args>
struct FunctionSignature<Ret (T::*)(Args...)> {
typedef FunctionSignatureType<Ret, T &, Args...> type;
};
template <typename T, typename Ret, typename... Args>
struct FunctionSignature<Ret (T::*)(Args...) const> {
typedef FunctionSignatureType<Ret, const T &, Args...> type;
};
#if defined(_MSC_VER) && _MSC_VER >= 1900 || defined(__cpp_ref_qualifiers)
template <typename T, typename Ret, typename... Args>
struct FunctionSignature<Ret (T::*)(Args...) const &> {
typedef FunctionSignatureType<Ret, const T &, Args...> type;
};
template <typename T, typename Ret, typename... Args>
struct FunctionSignature<Ret (T::*)(Args...) const &&> {
typedef FunctionSignatureType<Ret, const T &, Args...> type;
};
#endif
template <class Ret, class... Args> struct FunctionSignature<Ret (*)(Args...)> {
typedef FunctionSignatureType<Ret, Args...> type;
};
template <class Ret, class... Args> struct FunctionSignature<Ret(Args...)> {
typedef FunctionSignatureType<Ret, Args...> type;
};
template <typename F> struct FunctionResultType {
typedef typename FunctionSignature<F>::type::result_type type;
};
template <std::size_t remain, class Arg, bool flag = remain <= 0>
struct TypeIndexGet;
template <std::size_t remain, class Arg, class... Args>
struct TypeIndexGet<remain, TypeTuple<Arg, Args...>, true> {
typedef Arg type;
};
template <std::size_t remain, class Arg, class... Args>
struct TypeIndexGet<remain, TypeTuple<Arg, Args...>, false>
: TypeIndexGet<remain - 1, TypeTuple<Args...> > {};
template <int N, typename F> struct ArgumentType {
typedef typename TypeIndexGet<
N, typename FunctionSignature<F>::type::argument_type_tuple>::type type;
};
namespace detail {
template <class F, class ThisType, class... Args>
auto invoke_helper(F &&f, ThisType &&this_, Args &&... args)
-> decltype((std::forward<ThisType>(this_).*
f)(std::forward<Args>(args)...)) {
return (std::forward<ThisType>(this_).*f)(std::forward<Args>(args)...);
}
template <class F, class... Args>
auto invoke_helper(F &&f, Args &&... args)
-> decltype(f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
}
template <class F, class... Args>
typename FunctionResultType<typename traits::decay<F>::type>::type
invoke(F &&f, Args &&... args) {
return detail::invoke_helper(std::forward<F>(f), std::forward<Args>(args)...);
}
}
}

View file

@ -10,7 +10,7 @@ Actor::Actor(Tilemap *map, vec2i pos) : Entity(map, pos) {
range = 1.5f;
collision = true;
bt = nullptr;
team = TEAM_NONE;
faction = FACTION_NONE;
sprite_id = 1;
}
@ -32,8 +32,8 @@ void Actor::update() {
}
}
void Actor::damage(int strength) {
health -= strength;
void Actor::damage(int str) {
health -= str;
if (health <= 0) {
kill();
}
@ -54,7 +54,7 @@ void Actor::attack(vec2i dpos) {
auto acts = get_map()->get_entities(pos.x + dpos.x, pos.y + dpos.y, 0, ENTITY_ACTOR);
for (Entity* ent : acts) {
auto act = (Actor*)ent;
if (act->is_alive() && act->get_actor_team() != team) {
if (act->is_alive() && act->get_actor_faction() != faction) {
act->damage(strength);
break;
}

View file

@ -5,17 +5,17 @@
class BehaviourTree;
enum Actors {
enum Actors { // TODO: Softcode this
ACT_BASE,
ACT_HERO,
ACT_GOBLIN,
ACT_SHAMAN
};
enum ActorTeams {
TEAM_NONE,
TEAM_PLAYER,
TEAM_GOBS
enum ActorFactions { // TODO: Make factions dynamic
FACTION_NONE,
FACTION_PLAYER,
FACTION_GOBS
};
class Tilemap;
@ -30,7 +30,7 @@ protected:
int strength;
float range;
bool alive;
ActorTeams team;
ActorFactions faction;
public:
int id;
std::string name;
@ -44,7 +44,7 @@ public:
int get_strength() { return strength; }
int get_health() { return health; }
int get_health_max() { return health_max; }
ActorTeams get_actor_team() { return team; }
ActorFactions get_actor_faction() { return faction; }
float get_range() { return range; }
void kill() { alive = false; health = 0; collision = false; };
void update();

View file

@ -5,7 +5,9 @@
#include "App.h"
#include <SDL.h>
#include <ctime>
#include "Config.h"
#include <fstream>
#include <string>
#include <kaguya\kaguya.hpp>
#include "Renderer.h"
#include "imgui.h"
#include "Input.h"
@ -17,22 +19,55 @@ double currTime() {
return SDL_GetPerformanceCounter() / (double)perfFreq;
}
struct {
struct {
bool fullscreen = false;
int width = 792;
int height = 600;
} window;
struct {
bool vsync = false;
bool wireframes = false;
} gfx;
} config;
void load_config() {
kaguya::State state;
state["dungeon"] = kaguya::NewTable();
if (state.dofile("config.lua")) {
state(R"lua(
local cfg = {
window = {
fullscreen = false,
width = 792,
height = 600,
},
gfx = {
vsync = false,
wireframes = false,
}
}
if type(dungeon.config) == "function" then
dungeon.config(cfg)
end
config = cfg
)lua");
config.gfx.vsync = state["config"]["gfx"]["vsync"];
config.gfx.wireframes = state["config"]["gfx"]["wireframes"];
config.window.fullscreen = state["config"]["window"]["fullscreen"];
config.window.width = state["config"]["window"]["width"];
config.window.height = state["config"]["window"]["height"];
}
}
bool App::init() {
//setenv("MESA_DEBUG", "", 0);
Config cfg = Config("dungeon.cfg");
cfg.load();
int windowWidth = cfg.getInt("ResolutionX", 792);
int windowHeight = cfg.getInt("ResolutionY", 600);
bool vsync = cfg.getBool("VSync", false);
bool wireframe = cfg.getBool("Wireframes", false);
cfg.save();
int err = 0;
err = SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
if (err != 0) {
const char* error = SDL_GetError();
fprintf(stderr, error);
@ -41,8 +76,12 @@ bool App::init() {
}
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM,"SDL initialized.\n");
load_config();
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Config Loaded.\n");
renderer = new Renderer();
if (!renderer->Init("Dungeon", windowWidth, windowHeight)) {
if (!renderer->Init("Dungeon", config.window.width, config.window.height)) {
const char* error = SDL_GetError();
SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "%s", error);
SDL_ShowSimpleMessageBox(0, "Error", error, nullptr);
@ -50,12 +89,13 @@ bool App::init() {
return false;
}
renderer->set_vsync_enabled(vsync);
renderer->set_wireframes_enabled(wireframe);
renderer->set_vsync_enabled(config.gfx.vsync);
renderer->set_wireframes_enabled(config.gfx.wireframes);
input = new Input();
srand(static_cast<unsigned int>(time(nullptr)));
perfFreq = SDL_GetPerformanceFrequency();
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "App initialized.\n");
return true;
}

44
src/Color.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef DUNGEON_COLOR_H
#define DUNGEON_COLOR_H
struct Color {
float r = 1;
float g = 1;
float b = 1;
float a = 1;
Color() {}
Color(float r, float g, float b, float a) {
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
Color operator*(float n) {
return Color(r*n, g*n, b*n, a);
}
void operator*=(float n) {
r *= n;
g *= n;
b *= n;
}
Color operator/(float n) { return (*this) * (1.f / n); }
Color operator*(Color &col) {
return Color(r*col.r, g*col.g, b*col.b, a*col.a);
}
Color operator+(Color &col) {
return Color(r+col.r, g+col.g, b+col.b, a+col.a);
}
Color operator-(Color &col) {
return Color(r - col.r, g - col.g, b - col.b, a - col.a);
}
};
#endif

View file

@ -21,8 +21,7 @@ bool Entity::move(vec2i dpos) {
}
bool Entity::move(int dx, int dy) {
vec2i newpos = position + vec2i(dx, dy); //GoTo({0,0}, {dx,dy});
//dir = ParseDir(dx, dy);
vec2i newpos = position + vec2i(dx, dy);
if (!collision || !map->IsBlocked(newpos.x, newpos.y)) {
position = newpos;
return true;

View file

@ -7,6 +7,7 @@
#include "vec2i.h"
#include "Color.h"
class Tilemap;
@ -21,6 +22,7 @@ class Entity {
Tilemap* map;
protected:
unsigned int sprite_id;
Color sprite_color;
bool collision;
public:
Entity(Tilemap* map, vec2i pos);
@ -32,6 +34,7 @@ public:
bool move(vec2i dpos);
void set_position(vec2i pos);
unsigned int get_sprite_id() { return sprite_id; };
Color get_sprite_color() { return sprite_color; };
virtual EntityTypes entity_type() { return ENTITY_BASE; };
};

View file

@ -31,11 +31,11 @@ void FieldOfView::calc(vec2i pos, float range) {
}
bool FieldOfView::can_see(vec2i pos) {
return seen->GetTile(pos.x, pos.y) >= counter;
return seen->get_tile(pos.x, pos.y) >= counter;
}
bool FieldOfView::has_seen(vec2i pos) {
return seen->GetTile(pos.x, pos.y) > 0;
return seen->get_tile(pos.x, pos.y) > 0;
}
void FieldOfView::cast_light(int row, float start, float end, int xx, int xy, int yx, int yy, int startX, int startY,
@ -65,7 +65,7 @@ void FieldOfView::cast_light(int row, float start, float end, int xx, int xy, in
}
if (blocked) {
if (map->GetTile(currentX, currentY) == '#') { // TODO: Stop hardcoding tiles
if (map->get_tile(currentX, currentY) == '#') { // TODO: Stop hardcoding tiles
newStart = rightSlope;
continue;
}
@ -75,7 +75,7 @@ void FieldOfView::cast_light(int row, float start, float end, int xx, int xy, in
}
}
else {
if (map->GetTile(currentX, currentY) == '#' && distance < radius) { // TODO: Get rid of hardcoded tiles
if (map->get_tile(currentX, currentY) == '#' && distance < radius) { // TODO: Get rid of hardcoded tiles
blocked = true;
cast_light(distance + 1, start, leftSlope, xx, xy, yx, yy, startX, startY, radius);
newStart = rightSlope;
@ -98,7 +98,7 @@ bool line_of_sight(Tilemap *map, vec2i start, vec2i end) {
// error may go below zero
int error(delta.y - (delta.x >> 1));
while (start.x != end.x && map->GetTile(start.x, start.y) != '#') // TODO: Hardcoded tiles
while (start.x != end.x && map->get_tile(start.x, start.y) != '#') // TODO: Hardcoded tiles
{
// reduce error, while taking into account the corner case of error == 0
if ((error > 0) || (!error && (ix > 0)))
@ -117,7 +117,7 @@ bool line_of_sight(Tilemap *map, vec2i start, vec2i end) {
// error may go below zero
int error(delta.x - (delta.y >> 1));
while (start.y != end.y && map->GetTile(start.x, start.y) != '#') // TODO: Stop hardcoding tiles
while (start.y != end.y && map->get_tile(start.x, start.y) != '#') // TODO: Stop hardcoding tiles
{
// reduce error, while taking into account the corner case of error == 0
if ((error > 0) || (!error && (iy > 0)))

View file

@ -49,7 +49,7 @@ BehaviourTreeStatus FleeNode::tick(BTTick * tick) {
vec2i pos = tick->target->get_position();
std::vector<vec2i> neigh = map->getNeighbours(pos.x, pos.y);
std::vector<vec2i> neigh = map->get_neighbours(pos.x, pos.y);
std::vector<vec2i> options;
float lowestval = 999999;
for (vec2i npos : neigh) {

View file

@ -14,7 +14,8 @@ Goblin::Goblin(Tilemap* map, vec2i pos) : Actor(map, pos) {
health_max = 4;
strength = 1;
sprite_id = 'g';
team = TEAM_GOBS;
faction = FACTION_GOBS;
sprite_color = Color(.1f, .7f, .2f, 1);
if (gobtree == nullptr) {
auto * root = new BehaviourTreeSelector(nullptr);

View file

@ -15,7 +15,8 @@ Hero::Hero(Tilemap* map, vec2i pos) : Actor(map, pos) {
health_max = 6;
strength = 2;
sprite_id = '@';
team = TEAM_PLAYER;
faction = FACTION_PLAYER;
sprite_color = Color(0.1f, 0.4f, 0.9f, 1);
/*
BehaviourTreeSelector* root = new BehaviourTreeSelector(nullptr);
bt = new BehaviourTree(root);
@ -32,4 +33,4 @@ Hero::Hero(Tilemap* map, vec2i pos) : Actor(map, pos) {
}
Hero::~Hero() {}
Hero::~Hero() = default;

View file

@ -59,6 +59,9 @@ InputEvent Input::set_key(SDL_Keycode key, SDL_Keymod mod, bool pressed)
void Input::bind_key(SDL_Keycode key, InputAction action, SDL_Keymod mod) {
Bind bind = { key, mod };
if (binds.find(bind) != binds.end()) {
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Overriding existing bind! (bind: %s)", bind.get_name().c_str());
}
binds[bind] = action;
}

View file

@ -31,6 +31,15 @@ struct Bind {
}
return key < o.key;
}
std::string get_name() {
std::string bindname = "";
if (modifier & KMOD_CTRL) bindname += "CTRL+";
if (modifier & KMOD_ALT) bindname += "ALT+";
if (modifier & KMOD_SHIFT) bindname += "SHIFT+";
bindname += SDL_GetKeyName(key);
return bindname;
}
};
enum InputEventType {
@ -43,29 +52,26 @@ struct InputEvent {
InputAction action;
bool pressed;
struct MouseMoveEvent { // mouse click;
int x;
int y;
int dx;
int dy;
};
struct MouseClickEvent { // mouse click;
int x;
int y;
int button;
};
struct KeyPressEvent { // key
SDL_Keycode key;
SDL_Keymod mod;
bool echo;
};
union {
MouseMoveEvent mouse_move_event;
MouseClickEvent mouse_click_event;
KeyPressEvent key_press_event;
};
struct MouseMoveEvent { // mouse click;
int x;
int y;
int dx;
int dy;
} mouse_move_event;
struct MouseClickEvent { // mouse click;
int x;
int y;
int button;
} mouse_click_event;
struct KeyPressEvent { // key
SDL_Keycode key;
SDL_Keymod mod;
bool echo;
} key_press_event;
};
};
class Input

View file

@ -1,7 +1,5 @@
#include "App.h"
//#undef main
int main(int argc, char* argv[]) {
App app{};
int err = 1;

View file

@ -20,29 +20,23 @@ namespace Pathfinder
AStarNode* st = new AStarNode();
st->pos = start;
open.push_back(st);
open.emplace_back(st);
while (open.size() != 0)
{
while (open.size() != 0) {
AStarNode* current = nullptr;
int currentindex = -1;
for (int i = 0; i < open.size(); i++)
{
if (current == nullptr || current->f > open[i]->f)
{
for (int i = 0; i < open.size(); i++) {
if (current == nullptr || current->f > open[i]->f) {
current = open[i];
currentindex = i;
}
}
open.erase(open.begin()+currentindex);
closed.push_back(current);
//map->set_tile(current->pos.x, current->pos.y, TILE_CLOSED);
closed.emplace_back(current);
auto neighbours = map->getNeighbours(current->pos.x, current->pos.y);
for (auto pos : neighbours)
{
if (map->GetTile(pos.x, pos.y) == '#')
{
auto neighbours = map->get_neighbours(current->pos.x, current->pos.y);
for (auto pos : neighbours) {
if (map->get_tile(pos.x, pos.y) == '#') {
continue;
}
AStarNode* neighbour = new AStarNode();
@ -59,10 +53,10 @@ namespace Pathfinder
if (neighbour->pos == goal)
{
delete neighbour;
path.push_back(goal);
path.emplace_back(goal);
while (current->from != nullptr)
{
path.push_back(current->pos);
path.emplace_back(current->pos);
current = current->from;
}
for (AStarNode* var : open)
@ -88,8 +82,7 @@ namespace Pathfinder
{
closed.erase(it);
delete (*it);
open.push_back(neighbour);
//map->set_tile(neighbour->pos.x, neighbour->pos.y, TILE_OPENED);
open.emplace_back(neighbour);
isClosed = false;
}
break;
@ -110,8 +103,7 @@ namespace Pathfinder
{
open.erase(it);
delete (*it);
open.push_back(neighbour);
//map->set_tile(neighbour->pos.x, neighbour->pos.y, TILE_OPENED);
open.emplace_back(neighbour);
}
break;
}
@ -119,8 +111,7 @@ namespace Pathfinder
if (!isOpened)
{
open.push_back(neighbour);
//map->set_tile(neighbour->pos.x, neighbour->pos.y, TILE_OPENED);
open.emplace_back(neighbour);
}
}
else
@ -166,10 +157,10 @@ namespace Pathfinder
std::vector<vec2i> queue;
for (vec2i pos : *goals) {
auto neigh = map->getNeighbours(pos.x, pos.y);
auto neigh = map->get_neighbours(pos.x, pos.y);
for (vec2i npos : neigh) {
int val = out->getValue(npos.x, npos.y);
if (map->GetTile(npos.x, npos.y) != '#' && val > 1) {
if (map->get_tile(npos.x, npos.y) != '#' && val > 1) {
if (npos.x != 0 && npos.y != 0) {
out->setValue(npos.x, npos.y, 1.4f);
}
@ -185,7 +176,7 @@ namespace Pathfinder
vec2i current = queue.back();
queue.pop_back();
std::vector<vec2i> neigh = map->getNeighbours(current.x, current.y);
std::vector<vec2i> neigh = map->get_neighbours(current.x, current.y);
for (int i = 0; i < neigh.size(); i++) {
float val = out->getValue(current.x, current.y) + 1;
vec2i npos = neigh[i];
@ -193,7 +184,7 @@ namespace Pathfinder
if (dp.x != 0 && dp.y != 0) {
val += .4f;
}
if (map->GetTile(npos.x, npos.y) != '#' && out->getValue(npos.x, npos.y) > val) { // TODO: Remove hardcoded tile
if (map->get_tile(npos.x, npos.y) != '#' && out->getValue(npos.x, npos.y) > val) { // TODO: Remove hardcoded tile
out->setValue(npos.x, npos.y, val);
queue.push_back(neigh[i]);
}

View file

@ -38,10 +38,19 @@ void PlayState::load() {
app->input->bind_key(SDLK_DOWN, ACTION_MOVE_SOUTH);
app->input->bind_key(SDLK_LEFT, ACTION_MOVE_WEST);
app->input->bind_key(SDLK_RIGHT, ACTION_MOVE_EAST);
app->input->bind_key(SDLK_k, ACTION_MOVE_NORTH);
app->input->bind_key(SDLK_y, ACTION_MOVE_NORTHWEST);
app->input->bind_key(SDLK_u, ACTION_MOVE_NORTHEAST);
app->input->bind_key(SDLK_h, ACTION_MOVE_WEST);
app->input->bind_key(SDLK_l, ACTION_MOVE_EAST);
app->input->bind_key(SDLK_j, ACTION_MOVE_SOUTH);
app->input->bind_key(SDLK_n, ACTION_MOVE_SOUTHWEST);
app->input->bind_key(SDLK_m, ACTION_MOVE_SOUTHEAST);
app->input->bind_key(SDLK_F1, ACTION_TOGGLE_DEBUG);
app->input->bind_key(SDLK_r, ACTION_RESET);
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Keybinds bound.\n");
new_game();
}
@ -167,7 +176,7 @@ Gamestate *PlayState::update(double delta) {
}
for (auto ent : acts) {
auto act = (Actor*)ent;
if (act->is_alive() && act->get_actor_team() != hero->get_actor_team()) {
if (act->is_alive() && act->get_actor_faction() != hero->get_actor_faction()) {
hero->attack(act);
break;
}
@ -278,14 +287,38 @@ void PlayState::draw(double delta) {
tilemap->draw(app->renderer, ascii, margin.x, margin.y, -offset.x, -offset.y, tilesize.x, tilesize.y, fov);
auto entities = tilemap->get_entity_list();
// Draw dead actors
for (Entity* var : *entities) {
if (var->entity_type() == ENTITY_ACTOR && ((Actor*)var)->is_alive()) continue;
vec2i pos = var->get_position();
if (fov == nullptr || fov->can_see(pos)) {
app->renderer->set_color(0, 0, 0, 255);
if ((fov == nullptr || fov->can_see(pos))) {
app->renderer->set_color(0, 0, 0, 1);
app->renderer->draw_sprite(ascii->get_sprite(219), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);
int sprite = var->get_sprite_id();
app->renderer->set_color(1, 1, 1, 1);
app->renderer->set_color(var->get_sprite_color()*0.35f);
app->renderer->draw_sprite(ascii->get_sprite(sprite), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);
}
}
// Draw the rest of the entities
for (Entity* var : *entities) {
if (var->entity_type() == ENTITY_ACTOR && !((Actor*)var)->is_alive()) continue;
vec2i pos = var->get_position();
if ((fov == nullptr || fov->can_see(pos))) {
app->renderer->set_color(0, 0, 0, 1);
app->renderer->draw_sprite(ascii->get_sprite(219), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);
int sprite = var->get_sprite_id();
app->renderer->set_color(var->get_sprite_color());
app->renderer->draw_sprite(ascii->get_sprite(sprite), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);
}

View file

@ -1,7 +1,8 @@
#include "Renderer.h"
#define GLEW_STATIC
#include "glew.h"
#define GLEW_NO_GLU
#include <GL/glew.h>
#include <fstream>
#include <SDL.h>

View file

@ -2,20 +2,13 @@
#include <vector>
#include <map>
#include <string>
#include "Color.h"
struct SDL_Window;
struct SDL_Texture;
union SDL_Event;
typedef void *SDL_GLContext;
struct Color
{
float r;
float g;
float b;
float a;
};
struct Rect {
int x = 0, y = 0, w = 0, h = 0;
};

View file

@ -19,7 +19,8 @@ Shaman::Shaman(Tilemap* map, vec2i pos) : Actor(map, pos) {
strength = 1;
range = 6;
sprite_id = 's';
team = TEAM_GOBS;
faction = FACTION_GOBS;
sprite_color = Color(0.2, 0.7, 0.6, 1);
if (shamtree == nullptr) {
auto * root = new BehaviourTreeSelector(nullptr);
@ -39,5 +40,4 @@ Shaman::Shaman(Tilemap* map, vec2i pos) : Actor(map, pos) {
bt = shamtree;
}
Shaman::~Shaman() = default;

View file

@ -41,7 +41,7 @@ bool Tilemap::IsInsideBounds(int x, int y)
return x >= 0 && x < width && y >= 0 && y < height;
}
std::vector<vec2i> Tilemap::getNeighbours(int x, int y, int range)
std::vector<vec2i> Tilemap::get_neighbours(int x, int y, int range)
{
std::vector<vec2i> neigh;
if (range == 0)
@ -70,7 +70,7 @@ void Tilemap::set_tile(int x, int y, unsigned int tile)
}
}
int Tilemap::GetTile(int x, int y)
int Tilemap::get_tile(int x, int y)
{
if (IsInsideBounds(x, y))
{
@ -129,7 +129,7 @@ Entity * Tilemap::get_entity(int x, int y, EntityTypes type) {
std::vector<Entity*> Tilemap::get_entities(int x, int y, int range, EntityTypes type) {
std::vector<Entity*> found;
std::vector<vec2i> neigh = getNeighbours(x, y, range);
std::vector<vec2i> neigh = get_neighbours(x, y, range);
for (Entity* ent : entities) {
for (vec2i pos : neigh) {
if (ent->entity_type() == type) {
@ -158,7 +158,7 @@ void Tilemap::draw(Renderer *renderer, Tileset* tileset, int x, int y, int tx, i
if (IsInsideBounds(ax, ay)) {
if (view == nullptr || view->has_seen({ax, ay})) {
renderer->set_color(1, 1, 1, 1);
renderer->draw_sprite(tileset->get_sprite(GetTile(ax, ay)), x + ix * w, y + iy * h);
renderer->draw_sprite(tileset->get_sprite(get_tile(ax, ay)), x + ix * w, y + iy * h);
if (view != nullptr && !view->can_see({ax, ay})) {
renderer->set_color(0, 0, 0, .6f);
@ -173,7 +173,7 @@ void Tilemap::draw(Renderer *renderer, Tileset* tileset, int x, int y, int tx, i
void Tilemap::debug_print() {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
printf("\t%d", GetTile(x, y));
printf("\t%d", get_tile(x, y));
}
printf("\n");
}

View file

@ -19,9 +19,9 @@ public:
int GetHeight();
int GetIndex(int x, int y); // Converts [x,y] to a 1D index.
bool IsInsideBounds(int x, int y);
std::vector<vec2i> getNeighbours(int x, int y, int range = 1);
std::vector<vec2i> get_neighbours(int x, int y, int range = 1);
void set_tile(int x, int y, unsigned int tile); // "Tile" is inteded for tile ids, but can be anything really.
int GetTile(int x, int y);
int get_tile(int x, int y);
bool IsBlocked(int x, int y); // Checks if there is an actor blocking the tile.
void draw(Renderer *renderer, Tileset *tileset, int x, int y, int tx, int ty, int tw, int th, FieldOfView* view);

View file

@ -11,7 +11,7 @@ WanderNode::~WanderNode() = default;
BehaviourTreeStatus WanderNode::tick(BTTick * tick) {
vec2i pos = tick->target->get_position();
std::vector<vec2i> neighbours = tick->target->get_map()->getNeighbours(pos.x, pos.y);
std::vector<vec2i> neighbours = tick->target->get_map()->get_neighbours(pos.x, pos.y);
while (true) {
if (neighbours.empty()) {
previous.clear();

File diff suppressed because it is too large Load diff

28582
src/glew.c

File diff suppressed because it is too large Load diff

23686
src/glew.h

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@
#include <SDL.h>
#include <SDL_syswm.h>
#define GLEW_STATIC
#include "glew.h" // This example is using gl3w to access OpenGL functions (because it is small). You may use glew/glad/glLoadGen/etc. whatever already works for you.
#include <GL/glew.h> // This example is using gl3w to access OpenGL functions (because it is small). You may use glew/glad/glLoadGen/etc. whatever already works for you.
// Data
static double g_Time = 0.0f;