├── test ├── lua │ ├── syntax_error.lua │ ├── assign_value.lua │ ├── return_number.lua │ └── runtime_error.lua ├── shared_library_test │ ├── test_shared_class.hpp │ ├── test_shared_class_use.cpp │ ├── test_shared_class_reg.cpp │ ├── CMakeLists.txt │ └── test_shared_class_main.cpp ├── test_main.cpp ├── test_12_push_any.cpp ├── test_10_loadfile.cpp ├── test_14_error_message.cpp ├── CMakeLists.txt ├── test_13_another_binding_api.cpp ├── test_20_max_arg_20.cpp ├── test_07_vector_map_to_luatable.cpp ├── test_09_utility.cpp ├── test_08_optional.cpp └── test_01_primitive.cpp ├── examples ├── hello_lua_module.bat ├── hello_lua_module.sh ├── hello_lua_module_experimental.bat ├── hello_lua_module_experimental.sh ├── hello_lua_module_exec.lua ├── hello_lua_module_experimental_exec.lua ├── hello_lua_module_experimental.cpp ├── lua_exec.cpp ├── hello_world.cpp ├── hello_lua_module.cpp └── CMakeLists.txt ├── .clang-format ├── codecov.yml ├── docs ├── api_reference │ ├── lua_ref.rst │ ├── lua_table.rst │ ├── lua_thread.rst │ ├── lua_function.rst │ ├── lua_userdata.rst │ ├── metatable.rst │ ├── state.rst │ ├── index.rst │ ├── standard.rst │ ├── luaref.rst │ └── preprocessor_option.rst ├── getting_started │ ├── index.rst │ ├── requirements.rst │ ├── class_bindings.rst │ └── tutorial.rst ├── introduction │ └── index.rst ├── index.rst ├── Makefile └── make.bat ├── .gitignore ├── utils ├── Makefile ├── generate_one_header.py └── generate_preprocess_macro.py ├── Jenkinsfile ├── .gitattributes ├── include └── kaguya │ ├── kaguya.hpp │ ├── ref_tuple.hpp │ ├── push_tuple.hpp │ ├── preprocess.hpp │ ├── push_any.hpp │ ├── exception.hpp │ ├── detail │ ├── lua_variant_def.hpp │ └── lua_ref_impl.hpp │ ├── config.hpp │ ├── compatibility.hpp │ ├── utility_cxx11.hpp │ ├── function_tuple_def.hpp │ ├── error_handler.hpp │ ├── traits.hpp │ ├── optional.hpp │ ├── utility.hpp │ ├── native_function_cxx11.hpp │ ├── another_binding_api.hpp │ └── utility_cxx03.hpp ├── Lua-CMakeLists.txt ├── some_lua_version_test.sh ├── LICENSE_1_0.txt ├── cmake └── FindLua.cmake ├── .github └── workflows │ └── test.yml ├── benchmark ├── benchmark_function.hpp └── benchmark.cpp ├── CMakeLists.txt └── test_runner.py /test/lua/syntax_error.lua: -------------------------------------------------------------------------------- 1 | abc 2 | -------------------------------------------------------------------------------- /test/lua/assign_value.lua: -------------------------------------------------------------------------------- 1 | value = 1 -------------------------------------------------------------------------------- /test/lua/return_number.lua: -------------------------------------------------------------------------------- 1 | return 1 2 | -------------------------------------------------------------------------------- /test/lua/runtime_error.lua: -------------------------------------------------------------------------------- 1 | error("test error") 2 | -------------------------------------------------------------------------------- /examples/hello_lua_module.bat: -------------------------------------------------------------------------------- 1 | lua_exec hello_lua_module_exec.lua 2 | -------------------------------------------------------------------------------- /examples/hello_lua_module.sh: -------------------------------------------------------------------------------- 1 | ./lua_exec hello_lua_module_exec.lua 2 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | SortIncludes: false 4 | Standard: Cpp03 -------------------------------------------------------------------------------- /examples/hello_lua_module_experimental.bat: -------------------------------------------------------------------------------- 1 | lua_exec hello_lua_module_experimental_exec.lua 2 | -------------------------------------------------------------------------------- /examples/hello_lua_module_experimental.sh: -------------------------------------------------------------------------------- 1 | ./lua_exec hello_lua_module_experimental_exec.lua 2 | -------------------------------------------------------------------------------- /examples/hello_lua_module_exec.lua: -------------------------------------------------------------------------------- 1 | 2 | hello_module = require('hello_lua_module') 3 | 4 | hello_module.hello() 5 | -------------------------------------------------------------------------------- /examples/hello_lua_module_experimental_exec.lua: -------------------------------------------------------------------------------- 1 | 2 | hello_module = require('hello_lua_module') 3 | 4 | hello_module.hello() 5 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: header, changes, diff 3 | coverage: 4 | ignore: 5 | - test/.* 6 | status: 7 | patch: false 8 | -------------------------------------------------------------------------------- /docs/api_reference/lua_ref.rst: -------------------------------------------------------------------------------- 1 | 2 | LuaRef 3 | ================================== 4 | 5 | .. doxygenclass:: kaguya::LuaRef 6 | :members: 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | _build/ 3 | single_include 4 | .vscode 5 | lua-* 6 | *.exe 7 | *.dll 8 | LuaJIT-* 9 | docs/doxygen/ 10 | docs/_build/ -------------------------------------------------------------------------------- /docs/api_reference/lua_table.rst: -------------------------------------------------------------------------------- 1 | 2 | LuaTable 3 | ================================== 4 | 5 | .. doxygenclass:: kaguya::LuaTable 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/api_reference/lua_thread.rst: -------------------------------------------------------------------------------- 1 | 2 | LuaThread 3 | ================================== 4 | 5 | .. doxygenclass:: kaguya::LuaThread 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/api_reference/lua_function.rst: -------------------------------------------------------------------------------- 1 | 2 | LuaFunction 3 | ================================== 4 | 5 | .. doxygenclass:: kaguya::LuaFunction 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/api_reference/lua_userdata.rst: -------------------------------------------------------------------------------- 1 | 2 | LuaUserData 3 | ================================== 4 | 5 | .. doxygenclass:: kaguya::LuaUserData 6 | :members: 7 | -------------------------------------------------------------------------------- /docs/api_reference/metatable.rst: -------------------------------------------------------------------------------- 1 | 2 | UserdataMetatable 3 | ======================== 4 | 5 | 6 | .. doxygenclass:: kaguya::UserdataMetatable 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/api_reference/state.rst: -------------------------------------------------------------------------------- 1 | 2 | State 3 | ================================== 4 | State is lua_State* wrapper class 5 | 6 | .. doxygenclass:: kaguya::State 7 | :members: 8 | -------------------------------------------------------------------------------- /utils/Makefile: -------------------------------------------------------------------------------- 1 | all: one_header_file 2 | 3 | one_header_file: generate_one_header.py 4 | python generate_one_header.py > ../kaguya.hpp 5 | 6 | clean: 7 | 8 | .PHONY: all clean 9 | -------------------------------------------------------------------------------- /docs/getting_started/index.rst: -------------------------------------------------------------------------------- 1 | 2 | Getting Started 3 | ================================== 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | requirements 9 | tutorial 10 | class_bindings 11 | -------------------------------------------------------------------------------- /docs/api_reference/index.rst: -------------------------------------------------------------------------------- 1 | 2 | API Reference 3 | ================================== 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | preprocessor_option 9 | state 10 | metatable 11 | luaref 12 | standard 13 | -------------------------------------------------------------------------------- /test/shared_library_test/test_shared_class.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct A { 4 | A() : data(32) {} 5 | A(int v) : data(v) {} 6 | int data; 7 | }; 8 | struct DerivedA : A {}; 9 | 10 | struct B { 11 | virtual ~B() {} 12 | }; 13 | struct DerivedB : B {}; 14 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | stage('Test') { 2 | parallel linux: { 3 | node('linux') { 4 | checkout scm 5 | sh 'python test_runner.py' 6 | } 7 | }, 8 | mac: { 9 | node('mac') { 10 | checkout scm 11 | sh 'python test_runner.py' 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /examples/hello_lua_module_experimental.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define KAGUYA_DYNAMIC_LIB 5 | #include "kaguya/another_binding_api.hpp" 6 | 7 | void hello() 8 | { 9 | std::cout << "hello cpp world" << std::endl; 10 | } 11 | 12 | 13 | KAGUYA_BINDINGS(hello_lua_module_experimental) 14 | { 15 | using namespace kaguya; 16 | using kaguya::function; 17 | 18 | function("hello", &hello); 19 | } 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /examples/lua_exec.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include 3 | #include 4 | #include 5 | } 6 | #include 7 | #include 8 | 9 | int main(int argc,const char* argv[]) 10 | { 11 | lua_State* L = luaL_newstate(); 12 | luaL_openlibs(L); 13 | if (argc > 1 && luaL_dofile(L, argv[1])) 14 | { 15 | std::cerr << lua_tostring(L,-1) << std::endl; 16 | } 17 | #ifdef WIN32 18 | system("PAUSE"); 19 | #endif 20 | lua_close(L); 21 | } 22 | -------------------------------------------------------------------------------- /docs/introduction/index.rst: -------------------------------------------------------------------------------- 1 | 2 | Introduction 3 | ================================== 4 | 5 | Kaguya is Lua binding library for C++ 6 | 7 | * header-file only 8 | * Seamless access to lua elements 9 | * Type-safe and decent speed `benchmark `_ 10 | * Support old environment. see :doc:`../getting_started/requirements` 11 | 12 | License 13 | --------------------------------------- 14 | Licensed under Boost Software License 15 | -------------------------------------------------------------------------------- /examples/hello_world.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void hello_cpp_world() 5 | { 6 | std::cout << "hello cpp world" << std::endl; 7 | } 8 | 9 | int main() 10 | { 11 | using namespace kaguya; 12 | State state; 13 | state.dostring("print('hello lua world')"); 14 | 15 | state["hello_cpp_world"] = &hello_cpp_world;//bind function 16 | state.dostring("hello_cpp_world()"); 17 | 18 | #ifdef WIN32 19 | system("PAUSE"); 20 | #endif 21 | } 22 | -------------------------------------------------------------------------------- /include/kaguya/kaguya.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include "kaguya/config.hpp" 9 | #include "kaguya/lua_ref.hpp" 10 | #include "kaguya/native_function.hpp" 11 | #include "kaguya/state.hpp" 12 | #include "kaguya/lua_ref_table.hpp" 13 | #include "kaguya/lua_ref_function.hpp" 14 | #include "kaguya/ref_tuple.hpp" 15 | -------------------------------------------------------------------------------- /examples/hello_lua_module.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | void hello() 6 | { 7 | std::cout << "hello cpp module" << std::endl; 8 | } 9 | 10 | 11 | #if defined(_WIN32) || defined(_WIN64) 12 | extern "C" __declspec(dllexport) 13 | #else 14 | extern "C" __attribute__((visibility("default"))) 15 | #endif 16 | int luaopen_hello_lua_module(lua_State* L) 17 | { 18 | using namespace kaguya; 19 | 20 | State state(L); 21 | LuaTable module = state.newTable(); 22 | 23 | module["hello"]=kaguya::function(&hello); 24 | 25 | 26 | return module.push(); 27 | } 28 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Kaguya documentation master file, created by 2 | sphinx-quickstart on Sun Jul 24 22:35:49 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Kaguya's documentation! 7 | ================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | introduction/index 15 | getting_started/index 16 | api_reference/index 17 | 18 | 19 | Indices and tables 20 | ================== 21 | 22 | * :ref:`genindex` 23 | * :ref:`modindex` 24 | * :ref:`search` 25 | -------------------------------------------------------------------------------- /docs/getting_started/requirements.rst: -------------------------------------------------------------------------------- 1 | 2 | Requirements 3 | ================================== 4 | 5 | * Lua 5.1 to 5.3 (include luajit). 6 | * C++03 compiler with boost library Or C++11 compiler without boost. 7 | 8 | Tested Environment. 9 | ---------------------------------- 10 | 11 | * Compiler 12 | c++03 (with boost) 13 | gcc: 4.4.7 , 4.5.3 , 4.6.4 , 4.7.3 , 4.8.5 , 4.9.3 , 5.3.0 14 | 15 | Clang: 3.4.0 , 3.8.1 16 | 17 | Microsoft Visual Studio: 2008 , 2010 , 2012 18 | c++11 or later 19 | gcc: 4.7.3 , 4.8.5 , 4.9.3 , 5.3.0 20 | 21 | Clang: 3.4.0 , 3.8.1 22 | 23 | Microsoft Visual Studio: 2013 , 2015 24 | * Lua version 25 | 5.1.5 , 5.2.4 , 5.3.3 , luajit 26 | -------------------------------------------------------------------------------- /docs/api_reference/standard.rst: -------------------------------------------------------------------------------- 1 | 2 | kaguya::standard namespace 3 | ================================== 4 | 5 | This namespace store standard libraries. 6 | 7 | using boost library for not enough in C++03. 8 | 9 | In this way it has been defined in kaguya/config.hpp 10 | 11 | .. code-block:: c++ 12 | 13 | namespace kaguya 14 | { 15 | namespace standard 16 | { 17 | #if KAGUYA_USE_CPP11 18 | using namespace std; 19 | #else 20 | using namespace boost; 21 | #endif 22 | } 23 | } 24 | 25 | 26 | Used switched types 27 | ----------------------------- 28 | 29 | * tuple 30 | 31 | using multiple return value. 32 | 33 | * shared_ptr 34 | 35 | using shared_ptr assign. see :ref:`smartpointers`. 36 | -------------------------------------------------------------------------------- /test/test_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "test_util.hpp" 6 | 7 | int main(int argc, const char *argv[]) { 8 | std::vector test_set; 9 | 10 | const std::string run_test_opt = "--run_test="; 11 | for (int i = 1; i < argc; ++i) { 12 | if (strncmp(argv[i], run_test_opt.c_str(), run_test_opt.size()) == 0) { 13 | std::stringstream opt(argv[i] + run_test_opt.size()); 14 | while (opt.good()) { 15 | std::string testname; 16 | getline(opt, testname, ','); 17 | test_set.push_back(testname); 18 | } 19 | } 20 | } 21 | kaguya_test_util::TestRunner::instance().set_test_set(test_set); 22 | 23 | bool test_result = kaguya_test_util::TestRunner::instance().execute(); 24 | return test_result ? 0 : -1; 25 | } 26 | -------------------------------------------------------------------------------- /test/shared_library_test/test_shared_class_use.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include "../test_util.hpp" 3 | #include "test_shared_class.hpp" 4 | 5 | namespace { 6 | int A_fn(const A &a) { return a.data; } 7 | int B_fn(const B &) { return 22; } 8 | int DerivedB_fn(const DerivedB &) { return 33; } 9 | A create_A() { return A(1); } 10 | } 11 | 12 | #if defined(_WIN32) || defined(_WIN64) 13 | extern "C" __declspec(dllexport) 14 | #else 15 | extern "C" __attribute__((visibility("default"))) 16 | #endif 17 | int luaopen_test_shared_class_use(lua_State *L) { 18 | using namespace kaguya; 19 | 20 | State state(L); 21 | LuaTable module = state.newTable(); 22 | module["A_fn"] = &A_fn; 23 | module["create_A"] = &create_A; 24 | module["B_fn"] = &B_fn; 25 | module["DerivedB_fn"] = &DerivedB_fn; 26 | 27 | return module.push(); 28 | } 29 | -------------------------------------------------------------------------------- /test/shared_library_test/test_shared_class_reg.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include "test_shared_class.hpp" 3 | 4 | #if defined(_WIN32) || defined(_WIN64) 5 | extern "C" __declspec(dllexport) 6 | #else 7 | extern "C" __attribute__((visibility("default"))) 8 | #endif 9 | int luaopen_test_shared_class_reg(lua_State *L) { 10 | using namespace kaguya; 11 | 12 | State state(L); 13 | LuaTable module = state.newTable(); 14 | 15 | module["A"].setClass( 16 | UserdataMetatable().setConstructors().addProperty( 17 | "data", &A::data)); 18 | module["B"].setClass(UserdataMetatable().setConstructors()); 19 | module["DerivedA"].setClass( 20 | UserdataMetatable().setConstructors()); 21 | module["DerivedB"].setClass( 22 | UserdataMetatable().setConstructors()); 23 | 24 | return module.push(); 25 | } 26 | -------------------------------------------------------------------------------- /docs/api_reference/luaref.rst: -------------------------------------------------------------------------------- 1 | 2 | LuaRef 3 | ================================== 4 | 5 | LuaRef has strong reference to lua value. 6 | It means not collect by gc. 7 | 8 | 9 | LuaRef has specialized 4 types. 10 | 11 | * LuaTable is LUA_TTABLE 12 | * LuaUserData is LUA_TUSERDATA 13 | * LuaFunction is LUA_TFUNCTION 14 | * LuaThread is LUA_TTHREAD 15 | 16 | 17 | example 18 | 19 | .. code-block:: c++ 20 | 21 | state.dostring("mytable={}");//create table 22 | kaguya::LuaRef table = state["mytable"]; 23 | state.dostring("mytable.value = 3"); 24 | int v = table["value"];//v is 3 25 | 26 | state.dostring("mytable.value = 6");//assign new value 27 | state.dostring("mytable=nil");//remove from global table 28 | state.dostring("collectgarbage()");//run fullgc 29 | v = table["value"];//v is 6. 30 | 31 | .. toctree:: 32 | :maxdepth: 1 33 | 34 | lua_ref 35 | lua_table 36 | lua_thread 37 | lua_userdata 38 | lua_function 39 | -------------------------------------------------------------------------------- /Lua-CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project (lua) 3 | 4 | file(GLOB LIB_LUA_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 5 | src/*.h 6 | src/*.c 7 | include/*.h) 8 | 9 | include_directories("src/") 10 | include_directories("include/") 11 | 12 | list(REMOVE_ITEM LIB_LUA_SRCS src/lua.c src/luac.c) 13 | 14 | add_library(liblua STATIC ${LIB_LUA_SRCS}) 15 | SET_TARGET_PROPERTIES(liblua PROPERTIES OUTPUT_NAME lua) 16 | 17 | 18 | if(NOT EMSCRIPTEN) 19 | add_library(liblua_shared SHARED ${LIB_LUA_SRCS}) 20 | if(MSVC) 21 | target_compile_definitions(liblua_shared PRIVATE "-DLUA_BUILD_AS_DLL") 22 | endif(MSVC) 23 | endif(NOT EMSCRIPTEN) 24 | 25 | if(UNIX AND NOT EMSCRIPTEN) 26 | add_definitions("-DLUA_USE_POSIX -DLUA_USE_DLOPEN") 27 | target_link_libraries(liblua m dl) 28 | target_link_libraries(liblua_shared m dl) 29 | endif(UNIX AND NOT EMSCRIPTEN) 30 | 31 | #add_executable(lua src/lua.c) 32 | #target_link_libraries(lua liblua) 33 | 34 | #add_executable(luac src/luac.c) 35 | #target_link_libraries(luac liblua) 36 | -------------------------------------------------------------------------------- /some_lua_version_test.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | build_test_versions=("lua-5.3.3" "lua-5.2.4" "lua-5.1.5") 3 | build_test_cxx_flags=("-std=c++03" "-std=c++11") 4 | 5 | build_and_exec_test(){ 6 | if [ ! -e "build$2_$1" ]; then 7 | mkdir "build$2_$1" 8 | fi 9 | cd "build$2_$1" 10 | cmake ../ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_CXX_FLAGS=$2 -DLUA_SEARCH_LIB_NAME=$1 -DCOVERAGE=${TEST_COVERAGE} 11 | make -j4 12 | CTEST_OUTPUT_ON_FAILURE=1 make test 13 | cd ../ 14 | } 15 | 16 | for luaversion in "${build_test_versions[@]}" 17 | do 18 | if [ ! -e $luaversion ]; then 19 | if [ ! -e ${luaversion}.tar.gz ]; then 20 | wget https://www.lua.org/ftp/${luaversion}.tar.gz 21 | fi 22 | tar zxf ${luaversion}.tar.gz 23 | fi 24 | for cxxflag in "${build_test_cxx_flags[@]}" 25 | do 26 | build_and_exec_test $luaversion $cxxflag 27 | done 28 | done 29 | 30 | test_versions=("luajit") 31 | for luaversion in "${test_versions[@]}" 32 | do 33 | for cxxflag in "${build_test_cxx_flags[@]}" 34 | do 35 | build_and_exec_test $luaversion $cxxflag 36 | done 37 | done 38 | -------------------------------------------------------------------------------- /utils/generate_one_header.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import sys 4 | import re 5 | 6 | def inner_include_path(line): 7 | m = re.search('#include\s\"(?P.*)\"',line) 8 | if m: 9 | return m.group('headername') 10 | return None; 11 | 12 | def parseheader(out,filepath,basedir,onceincludedfiles): 13 | 14 | for line in open(os.path.join(basedir,filepath), 'r'): 15 | if line.find('#pragma once') != -1: 16 | onceincludedfiles.append(os.path.join(basedir,filepath)) 17 | continue 18 | path = inner_include_path(line) 19 | if path: 20 | if not os.path.join(basedir,path) in onceincludedfiles: 21 | parseheader(out,path,basedir,onceincludedfiles) 22 | else: 23 | out.write(line) 24 | 25 | if __name__ == "__main__": 26 | onceincludedfiles=[] 27 | sys.stdout.write('#ifndef KAGUYA_LUABINDING_HPP_INCLUDED\n') 28 | sys.stdout.write('#define KAGUYA_LUABINDING_HPP_INCLUDED\n') 29 | parseheader(sys.stdout,'kaguya/kaguya.hpp','../include/',onceincludedfiles) 30 | sys.stdout.write('#endif// KAGUYA_LUABINDING_HPP_INCLUDED\n') 31 | -------------------------------------------------------------------------------- /test/test_12_push_any.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include "test_util.hpp" 3 | 4 | KAGUYA_TEST_GROUP_START(test_12_push_any) 5 | using namespace kaguya_test_util; 6 | 7 | KAGUYA_TEST_FUNCTION_DEF(push_any_type)(kaguya::State &state) { 8 | using namespace kaguya; 9 | 10 | std::vector data; 11 | data.push_back(3); 12 | data.push_back("data"); 13 | data.push_back("abc"); 14 | data.push_back(std::string("abc")); 15 | 16 | TEST_COMPARE_EQ(state.newRef(AnyDataPusher(3)), 3); 17 | TEST_COMPARE_EQ(state.newRef(AnyDataPusher("data")), "data"); 18 | TEST_COMPARE_EQ(state.newRef(AnyDataPusher(std::string("abc"))), 19 | std::string("abc")); 20 | 21 | AnyDataPusher a("d"); 22 | AnyDataPusher b(4); 23 | a = b; 24 | AnyDataPusher c; 25 | TEST_COMPARE_EQ(state.newRef(a), 4); 26 | TEST_COMPARE_EQ(state.newRef(b), 4); 27 | TEST_CHECK(!state.newRef(c)); 28 | } 29 | 30 | KAGUYA_TEST_FUNCTION_DEF(push_const_shared_ptr_type)(kaguya::State &state) { 31 | using namespace kaguya; 32 | using namespace kaguya::standard; 33 | shared_ptr s(new int(4)); 34 | LuaRef ref = state.newRef(s); 35 | shared_ptr other = ref; 36 | 37 | TEST_CHECK(!other); 38 | } 39 | KAGUYA_TEST_GROUP_END(test_12_push_any) 40 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /test/test_10_loadfile.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include "test_util.hpp" 3 | 4 | KAGUYA_TEST_GROUP_START(test_10_loadfile) 5 | using namespace kaguya_test_util; 6 | 7 | std::string last_error_message; 8 | void ignore_error_fun(int status, const char *message) { 9 | KAGUYA_UNUSED(status); 10 | last_error_message = message ? message : ""; 11 | } 12 | 13 | KAGUYA_TEST_FUNCTION_DEF(load_return_number)(kaguya::State &state) { 14 | TEST_CHECK(state.dofile("lua/return_number.lua")); 15 | TEST_CHECK(state.loadfile("lua/return_number.lua")); 16 | } 17 | 18 | KAGUYA_TEST_FUNCTION_DEF(load_assign_value)(kaguya::State &state) { 19 | TEST_CHECK(state.dofile("lua/assign_value.lua")); 20 | TEST_EQUAL(state["value"], 1); 21 | state["value"] = 5; 22 | kaguya::LuaTable env = state.newTable(); 23 | TEST_CHECK(state.dofile("lua/assign_value.lua", env)); 24 | TEST_CHECK(state.loadfile("lua/assign_value.lua")); 25 | TEST_EQUAL(env["value"], 1); 26 | } 27 | 28 | KAGUYA_TEST_FUNCTION_DEF(load_syntax_error_script)(kaguya::State &state) { 29 | last_error_message = ""; 30 | state.setErrorHandler(ignore_error_fun); 31 | 32 | TEST_CHECK(!state.loadfile("lua/syntax_error.lua")); 33 | TEST_CHECK(!state.dofile("lua/syntax_error.lua")); 34 | TEST_COMPARE_NE(last_error_message, ""); 35 | } 36 | 37 | KAGUYA_TEST_FUNCTION_DEF(runtime_error_script)(kaguya::State &state) { 38 | last_error_message = ""; 39 | state.setErrorHandler(ignore_error_fun); 40 | 41 | TEST_CHECK(!state.dofile("lua/runtime_error.lua")); 42 | TEST_COMPARE_NE(last_error_message, ""); 43 | } 44 | 45 | KAGUYA_TEST_GROUP_END(test_10_loadfile) 46 | -------------------------------------------------------------------------------- /cmake/FindLua.cmake: -------------------------------------------------------------------------------- 1 | if(NOT LOCAL_LUA_DIRECTORY) 2 | set(LOCAL_LUA_DIRECTORY ${LUA_SEARCH_LIB_NAME}) 3 | endif() 4 | 5 | if(LOCAL_LUA_DIRECTORY) 6 | #search local directory 7 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LOCAL_LUA_DIRECTORY}) 8 | file(COPY Lua-CMakeLists.txt DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/${LOCAL_LUA_DIRECTORY}) 9 | file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/${LOCAL_LUA_DIRECTORY}/Lua-CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/${LOCAL_LUA_DIRECTORY}/CMakeLists.txt) 10 | add_subdirectory(${LOCAL_LUA_DIRECTORY}) 11 | 12 | set(LUA_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/${LOCAL_LUA_DIRECTORY}/src) 13 | if(NOT EXISTS ${LUA_INCLUDE_DIRS}/lua.h) 14 | set(LUA_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/${LOCAL_LUA_DIRECTORY}/include) 15 | endif() 16 | set(LUA_LIBRARIES liblua) 17 | if(NOT EMSCRIPTEN) 18 | set(LUA_SHARED_LIBRARIES liblua_shared) 19 | set(LUA_BUILD true) 20 | endif(NOT EMSCRIPTEN) 21 | endif() 22 | endif() 23 | 24 | if(NOT LUA_INCLUDE_DIRS) 25 | find_package(PkgConfig) 26 | set(LUA_SEARCHVERS ${LUA_SEARCH_LIB_NAME} lua5.3 lua5.2 luajit lua5.1 lua) 27 | foreach(modulename ${LUA_SEARCHVERS}) 28 | pkg_search_module(LUA ${modulename}) 29 | endforeach(modulename) 30 | # maybe system library is shared library 31 | set(LUA_SHARED_LIBRARIES ${LUA_LIBRARIES}) 32 | endif(NOT LUA_INCLUDE_DIRS) 33 | 34 | if(NOT LUA_INCLUDE_DIRS) 35 | # message(SEND_ERROR "Can't find lua library") 36 | endif(NOT LUA_INCLUDE_DIRS) 37 | 38 | 39 | if(NOT EXISTS ${LUA_INCLUDE_DIRS}/lua.h) 40 | message(SEND_ERROR "Can't find lua.h in ${LUA_INCLUDE_DIRS}") 41 | endif() 42 | -------------------------------------------------------------------------------- /test/test_14_error_message.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/another_binding_api.hpp" 2 | #include "test_util.hpp" 3 | 4 | KAGUYA_TEST_GROUP_START(test_14_error_message) 5 | using namespace kaguya_test_util; 6 | using namespace kaguya; 7 | 8 | std::string last_error_message; 9 | void error_fun(int status, const char *message) { 10 | KAGUYA_UNUSED(status); 11 | last_error_message = message ? message : "unknown error"; 12 | } 13 | 14 | void defargfn(int a = 3, int b = 2, int c = 1) { 15 | TEST_EQUAL(a, 3); 16 | TEST_EQUAL(b, 2); 17 | TEST_EQUAL(c, 1); 18 | } 19 | 20 | void defargfn2(int a, int b, int c = 1) { 21 | TEST_EQUAL(a, 3); 22 | TEST_EQUAL(b, 2); 23 | TEST_EQUAL(c, 1); 24 | } 25 | 26 | KAGUYA_FUNCTION_OVERLOADS(defargfn_wrapper, defargfn, 0, 3) 27 | KAGUYA_FUNCTION_OVERLOADS(defargfn_wrapper2, defargfn2, 2, 3) 28 | 29 | KAGUYA_TEST_FUNCTION_DEF(defaultarguments)(kaguya::State &state) { 30 | state.setErrorHandler(error_fun); 31 | state["defargfn"] = kaguya::function(defargfn_wrapper()); 32 | state["defargfn2"] = kaguya::function(defargfn_wrapper2()); 33 | 34 | std::string intname = kaguya::util::pretty_name(typeid(int)); 35 | 36 | if (intname == "int") { 37 | state.dostring("defargfn('abc')"); 38 | TEST_CHECK_M(last_error_message.find("[OPT]int,[OPT]int,[OPT]int") != 39 | std::string::npos, 40 | last_error_message); 41 | state.dostring("defargfn2('abc',3)"); 42 | TEST_CHECK_M(last_error_message.find("int,int,[OPT]int") != 43 | std::string::npos, 44 | last_error_message); 45 | } 46 | } 47 | 48 | KAGUYA_TEST_GROUP_END(test_14_error_message) 49 | -------------------------------------------------------------------------------- /docs/api_reference/preprocessor_option.rst: -------------------------------------------------------------------------------- 1 | 2 | Preprocessor Options 3 | ================================== 4 | 5 | This option must be same between translation units. 6 | 7 | .. _preprocessor-use-cpp11: 8 | * KAGUYA_USE_CPP11 9 | 10 | | If defined 1, kaguya use C++11 feature. 11 | | If defined 0, kaguya use C++03 only (need boost library). 12 | | default is auto detect (using _MSC_VER or __cplusplus). 13 | 14 | | 15 | 16 | * KAGUYA_NO_USERDATA_TYPE_CHECK 17 | 18 | If defined 1, Skip type check for userdata created without kaguya. 19 | 20 | .. warning:: 21 | 22 | This option is dangerous to be used in conjunction with other Lua library. 23 | 24 | example: 25 | 26 | .. code-block:: lua 27 | 28 | --io.stdin is created by lua standard library. 29 | kaguya_binded_receive_userdata_fn(io.stdin) -- Error not detected. this is undefined behavior. 30 | 31 | | 32 | 33 | * KAGUYA_NO_VECTOR_AND_MAP_TO_TABLE 34 | 35 | If defined, std::map and std::vector will not be converted to a lua-table 36 | 37 | | 38 | 39 | * KAGUYA_NO_STD_VECTOR_TO_TABLE 40 | 41 | If defined, std::vector will not be converted to a lua-table 42 | 43 | | 44 | 45 | * KAGUYA_NO_STD_MAP_TO_TABLE 46 | 47 | If defined, std::map will not be converted to a lua-table 48 | 49 | | 50 | 51 | * KAGUYA_FUNCTION_MAX_ARGS 52 | 53 | Define max argument count for binding function. default is 9. 54 | 55 | .. note:: 56 | 57 | Effect in the C++03 only 58 | 59 | | 60 | 61 | * KAGUYA_FUNCTION_MAX_OVERLOADS 62 | 63 | Define max overloads function count for binding functions. default is 9. 64 | 65 | .. note:: 66 | 67 | Effect in the C++03 only 68 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | if(COVERAGE) 3 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall -Woverloaded-virtual -Wwrite-strings -fprofile-arcs -ftest-coverage -coverage -fno-inline -fno-inline-small-functions -fno-default-inline") 4 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall -fprofile-arcs -ftest-coverage -coverage -fno-inline -fno-inline-small-functions -fno-default-inline") 5 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -coverage -fno-inline -fno-inline-small-functions -fno-default-inline") 6 | endif(COVERAGE) 7 | 8 | file(GLOB TEST_SRCS files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test_*.cpp) 9 | 10 | 11 | file(GLOB KAGUYA_HEADER RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 12 | ../include/kaguya/*.hpp 13 | ../include/kaguya/detail/*.hpp) 14 | 15 | add_executable(test_runner ${TEST_SRCS} ${KAGUYA_HEADER}) 16 | target_link_libraries(test_runner ${LUA_LIBRARIES}) 17 | if(HAVE_FLAG_SANITIZE_ADDRESS) 18 | SET_TARGET_PROPERTIES(test_runner PROPERTIES COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer") 19 | SET_TARGET_PROPERTIES(test_runner PROPERTIES LINK_FLAGS "-fsanitize=address") 20 | endif(HAVE_FLAG_SANITIZE_ADDRESS) 21 | 22 | 23 | if(EMSCRIPTEN) 24 | SET_TARGET_PROPERTIES(test_runner PROPERTIES LINK_FLAGS "-s DEMANGLE_SUPPORT=1 -s TOTAL_MEMORY=36777216 -s DISABLE_EXCEPTION_CATCHING=0 --preload-file ${CMAKE_SOURCE_DIR}/test/lua@/lua") 25 | endif(EMSCRIPTEN) 26 | 27 | 28 | add_test( 29 | NAME test_runner 30 | COMMAND $ 31 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 32 | 33 | if(LUA_SHARED_LIBRARIES) 34 | add_subdirectory(shared_library_test) 35 | endif(LUA_SHARED_LIBRARIES) -------------------------------------------------------------------------------- /test/test_13_another_binding_api.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/another_binding_api.hpp" 2 | #include "test_util.hpp" 3 | 4 | KAGUYA_TEST_GROUP_START(test_13_predefined_binding_api) 5 | using namespace kaguya_test_util; 6 | 7 | using namespace kaguya; 8 | 9 | int squared(int a) { return a * a; } 10 | 11 | enum ENUM_TEST_TYPE { ENUM_TEST_A = 2, ENUM_TEST_B = 4 }; 12 | 13 | KAGUYA_BINDINGS(test_bind) { 14 | class_("TestClass") 15 | .constructor() 16 | .def("getInt", &TestClass::getInt); 17 | 18 | { 19 | scope newscope("submodule"); 20 | def("squared", &squared); 21 | { 22 | scope newscope("submodule"); 23 | def("squared3", &squared); 24 | } 25 | } 26 | function("squared", &squared); 27 | scope().attr("x") = 1; 28 | 29 | enum_("ENUM_TEST_TYPE") 30 | .value("ENUM_TEST_A", ENUM_TEST_A) 31 | .value("ENUM_TEST_B", ENUM_TEST_B); 32 | } 33 | 34 | KAGUYA_TEST_FUNCTION_DEF(int_constructor)(kaguya::State &state) { 35 | state.openlib("test_bind", &luaopen_test_bind); 36 | 37 | TEST_CHECK(state("value = assert(test_bind.TestClass.new(32))")); 38 | TEST_CHECK(state("assert(value:getInt() == 32)")); 39 | TEST_CHECK(state("assert(test_bind.squared(3) == 9)")); 40 | TEST_CHECK(state("assert(test_bind.submodule.squared(6) == 36)")); 41 | TEST_CHECK(state("assert(test_bind.submodule.submodule.squared3(6) == 36)")); 42 | 43 | TEST_CHECK(state("assert(test_bind.x == 1)")) 44 | TEST_CHECK(state("assert(test_bind.ENUM_TEST_TYPE.ENUM_TEST_A == 2)")); 45 | TEST_CHECK(state("assert(test_bind.ENUM_TEST_TYPE.ENUM_TEST_B == 4)")); 46 | } 47 | 48 | KAGUYA_TEST_GROUP_END(test_13_predefined_binding_api) 49 | -------------------------------------------------------------------------------- /test/shared_library_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | if(LUA_BUILD) 3 | add_custom_target(copy_lua_shared_lib 4 | COMMAND ${CMAKE_COMMAND} -E copy_if_different $ ${CMAKE_CURRENT_BINARY_DIR} 5 | DEPENDS ${LUA_SHARED_LIBRARIES} 6 | ) 7 | endif(LUA_BUILD) 8 | 9 | add_definitions(-DKAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY=1) 10 | 11 | add_library(test_shared_class_reg SHARED test_shared_class_reg.cpp) 12 | target_link_libraries(test_shared_class_reg ${LUA_SHARED_LIBRARIES}) 13 | SET_TARGET_PROPERTIES(test_shared_class_reg PROPERTIES PREFIX "") 14 | 15 | add_library(test_shared_class_use SHARED test_shared_class_use.cpp) 16 | target_link_libraries(test_shared_class_use ${LUA_SHARED_LIBRARIES}) 17 | SET_TARGET_PROPERTIES(test_shared_class_use PROPERTIES PREFIX "") 18 | 19 | add_executable(test_shared_class_main test_shared_class_main.cpp) 20 | target_link_libraries(test_shared_class_main ${LUA_SHARED_LIBRARIES}) 21 | 22 | add_dependencies(test_shared_class_main test_shared_class_reg test_shared_class_use copy_lua_shared_lib) 23 | 24 | if(HAVE_FLAG_SANITIZE_ADDRESS) 25 | SET_TARGET_PROPERTIES(test_shared_class_reg PROPERTIES COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer") 26 | SET_TARGET_PROPERTIES(test_shared_class_reg PROPERTIES LINK_FLAGS "-fsanitize=address") 27 | SET_TARGET_PROPERTIES(test_shared_class_use PROPERTIES COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer") 28 | SET_TARGET_PROPERTIES(test_shared_class_use PROPERTIES LINK_FLAGS "-fsanitize=address") 29 | SET_TARGET_PROPERTIES(test_shared_class_main PROPERTIES COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer") 30 | SET_TARGET_PROPERTIES(test_shared_class_main PROPERTIES LINK_FLAGS "-fsanitize=address") 31 | endif(HAVE_FLAG_SANITIZE_ADDRESS) 32 | 33 | 34 | add_test( 35 | NAME test_shared_class 36 | COMMAND $ 37 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | function(add_target_copy_to_bin_dir target_name) 3 | set (copynum ${ARGN}) 4 | list(GET copynum 0 copy_files) 5 | foreach(v IN LISTS copy_files) 6 | add_custom_command( 7 | TARGET ${target_name} POST_BUILD 8 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${v} $/${v}) 9 | endforeach() 10 | endfunction(add_target_copy_to_bin_dir) 11 | 12 | 13 | add_executable(hello_world hello_world.cpp) 14 | target_link_libraries(hello_world ${LUA_LIBRARIES}) 15 | 16 | set(EXAMPLE_BINARIES ${EXAMPLE_BINARIES} hello_world) 17 | 18 | #if(NOT EMSCRIPTEN) 19 | 20 | # add_executable(lua_exec lua_exec.cpp) 21 | # target_link_libraries(lua_exec ${LUA_LIBRARIES}) 22 | 23 | # add_library(hello_lua_module MODULE hello_lua_module.cpp) 24 | # target_link_libraries(hello_lua_module ${LUA_LIBRARIES}) 25 | # add_dependencies(hello_lua_module lua_exec) 26 | # add_target_copy_to_bin_dir(hello_lua_module hello_lua_module_exec.lua) 27 | # add_target_copy_to_bin_dir(hello_lua_module hello_lua_module.sh) 28 | # add_target_copy_to_bin_dir(hello_lua_module hello_lua_module.bat) 29 | 30 | # add_library(hello_lua_module_experimental MODULE hello_lua_module_experimental.cpp) 31 | # target_link_libraries(hello_lua_module_experimental ${LUA_LIBRARIES}) 32 | # add_dependencies(hello_lua_module_experimental lua_exec) 33 | # add_target_copy_to_bin_dir(hello_lua_module_experimental hello_lua_module_experimental_exec.lua) 34 | # add_target_copy_to_bin_dir(hello_lua_module_experimental hello_lua_module_experimental.sh) 35 | # add_target_copy_to_bin_dir(hello_lua_module_experimental hello_lua_module_experimental.bat) 36 | # set(EXAMPLE_BINARIES ${EXAMPLE_BINARIES} hello_lua_module hello_lua_module_experimental lua_exec) 37 | #endif(NOT EMSCRIPTEN) 38 | 39 | set_target_properties(${EXAMPLE_BINARIES} PROPERTIES FOLDER "Examples") 40 | set_target_properties(${EXAMPLE_BINARIES} PROPERTIES PREFIX "") 41 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 11 | BUILD_TYPE: Release 12 | 13 | jobs: 14 | test: 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest] 18 | luaversion: [lua-5.1.5,lua-5.2.4,lua-5.3.6,lua-5.4.3,lua-5.4.7] 19 | fail-fast: false 20 | # The CMake configure and build commands are platform agnostic and should work equally 21 | # well on Windows or Mac. You can convert this to a matrix build if you need 22 | # cross-platform coverage. 23 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 24 | runs-on: ${{ matrix.os }} 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: Download Lua 29 | run: wget https://www.lua.org/ftp/${{ matrix.luaversion }}.tar.gz && tar zxf ${{ matrix.luaversion }}.tar.gz 30 | - name: Configure CMake 31 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 32 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 33 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DLUA_SEARCH_LIB_NAME=${{ matrix.luaversion }} 34 | 35 | - name: Build 36 | # Build your program with the given configuration 37 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 38 | 39 | - name: Test 40 | working-directory: ${{github.workspace}}/build 41 | # Execute tests defined by the CMake configuration. 42 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 43 | run: ctest --output-on-failure -C ${{env.BUILD_TYPE}} 44 | 45 | -------------------------------------------------------------------------------- /benchmark/benchmark_function.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace kaguyaapi 3 | { 4 | 5 | void simple_get_set(kaguya::State& state); 6 | 7 | void simple_get_set_raw_ptr(kaguya::State& state); 8 | void simple_get_set_shared_ptr(kaguya::State& state); 9 | #if KAGUYA_USE_CPP11 10 | void simple_get_set_unique_ptr(kaguya::State& state); 11 | #endif 12 | void overloaded_get_set(kaguya::State& state); 13 | void simple_get_set_contain_property_member(kaguya::State& state); 14 | 15 | void call_construct(kaguya::State& state); 16 | void new_construct(kaguya::State& state); 17 | 18 | void object_get_set(kaguya::State& state); 19 | void object_get_set_property(kaguya::State& state); 20 | void object_get_set_property_function(kaguya::State& state); 21 | void object_to_table_get_set(kaguya::State& state); 22 | void object_to_table_property(kaguya::State& state); 23 | 24 | void multiple_inheritance_get_set(kaguya::State& state); 25 | void multiple_inheritance_property(kaguya::State& state); 26 | 27 | void call_native_function(kaguya::State& state); 28 | void call_overloaded_function(kaguya::State& state); 29 | 30 | void call_lua_function(kaguya::State& state); 31 | void call_lua_function_operator_functional(kaguya::State& state); 32 | void lua_table_access(kaguya::State& state); 33 | void lua_table_bracket_operator_access(kaguya::State& state); 34 | void lua_table_bracket_operator_assign(kaguya::State& state); 35 | void lua_table_bracket_operator_get(kaguya::State& state); 36 | void lua_table_bracket_const_operator_get(kaguya::State& state); 37 | 38 | void property_access(kaguya::State& state); 39 | 40 | void table_to_vector(kaguya::State& state); 41 | void table_to_vector_with_typecheck(kaguya::State& state); 42 | void vector_to_table(kaguya::State& state); 43 | 44 | 45 | void lua_allocation(kaguya::State& state); 46 | } 47 | 48 | namespace plain_api 49 | { 50 | void simple_get_set(kaguya::State& state); 51 | void object_get_set(kaguya::State& state); 52 | void call_native_function(kaguya::State& state); 53 | void call_lua_function(kaguya::State& state); 54 | void lua_table_access(kaguya::State& state); 55 | void lua_allocation(kaguya::State& state); 56 | } -------------------------------------------------------------------------------- /include/kaguya/ref_tuple.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include "kaguya/config.hpp" 9 | 10 | namespace kaguya { 11 | 12 | template struct ref_tuple { 13 | RefTuple tref; 14 | ref_tuple(const RefTuple &va) : tref(va) {} 15 | void operator=(const FunctionResults &fres) { 16 | tref = fres.get_result(types::typetag()); 17 | } 18 | template void operator=(const T &fres) { tref = fres; } 19 | }; 20 | #if KAGUYA_USE_CPP11 21 | template 22 | ref_tuple, standard::tuple > 23 | tie(Args &... va) { 24 | typedef standard::tuple RefTuple; 25 | typedef standard::tuple GetTuple; 26 | return ref_tuple(RefTuple(va...)); 27 | } 28 | #else 29 | #define KAGUYA_VARIADIC_REFARG_REP(N) KAGUYA_PP_CAT(A, N) & KAGUYA_PP_CAT(a, N) 30 | #define KAGUYA_VARIADIC_TREFARG_REP(N) KAGUYA_PP_CAT(A, N) & 31 | #define KAGUYA_TEMPLATE_REFARG_REPEAT(N) \ 32 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_VARIADIC_TREFARG_REP) 33 | #define KAGUYA_REF_TUPLE(N) standard::tuple 34 | #define KAGUYA_GET_TUPLE(N) standard::tuple 35 | #define KAGUYA_REF_TUPLE_DEF(N) \ 36 | template \ 37 | ref_tuple tie( \ 38 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_VARIADIC_REFARG_REP)) { \ 39 | return ref_tuple( \ 40 | KAGUYA_REF_TUPLE(N)(KAGUYA_PP_ARG_REPEAT(N))); \ 41 | } 42 | 43 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_TUPLE_SIZE, KAGUYA_REF_TUPLE_DEF) 44 | #undef KAGUYA_VARIADIC_REFARG_REP 45 | #undef KAGUYA_TEMPLATE_REFARG_REPEAT 46 | #undef KAGUYA_REF_TUPLE 47 | #undef KAGUYA_GET_TUPLE 48 | #undef KAGUYA_REF_TUPLE_DEF 49 | #endif 50 | } 51 | -------------------------------------------------------------------------------- /test/shared_library_test/test_shared_class_main.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include "../test_util.hpp" 3 | #include "test_shared_class.hpp" 4 | 5 | KAGUYA_TEST_GROUP_START(test_shared_library) 6 | 7 | KAGUYA_TEST_FUNCTION_DEF(multi_shared_lib)(kaguya::State &L) { 8 | bool ret = 9 | L.dostring("package.cpath = package.cpath .. ';?.dylib' " 10 | "test_shared_class_reg = require('test_shared_class_reg') " 11 | "test_shared_class_use = require('test_shared_class_use') " 12 | "local a = test_shared_class_reg.A(32) " 13 | "local b = test_shared_class_reg.B() " 14 | "assert(a.data == 32) " 15 | "assert(test_shared_class_use.A_fn(a) == 32) " 16 | "assert(test_shared_class_use.B_fn(b) == 22) " 17 | "assert(test_shared_class_use.create_A().data == 1) "); 18 | 19 | TEST_CHECK(ret); 20 | } 21 | 22 | void ignore_error_fun(int, const char *) {} 23 | 24 | KAGUYA_TEST_FUNCTION_DEF(typemismatch_test)(kaguya::State &L) { 25 | 26 | L.setErrorHandler(ignore_error_fun); 27 | bool ret = 28 | L.dostring("package.cpath = package.cpath .. ';?.dylib' " 29 | "test_shared_class_reg = require('test_shared_class_reg') " 30 | "test_shared_class_use = require('test_shared_class_use') "); 31 | TEST_CHECK(ret); 32 | TEST_EQUAL(false, 33 | L.dostring("local b = test_shared_class_reg.B(); " 34 | "test_shared_class_use.A_fn(b)")); 35 | } 36 | 37 | KAGUYA_TEST_FUNCTION_DEF(create_self)(kaguya::State &L) { 38 | 39 | bool ret = 40 | L.dostring("package.cpath = package.cpath .. ';?.dylib' " 41 | "test_shared_class_reg = require('test_shared_class_reg') " 42 | "test_shared_class_use = require('test_shared_class_use') "); 43 | TEST_CHECK(ret); 44 | 45 | L["a"] = A(43); 46 | TEST_CHECK(L.dostring("assert(a.data == 43)")); 47 | DerivedB derived_b; 48 | L["derived_b"] = derived_b; 49 | TEST_CHECK(L.dostring("assert(test_shared_class_use.B_fn(derived_b) == 22)")); 50 | TEST_CHECK( 51 | L.dostring("assert(test_shared_class_use.DerivedB_fn(derived_b) == 33)")); 52 | } 53 | 54 | KAGUYA_TEST_GROUP_END(test_shared_library) 55 | #include "../test_main.cpp" 56 | -------------------------------------------------------------------------------- /include/kaguya/push_tuple.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include "kaguya/config.hpp" 9 | #include "kaguya/traits.hpp" 10 | 11 | namespace kaguya { 12 | #if KAGUYA_USE_CPP11 13 | namespace detail { 14 | template struct index_tuple {}; 15 | template , 16 | bool flag = first >= last> 17 | struct index_range { 18 | using type = result; 19 | }; 20 | template 21 | struct index_range, false> 22 | : index_range > {}; 23 | 24 | template 25 | int push_tuple(lua_State *l, index_tuple, std::tuple &&v) { 26 | return util::push_args(l, std::get(v)...); 27 | } 28 | } 29 | 30 | /// @ingroup lua_type_traits 31 | /// @brief lua_type_traits for std::tuple or boost::tuple 32 | template struct lua_type_traits > { 33 | static int push(lua_State *l, std::tuple &&v) { 34 | typename detail::index_range<0, sizeof...(Args)>::type index; 35 | return detail::push_tuple(l, index, std::forward >(v)); 36 | } 37 | }; 38 | #else 39 | #define KAGUYA_PP_GET_DATA(N) standard::get(v) 40 | #define KAGUYA_PUSH_TUPLE_DEF(N) \ 41 | template \ 42 | struct lua_type_traits > { \ 43 | static int \ 44 | push(lua_State *l, \ 45 | const standard::tuple &v) { \ 46 | return util::push_args(l, KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_GET_DATA)); \ 47 | } \ 48 | }; 49 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_TUPLE_SIZE, KAGUYA_PUSH_TUPLE_DEF) 50 | #undef KAGUYA_PP_GET_DATA 51 | #undef KAGUYA_PUSH_TUPLE_DEF 52 | #endif 53 | } 54 | -------------------------------------------------------------------------------- /include/kaguya/preprocess.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // for c++03 implement 4 | 5 | #define KAGUYA_VA_ARG(...) __VA_ARGS__ 6 | 7 | #define KAGUYA_PP_CAT(F, B) F##B 8 | 9 | #include "kaguya/preprocess_repeate.hpp" 10 | 11 | #define KAGUYA_PP_VARIADIC_TARG_CONCAT_REP(N) , KAGUYA_PP_CAT(A, N) 12 | #define KAGUYA_PP_VARIADIC_TARG_REP(N) KAGUYA_PP_CAT(A, N) 13 | 14 | #define KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N) \ 15 | KAGUYA_PP_REPEAT(N, KAGUYA_PP_VARIADIC_TARG_CONCAT_REP) 16 | #define KAGUYA_PP_TEMPLATE_ARG_REPEAT(N) \ 17 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_VARIADIC_TARG_REP) 18 | 19 | #define KAGUYA_PP_ARG_DEF_CONCAT_REP(N) \ 20 | , KAGUYA_PP_CAT(A, N) KAGUYA_PP_CAT(a, N) 21 | #define KAGUYA_PP_ARG_DEF_REP(N) KAGUYA_PP_CAT(A, N) KAGUYA_PP_CAT(a, N) 22 | 23 | #define KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N) \ 24 | KAGUYA_PP_REPEAT(N, KAGUYA_PP_ARG_DEF_CONCAT_REP) 25 | #define KAGUYA_PP_ARG_DEF_REPEAT(N) \ 26 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_ARG_DEF_REP) 27 | 28 | #define KAGUYA_PP_ARG_CR_DEF_CONCAT_REP(N) \ 29 | , const KAGUYA_PP_CAT(A, N) & KAGUYA_PP_CAT(a, N) 30 | #define KAGUYA_PP_ARG_CR_DEF_REP(N) \ 31 | const KAGUYA_PP_CAT(A, N) & KAGUYA_PP_CAT(a, N) 32 | 33 | #define KAGUYA_PP_ARG_CR_DEF_REPEAT_CONCAT(N) \ 34 | KAGUYA_PP_REPEAT(N, KAGUYA_PP_ARG_CR_DEF_CONCAT_REP) 35 | #define KAGUYA_PP_ARG_CR_DEF_REPEAT(N) \ 36 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_ARG_CR_DEF_REP) 37 | 38 | #define KAGUYA_PP_ARG_CONCAT_REP(N) , KAGUYA_PP_CAT(a, N) 39 | #define KAGUYA_PP_ARG_REP(N) KAGUYA_PP_CAT(a, N) 40 | 41 | #define KAGUYA_PP_ARG_REPEAT_CONCAT(N) \ 42 | KAGUYA_PP_REPEAT(N, KAGUYA_PP_ARG_CONCAT_REP) 43 | #define KAGUYA_PP_ARG_REPEAT(N) KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_ARG_REP) 44 | 45 | #define KAGUYA_PP_VARIADIC_TDEF_CONCAT_REP(N) , KAGUYA_PP_CAT(typename A, N) 46 | #define KAGUYA_PP_VARIADIC_TDEF_REP(N) KAGUYA_PP_CAT(typename A, N) 47 | 48 | #define KAGUYA_PP_TEMPLATE_DEF_REPEAT_CONCAT(N) \ 49 | KAGUYA_PP_REPEAT(N, KAGUYA_PP_VARIADIC_TDEF_CONCAT_REP) 50 | #define KAGUYA_PP_TEMPLATE_DEF_REPEAT(N) \ 51 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_VARIADIC_TDEF_REP) 52 | 53 | #define KAGUYA_PP_ADD(X, Y) KAGUYA_PP_WHILE(Y, X, KAGUYA_PP_INC) 54 | #define KAGUYA_PP_SUB(X, Y) KAGUYA_PP_WHILE(Y, X, KAGUYA_PP_DEC) 55 | -------------------------------------------------------------------------------- /docs/getting_started/class_bindings.rst: -------------------------------------------------------------------------------- 1 | 2 | Class Bindings 3 | ================================== 4 | C++ classes binding use :doc:`/api_reference/metatable`. 5 | 6 | 7 | A quick example 8 | ------------------------- 9 | 10 | Exposing classes to Lua 11 | 12 | .. code-block:: c++ 13 | 14 | //C++ 15 | struct MyClass 16 | { 17 | MyClass():x(0),y() {} 18 | MyClass(int x,const std::string& y):x(x),y(y) {} 19 | void setX(int v){x=v;} 20 | int getX()const{return x;} 21 | void setY(const char* v){y=v;} 22 | const std::string& getY()const{return y;} 23 | private: 24 | int x; 25 | std::string y; 26 | }; 27 | 28 | ... 29 | state["MyClass"] = kaguya::UserdataMetatable() 30 | .setConstructors() 31 | .addFunction("setX", &MyClass::setX) 32 | .addFunction("getX", &MyClass::getX) 33 | .addProperty("y", &MyClass::getY, &MyClass::setY) 34 | ; 35 | 36 | 37 | Usage in Lua 38 | 39 | .. code-block:: lua 40 | 41 | local v = MyClass.new(4,'text') 42 | print(v:getX()) -- output 4 43 | print(v.y) -- output 'text' 44 | 45 | 46 | 47 | Object lifetime 48 | ------------------------- 49 | 50 | Copy assign 51 | ^^^^^^^^^^^^^^^^^^^^^^ 52 | 53 | Basic assign. 54 | Copy object and managing lifetime by Lua. 55 | 56 | example: 57 | 58 | .. code-block:: c++ 59 | 60 | { 61 | MyClass myobj; 62 | state["a"] = myobj; 63 | } 64 | state.dostring("print(a.y)");//myobj is destroyed, but a is living. 65 | state["a"] = 0;//override a. 66 | state.gc().collect(); //copied object is garbage collected. 67 | 68 | Pointer assign 69 | ^^^^^^^^^^^^^^^^^^^^^^ 70 | 71 | You need managing object lifetime by yourself. 72 | 73 | broken code example: 74 | 75 | .. code-block:: c++ 76 | 77 | MyClass* myptr = new MyClass(); 78 | state["a"] = myptr; 79 | delete myptr; 80 | state.dostring("print(a.y)")// a is destroyed. This is undefined behavior as dangling pointer. 81 | 82 | 83 | Smartpointers 84 | ^^^^^^^^^^^^^^^^^^^^^^ 85 | .. _class-bindings-smartpointers: 86 | 87 | If you think troublesome for managing lifetime, can use shared_ptr. 88 | 89 | .. code-block:: c++ 90 | 91 | kaguya::standard::shared_ptr mysptr = kaguya::standard::make_shared(); 92 | state["a"] = mysptr; 93 | state.dostring("print(a.y)"); 94 | 95 | .. note:: 96 | 97 | If :ref:`KAGUYA_USE_CPP11` is 0, 98 | std::shared_ptr(and std::tr1::shared_ptr) is unrecognized, and vice versa. 99 | see :doc:`/api_reference/standard` 100 | -------------------------------------------------------------------------------- /include/kaguya/push_any.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | #include 7 | 8 | #include "kaguya/config.hpp" 9 | #include "kaguya/traits.hpp" 10 | #include "kaguya/utility.hpp" 11 | 12 | namespace kaguya { 13 | /// @brief any data holder class for push to lua 14 | class AnyDataPusher { 15 | public: 16 | int pushToLua(lua_State *state) const { 17 | if (empty()) { 18 | lua_pushnil(state); 19 | return 1; 20 | } else { 21 | return holder_->pushToLua(state); 22 | } 23 | } 24 | 25 | AnyDataPusher() : holder_() {} 26 | 27 | template 28 | AnyDataPusher(const DataType &v) : holder_(new DataHolder(v)) {} 29 | 30 | #if KAGUYA_USE_CPP11 31 | AnyDataPusher(AnyDataPusher &&other) : holder_(std::move(other.holder_)) {} 32 | AnyDataPusher &operator=(AnyDataPusher &&rhs) { 33 | holder_ = std::move(rhs.holder_); 34 | return *this; 35 | } 36 | template 37 | AnyDataPusher(DataType &&v) 38 | : holder_(new DataHolder(std::move(v))) {} 39 | #endif 40 | AnyDataPusher(const AnyDataPusher &other) : holder_(other.holder_) {} 41 | AnyDataPusher &operator=(const AnyDataPusher &other) { 42 | holder_ = other.holder_; 43 | return *this; 44 | } 45 | 46 | bool empty() const { return !holder_.get(); } 47 | 48 | private: 49 | struct DataHolderBase { 50 | virtual int pushToLua(lua_State *data) const = 0; 51 | // virtual DataHolderBase * clone(void) = 0; 52 | virtual ~DataHolderBase() {} 53 | }; 54 | template class DataHolder : public DataHolderBase { 55 | typedef typename traits::decay::type DataType; 56 | 57 | public: 58 | #if KAGUYA_USE_CPP11 59 | explicit DataHolder(DataType &&v) : data_(std::forward(v)) {} 60 | #else 61 | explicit DataHolder(const DataType &v) : data_(v) {} 62 | #endif 63 | virtual int pushToLua(lua_State *state) const { 64 | return util::push_args(state, data_); 65 | } 66 | 67 | private: 68 | DataType data_; 69 | }; 70 | // specialize for string literal 71 | template struct DataHolder : DataHolder { 72 | explicit DataHolder(const char *v) 73 | : DataHolder( 74 | std::string(v, v[N - 1] != '\0' ? v + N : v + N - 1)) {} 75 | }; 76 | template struct DataHolder : DataHolder { 77 | explicit DataHolder(const char *v) 78 | : DataHolder( 79 | std::string(v, v[N - 1] != '\0' ? v + N : v + N - 1)) {} 80 | }; 81 | standard::shared_ptr holder_; 82 | }; 83 | 84 | /// @ingroup lua_type_traits 85 | /// @brief lua_type_traits for AnyDataPusher 86 | template <> struct lua_type_traits { 87 | static int push(lua_State *l, const AnyDataPusher &data) { 88 | return data.pushToLua(l); 89 | } 90 | }; 91 | } 92 | -------------------------------------------------------------------------------- /test/test_20_max_arg_20.cpp: -------------------------------------------------------------------------------- 1 | #define KAGUYA_FUNCTION_MAX_ARGS 20 2 | #define KAGUYA_FUNCTION_MAX_OVERLOADS 25 3 | #include "kaguya/another_binding_api.hpp" 4 | #include "test_util.hpp" 5 | 6 | KAGUYA_TEST_GROUP_START(test_20_max_arg_20) 7 | using namespace kaguya_test_util; 8 | using namespace kaguya; 9 | 10 | void defargfn(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, 11 | int a9, int a10 = 10, int a11 = 11, int a12 = 12, int a13 = 13, 12 | int a14 = 14, int a15 = 15, int a16 = 16, int a17 = 17, 13 | int a18 = 18, int a19 = 19, int a20 = 20) { 14 | TEST_EQUAL(a1, 1); 15 | TEST_EQUAL(a2, 2); 16 | TEST_EQUAL(a3, 3); 17 | TEST_EQUAL(a4, 4); 18 | TEST_EQUAL(a5, 5); 19 | TEST_EQUAL(a6, 6); 20 | TEST_EQUAL(a7, 7); 21 | TEST_EQUAL(a8, 8); 22 | TEST_EQUAL(a9, 9); 23 | TEST_EQUAL(a10, 10); 24 | TEST_EQUAL(a11, 11); 25 | TEST_EQUAL(a12, 12); 26 | TEST_EQUAL(a13, 13); 27 | TEST_EQUAL(a14, 14); 28 | TEST_EQUAL(a15, 15); 29 | TEST_EQUAL(a16, 16); 30 | TEST_EQUAL(a17, 17); 31 | TEST_EQUAL(a18, 18); 32 | TEST_EQUAL(a19, 19); 33 | TEST_EQUAL(a20, 20); 34 | } 35 | 36 | KAGUYA_TEST_FUNCTION_DEF(many_arg_fn)(kaguya::State &state) { 37 | state["f"] = kaguya::function(&defargfn); 38 | state.dostring("f(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)"); 39 | } 40 | KAGUYA_FUNCTION_OVERLOADS(defargfn_wrapper, defargfn, 10, 20) 41 | 42 | KAGUYA_TEST_FUNCTION_DEF(defaultarguments)(kaguya::State &state) { 43 | state["defargfn"] = kaguya::function(defargfn_wrapper()); 44 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10)"); 45 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11)"); 46 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12)"); 47 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13)"); 48 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13,14)"); 49 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)"); 50 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)"); 51 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)"); 52 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)"); 53 | state.dostring("defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)"); 54 | state.dostring( 55 | "defargfn(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)"); 56 | } 57 | 58 | KAGUYA_TEST_FUNCTION_DEF(many_overloads)(kaguya::State &state) { 59 | state["defargfn"] = 60 | kaguya::UserdataMetatable() 61 | .setConstructors(); 68 | } 69 | 70 | KAGUYA_TEST_GROUP_END(test_20_max_arg_20) 71 | -------------------------------------------------------------------------------- /include/kaguya/exception.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | namespace kaguya { 12 | class LuaException : public std::exception { 13 | int status_; 14 | std::string what_; 15 | const char *what_c_; 16 | 17 | public: 18 | LuaException(int status, const char *what) throw() 19 | : status_(status), what_c_(what) {} 20 | LuaException(int status, const std::string &what) 21 | : status_(status), what_(what), what_c_(0) {} 22 | int status() const throw() { return status_; } 23 | const char *what() const throw() { return what_c_ ? what_c_ : what_.c_str(); } 24 | 25 | ~LuaException() throw() {} 26 | }; 27 | class KaguyaException : public std::exception { 28 | std::string what_; 29 | const char *what_c_; 30 | 31 | public: 32 | KaguyaException(const char *what) throw() : what_c_(what) {} 33 | KaguyaException(const std::string &what) : what_(what), what_c_(0) {} 34 | const char *what() const throw() { return what_c_ ? what_c_ : what_.c_str(); } 35 | 36 | ~KaguyaException() throw() {} 37 | }; 38 | class LuaTypeMismatch : public LuaException { 39 | public: 40 | LuaTypeMismatch() throw() : LuaException(0, "type mismatch!!") {} 41 | LuaTypeMismatch(const char *what) throw() : LuaException(0, what) {} 42 | LuaTypeMismatch(const std::string &what) : LuaException(0, what) {} 43 | }; 44 | class LuaMemoryError : public LuaException { 45 | public: 46 | LuaMemoryError(int status, const char *what) throw() 47 | : LuaException(status, what) {} 48 | LuaMemoryError(int status, const std::string &what) 49 | : LuaException(status, what) {} 50 | }; 51 | class LuaRuntimeError : public LuaException { 52 | public: 53 | LuaRuntimeError(int status, const char *what) throw() 54 | : LuaException(status, what) {} 55 | LuaRuntimeError(int status, const std::string &what) 56 | : LuaException(status, what) {} 57 | }; 58 | class LuaErrorRunningError : public LuaException { 59 | public: 60 | LuaErrorRunningError(int status, const char *what) throw() 61 | : LuaException(status, what) {} 62 | LuaErrorRunningError(int status, const std::string &what) 63 | : LuaException(status, what) {} 64 | }; 65 | class LuaGCError : public LuaException { 66 | public: 67 | LuaGCError(int status, const char *what) throw() 68 | : LuaException(status, what) {} 69 | LuaGCError(int status, const std::string &what) 70 | : LuaException(status, what) {} 71 | }; 72 | class LuaUnknownError : public LuaException { 73 | public: 74 | LuaUnknownError(int status, const char *what) throw() 75 | : LuaException(status, what) {} 76 | LuaUnknownError(int status, const std::string &what) 77 | : LuaException(status, what) {} 78 | }; 79 | 80 | class LuaSyntaxError : public LuaException { 81 | public: 82 | LuaSyntaxError(int status, const std::string &what) 83 | : LuaException(status, what) {} 84 | }; 85 | 86 | namespace except { 87 | void OtherError(lua_State *state, const std::string &message); 88 | void typeMismatchError(lua_State *state, const std::string &message); 89 | void memoryError(lua_State *state, const char *message); 90 | bool checkErrorAndThrow(int status, lua_State *state); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /utils/generate_preprocess_macro.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import sys 4 | import re 5 | import argparse 6 | 7 | def gen_repeate_macro(out,format,count,start=1): 8 | for num in range(start, count): 9 | out.write(format.format(no=num,dec=num-1,inc=num+1)) 10 | out.write('\n') 11 | 12 | def KAGUYA_PP_REPEAT(out,count): 13 | out.write('#define KAGUYA_PP_REPEAT0(MACRO)\n') 14 | gen_repeate_macro(out,'#define KAGUYA_PP_REPEAT{no}(MACRO) KAGUYA_PP_REPEAT{dec}(MACRO) MACRO({no})',count) 15 | out.write('#define KAGUYA_PP_REPEAT(COUNT,MACRO) KAGUYA_PP_CAT(KAGUYA_PP_REPEAT,COUNT)(MACRO)\n') 16 | 17 | def KAGUYA_PP_REPEAT_DEF(out,count): 18 | out.write('#define KAGUYA_PP_REPEAT_DEF0(MACRO)\n') 19 | gen_repeate_macro(out,'#define KAGUYA_PP_REPEAT_DEF{no}(MACRO) KAGUYA_PP_REPEAT_DEF{dec}(MACRO) MACRO({no})',count) 20 | out.write('#define KAGUYA_PP_REPEAT_DEF(COUNT,MACRO) KAGUYA_PP_CAT(KAGUYA_PP_REPEAT_DEF,COUNT)(MACRO)\n') 21 | 22 | def KAGUYA_PP_REVERSE_REPEAT(out,count): 23 | out.write('#define KAGUYA_PP_REVERSE_REPEAT0(MACRO)\n') 24 | gen_repeate_macro(out,'#define KAGUYA_PP_REVERSE_REPEAT{no}(MACRO) MACRO({no}) KAGUYA_PP_REVERSE_REPEAT{dec}(MACRO)',count) 25 | out.write('#define KAGUYA_PP_REVERSE_REPEAT(COUNT,MACRO) KAGUYA_PP_CAT(KAGUYA_PP_REVERSE_REPEAT,COUNT)(MACRO)\n') 26 | 27 | def KAGUYA_PP_REPEAT_ARG(out,count): 28 | out.write('#define KAGUYA_PP_REPEAT_ARG0(MACRO)\n') 29 | out.write('#define KAGUYA_PP_REPEAT_ARG1(MACRO) MACRO(1)\n') 30 | gen_repeate_macro(out,'#define KAGUYA_PP_REPEAT_ARG{no}(MACRO) KAGUYA_PP_REPEAT_ARG{dec}(MACRO), MACRO({no})',count,2) 31 | out.write('#define KAGUYA_PP_REPEAT_ARG(COUNT,MACRO) KAGUYA_PP_CAT(KAGUYA_PP_REPEAT_ARG,COUNT)(MACRO)\n') 32 | 33 | def KAGUYA_PP_REPEAT_DEF_VA_ARG(out,count): 34 | out.write('#define KAGUYA_PP_REPEAT_DEF_VA_ARG0(MACRO, ...)\n') 35 | gen_repeate_macro(out,'#define KAGUYA_PP_REPEAT_DEF_VA_ARG{no}(MACRO, ...) KAGUYA_VA_ARG(KAGUYA_PP_REPEAT_DEF_VA_ARG{dec}(MACRO,__VA_ARGS__) MACRO({no},__VA_ARGS__))',count) 36 | out.write('#define KAGUYA_PP_REPEAT_DEF_VA_ARG(COUNT,MACRO, ...) KAGUYA_VA_ARG(KAGUYA_PP_CAT(KAGUYA_PP_REPEAT_DEF_VA_ARG,COUNT)(MACRO,__VA_ARGS__))\n') 37 | 38 | def KAGUYA_PP_WHILE(out,count): 39 | out.write('#define KAGUYA_PP_WHILE0(MACRO,R) R\n') 40 | gen_repeate_macro(out,'#define KAGUYA_PP_WHILE{no}(MACRO,R) MACRO(KAGUYA_PP_WHILE{dec}(MACRO,R))',count) 41 | out.write('#define KAGUYA_PP_WHILE(COUNT,R,MACRO) KAGUYA_PP_CAT(KAGUYA_PP_WHILE,COUNT)(MACRO,R)\n') 42 | 43 | 44 | def KAGUYA_PP_INC(out,count): 45 | gen_repeate_macro(out,'#define KAGUYA_PP_INC{no} {inc}',count,0) 46 | out.write('#define KAGUYA_PP_INC(N) KAGUYA_PP_CAT(KAGUYA_PP_INC,N)\n') 47 | 48 | def KAGUYA_PP_DEC(out,count): 49 | gen_repeate_macro(out,'#define KAGUYA_PP_DEC{no} {dec}',count) 50 | out.write('#define KAGUYA_PP_DEC(N) KAGUYA_PP_CAT(KAGUYA_PP_DEC,N)\n') 51 | 52 | if __name__ == "__main__": 53 | parser = argparse.ArgumentParser() 54 | parser.add_argument("count", help="count of generate macro",type=int) 55 | args = parser.parse_args() 56 | out = sys.stdout 57 | out.write('//generated by '+__file__+'\n') 58 | out.write('#pragma once\n') 59 | KAGUYA_PP_REPEAT(out,args.count) 60 | out.write('\n\n') 61 | KAGUYA_PP_REPEAT_DEF(out,args.count) 62 | out.write('\n\n') 63 | KAGUYA_PP_REVERSE_REPEAT(out,args.count) 64 | out.write('\n\n') 65 | KAGUYA_PP_REPEAT_ARG(out,args.count) 66 | out.write('\n\n') 67 | KAGUYA_PP_REPEAT_DEF_VA_ARG(out,args.count) 68 | out.write('\n\n') 69 | KAGUYA_PP_WHILE(out,args.count) 70 | out.write('\n\n') 71 | KAGUYA_PP_INC(out,args.count) 72 | out.write('\n\n') 73 | KAGUYA_PP_DEC(out,args.count) 74 | -------------------------------------------------------------------------------- /benchmark/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include 3 | #include "benchmark_function.hpp" 4 | 5 | 6 | 7 | typedef void(*benchmark_function_t)(kaguya::State&); 8 | typedef std::vector > benchmark_function_map_t; 9 | void empty(kaguya::State&) 10 | { 11 | 12 | } 13 | 14 | void execute_benchmark(const benchmark_function_map_t& testmap) 15 | { 16 | std::map scoremap; 17 | 18 | for (benchmark_function_map_t::const_iterator it = testmap.begin(); it != testmap.end(); ++it) 19 | { 20 | const std::string& test_name = it->first; 21 | 22 | 23 | double mintime = std::numeric_limits::max(); 24 | 25 | kaguya::State clockstate; 26 | 27 | static const int N = 10; 28 | for (int i = 0; i < N; ++i) 29 | { 30 | double start = clockstate["os"]["clock"](); 31 | { 32 | kaguya::State state; 33 | it->second(state); 34 | } 35 | 36 | double end = clockstate["os"]["clock"](); 37 | mintime = std::min(mintime, end - start); 38 | } 39 | 40 | scoremap[test_name] = mintime; 41 | std::cerr << test_name << "," << mintime << std::endl; 42 | } 43 | 44 | 45 | for (benchmark_function_map_t::const_iterator it = testmap.begin(); it != testmap.end(); ++it) 46 | { 47 | std::cout << it->first << ","; 48 | } 49 | std::cout << std::endl; 50 | 51 | for (benchmark_function_map_t::const_iterator it = testmap.begin(); it != testmap.end(); ++it) 52 | { 53 | std::cout << scoremap[it->first] << ","; 54 | } 55 | std::cout << std::endl; 56 | } 57 | 58 | 59 | int main() 60 | { 61 | benchmark_function_map_t functionmap; 62 | #define ADD_BENCHMARK(function) functionmap.push_back(std::make_pair(#function,&function)); 63 | ADD_BENCHMARK(empty); 64 | ADD_BENCHMARK(plain_api::simple_get_set); 65 | ADD_BENCHMARK(kaguyaapi::simple_get_set); 66 | 67 | ADD_BENCHMARK(kaguyaapi::simple_get_set_raw_ptr); 68 | ADD_BENCHMARK(kaguyaapi::simple_get_set_shared_ptr); 69 | #if KAGUYA_USE_CPP11 70 | ADD_BENCHMARK(kaguyaapi::simple_get_set_unique_ptr); 71 | ADD_BENCHMARK(kaguyaapi::simple_get_set_contain_property_member); 72 | #endif 73 | // ADD_BENCHMARK(plain_api::object_get_set); 74 | ADD_BENCHMARK(kaguyaapi::new_construct); 75 | ADD_BENCHMARK(kaguyaapi::call_construct); 76 | 77 | ADD_BENCHMARK(kaguyaapi::object_get_set); 78 | ADD_BENCHMARK(kaguyaapi::object_get_set_property); 79 | ADD_BENCHMARK(kaguyaapi::object_get_set_property_function); 80 | ADD_BENCHMARK(kaguyaapi::object_to_table_get_set); 81 | ADD_BENCHMARK(kaguyaapi::object_to_table_property); 82 | ADD_BENCHMARK(kaguyaapi::overloaded_get_set); 83 | ADD_BENCHMARK(kaguyaapi::property_access); 84 | 85 | ADD_BENCHMARK(kaguyaapi::multiple_inheritance_get_set); 86 | ADD_BENCHMARK(kaguyaapi::multiple_inheritance_property); 87 | 88 | ADD_BENCHMARK(kaguyaapi::call_native_function); 89 | ADD_BENCHMARK(plain_api::call_native_function); 90 | ADD_BENCHMARK(kaguyaapi::call_lua_function); 91 | ADD_BENCHMARK(plain_api::call_lua_function); 92 | ADD_BENCHMARK(kaguyaapi::call_lua_function_operator_functional); 93 | ADD_BENCHMARK(kaguyaapi::lua_table_access); 94 | ADD_BENCHMARK(plain_api::lua_table_access); 95 | ADD_BENCHMARK(kaguyaapi::lua_table_bracket_operator_access); 96 | ADD_BENCHMARK(kaguyaapi::lua_table_bracket_operator_assign); 97 | ADD_BENCHMARK(kaguyaapi::lua_table_bracket_operator_get); 98 | ADD_BENCHMARK(kaguyaapi::lua_table_bracket_const_operator_get); 99 | 100 | ADD_BENCHMARK(kaguyaapi::lua_allocation); 101 | ADD_BENCHMARK(plain_api::lua_allocation); 102 | 103 | ADD_BENCHMARK(kaguyaapi::table_to_vector); 104 | ADD_BENCHMARK(kaguyaapi::table_to_vector_with_typecheck); 105 | 106 | 107 | ADD_BENCHMARK(kaguyaapi::vector_to_table); 108 | 109 | execute_benchmark(functionmap); 110 | 111 | } 112 | -------------------------------------------------------------------------------- /include/kaguya/detail/lua_variant_def.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include "kaguya/detail/lua_function_def.hpp" 9 | #include "kaguya/detail/lua_table_def.hpp" 10 | 11 | namespace kaguya { 12 | class LuaRef; 13 | class LuaTable; 14 | template class TableKeyReferenceProxy; 15 | class MemberFunctionBinder; 16 | 17 | namespace detail { 18 | 19 | template 20 | class LuaVariantImpl : public LuaTableImpl, 21 | public LuaTableOrUserDataImpl, 22 | public detail::LuaFunctionImpl, 23 | public detail::LuaThreadImpl, 24 | public LuaBasicTypeFunctions { 25 | private: 26 | lua_State *state_() const { 27 | return static_cast(this)->state(); 28 | } 29 | int pushStackIndex_(lua_State *state) const { 30 | return static_cast(this)->pushStackIndex(state); 31 | } 32 | 33 | public: 34 | using LuaBasicTypeFunctions::type; 35 | using LuaBasicTypeFunctions::typeName; 36 | 37 | /// @brief deprecated, use isType instead. 38 | template bool typeTest() const { return isType(); } 39 | 40 | /// @brief deprecated, use isConvertible instead. 41 | template bool weakTypeTest() const { return isConvertible(); } 42 | 43 | /// @brief is type test 44 | template bool isType() const { 45 | lua_State *state = state_(); 46 | util::ScopedSavedStack save(state); 47 | return lua_type_traits::strictCheckType(state, pushStackIndex_(state)); 48 | } 49 | 50 | template bool isConvertible() const { 51 | lua_State *state = state_(); 52 | util::ScopedSavedStack save(state); 53 | return lua_type_traits::checkType(state, pushStackIndex_(state)); 54 | } 55 | 56 | template typename lua_type_traits::get_type get() const { 57 | lua_State *state = state_(); 58 | util::ScopedSavedStack save(state); 59 | return lua_type_traits::get(state, state ? pushStackIndex_(state) : 0); 60 | } 61 | template 62 | typename lua_type_traits::get_type value_or(U v) const { 63 | lua_State *state = state_(); 64 | util::ScopedSavedStack save(state); 65 | return lua_type_traits >::get( 66 | state, state ? pushStackIndex_(state) : 0) 67 | .value_or(v); 68 | } 69 | 70 | // deprecated. use get >() instead; 71 | template 72 | typename lua_type_traits::get_type 73 | get(bool &was_valid, bool allow_convertible = true) const { 74 | lua_State *state = state_(); 75 | util::ScopedSavedStack save(state); 76 | int stackindex = pushStackIndex_(state); 77 | if (allow_convertible) { 78 | was_valid = lua_type_traits::checkType(state, stackindex); 79 | } else { 80 | was_valid = lua_type_traits::strictCheckType(state, stackindex); 81 | } 82 | if (was_valid) { 83 | return lua_type_traits::get(state, stackindex); 84 | } else { 85 | return T(); 86 | } 87 | } 88 | template operator T() const { return get(); } 89 | 90 | #if KAGUYA_USE_CPP11 91 | template FunctionResults operator()(Args &&... args); 92 | #else 93 | inline FunctionResults operator()(); 94 | 95 | #define KAGUYA_OP_FN_DEF(N) \ 96 | template \ 97 | inline FunctionResults operator()(KAGUYA_PP_ARG_CR_DEF_REPEAT(N)); 98 | 99 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_OP_FN_DEF) 100 | #undef KAGUYA_OP_FN_DEF 101 | #endif 102 | }; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_LEGACY_CYGWIN_WIN32 0) 2 | cmake_minimum_required(VERSION 3.16..3.20) 3 | project(Kaguya) 4 | 5 | include(cmake/FindLua.cmake) 6 | 7 | 8 | option(KAGUYA_BUILD_EXAMPLES "Build the Kaguya example programs" ON) 9 | option(KAGUYA_BUILD_BENCHMARK "Build the Kaguya benchmark programs" OFF) 10 | option(KAGUYA_BUILD_EXAMPLE_GLFW_BIND "Build the Kaguya example glfw bind" OFF) 11 | option(KAGUYA_SINGLE_HEADER_VERSION "generate single header" OFF) 12 | 13 | include_directories(SYSTEM ${LUA_INCLUDE_DIRS}) 14 | link_directories(${LUA_LIBRARY_DIRS}) 15 | 16 | 17 | find_package(Boost) 18 | if(Boost_INCLUDE_DIR) 19 | include_directories(SYSTEM ${Boost_INCLUDE_DIR}) 20 | endif(Boost_INCLUDE_DIR) 21 | 22 | 23 | if(KAGUYA_SINGLE_HEADER_VERSION) 24 | file(MAKE_DIRECTORY single_include/kaguya) 25 | file(COPY include/kaguya/another_binding_api.hpp DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/single_include/kaguya/) 26 | execute_process( 27 | COMMAND python generate_one_header.py 28 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/utils OUTPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/single_include/kaguya/kaguya.hpp) 29 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/single_include") 30 | 31 | else(KAGUYA_SINGLE_HEADER_VERSION) 32 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include") 33 | endif(KAGUYA_SINGLE_HEADER_VERSION) 34 | 35 | file(GLOB KAGUYA_HEADER RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 36 | include/kaguya/*.hpp 37 | include/kaguya/detail/*.hpp) 38 | 39 | if(ADDITIONAL_INCLUDE_PATH) 40 | include_directories(SYSTEM ${ADDITIONAL_INCLUDE_PATH}) 41 | endif() 42 | 43 | if(NOT MSVC)#-Wall nonsense on MSVC 44 | add_definitions(-Wall -W -Werror) 45 | add_definitions(-pedantic) 46 | add_definitions(-Wno-variadic-macros) 47 | add_definitions ("-Wno-unused-local-typedefs") 48 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13) 49 | add_definitions(-Wno-dangling-reference) 50 | endif() 51 | add_definitions ("-Wno-unknown-warning-option") 52 | #add_definitions("-std=c++11") 53 | endif(NOT MSVC) 54 | 55 | 56 | if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") 57 | add_definitions ("-fno-strict-overflow") 58 | endif() 59 | 60 | if(KAGUYA_NO_USERDATA_TYPE_CHECK) 61 | add_definitions("-DKAGUYA_NO_USERDATA_TYPE_CHECK=1") 62 | endif() 63 | 64 | if(KAGUYA_USE_SHARED_LUAREF) 65 | add_definitions("-DKAGUYA_USE_SHARED_LUAREF=1") 66 | endif() 67 | 68 | if(EMSCRIPTEN) 69 | include_directories(SYSTEM "${EMSCRIPTEN_ROOT_PATH}/system/lib/libcxxabi/include/") 70 | add_definitions("-std=c++11") 71 | set(CMAKE_EXECUTABLE_SUFFIX ".html") 72 | endif(EMSCRIPTEN) 73 | 74 | #check for address sanitizer support 75 | if(NOT DISABLE_ADDRESS_SANITIZER) 76 | if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") 77 | if (${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 4.8) 78 | set(HAVE_FLAG_SANITIZE_ADDRESS TRUE) 79 | endif() 80 | elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") 81 | if (${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 3.2) 82 | set(HAVE_FLAG_SANITIZE_ADDRESS TRUE) 83 | endif() 84 | #detect stack-buffer-overflow at clang++3.4(on ubuntu 12.04) with luajit but don't know reason 85 | if(${CMAKE_CXX_COMPILER_VERSION} VERSION_EQUAL 3.4) 86 | if(${LUA_SEARCH_LIB_NAME} STREQUAL "luajit") 87 | unset(HAVE_FLAG_SANITIZE_ADDRESS) 88 | endif() 89 | endif() 90 | endif() 91 | if(CYGWIN OR WIN32) 92 | unset(HAVE_FLAG_SANITIZE_ADDRESS) 93 | endif() 94 | endif(NOT DISABLE_ADDRESS_SANITIZER) 95 | 96 | if(KAGUYA_BUILD_BENCHMARK) 97 | set(BENCHMARK_SRCS benchmark/benchmark.cpp benchmark/benchmark_function.cpp benchmark/benchmark_function.hpp) 98 | add_executable(benchmark ${BENCHMARK_SRCS} ${KAGUYA_HEADER}) 99 | target_link_libraries(benchmark ${LUA_LIBRARIES}) 100 | endif(KAGUYA_BUILD_BENCHMARK) 101 | 102 | if(KAGUYA_BUILD_EXAMPLES) 103 | add_subdirectory(examples) 104 | endif(KAGUYA_BUILD_EXAMPLES) 105 | 106 | if(EMSCRIPTEN) 107 | if(KAGUYA_BUILD_BENCHMARK) 108 | SET_TARGET_PROPERTIES(benchmark PROPERTIES LINK_FLAGS "-s DEMANGLE_SUPPORT=1 -s TOTAL_MEMORY=36777216") 109 | endif(KAGUYA_BUILD_BENCHMARK) 110 | endif(EMSCRIPTEN) 111 | 112 | 113 | enable_testing() 114 | add_subdirectory(test) 115 | -------------------------------------------------------------------------------- /include/kaguya/config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | 7 | #include 8 | extern "C" { 9 | #include 10 | #include 11 | #include 12 | } 13 | 14 | #ifndef KAGUYA_USE_CPP11 15 | #if defined(__cpp_decltype) || __cplusplus >= 201103L || \ 16 | (defined(_MSC_VER) && _MSC_VER >= 1800) 17 | #define KAGUYA_USE_CPP11 1 18 | #else 19 | #define KAGUYA_USE_CPP11 0 20 | #endif 21 | #endif 22 | 23 | #if KAGUYA_USE_CPP11 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #else 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #endif 40 | 41 | #ifndef KAGUYA_NO_USERDATA_TYPE_CHECK 42 | #define KAGUYA_NO_USERDATA_TYPE_CHECK 0 43 | #endif 44 | 45 | //If you want use registered class by kaguya between multiple shared library, 46 | //please switch to 1 for KAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY and KAGUYA_NAME_BASED_TYPE_CHECK 47 | #ifndef KAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY 48 | #define KAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY 0 49 | #endif 50 | 51 | #ifndef KAGUYA_NAME_BASED_TYPE_CHECK 52 | #define KAGUYA_NAME_BASED_TYPE_CHECK KAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY 53 | #endif 54 | 55 | #ifndef KAGUYA_USE_RVALUE_REFERENCE 56 | #if KAGUYA_USE_CPP11 57 | #define KAGUYA_USE_RVALUE_REFERENCE 1 58 | #else 59 | #define KAGUYA_USE_RVALUE_REFERENCE 0 60 | #endif 61 | #endif 62 | 63 | #ifdef KAGUYA_NO_VECTOR_AND_MAP_TO_TABLE 64 | #define KAGUYA_NO_STD_VECTOR_TO_TABLE 65 | #define KAGUYA_NO_STD_MAP_TO_TABLE 66 | #endif 67 | 68 | #if !KAGUYA_USE_CPP11 69 | #ifndef KAGUYA_FUNCTION_MAX_ARGS 70 | ///! max argument number for binding function. this define used C++03 only. 71 | #define KAGUYA_FUNCTION_MAX_ARGS 9 72 | #endif 73 | 74 | #ifndef KAGUYA_FUNCTION_MAX_TUPLE_SIZE 75 | ///! this define used C++03 only. 76 | #define KAGUYA_FUNCTION_MAX_TUPLE_SIZE 9 77 | #endif 78 | 79 | #ifndef KAGUYA_FUNCTION_MAX_OVERLOADS 80 | #define KAGUYA_FUNCTION_MAX_OVERLOADS 9 81 | #endif 82 | 83 | #endif 84 | 85 | #ifndef KAGUYA_CLASS_MAX_BASE_CLASSES 86 | #define KAGUYA_CLASS_MAX_BASE_CLASSES 9 87 | #endif 88 | 89 | #ifndef KAGUYA_USE_CXX_ABI_DEMANGLE 90 | #if defined(__GNUC__) || defined(__clang__) 91 | #define KAGUYA_USE_CXX_ABI_DEMANGLE 1 92 | #else 93 | #define KAGUYA_USE_CXX_ABI_DEMANGLE 0 94 | #endif 95 | #endif 96 | 97 | #ifndef KAGUYA_USE_SHARED_LUAREF 98 | #define KAGUYA_USE_SHARED_LUAREF 0 99 | #endif 100 | 101 | #ifndef KAGUYA_NOEXCEPT 102 | #if KAGUYA_USE_CPP11 && (!defined(_MSC_VER) || _MSC_VER >= 1900) 103 | #define KAGUYA_NOEXCEPT noexcept 104 | #else 105 | #define KAGUYA_NOEXCEPT throw() 106 | #endif 107 | #endif 108 | 109 | #ifndef KAGUYA_DEPRECATED_FEATURE 110 | #if __cplusplus >= 201402L && defined(__has_cpp_attribute) 111 | #if __has_cpp_attribute(deprecated) 112 | // C++ standard deprecated 113 | #define KAGUYA_DEPRECATED_FEATURE(MSG) [[deprecated(MSG)]] 114 | #endif 115 | #endif 116 | #endif 117 | #ifndef KAGUYA_DEPRECATED_FEATURE 118 | #if defined(_MSC_VER) 119 | // MSVC deprecated 120 | #define KAGUYA_DEPRECATED_FEATURE(MSG) __declspec(deprecated(MSG)) 121 | #elif defined(__GNUC__) || defined(__clang__) 122 | #define KAGUYA_DEPRECATED_FEATURE(MSG) __attribute__((deprecated)) 123 | #else 124 | #define KAGUYA_DEPRECATED_FEATURE(MSG) 125 | #endif 126 | 127 | #endif 128 | 129 | #define KAGUYA_UNUSED(V) (void)(V) 130 | 131 | namespace kaguya { 132 | #if defined(_MSC_VER) && _MSC_VER <= 1500 133 | typedef unsigned char uint8_t; 134 | typedef int int32_t; 135 | typedef long long int64_t; 136 | #endif 137 | 138 | namespace standard { 139 | #if KAGUYA_USE_CPP11 140 | using namespace std; 141 | #define KAGUYA_STATIC_ASSERT static_assert 142 | 143 | #else 144 | using namespace boost; 145 | #define KAGUYA_STATIC_ASSERT BOOST_STATIC_ASSERT_MSG 146 | #endif 147 | } 148 | 149 | #if LUA_VERSION_NUM > 502 150 | typedef lua_Integer luaInt; 151 | #else 152 | typedef int32_t luaInt; 153 | #endif 154 | } 155 | -------------------------------------------------------------------------------- /include/kaguya/compatibility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | 7 | #include "kaguya/config.hpp" 8 | 9 | namespace kaguya { 10 | // for lua version compatibility 11 | namespace compat { 12 | #if LUA_VERSION_NUM >= 504 13 | #elif LUA_VERSION_NUM < 502 14 | inline int lua_resume(lua_State *L, lua_State *from, int nargs, int* nresults) { 15 | KAGUYA_UNUSED(from); 16 | *nresults = 1; 17 | return ::lua_resume(L, nargs); 18 | } 19 | #else 20 | inline int lua_resume(lua_State *L, lua_State *from, int nargs, int* nresults) { 21 | *nresults = 1; 22 | return ::lua_resume(L, from, nargs); 23 | } 24 | #endif 25 | #if LUA_VERSION_NUM >= 503 26 | inline int lua_rawgetp_rtype(lua_State *L, int idx, const void *ptr) { 27 | return lua_rawgetp(L, idx, ptr); 28 | } 29 | inline int lua_rawget_rtype(lua_State *L, int idx) { 30 | return lua_rawget(L, idx); 31 | } 32 | inline int lua_getfield_rtype(lua_State *L, int idx, const char *k) { 33 | return lua_getfield(L, idx, k); 34 | } 35 | inline int lua_gettable_rtype(lua_State *L, int idx) { 36 | return lua_gettable(L, idx); 37 | } 38 | #elif LUA_VERSION_NUM == 502 39 | inline int lua_rawgetp_rtype(lua_State *L, int idx, const void *ptr) { 40 | lua_rawgetp(L, idx, ptr); 41 | return lua_type(L, -1); 42 | } 43 | #elif LUA_VERSION_NUM < 502 44 | enum LUA_OPEQ { LUA_OPEQ, LUA_OPLT, LUA_OPLE }; 45 | inline int lua_compare(lua_State *L, int index1, int index2, int op) { 46 | switch (op) { 47 | case LUA_OPEQ: 48 | return lua_equal(L, index1, index2); 49 | case LUA_OPLT: 50 | return lua_lessthan(L, index1, index2); 51 | case LUA_OPLE: 52 | return lua_equal(L, index1, index2) || lua_lessthan(L, index1, index2); 53 | default: 54 | return 0; 55 | } 56 | } 57 | 58 | inline void lua_pushglobaltable(lua_State *L) { 59 | lua_pushvalue(L, LUA_GLOBALSINDEX); 60 | } 61 | inline size_t lua_rawlen(lua_State *L, int index) { 62 | int type = lua_type(L, index); 63 | if (type != LUA_TSTRING && type != LUA_TTABLE && type != LUA_TUSERDATA && 64 | type != LUA_TLIGHTUSERDATA) { 65 | return 0; 66 | } 67 | return lua_objlen(L, index); 68 | } 69 | 70 | inline int lua_absindex(lua_State *L, int idx) { 71 | return (idx > 0 || (idx <= LUA_REGISTRYINDEX)) ? idx 72 | : lua_gettop(L) + 1 + idx; 73 | } 74 | inline int lua_rawgetp_rtype(lua_State *L, int idx, const void *ptr) { 75 | int absidx = lua_absindex(L, idx); 76 | lua_pushlightuserdata(L, (void *)ptr); 77 | lua_rawget(L, absidx); 78 | return lua_type(L, -1); 79 | } 80 | inline void lua_rawsetp(lua_State *L, int idx, const void *ptr) { 81 | int absidx = lua_absindex(L, idx); 82 | lua_pushvalue(L, -1); 83 | lua_pushlightuserdata(L, (void *)ptr); 84 | lua_replace(L, -3); 85 | lua_rawset(L, absidx); 86 | } 87 | inline void luaL_requiref(lua_State *L, const char *modname, 88 | lua_CFunction openf, int glb) { 89 | 90 | lua_pushcfunction(L, openf); 91 | lua_pushstring(L, modname); 92 | lua_call(L, 1, 1); 93 | 94 | if (glb) { 95 | lua_pushvalue(L, -1); 96 | lua_setglobal(L, modname); 97 | } 98 | } 99 | inline lua_Number lua_tonumberx(lua_State *L, int index, int *isnum) { 100 | if (isnum) { 101 | *isnum = lua_isnumber(L, index); 102 | } 103 | return lua_tonumber(L, index); 104 | } 105 | #endif 106 | #if LUA_VERSION_NUM < 503 107 | inline void lua_seti(lua_State *L, int index, lua_Integer n) { 108 | int absidx = lua_absindex(L, index); 109 | lua_pushvalue(L, -1); 110 | lua_pushinteger(L, n); 111 | lua_replace(L, -3); 112 | lua_rawset(L, absidx); 113 | } 114 | inline int lua_geti(lua_State *L, int index, lua_Integer i) { 115 | int absidx = lua_absindex(L, index); 116 | lua_pushinteger(L, i); 117 | lua_rawget(L, absidx); 118 | return lua_type(L, -1); 119 | } 120 | inline int lua_getfield_rtype(lua_State *L, int idx, const char *k) { 121 | lua_getfield(L, idx, k); 122 | return lua_type(L, -1); 123 | } 124 | inline int lua_gettable_rtype(lua_State *L, int idx) { 125 | lua_gettable(L, idx); 126 | return lua_type(L, -1); 127 | } 128 | inline int lua_rawget_rtype(lua_State *L, int idx) { 129 | lua_rawget(L, idx); 130 | return lua_type(L, -1); 131 | } 132 | #endif 133 | #if LUA_VERSION_NUM < 501 134 | void lua_createtable(lua_State *L, int narr, int nrec) { lua_newtable(L); } 135 | #endif 136 | } 137 | 138 | using namespace compat; 139 | } 140 | -------------------------------------------------------------------------------- /include/kaguya/utility_cxx11.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "kaguya/config.hpp" 10 | 11 | namespace kaguya { 12 | namespace util { 13 | struct null_type {}; 14 | 15 | template struct TypeTuple {}; 16 | template struct FunctionSignatureType { 17 | typedef Ret result_type; 18 | typedef TypeTuple argument_type_tuple; 19 | static const size_t argument_count = sizeof...(Args); 20 | typedef Ret (*c_function_type)(Args...); 21 | }; 22 | template struct FunctorSignature {}; 23 | 24 | template 25 | struct FunctorSignature { 26 | typedef FunctionSignatureType type; 27 | }; 28 | template 29 | struct FunctorSignature { 30 | typedef FunctionSignatureType type; 31 | }; 32 | 33 | #if defined(_MSC_VER) && _MSC_VER < 1900 34 | template 35 | struct FunctionSignature : public FunctorSignature {}; 36 | #else 37 | 38 | template struct FunctionSignature; 39 | 40 | template 41 | struct has_operator_fn : std::false_type {}; 42 | template 43 | struct has_operator_fn::value>::type> 45 | : std::true_type {}; 46 | 47 | template 48 | struct FunctionSignature< 49 | T, typename std::enable_if::value>::type> 50 | : public FunctorSignature {}; 51 | #endif 52 | 53 | template 54 | struct FunctionSignature { 55 | typedef FunctionSignatureType type; 56 | }; 57 | template 58 | struct FunctionSignature { 59 | typedef FunctionSignatureType type; 60 | }; 61 | 62 | #if defined(_MSC_VER) && _MSC_VER >= 1900 || defined(__cpp_ref_qualifiers) 63 | template 64 | struct FunctionSignature { 65 | typedef FunctionSignatureType type; 66 | }; 67 | template 68 | struct FunctionSignature { 69 | typedef FunctionSignatureType type; 70 | }; 71 | #endif 72 | 73 | template struct FunctionSignature { 74 | typedef FunctionSignatureType type; 75 | }; 76 | template struct FunctionSignature { 77 | typedef FunctionSignatureType type; 78 | }; 79 | 80 | template struct FunctionResultType { 81 | typedef typename FunctionSignature::type::result_type type; 82 | }; 83 | 84 | template 85 | struct TypeIndexGet; 86 | 87 | template 88 | struct TypeIndexGet, true> { 89 | typedef Arg type; 90 | }; 91 | 92 | template 93 | struct TypeIndexGet, false> 94 | : TypeIndexGet > {}; 95 | template struct ArgumentType { 96 | typedef typename TypeIndexGet< 97 | N, typename FunctionSignature::type::argument_type_tuple>::type type; 98 | }; 99 | 100 | namespace detail { 101 | template 102 | auto invoke_helper(F &&f, ThisType &&this_, Args &&... args) 103 | -> decltype((std::forward(this_).* 104 | f)(std::forward(args)...)) { 105 | return (std::forward(this_).*f)(std::forward(args)...); 106 | } 107 | 108 | template 109 | auto invoke_helper(F &&f, Args &&... args) 110 | -> decltype(f(std::forward(args)...)) { 111 | return f(std::forward(args)...); 112 | } 113 | } 114 | template 115 | typename FunctionResultType::type>::type 116 | invoke(F &&f, Args &&... args) { 117 | return detail::invoke_helper(std::forward(f), std::forward(args)...); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /include/kaguya/function_tuple_def.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "kaguya/config.hpp" 10 | #include "kaguya/utility.hpp" 11 | #include "kaguya/preprocess.hpp" 12 | 13 | namespace kaguya { 14 | namespace fntuple { 15 | 16 | #if KAGUYA_USE_CPP11 && !defined(KAGUYA_FUNCTION_MAX_OVERLOADS) 17 | // In Clang with libstdc++. 18 | // std::tuple elements is limited to 16 for template depth limit 19 | using std::tuple; 20 | using std::get; 21 | using std::tuple_element; 22 | using std::tuple_size; 23 | #else 24 | using util::null_type; 25 | // boost::tuple is max 26 | #define KAGUYA_PP_STRUCT_TDEF_REP(N) KAGUYA_PP_CAT(typename A, N) = null_type 27 | #define KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(N) \ 28 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_STRUCT_TDEF_REP) 29 | 30 | template 32 | struct tuple {}; 33 | #undef KAGUYA_PP_STRUCT_TDEF_REP 34 | #undef KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT 35 | 36 | #define KAGUYA_FUNCTION_TUPLE_ELEMENT(N) \ 37 | KAGUYA_PP_CAT(A, N) KAGUYA_PP_CAT(elem, N); 38 | #define KAGUYA_FUNCTION_TUPLE_ELEMENT_INIT(N) \ 39 | KAGUYA_PP_CAT(elem, N)(KAGUYA_PP_CAT(a, N)) 40 | #define KAGUYA_FUNCTION_TUPLE_IMPL_DEF(N) \ 41 | template \ 42 | struct tuple { \ 43 | KAGUYA_PP_REPEAT(N, KAGUYA_FUNCTION_TUPLE_ELEMENT) \ 44 | tuple(KAGUYA_PP_ARG_DEF_REPEAT(N)) \ 45 | : KAGUYA_PP_REPEAT_ARG(N, KAGUYA_FUNCTION_TUPLE_ELEMENT_INIT) {} \ 46 | }; 47 | 48 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, 49 | KAGUYA_FUNCTION_TUPLE_IMPL_DEF) 50 | 51 | template struct tuple_size; 52 | 53 | #define KAGUYA_TUPLE_SIZE_DEF(N) \ 54 | template \ 55 | struct tuple_size > { \ 56 | static const size_t value = N; \ 57 | }; 58 | 59 | KAGUYA_TUPLE_SIZE_DEF(0) 60 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_SIZE_DEF) 61 | #undef KAGUYA_TUPLE_SIZE_DEF 62 | 63 | template 64 | struct tuple_element {}; 65 | #define KAGUYA_TUPLE_ELEMENT_DEF(N) \ 66 | template \ 68 | struct tuple_element< \ 69 | remain, tuple, true> { \ 70 | typedef arg type; \ 71 | }; \ 72 | template \ 74 | struct tuple_element< \ 75 | remain, tuple, false> \ 76 | : tuple_element > { \ 77 | }; 78 | 79 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_ELEMENT_DEF) 80 | 81 | #undef KAGUYA_TUPLE_SIZE_DEF 82 | 83 | template struct tuple_get_helper; 84 | #define KAGUYA_TUPLE_GET_DEF(N) \ 85 | template struct tuple_get_helper { \ 86 | static typename tuple_element::type &get(T &t) { \ 87 | return t.KAGUYA_PP_CAT(elem, N); \ 88 | } \ 89 | static const typename tuple_element::type &cget(const T &t) { \ 90 | return t.KAGUYA_PP_CAT(elem, N); \ 91 | } \ 92 | }; 93 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_OVERLOADS, KAGUYA_TUPLE_GET_DEF) 94 | 95 | template typename tuple_element::type &get(T &t) { 96 | return tuple_get_helper::get(t); 97 | } 98 | template 99 | const typename tuple_element::type &get(const T &t) { 100 | return tuple_get_helper::cget(t); 101 | } 102 | #endif 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /test/test_07_vector_map_to_luatable.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include "test_util.hpp" 3 | 4 | KAGUYA_TEST_GROUP_START(test_07_vector_map_to_luatable) 5 | 6 | #ifndef KAGUYA_NO_STD_VECTOR_TO_TABLE 7 | KAGUYA_TEST_FUNCTION_DEF(vector_from_table)(kaguya::State &state) { 8 | state("arraytablefn =function() return {32,1,2,4,8,16} end"); 9 | std::vector b = state["arraytablefn"](); 10 | TEST_EQUAL(b.size(), 6); 11 | TEST_EQUAL(b[0], 32); 12 | TEST_EQUAL(b[1], 1); 13 | TEST_EQUAL(b[2], 2); 14 | TEST_EQUAL(b[3], 4); 15 | TEST_EQUAL(b[4], 8); 16 | TEST_EQUAL(b[5], 16); 17 | TEST_CHECK(state["arraytablefn"]().typeTest >()); 18 | } 19 | 20 | KAGUYA_TEST_FUNCTION_DEF(vector_to_table)(kaguya::State &state) { 21 | std::vector v; 22 | v.push_back(3); 23 | v.push_back(13); 24 | v.push_back(2); 25 | v.push_back(99); 26 | state["v"] = v; 27 | TEST_CHECK( 28 | state("assert(v[1] == 3 and v[2] == 13 and v[3] == 2 and v[4] == 99)")); 29 | } 30 | KAGUYA_TEST_FUNCTION_DEF(vector_bool_from_table)(kaguya::State &state) { 31 | state( 32 | "arraytablefn =function() return {true,false,false,true,false,true} end"); 33 | std::vector b = state["arraytablefn"](); 34 | TEST_EQUAL(b.size(), 6); 35 | TEST_EQUAL(b[0], true); 36 | TEST_EQUAL(b[1], false); 37 | TEST_EQUAL(b[2], false); 38 | TEST_EQUAL(b[3], true); 39 | TEST_EQUAL(b[4], false); 40 | TEST_EQUAL(b[5], true); 41 | TEST_CHECK(state["arraytablefn"]().typeTest >()); 42 | } 43 | 44 | KAGUYA_TEST_FUNCTION_DEF(vector_bool_to_table)(kaguya::State &state) { 45 | std::vector v; 46 | v.push_back(true); 47 | v.push_back(false); 48 | v.push_back(false); 49 | v.push_back(true); 50 | state["v"] = v; 51 | TEST_CHECK(state("assert(v[1] == true and v[2] == false and v[3] == false " 52 | "and v[4] == true)")); 53 | } 54 | #endif 55 | 56 | #ifndef KAGUYA_NO_STD_MAP_TO_TABLE 57 | 58 | KAGUYA_TEST_FUNCTION_DEF(map_from_table)(kaguya::State &state) { 59 | state("tablefn =function() return {a=32,b=1,c=2} end"); 60 | std::map m = state["tablefn"](); 61 | 62 | TEST_EQUAL(m["a"], 32); 63 | TEST_EQUAL(m["b"], 1); 64 | TEST_EQUAL(m["c"], 2); 65 | 66 | kaguya::LuaRef t = state["tablefn"](); 67 | TEST_CHECK(!t.isType >()); 68 | bool r = t.isType >(); 69 | TEST_CHECK(r); 70 | r = t.isType >(); 71 | TEST_CHECK(r); 72 | r = t.isConvertible >(); 73 | TEST_CHECK(r); 74 | } 75 | 76 | KAGUYA_TEST_FUNCTION_DEF(map_to_table)(kaguya::State &state) { 77 | std::map m; 78 | m["a"] = 4; 79 | m["b"] = 32; 80 | m["c"] = 24; 81 | state["m"] = m; 82 | TEST_CHECK(state("assert(m['a'] == 4 and m['b'] == 32 and m['c'] == 24)")); 83 | } 84 | std::map myMap; 85 | int myVal; 86 | 87 | class FooClass { 88 | public: 89 | void mapCallback(const std::map &map) { myMap = map; } 90 | void mapOverload() { myMap.clear(); } 91 | void mapOverload(const std::map &map) { myMap = map; } 92 | void mapOverload(const std::map &map, int val) { 93 | myMap = map; 94 | myVal = val; 95 | } 96 | }; 97 | 98 | KAGUYA_TEST_FUNCTION_DEF(testWrongClassUseWihMap)(kaguya::State &state) { 99 | state["testMap"].setClass( 100 | kaguya::UserdataMetatable() 101 | .addFunction("testMap", &FooClass::mapCallback) 102 | .addOverloadedFunctions( 103 | "mapOverload", 104 | static_cast(&FooClass::mapOverload), 105 | static_cast &)>( 107 | &FooClass::mapOverload), 108 | static_cast &, int)>( 110 | &FooClass::mapOverload))); 111 | state["foo"] = FooClass(); 112 | state("myMap = {[1] = 2, [3] = 4, [5] = 6}"); 113 | try { 114 | // This uses an invalid function call which should throw an error 115 | state("foo.testMap(myMap)"); 116 | TEST_CHECK(false); 117 | } catch (std::runtime_error &) { 118 | } 119 | TEST_CHECK(myMap.empty()); 120 | // This is the correct call 121 | state("foo:testMap(myMap)"); 122 | TEST_EQUAL(myMap[1], 2); 123 | TEST_EQUAL(myMap[3], 4); 124 | TEST_EQUAL(myMap[5], 6); 125 | state("foo:mapOverload()"); 126 | TEST_CHECK(myMap.empty()); 127 | try { 128 | // This uses an invalid function call which should throw an error 129 | state("foo.mapOverload(myMap)"); 130 | TEST_CHECK(false); 131 | } catch (std::runtime_error &) { 132 | } 133 | state("foo:mapOverload(myMap)"); 134 | TEST_EQUAL(myMap[1], 2); 135 | TEST_EQUAL(myMap[3], 4); 136 | TEST_EQUAL(myMap[5], 6); 137 | myMap.clear(); 138 | state("foo:mapOverload(myMap, 42)"); 139 | TEST_EQUAL(myMap[1], 2); 140 | TEST_EQUAL(myMap[3], 4); 141 | TEST_EQUAL(myMap[5], 6); 142 | TEST_EQUAL(myVal, 42); 143 | } 144 | 145 | #endif 146 | 147 | KAGUYA_TEST_GROUP_END(test_07_vector_map_to_luatable) 148 | -------------------------------------------------------------------------------- /include/kaguya/error_handler.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "kaguya/config.hpp" 11 | #include "kaguya/type.hpp" 12 | 13 | namespace kaguya { 14 | inline const char *get_error_message(lua_State *state) { 15 | if (lua_type(state, -1) == LUA_TSTRING) { 16 | const char *message = lua_tostring(state, -1); 17 | return message ? message : "unknown error"; 18 | } else { 19 | return "unknown error"; 20 | } 21 | } 22 | inline int lua_pcall_wrap(lua_State *state, int argnum, int retnum) { 23 | int result = lua_pcall(state, argnum, retnum, 0); 24 | return result; 25 | } 26 | 27 | struct ErrorHandler { 28 | typedef standard::function function_type; 29 | 30 | static bool handle(const char *message, lua_State *state) { 31 | function_type *handler = getFunctionPointer(state); 32 | if (handler) { 33 | (*handler)(0, message); 34 | return true; 35 | } 36 | return false; 37 | } 38 | static bool handle(int status_code, const char *message, lua_State *state) { 39 | function_type *handler = getFunctionPointer(state); 40 | if (handler) { 41 | (*handler)(status_code, message); 42 | return true; 43 | } 44 | return false; 45 | } 46 | static bool handle(int status_code, lua_State *state) { 47 | function_type *handler = getFunctionPointer(state); 48 | if (handler) { 49 | (*handler)(status_code, get_error_message(state)); 50 | return true; 51 | } 52 | return false; 53 | } 54 | 55 | static function_type getHandler(lua_State *state) { 56 | function_type *funptr = getFunctionPointer(state); 57 | if (funptr) { 58 | return *funptr; 59 | } 60 | return function_type(); 61 | } 62 | 63 | static void unregisterHandler(lua_State *state) { 64 | if (state) { 65 | function_type *funptr = getFunctionPointer(state); 66 | if (funptr) { 67 | *funptr = function_type(); 68 | } 69 | } 70 | } 71 | static void registerHandler(lua_State *state, function_type f) { 72 | if (state) { 73 | function_type *funptr = getFunctionPointer(state); 74 | if (!funptr) { 75 | util::ScopedSavedStack save(state); 76 | #if KAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY 77 | lua_pushstring(state, handlerRegistryKey()); 78 | #else 79 | lua_pushlightuserdata(state, handlerRegistryKey()); 80 | #endif 81 | void *ptr = lua_newuserdata( 82 | state, sizeof(function_type)); // dummy data for gc call 83 | funptr = new (ptr) function_type(); 84 | 85 | // create function_type metatable 86 | lua_newtable(state); 87 | lua_pushcclosure(state, &error_handler_cleanner, 0); 88 | lua_setfield(state, -2, "__gc"); 89 | lua_pushvalue(state, -1); 90 | lua_setfield(state, -1, "__index"); 91 | lua_setmetatable(state, -2); 92 | 93 | lua_rawset(state, LUA_REGISTRYINDEX); 94 | } 95 | *funptr = f; 96 | } 97 | } 98 | 99 | static void throwDefaultError(int status, const char *message = 0) { 100 | switch (status) { 101 | case LUA_ERRSYNTAX: 102 | throw LuaSyntaxError( 103 | status, message ? std::string(message) : "unknown syntax error"); 104 | case LUA_ERRRUN: 105 | throw LuaRuntimeError( 106 | status, message ? std::string(message) : "unknown runtime error"); 107 | case LUA_ERRMEM: 108 | throw LuaMemoryError(status, 109 | message ? std::string(message) 110 | : "lua memory allocation error"); 111 | case LUA_ERRERR: 112 | throw LuaErrorRunningError(status, 113 | message ? std::string(message) 114 | : "unknown error running error"); 115 | #ifdef LUA_ERRGCMM 116 | case LUA_ERRGCMM: 117 | throw LuaGCError(status, 118 | message ? std::string(message) : "unknown gc error"); 119 | #endif 120 | default: 121 | throw LuaUnknownError( 122 | status, message ? std::string(message) : "lua unknown error"); 123 | } 124 | } 125 | 126 | private: 127 | #if KAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY 128 | static const char *handlerRegistryKey() { 129 | return "\x80KAGUYA_ERROR_HANDLER_REGISTRY_KEY"; 130 | } 131 | #else 132 | static void *handlerRegistryKey() { 133 | static void *key; 134 | return key; 135 | } 136 | #endif 137 | static function_type *getFunctionPointer(lua_State *state) { 138 | if (state) { 139 | util::ScopedSavedStack save(state); 140 | #if KAGUYA_SUPPORT_MULTIPLE_SHARED_LIBRARY 141 | lua_pushstring(state, handlerRegistryKey()); 142 | #else 143 | lua_pushlightuserdata(state, handlerRegistryKey()); 144 | #endif 145 | lua_rawget(state, LUA_REGISTRYINDEX); 146 | function_type *ptr = (function_type *)lua_touserdata(state, -1); 147 | return ptr; 148 | } 149 | return 0; 150 | } 151 | 152 | ErrorHandler() {} 153 | 154 | ErrorHandler(const ErrorHandler &); 155 | ErrorHandler &operator=(const ErrorHandler &); 156 | 157 | static int error_handler_cleanner(lua_State *state) { 158 | function_type *ptr = (function_type *)lua_touserdata(state, 1); 159 | ptr->~function_type(); 160 | return 0; 161 | } 162 | }; 163 | 164 | namespace except { 165 | inline void OtherError(lua_State *state, const std::string &message) { 166 | if (ErrorHandler::handle(message.c_str(), state)) { 167 | return; 168 | } 169 | } 170 | inline void typeMismatchError(lua_State *state, const std::string &message) { 171 | if (ErrorHandler::handle(message.c_str(), state)) { 172 | return; 173 | } 174 | } 175 | inline void memoryError(lua_State *state, const char *message) { 176 | if (ErrorHandler::handle(message, state)) { 177 | return; 178 | } 179 | } 180 | inline bool checkErrorAndThrow(int status, lua_State *state) { 181 | if (status != 0 && status != LUA_YIELD) { 182 | ErrorHandler::handle(status, state); 183 | 184 | return false; 185 | } 186 | return true; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /include/kaguya/traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "kaguya/config.hpp" 13 | #include "kaguya/optional.hpp" 14 | 15 | namespace kaguya { 16 | namespace traits { 17 | using standard::integral_constant; 18 | using standard::true_type; 19 | using standard::false_type; 20 | using standard::remove_reference; 21 | using standard::remove_pointer; 22 | using standard::remove_const; 23 | using standard::remove_volatile; 24 | using standard::remove_cv; 25 | using standard::is_function; 26 | using standard::is_floating_point; 27 | using standard::is_integral; 28 | using standard::is_enum; 29 | using standard::is_convertible; 30 | using standard::is_same; 31 | using standard::is_arithmetic; 32 | using standard::is_union; 33 | using standard::is_class; 34 | using standard::is_pointer; 35 | using standard::is_lvalue_reference; 36 | using standard::is_const; 37 | using standard::is_void; 38 | #if KAGUYA_USE_CPP11 39 | using std::enable_if; 40 | #else 41 | template 42 | struct enable_if : boost::enable_if_c {}; 43 | #endif 44 | 45 | class Helper {}; 46 | /// @brief Check if T_Mem is a member object of a type. That is true if it is 47 | /// not a member function 48 | /// Required as MSVC throws a COMDAT error when using is_member_object_pointer 49 | template struct is_object { 50 | typedef typename standard::is_member_function_pointer::type 51 | NotResult; 52 | enum { value = !NotResult::value }; 53 | }; 54 | 55 | /// @brief Similar to std::decay but also removes const and volatile modifiers 56 | /// if T is neither an array nor a function 57 | template struct decay { 58 | private: 59 | ///@ If T is a reference type, the type referrered to by T. Otherwise, T. 60 | typedef typename standard::remove_reference::type U; 61 | 62 | public: 63 | typedef typename standard::conditional< 64 | standard::is_array::value, typename standard::remove_extent::type *, 65 | typename standard::conditional< 66 | is_function::value, typename standard::add_pointer::type, 67 | typename standard::remove_cv::type>::type>::type type; 68 | }; 69 | 70 | /// @brief Trait class that identifies whether T is a const reference type. 71 | template struct is_const_reference : false_type {}; 72 | template struct is_const_reference : true_type {}; 73 | 74 | /// @brief Obtains the type T without top-level const and reference. 75 | template struct remove_const_and_reference { 76 | /// @brief If T is const or reference, the same type as T but with the const 77 | /// reference removed.Otherwise, T 78 | typedef T type; 79 | }; 80 | /// @brief Obtains the type T without top-level const and reference. 81 | template struct remove_const_and_reference { 82 | /// @brief If T is const or reference, the same type as T but with the const 83 | /// reference removed.Otherwise, T 84 | typedef T type; 85 | }; 86 | /// @brief Obtains the type T without top-level const and reference. 87 | template struct remove_const_and_reference { 88 | /// @brief If T is const or reference, the same type as T but with the const 89 | /// reference removed.Otherwise, T 90 | typedef T type; 91 | }; 92 | /// @brief Obtains the type T without top-level const and reference. 93 | template struct remove_const_and_reference { 94 | /// @brief If T is const or reference, the same type as T but with the const 95 | /// reference removed.Otherwise, T 96 | typedef T type; 97 | }; 98 | 99 | /// @brief Obtains the type T without top-level const reference. 100 | template struct remove_const_reference { 101 | /// @brief If T is const reference, the same type as T but with the const 102 | /// reference removed.Otherwise, T 103 | typedef T type; 104 | }; 105 | /// @brief Obtains the type T without top-level const reference. 106 | template struct remove_const_reference { 107 | /// @brief If T is const reference, the same type as T but with the const 108 | /// reference removed.Otherwise, T 109 | typedef T type; 110 | }; 111 | 112 | /// @brief Trait class that identifies whether T is a std::vector type. 113 | template struct is_std_vector : false_type {}; 114 | template 115 | struct is_std_vector > : true_type {}; 116 | 117 | /// @brief Trait class that identifies whether T is a std::map type. 118 | template struct is_std_map : false_type {}; 119 | template 120 | struct is_std_map > : true_type {}; 121 | } 122 | 123 | /// @addtogroup lua_type_traits 124 | 125 | /// @ingroup lua_type_traits 126 | /// @brief If you want to customize the conversion to type of lua yourself , 127 | /// implement specialize of this class 128 | template struct lua_type_traits { 129 | typedef void Registerable; 130 | 131 | typedef typename traits::decay::type NCRT; 132 | typedef const NCRT &get_type; 133 | typedef optional opt_type; 134 | typedef const NCRT &push_type; 135 | 136 | static bool checkType(lua_State *l, int index); 137 | static bool strictCheckType(lua_State *l, int index); 138 | 139 | static get_type get(lua_State *l, int index); 140 | static opt_type opt(lua_State *l, int index) KAGUYA_NOEXCEPT; 141 | static int push(lua_State *l, push_type v); 142 | #if KAGUYA_USE_RVALUE_REFERENCE 143 | static int push(lua_State *l, NCRT &&v); 144 | #endif 145 | }; 146 | 147 | /// @brief Trait class that identifies whether T is a userdata type. 148 | template 149 | struct is_usertype : traits::false_type {}; 150 | template 151 | struct is_usertype::Registerable> 152 | : traits::true_type {}; 153 | 154 | /// @brief Trait class that identifies whether T is a registerable by 155 | /// UserdataMetatable. 156 | template struct is_registerable : is_usertype {}; 157 | } 158 | -------------------------------------------------------------------------------- /include/kaguya/optional.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | #include 8 | #include "kaguya/config.hpp" 9 | 10 | namespace kaguya { 11 | /// @addtogroup optional 12 | /// @{ 13 | 14 | struct bad_optional_access : std::exception {}; 15 | struct nullopt_t {}; 16 | 17 | /// @brief self implement for std::optional(C++17 feature). 18 | template class optional { 19 | typedef void (optional::*bool_type)() const; 20 | void this_type_does_not_support_comparisons() const {} 21 | 22 | public: 23 | optional() : value_(0){}; 24 | optional(nullopt_t) : value_(0){}; 25 | optional(const optional &other) : value_(0) { 26 | if (other) { 27 | value_ = new (&storage_) T(other.value()); 28 | } 29 | } 30 | optional(const T &value) { value_ = new (&storage_) T(value); } 31 | 32 | ~optional() { destruct(); } 33 | optional &operator=(nullopt_t) { 34 | destruct(); 35 | return *this; 36 | } 37 | optional &operator=(const optional &other) { 38 | if (other) { 39 | *this = other.value(); 40 | } else { 41 | destruct(); 42 | } 43 | return *this; 44 | } 45 | optional &operator=(const T &value) { 46 | if (value_) { 47 | *value_ = value; 48 | } else { 49 | value_ = new (&storage_) T(value); 50 | } 51 | return *this; 52 | } 53 | 54 | #if KAGUYA_USE_CPP11 55 | optional(optional &&other) : value_(0) { 56 | if (other) { 57 | value_ = new (&storage_) T(std::move(other.value())); 58 | } 59 | } 60 | optional(T &&value) { value_ = new (&storage_) T(std::move(value)); } 61 | optional &operator=(optional &&other) { 62 | if (other) { 63 | *this = std::move(other.value()); 64 | } else { 65 | destruct(); 66 | } 67 | return *this; 68 | } 69 | optional &operator=(T &&value) { 70 | if (value_) { 71 | *value_ = std::move(value); 72 | } else { 73 | value_ = new (&storage_) T(std::move(value)); 74 | } 75 | return *this; 76 | } 77 | #endif 78 | 79 | operator bool_type() const { 80 | this_type_does_not_support_comparisons(); 81 | return value_ != 0 ? &optional::this_type_does_not_support_comparisons : 0; 82 | } 83 | T &value() { 84 | if (value_) { 85 | return *value_; 86 | } 87 | throw bad_optional_access(); 88 | } 89 | const T &value() const { 90 | if (value_) { 91 | return *value_; 92 | } 93 | throw bad_optional_access(); 94 | } 95 | 96 | #if KAGUYA_USE_CPP11 97 | template T value_or(U &&default_value) const { 98 | if (value_) { 99 | return *value_; 100 | } 101 | return default_value; 102 | } 103 | #else 104 | template T value_or(const U &default_value) const { 105 | if (value_) { 106 | return *value_; 107 | } 108 | return default_value; 109 | } 110 | #endif 111 | const T *operator->() const { 112 | assert(value_); 113 | return value_; 114 | } 115 | T *operator->() { 116 | assert(value_); 117 | return value_; 118 | } 119 | const T &operator*() const { 120 | assert(value_); 121 | return *value_; 122 | } 123 | T &operator*() { 124 | assert(value_); 125 | return *value_; 126 | } 127 | 128 | private: 129 | void destruct() { 130 | if (value_) { 131 | value_->~T(); 132 | value_ = 0; 133 | } 134 | } 135 | 136 | typename standard::aligned_storage< 137 | sizeof(T), standard::alignment_of::value>::type storage_; 138 | 139 | T *value_; 140 | }; 141 | 142 | /// @brief specialize optional for reference. 143 | /// sizeof(optional) == sizeof(T*) 144 | template class optional { 145 | typedef void (optional::*bool_type)() const; 146 | void this_type_does_not_support_comparisons() const {} 147 | 148 | public: 149 | optional() : value_(0){}; 150 | optional(nullopt_t) : value_(0){}; 151 | 152 | optional(const optional &other) : value_(other.value_) {} 153 | optional(T &value) : value_(&value) {} 154 | 155 | ~optional() {} 156 | optional &operator=(nullopt_t) { 157 | value_ = 0; 158 | return *this; 159 | } 160 | optional &operator=(const optional &other) { 161 | value_ = other.value_; 162 | return *this; 163 | } 164 | optional &operator=(T &value) { 165 | value_ = &value; 166 | return *this; 167 | } 168 | operator bool_type() const { 169 | this_type_does_not_support_comparisons(); 170 | return value_ != 0 ? &optional::this_type_does_not_support_comparisons : 0; 171 | } 172 | T &value() { 173 | if (value_) { 174 | return *value_; 175 | } 176 | throw bad_optional_access(); 177 | } 178 | const T &value() const { 179 | if (value_) { 180 | return *value_; 181 | } 182 | throw bad_optional_access(); 183 | } 184 | 185 | #if KAGUYA_USE_CPP11 186 | T &value_or(T &default_value) const { 187 | if (value_) { 188 | return *value_; 189 | } 190 | return default_value; 191 | } 192 | #else 193 | T &value_or(T &default_value) const { 194 | if (value_) { 195 | return *value_; 196 | } 197 | return default_value; 198 | } 199 | #endif 200 | 201 | const T *operator->() const { 202 | assert(value_); 203 | return value_; 204 | } 205 | T *operator->() { 206 | assert(value_); 207 | return value_; 208 | } 209 | const T &operator*() const { 210 | assert(value_); 211 | return *value_; 212 | } 213 | T &operator*() { 214 | assert(value_); 215 | return *value_; 216 | } 217 | 218 | private: 219 | T *value_; 220 | }; 221 | 222 | /// @name relational operators 223 | /// @brief 224 | ///@{ 225 | template 226 | bool operator==(const optional &lhs, const optional &rhs) { 227 | if (bool(lhs) != bool(rhs)) { 228 | return false; 229 | } 230 | if (bool(lhs) == false) { 231 | return true; 232 | } 233 | return lhs.value() == rhs.value(); 234 | } 235 | template 236 | bool operator!=(const optional &lhs, const optional &rhs) { 237 | return !(lhs == rhs); 238 | } 239 | template 240 | bool operator<(const optional &lhs, const optional &rhs) { 241 | if (!bool(rhs)) { 242 | return false; 243 | } 244 | if (!bool(lhs)) { 245 | return true; 246 | } 247 | return lhs.value() < rhs.value(); 248 | } 249 | template 250 | bool operator<=(const optional &lhs, const optional &rhs) { 251 | return !(rhs < lhs); 252 | } 253 | template 254 | bool operator>(const optional &lhs, const optional &rhs) { 255 | return rhs < lhs; 256 | } 257 | template 258 | bool operator>=(const optional &lhs, const optional &rhs) { 259 | return !(lhs < rhs); 260 | } 261 | /// @} 262 | 263 | /// @} 264 | } 265 | -------------------------------------------------------------------------------- /docs/getting_started/tutorial.rst: -------------------------------------------------------------------------------- 1 | 2 | Tutorial 3 | ================================== 4 | 5 | .. contents:: 6 | :depth: 2 7 | :local: 8 | 9 | Installation 10 | ---------------------------------- 11 | add "kaguya/include" directory to "header search path" of your project. 12 | 13 | Or generate single header file and add it to your project. 14 | 15 | .. code-block:: bash 16 | 17 | cd utils 18 | python generate_one_header.py > ../kaguya.hpp 19 | 20 | 21 | Hello world 22 | ---------------------------------- 23 | 24 | Create Lua context, and execute Lua code. 25 | 26 | kaguya is automatically load all standard libraries. 27 | 28 | .. code-block:: c++ 29 | 30 | #include 31 | int main() 32 | { 33 | using namespace kaguya; 34 | State state;//create Lua context 35 | state.dostring("print('hello lua world')"); 36 | } 37 | 38 | 39 | 40 | 41 | 42 | Initialize State 43 | ---------------------------------- 44 | 45 | 1. default construct. 46 | 47 | Create lua_State and load all standard libraries. 48 | 49 | .. code-block:: c++ 50 | 51 | kaguya::State state; 52 | 53 | 2. Load library control. 54 | 55 | Create lua_State without load libraries. 56 | 57 | .. code-block:: c++ 58 | 59 | kaguya::State state(NoLoadLib()); 60 | 61 | Create lua_State and load base library. 62 | 63 | .. code-block:: c++ 64 | 65 | kaguya::LoadLibs libs; 66 | libs.push_back(kaguya::LoadLib("_G", luaopen_base)); 67 | kaguya::State state(libs); 68 | 69 | 70 | 3. Memory management. 71 | 72 | .. warning:: 73 | Do not work luajit on x64 74 | 75 | Create lua_State with allocator. Need Allocator concept. 76 | 77 | .. code-block:: c++ 78 | 79 | kaguya::State state(std::make_shared()); 80 | 81 | 4. Wrap existing lua_State. 82 | 83 | .. code-block:: c++ 84 | 85 | lua_State* L = luaL_newstate();//create lua_State by plain API 86 | { 87 | kaguya::State state(L); 88 | } 89 | lua_close(L);//Must lua_close yourself. 90 | 91 | 92 | 93 | Running Lua code 94 | ---------------------------------- 95 | 96 | 1. from string 97 | 98 | .. code-block:: c++ 99 | 100 | kaguya::State state; 101 | state.dostring("a = 1"); 102 | 103 | 2. from file 104 | 105 | .. code-block:: c++ 106 | 107 | kaguya::State state; 108 | state.dofile("path/to/file.lua"); 109 | 110 | 111 | 3. from stream 112 | 113 | .. code-block:: c++ 114 | 115 | kaguya::State state; 116 | std::ifstream ifs("path/to/file.lua", ios::in | ios::binary); 117 | state.dostream(ifs,"chunkname e.g filename"); 118 | 119 | Accessing Lua table values 120 | ---------------------------------- 121 | 122 | .. code-block:: c++ 123 | 124 | kaguya::State state; 125 | state.dostring("a = 'test'"); 126 | std::string a_value = state["a"]; 127 | assert(a_value == "test"); 128 | 129 | state["tbl"] = kaguya::NewTable();//tbl ={}; 130 | state["tbl"]["value"] = 1;//tbl.value = 1 in lua 131 | 132 | state["tbl"] = kaguya::TableData{ 23,"test",{"key","value"}}; //using initializer list(C++11) 133 | state.dostring("assert(tbl[1] == 23)"); 134 | state.dostring("assert(tbl[2] == 'test')"); 135 | state.dostring("assert(tbl['key'] == 'value')"); 136 | 137 | 138 | Invoke lua function 139 | ---------------------------------- 140 | 141 | basic 142 | 143 | .. code-block:: c++ 144 | 145 | int ret = state["math"]["abs"](-32); 146 | assert(ret == 32); 147 | 148 | Specified result type 149 | 150 | .. code-block:: c++ 151 | 152 | auto ret = state["math"]["abs"].call(-32); 153 | assert(ret == 32); 154 | 155 | Optional result value 156 | 157 | .. code-block:: c++ 158 | 159 | kaguya::optional ret = state["math"]["abs"](-32); 160 | assert(ret && *ret == 32); 161 | 162 | Multiple results 163 | 164 | .. code-block:: c++ 165 | 166 | state("multresfun =function() return 1,2,4 end"); 167 | int a, b, c; 168 | kaguya::tie(a, b, c) = state["multresfun"](); 169 | std::cout << a << "," << b << "," << c << std::endl;//1,2,4 170 | 171 | 172 | Registering c function 173 | ---------------------------------- 174 | 175 | free function 176 | 177 | .. code-block:: c++ 178 | 179 | void f(int v){std::cout <<"f called:" << v << std::endl} 180 | ... 181 | state["fun"] = &f; 182 | state["fun"](54); //f called:54 183 | state.dostring("fun(22)"); //f called:22 184 | 185 | C++11 lambda 186 | 187 | .. code-block:: c++ 188 | 189 | state["lambda"] = kaguya::function([]{std::cout << "lambda called" << std::endl;}); 190 | state.dostring("lambda()");//lambda called 191 | 192 | function overloads 193 | 194 | .. code-block:: c++ 195 | 196 | void f1(int v){std::cout <<"int version" << std::endl} 197 | void f2(const std::string& v){std::cout <<"string version" << std::endl} 198 | void f3(){std::cout <<"no argument version" << std::endl} 199 | ... 200 | state["overload"] = kaguya::overload(f1,f2,f3); 201 | 202 | state.dostring("overload()");//no args version 203 | state.dostring("overload(2)");//int version 204 | state.dostring("overload('text')");//string version 205 | 206 | default arguments 207 | 208 | .. code-block:: c++ 209 | 210 | int defargfn(int a = 3, int b = 2, int c = 1) 211 | { 212 | return a*b*c; 213 | } 214 | KAGUYA_FUNCTION_OVERLOADS(defargfn_wrapper, defargfn,0,3) 215 | ... 216 | state["defarg"] = kaguya::function(defargfn_wrapper()); 217 | state.dostring("assert(defarg() == 6)"); 218 | state.dostring("assert(defarg(6) == 12)"); 219 | state.dostring("assert(defarg(6,5) == 30)"); 220 | state.dostring("assert(defarg(2,2,2) == 8)"); 221 | 222 | 223 | Registering Classes 224 | ---------------------------------- 225 | 226 | .. code-block:: c++ 227 | 228 | //C++ 229 | struct ABC 230 | { 231 | ABC():v(0) {} 232 | ABC(int value) :v(value) {} 233 | int value()const { return v; } 234 | void setValue(int v) { v_ = v; } 235 | void overload() {std::cout << "call overload1"<() 245 | .setConstructors() 246 | .addFunction("get_value", &ABC::value) 247 | .addFunction("set_value", &ABC::setValue) 248 | .addOverloadedFunctions("overload", &ABC::overload1, &ABC::overload2) 249 | .addStaticFunction("nonmemberfun", [](ABC* self,int){return 1;})//c++11 lambda function 250 | .addFunction("defarg", default_arguments_function_wrapper()) 251 | ); 252 | 253 | .. code-block:: Lua 254 | 255 | -- Lua 256 | local abc = ABC.new() 257 | assert(0 == abc:get_value()) 258 | abc = ABC.new(42)--call (int) constructor 259 | assert(42 == abc:get_value()) 260 | abc:set_value(30) 261 | assert(30 == abc:get_value()) 262 | abc:overload() -- call overload1 263 | abc:overload(1) --call overload2 264 | 265 | assert(abc:defarg() == 6) 266 | assert(abc:defarg(6) == 12) 267 | assert(abc:defarg(6,5) == 30) 268 | assert(abc:defarg(2,2,2) == 8) 269 | 270 | 271 | Handling Errors 272 | ---------------------------------- 273 | 274 | Lua error encountered will write to the console by default, and it is customizable: 275 | 276 | .. code-block:: c++ 277 | 278 | void HandleError(int errCode, const char * szError) 279 | { 280 | //customize your error handling, eg. write to file... 281 | } 282 | kaguya::State l; 283 | l.setErrorHandler(HandleError); 284 | l.dofile("./scripts/custom.lua"); // eg. accessing a file not existed will invoke HandleError above 285 | -------------------------------------------------------------------------------- /test_runner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import shlex,subprocess 3 | import os 4 | import urllib 5 | import tarfile 6 | 7 | 8 | 9 | boost_dir=os.environ.get("BOOST_PATH") 10 | if not boost_dir: 11 | boost_dir='D:\\boost_1_60_0' 12 | 13 | lua_versions = ["lua-5.3.3","lua-5.2.4","lua-5.1.5","luajit"] 14 | maijor_test_lua_versions = ["lua-5.3.3"] 15 | 16 | test_msvc_vers = [("msvc2015","Visual Studio 14 2015","",True) 17 | ,("msvc2015win64","Visual Studio 14 2015 Win64","",True) 18 | ,("msvc2013","Visual Studio 12 2013","",False) 19 | ,("msvc2013win64","Visual Studio 12 2013 Win64","",False) 20 | ,("msvc2012","Visual Studio 11 2012","-DADDITIONAL_INCLUDE_PATH="+boost_dir,False) 21 | ,("msvc2010","Visual Studio 10 2010","-DADDITIONAL_INCLUDE_PATH="+boost_dir,False) 22 | ,("msvc2008","Visual Studio 9 2008","-DADDITIONAL_INCLUDE_PATH="+boost_dir,True) 23 | ,("msvc2015","Visual Studio 14 2015","",True) 24 | ,("msvc2015win64","Visual Studio 14 2015 Win64","-DKAGUYA_USE_SHARED_LUAREF=1",False) 25 | ,("msvc2013","Visual Studio 12 2013","-DKAGUYA_USE_SHARED_LUAREF=1",False) 26 | ,("msvc2013win64","Visual Studio 12 2013 Win64","-DKAGUYA_USE_SHARED_LUAREF=1",False) 27 | ,("msvc2012","Visual Studio 11 2012","-DKAGUYA_USE_SHARED_LUAREF=1 -DADDITIONAL_INCLUDE_PATH="+boost_dir,False) 28 | ,("msvc2010","Visual Studio 10 2010","-DKAGUYA_USE_SHARED_LUAREF=1 -DADDITIONAL_INCLUDE_PATH="+boost_dir,False) 29 | ,("msvc2008","Visual Studio 9 2008","-DKAGUYA_USE_SHARED_LUAREF=1 -DADDITIONAL_INCLUDE_PATH="+boost_dir,False)] 30 | 31 | test_compilers = [ 32 | ('gcc-3.3','g++-3.3','',False) 33 | ,('gcc-4.4','g++-4.4','',False) 34 | ,('gcc-4.5','g++-4.5','',False) 35 | ,('gcc-4.6','g++-4.6','-DCMAKE_CXX_FLAGS=-std=c++03',False) 36 | ,('gcc-4.7','g++-4.7','-DCMAKE_CXX_FLAGS=-std=c++03',False) 37 | ,('gcc-4.8','g++-4.8','-DCMAKE_CXX_FLAGS=-std=c++03',False) 38 | ,('gcc-4.8','g++-4.8','-DCMAKE_CXX_FLAGS=-std=c++11',False) 39 | ,('gcc-4.9','g++-4.9','-DCMAKE_CXX_FLAGS=-std=c++03',False) 40 | ,('gcc-4.9','g++-4.9','-DCMAKE_CXX_FLAGS=-std=c++11',False) 41 | ,('gcc-5','g++-5','-DCMAKE_CXX_FLAGS=-std=c++03',False) 42 | ,('gcc-5','g++-5','-DCMAKE_CXX_FLAGS=-std=c++11',False) 43 | ,('gcc-6','g++-6','-DCMAKE_CXX_FLAGS=-std=c++03',False) 44 | ,('gcc-6','g++-6','-DCMAKE_CXX_FLAGS=-std=c++11',False) 45 | ,('gcc-6','g++-6','-DCMAKE_CXX_FLAGS=-std=c++14',False) 46 | ,('gcc','g++','-DCMAKE_CXX_FLAGS=-std=c++03',True) 47 | ,('gcc','g++','-DCMAKE_CXX_FLAGS=-std=c++11',True) 48 | ,('gcc','g++','-DCMAKE_CXX_FLAGS=-std=c++03 -DKAGUYA_SINGLE_HEADER_VERSION=1',True) 49 | ,('gcc','g++','-DCMAKE_CXX_FLAGS=-std=c++11 -DKAGUYA_SINGLE_HEADER_VERSION=1',True) 50 | ,('clang','clang++','-DCMAKE_CXX_FLAGS=-std=c++03',True) 51 | ,('clang','clang++','-DCMAKE_CXX_FLAGS=-std=c++11',True) 52 | ,('clang-3.5','clang++-3.5','-DCMAKE_CXX_FLAGS=-std=c++03',False) 53 | ,('clang-3.6','clang++-3.6','-DCMAKE_CXX_FLAGS=-std=c++03',False) 54 | ,('clang-3.7','clang++-3.7','-DCMAKE_CXX_FLAGS=-std=c++03',False) 55 | ,('clang-3.8','clang++-3.8','-DCMAKE_CXX_FLAGS=-std=c++03',False) 56 | ,('clang-3.9','clang++-3.9','-DCMAKE_CXX_FLAGS=-std=c++03',False) 57 | ,('clang-4.0','clang++-4.0','-DCMAKE_CXX_FLAGS=-std=c++03',False) 58 | ,('clang-3.5','clang++-3.5','-DCMAKE_CXX_FLAGS=-std=c++11',False) 59 | ,('clang-3.6','clang++-3.6','-DCMAKE_CXX_FLAGS=-std=c++11',False) 60 | ,('clang-3.7','clang++-3.7','-DCMAKE_CXX_FLAGS=-std=c++11',False) 61 | ,('clang-3.8','clang++-3.8','-DCMAKE_CXX_FLAGS=-std=c++11',False) 62 | ,('clang-3.9','clang++-3.9','-DCMAKE_CXX_FLAGS=-std=c++11',False) 63 | ,('clang-4.0','clang++-4.0','-DCMAKE_CXX_FLAGS=-std=c++11',False) 64 | ,('clang-3.8','clang++-3.8','-DCMAKE_CXX_FLAGS=-std=c++14',False) 65 | ,('clang-3.9','clang++-3.9','-DCMAKE_CXX_FLAGS=-std=c++14',False) 66 | ,('clang-4.0','clang++-4.0','-DCMAKE_CXX_FLAGS=-std=c++14',False) 67 | ,('clang-3.8','clang++-3.8','-DCMAKE_CXX_FLAGS=-std=c++03 -DKAGUYA_USE_SHARED_LUAREF=1',False) 68 | ,('clang-3.8','clang++-3.8','-DCMAKE_CXX_FLAGS=-std=c++11 -DKAGUYA_USE_SHARED_LUAREF=1',False) 69 | ,('clang-3.8','clang++-3.8','-DCMAKE_CXX_FLAGS=-std=c++14 -DKAGUYA_USE_SHARED_LUAREF=1',False) 70 | ,('gcc-6','g++-6','-DCMAKE_CXX_FLAGS=-std=c++03 -DKAGUYA_USE_SHARED_LUAREF=1',False) 71 | ,('gcc-6','g++-6','-DCMAKE_CXX_FLAGS=-std=c++11 -DKAGUYA_USE_SHARED_LUAREF=1',False) 72 | ,('gcc-6','g++-6','-DCMAKE_CXX_FLAGS=-std=c++14 -DKAGUYA_USE_SHARED_LUARE=1F',False) 73 | ] 74 | 75 | def build_and_exec_test(compiler,lua_version,build_type,dir_opt): 76 | ccompiler = compiler[0] 77 | cxxcompiler = compiler[1] 78 | addopt = compiler[2] 79 | if os.system(cxxcompiler+' -v 2> /dev/null')!=0: return 80 | buildpath = os.path.join('_build',compiler[0]+"_"+lua_version+"_"+build_type+"_"+dir_opt) 81 | if not os.path.exists(buildpath): 82 | os.makedirs(buildpath) 83 | os.chdir(buildpath) 84 | ret = os.system('CC='+ccompiler+' CXX='+cxxcompiler+' cmake ../../ -DKAGUYA_BUILD_EXAMPLES=OFF '+addopt+' -DLUA_SEARCH_LIB_NAME='+lua_version+' -DCMAKE_BUILD_TYPE='+build_type) 85 | if ret != 0:#pass through cmake failed. e.g. not found lua 86 | if lua_version in maijor_test_lua_versions: 87 | raise Exception("cmake error at"+buildpath) 88 | os.chdir("../../") 89 | return 90 | ret = os.system('make -j 2') 91 | if ret != 0: raise Exception("build error at"+buildpath) 92 | ret = os.system('ctest --output-on-failure') 93 | if ret != 0: raise Exception("test error at"+buildpath) 94 | os.chdir("../../") 95 | 96 | def build_with_target_compiler(lua_version): 97 | for i,compiler in enumerate(test_compilers): 98 | if not compiler[3] and lua_version not in maijor_test_lua_versions: 99 | continue 100 | build_and_exec_test(compiler,lua_version,"Debug",str(i)) 101 | if compiler[3]: 102 | build_and_exec_test(compiler,lua_version,"Release",str(i)) 103 | 104 | def build_msvc_and_exec_test(msvcver,lua_version,build_type): 105 | buildpath = os.path.join('_build',msvcver[0]+'_'+lua_version) 106 | if not os.path.exists(buildpath): 107 | os.makedirs(buildpath) 108 | os.chdir(buildpath) 109 | ret = os.system('cmake ../../ -DLUA_SEARCH_LIB_NAME='+lua_version+' -G "'+msvcver[1]+'" '+msvcver[2]) 110 | if ret != 0:#pass through cmake failed. e.g. not found lua 111 | if lua_version in maijor_test_lua_versions: 112 | raise Exception("cmake error at"+buildpath) 113 | os.chdir("../../") 114 | return 115 | ret = os.system('cmake --build . --config '+build_type) 116 | if ret != 0: raise Exception("build error at"+buildpath) 117 | ret = os.system('ctest --output-on-failure -C '+build_type) 118 | if ret != 0: raise Exception("test error at"+buildpath) 119 | os.chdir("../../") 120 | 121 | def build_with_msvc_ver(lua_version): 122 | for msvcver in test_msvc_vers: 123 | if not msvcver[3] and lua_version not in maijor_test_lua_versions: 124 | continue 125 | build_msvc_and_exec_test(msvcver,lua_version,'Debug') 126 | if msvcver[3]: 127 | build_msvc_and_exec_test(msvcver,lua_version,'Release') 128 | 129 | 130 | 131 | for i,luaversion in enumerate(lua_versions): 132 | if not os.path.exists(luaversion) and luaversion != 'luajit': 133 | if not os.path.exists(luaversion+".tar.gz"): 134 | lua_url = "https://www.lua.org/ftp/"+luaversion+".tar.gz" 135 | urllib.urlretrieve(lua_url,"{0}".format(luaversion+".tar.gz")) 136 | tf = tarfile.open(luaversion+".tar.gz", 'r') 137 | tf.extractall("./") 138 | 139 | if os.name == 'nt': 140 | build_with_msvc_ver(luaversion,) 141 | else: 142 | build_with_target_compiler(luaversion) 143 | -------------------------------------------------------------------------------- /include/kaguya/utility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | #include 7 | 8 | #if KAGUYA_USE_CXX_ABI_DEMANGLE 9 | #include 10 | #endif 11 | 12 | #include "kaguya/config.hpp" 13 | #include "kaguya/compatibility.hpp" 14 | #include "kaguya/traits.hpp" 15 | #include "kaguya/preprocess.hpp" 16 | #include "kaguya/exception.hpp" 17 | 18 | #if KAGUYA_USE_CPP11 19 | #include "kaguya/utility_cxx11.hpp" 20 | #else 21 | #include "kaguya/utility_cxx03.hpp" 22 | #endif 23 | 24 | namespace kaguya { 25 | namespace util { 26 | /// @brief save stack count and restore on destructor 27 | class ScopedSavedStack { 28 | lua_State *state_; 29 | int saved_top_index_; 30 | 31 | public: 32 | /// @brief save stack count 33 | /// @param state 34 | explicit ScopedSavedStack(lua_State *state) 35 | : state_(state), saved_top_index_(state_ ? lua_gettop(state_) : 0) {} 36 | 37 | /// @brief save stack count 38 | /// @param state 39 | /// @param count stack count 40 | explicit ScopedSavedStack(lua_State *state, int count) 41 | : state_(state), saved_top_index_(count) {} 42 | 43 | /// @brief restore stack count 44 | ~ScopedSavedStack() { 45 | if (state_) { 46 | lua_settop(state_, saved_top_index_); 47 | } 48 | } 49 | 50 | private: 51 | ScopedSavedStack(ScopedSavedStack const &); 52 | ScopedSavedStack &operator=(ScopedSavedStack const &); 53 | }; 54 | inline void traceBack(lua_State *state, const char *message, int level = 0) { 55 | #if LUA_VERSION_NUM >= 502 56 | luaL_traceback(state, state, message, level); 57 | #else 58 | KAGUYA_UNUSED(level); 59 | lua_pushstring(state, message); 60 | #endif 61 | } 62 | 63 | inline void stackDump(lua_State *L) { 64 | int i; 65 | int top = lua_gettop(L); 66 | for (i = 1; i <= top; i++) { /* repeat for each level */ 67 | int t = lua_type(L, i); 68 | switch (t) { 69 | 70 | case LUA_TSTRING: /* strings */ 71 | printf("`%s'", lua_tostring(L, i)); 72 | break; 73 | 74 | case LUA_TBOOLEAN: /* booleans */ 75 | printf(lua_toboolean(L, i) ? "true" : "false"); 76 | break; 77 | 78 | case LUA_TNUMBER: /* numbers */ 79 | printf("%g", lua_tonumber(L, i)); 80 | break; 81 | case LUA_TUSERDATA: 82 | if (luaL_getmetafield(L, i, "__name") == LUA_TSTRING) { 83 | printf("userdata:%s", lua_tostring(L, -1)); 84 | lua_pop(L, 1); 85 | break; 86 | } 87 | default: /* other values */ 88 | printf("%s", lua_typename(L, t)); 89 | break; 90 | } 91 | printf(" "); /* put a separator */ 92 | } 93 | printf("\n"); /* end the listing */ 94 | } 95 | 96 | inline void stackValueDump(std::ostream &os, lua_State *state, int stackIndex, 97 | int max_recursive = 2) { 98 | stackIndex = lua_absindex(state, stackIndex); 99 | util::ScopedSavedStack save(state); 100 | int type = lua_type(state, stackIndex); 101 | switch (type) { 102 | case LUA_TNONE: 103 | os << "none"; 104 | break; 105 | case LUA_TNIL: 106 | os << "nil"; 107 | break; 108 | case LUA_TBOOLEAN: 109 | os << ((lua_toboolean(state, stackIndex) != 0) ? "true" : "false"); 110 | break; 111 | case LUA_TNUMBER: 112 | os << lua_tonumber(state, stackIndex); 113 | break; 114 | case LUA_TSTRING: 115 | os << "'" << lua_tostring(state, stackIndex) << "'"; 116 | break; 117 | case LUA_TTABLE: { 118 | os << "{"; 119 | if (max_recursive <= 1) { 120 | os << "..."; 121 | } else { 122 | lua_pushnil(state); 123 | if ((lua_next(state, stackIndex) != 0)) { 124 | stackValueDump(os, state, -2, max_recursive - 1); 125 | os << "="; 126 | stackValueDump(os, state, -1, max_recursive - 1); 127 | lua_pop(state, 1); // pop value 128 | 129 | while (lua_next(state, stackIndex) != 0) { 130 | os << ","; 131 | stackValueDump(os, state, -2, max_recursive - 1); 132 | os << "="; 133 | stackValueDump(os, state, -1, max_recursive - 1); 134 | lua_pop(state, 1); // pop value 135 | } 136 | } 137 | } 138 | os << "}"; 139 | } break; 140 | case LUA_TUSERDATA: 141 | case LUA_TLIGHTUSERDATA: 142 | case LUA_TTHREAD: 143 | os << lua_typename(state, type) << "(" << lua_topointer(state, stackIndex) 144 | << ")"; 145 | break; 146 | case LUA_TFUNCTION: 147 | os << lua_typename(state, type); 148 | break; 149 | default: 150 | os << "unknown type value"; 151 | break; 152 | } 153 | } 154 | 155 | #if LUA_VERSION_NUM >= 502 156 | inline lua_State *toMainThread(lua_State *state) { 157 | if (state) { 158 | lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); 159 | lua_State *mainthread = lua_tothread(state, -1); 160 | lua_pop(state, 1); 161 | if (mainthread) { 162 | return mainthread; 163 | } 164 | } 165 | return state; 166 | } 167 | 168 | #else 169 | inline lua_State *toMainThread(lua_State *state) { 170 | if (state) { 171 | // lua_pushthread return 1 if state is main thread 172 | bool state_is_main = lua_pushthread(state) == 1; 173 | lua_pop(state, 1); 174 | if (state_is_main) { 175 | return state; 176 | } 177 | lua_getfield(state, LUA_REGISTRYINDEX, "KAGUYA_REG_MAINTHREAD"); 178 | lua_State *mainthread = lua_tothread(state, -1); 179 | lua_pop(state, 1); 180 | if (mainthread) { 181 | return mainthread; 182 | } 183 | } 184 | return state; 185 | } 186 | inline bool registerMainThread(lua_State *state) { 187 | if (lua_pushthread(state)) { 188 | lua_setfield(state, LUA_REGISTRYINDEX, "KAGUYA_REG_MAINTHREAD"); 189 | return true; 190 | } else { 191 | lua_pop(state, 1); 192 | return false; 193 | } 194 | } 195 | #endif 196 | 197 | #if KAGUYA_USE_CPP11 198 | inline int push_args(lua_State *) { return 0; } 199 | template 200 | inline int push_args(lua_State *l, Arg &&arg, Args &&... args) { 201 | int c = lua_type_traits::type>::push( 202 | l, std::forward(arg)); 203 | return c + push_args(l, std::forward(args)...); 204 | } 205 | template 206 | inline int push_args(lua_State *l, const Arg &arg, Args &&... args) { 207 | int c = lua_type_traits::push(l, arg); 208 | return c + push_args(l, std::forward(args)...); 209 | } 210 | #else 211 | inline int push_args(lua_State *) { return 0; } 212 | 213 | #define KAGUYA_PUSH_DEF(N) \ 214 | c += lua_type_traits::push(l, KAGUYA_PP_CAT(a, N)); 215 | #define KAGUYA_PUSH_ARG_DEF(N) \ 216 | template \ 217 | inline int push_args(lua_State *l, KAGUYA_PP_ARG_CR_DEF_REPEAT(N)) { \ 218 | int c = 0; \ 219 | KAGUYA_PP_REPEAT(N, KAGUYA_PUSH_DEF) \ 220 | return c; \ 221 | } 222 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_PUSH_ARG_DEF) 223 | #undef KAGUYA_PUSH_DEF 224 | #undef KAGUYA_PUSH_ARG_DEF 225 | #endif 226 | 227 | #if KAGUYA_USE_CPP11 228 | template inline bool one_push(lua_State *state, T &&v) { 229 | int count = util::push_args(state, std::forward(v)); 230 | if (count > 1) { 231 | lua_pop(state, count - 1); 232 | } 233 | return count != 0; 234 | } 235 | #else 236 | template inline bool one_push(lua_State *state, const T &v) { 237 | int count = util::push_args(state, v); 238 | if (count > 1) { 239 | lua_pop(state, count - 1); 240 | } 241 | return count != 0; 242 | } 243 | #endif 244 | 245 | inline std::string pretty_name(const std::type_info &t) { 246 | #if KAGUYA_USE_CXX_ABI_DEMANGLE 247 | int status = 0; 248 | char *demangle_name = abi::__cxa_demangle(t.name(), 0, 0, &status); 249 | struct deleter { 250 | char *data; 251 | deleter(char *d) : data(d) {} 252 | ~deleter() { std::free(data); } 253 | } d(demangle_name); 254 | return demangle_name; 255 | #else 256 | return t.name(); 257 | #endif 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /test/test_09_utility.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include "test_util.hpp" 3 | 4 | namespace { 5 | struct ProxyClassTest { 6 | ProxyClassTest(const std::string &v) 7 | : str(v), num(0), object(0), vec_ptr(0) {} 8 | ProxyClassTest(const int &v) : str(), num(v), object(0), vec_ptr(0) {} 9 | 10 | ProxyClassTest(kaguya_test_util::TestClass *v) 11 | : str(), num(0), object(v), vec_ptr(0) {} 12 | 13 | ProxyClassTest(const std::vector &v) 14 | : str(), num(0), object(0), vec_ptr(&v) {} 15 | 16 | std::string str; 17 | int num; 18 | kaguya_test_util::TestClass *object; 19 | const std::vector *vec_ptr; 20 | }; 21 | } 22 | 23 | namespace kaguya { 24 | template <> 25 | struct lua_type_traits 26 | : util::ConvertibleRegisterHelper< 27 | util::ConvertibleRegisterHelperProxy, int, 28 | std::string, kaguya_test_util::TestClass *, 29 | const std::vector &> {}; 30 | } 31 | 32 | KAGUYA_TEST_GROUP_START(test_09_utility) 33 | 34 | using namespace kaguya_test_util; 35 | 36 | std::string last_error_message; 37 | void ignore_error_fun(int status, const char *message) { 38 | KAGUYA_UNUSED(status); 39 | last_error_message = message ? message : ""; 40 | } 41 | 42 | KAGUYA_TEST_FUNCTION_DEF(lua_resume_test)(kaguya::State &s) { 43 | using namespace kaguya; 44 | 45 | LuaThread t = s.newThread(s.loadstring("v={...}")); 46 | 47 | lua_State *co = t; 48 | lua_pushnumber(co, 2); 49 | lua_pushnumber(co, 3); 50 | 51 | int nres; 52 | lua_resume(co, s.state(), 2, &nres); 53 | 54 | TEST_EQUAL(s["v"][1], 2); 55 | TEST_EQUAL(s["v"][2], 3); 56 | } 57 | KAGUYA_TEST_FUNCTION_DEF(lua_compare_test)(kaguya::State &s) { 58 | using namespace kaguya; 59 | 60 | s.pushToStack(2); 61 | s.pushToStack(2); 62 | TEST_CHECK(lua_compare(s.state(), -2, -1, LUA_OPEQ)); 63 | TEST_CHECK(lua_compare(s.state(), -2, -1, LUA_OPLE)); 64 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPLT)); 65 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPLE + 2)); // invalid option 66 | s.popFromStack(); 67 | s.popFromStack(); 68 | 69 | s.pushToStack(4); 70 | s.pushToStack(2); 71 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPEQ)); 72 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPLE)); 73 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPLT)); 74 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPLE + 2)); // invalid option 75 | s.popFromStack(); 76 | s.popFromStack(); 77 | 78 | s.pushToStack(2); 79 | s.pushToStack(4); 80 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPEQ)); 81 | TEST_CHECK(lua_compare(s.state(), -2, -1, LUA_OPLE)); 82 | TEST_CHECK(lua_compare(s.state(), -2, -1, LUA_OPLT)); 83 | TEST_CHECK(!lua_compare(s.state(), -2, -1, LUA_OPLE + 2)); // invalid option 84 | s.popFromStack(); 85 | s.popFromStack(); 86 | } 87 | 88 | int lua_mylibf(lua_State *L) { 89 | kaguya::State state(L); 90 | kaguya::LuaTable t = state.newTable(); 91 | t["value"] = 111; 92 | return t.push(); 93 | } 94 | 95 | KAGUYA_TEST_FUNCTION_DEF(luaL_requiref_test)(kaguya::State &s) { 96 | using namespace kaguya; 97 | 98 | luaL_requiref(s.state(), "mylib", lua_mylibf, false); 99 | kaguya::LuaStackRef ref(s.state(), -1, true); 100 | TEST_EQUAL(ref["value"], 111); 101 | TEST_CHECK(s("assert(mylib == nil)")); 102 | } 103 | 104 | KAGUYA_TEST_FUNCTION_DEF(stackValueDump)(kaguya::State &s) { 105 | using namespace kaguya; 106 | util::stackValueDump(std::cout, s.state(), 4, 2); 107 | } 108 | 109 | struct A { 110 | int a[4]; 111 | }; 112 | KAGUYA_TEST_FUNCTION_DEF(lua_rawlen_test)(kaguya::State &s) { 113 | using namespace kaguya; 114 | 115 | s.pushToStack("string"); 116 | TEST_EQUAL(lua_rawlen(s.state(), -1), 6); 117 | 118 | LuaTable tbl = s.newTable(); 119 | tbl["2"] = 3; 120 | tbl["1"] = 3; 121 | s.pushToStack(tbl); 122 | TEST_EQUAL(lua_rawlen(s.state(), -1), 0); 123 | 124 | s.pushToStack(A()); 125 | TEST_COMPARE_GE(lua_rawlen(s.state(), -1), sizeof(A)); 126 | 127 | A a; 128 | s.pushToStack(&a); 129 | TEST_EQUAL(lua_type(s.state(), -1), LUA_TLIGHTUSERDATA); 130 | TEST_COMPARE_EQ(lua_rawlen(s.state(), -1), 0); 131 | 132 | s.pushToStack(2); 133 | TEST_EQUAL(lua_rawlen(s.state(), -1), 0); 134 | 135 | lua_settop(s.state(), 0); 136 | } 137 | 138 | void checkf() {} 139 | 140 | template void function_argcount_check(F, size_t count) { 141 | TEST_EQUAL(kaguya::util::FunctionSignature::type::argument_count, count); 142 | } 143 | 144 | template void function_return_type_check(F) { 145 | bool ret = kaguya::standard::is_same< 146 | typename kaguya::util::FunctionSignature::type::result_type, 147 | RET>::value; 148 | TEST_CHECK(ret); 149 | } 150 | KAGUYA_TEST_FUNCTION_DEF(check_function_signature)(kaguya::State &s) { 151 | using namespace kaguya; 152 | 153 | standard::function stdfn(checkf); 154 | 155 | TEST_CHECK(nativefunction::checkArgTypes(s.state(), checkf)); 156 | TEST_CHECK(nativefunction::strictCheckArgTypes(s.state(), checkf)); 157 | TEST_EQUAL(nativefunction::argTypesName(checkf), std::string("")); 158 | TEST_EQUAL(nativefunction::minArgCount(checkf), 0); 159 | TEST_EQUAL(nativefunction::maxArgCount(checkf), 0); 160 | 161 | TEST_CHECK(nativefunction::checkArgTypes(s.state(), &checkf)); 162 | TEST_CHECK(nativefunction::strictCheckArgTypes(s.state(), &checkf)); 163 | TEST_EQUAL(nativefunction::argTypesName(&checkf), std::string("")); 164 | TEST_EQUAL(nativefunction::minArgCount(&checkf), 0); 165 | TEST_EQUAL(nativefunction::maxArgCount(&checkf), 0); 166 | 167 | TEST_CHECK(nativefunction::checkArgTypes(s.state(), stdfn)); 168 | TEST_CHECK(nativefunction::strictCheckArgTypes(s.state(), stdfn)); 169 | TEST_EQUAL(nativefunction::argTypesName(stdfn), std::string("")); 170 | TEST_EQUAL(nativefunction::minArgCount(stdfn), 0); 171 | TEST_EQUAL(nativefunction::maxArgCount(stdfn), 0); 172 | 173 | bool ret = traits::is_same::value; 174 | TEST_CHECK(ret); 175 | ret = 176 | traits::is_same::type>::value; 177 | TEST_CHECK(ret); 178 | ret = traits::is_same< 179 | std::string, util::ArgumentType<1, void(int, std::string)>::type>::value; 180 | TEST_CHECK(ret); 181 | 182 | function_argcount_check(checkf, 0); 183 | function_argcount_check(&TestClass::default_arg, 4); 184 | function_argcount_check(stdfn, 0); 185 | 186 | function_return_type_check(checkf); 187 | function_return_type_check(&TestClass::default_arg); 188 | function_return_type_check(stdfn); 189 | } 190 | 191 | KAGUYA_TEST_FUNCTION_DEF(preprocessor)(kaguya::State &) { 192 | TEST_EQUAL(KAGUYA_PP_INC(1), 2); 193 | TEST_EQUAL(KAGUYA_PP_INC(2), 3); 194 | TEST_EQUAL(KAGUYA_PP_ADD(1, 2), 3); 195 | TEST_EQUAL(KAGUYA_PP_SUB(3, 2), 1); 196 | TEST_EQUAL(KAGUYA_PP_SUB(3, 3), 0); 197 | TEST_EQUAL(KAGUYA_PP_SUB(3, 0), 3); 198 | } 199 | KAGUYA_TEST_FUNCTION_DEF(pretty_type_name)(kaguya::State &) { 200 | using kaguya::util::pretty_name; 201 | 202 | TEST_EQUAL(pretty_name(typeid(int)), "int"); 203 | TEST_EQUAL(pretty_name(typeid(long)), "long"); 204 | } 205 | 206 | void proxy_class_test_func(ProxyClassTest t) { TEST_EQUAL(t.str, "test"); } 207 | void proxy_class_test_func2(const ProxyClassTest &t) { TEST_EQUAL(t.num, 5); } 208 | void proxy_class_test_func3(const ProxyClassTest &t) { 209 | TEST_EQUAL(t.object->stringmember, "test"); 210 | } 211 | void proxy_class_test_func_array(const ProxyClassTest &t) { 212 | std::vector v; 213 | v.push_back(0); 214 | v.push_back(1); 215 | v.push_back(2); 216 | v.push_back(3); 217 | TEST_CHECK(*t.vec_ptr == v); 218 | } 219 | 220 | KAGUYA_TEST_FUNCTION_DEF(proxy_class_test)(kaguya::State &state) { 221 | state["testf"] = &proxy_class_test_func; 222 | TEST_CHECK(state("testf('test')")); 223 | state["testf2"] = &proxy_class_test_func2; 224 | TEST_CHECK(state("testf2(5)")); 225 | 226 | state.setErrorHandler(ignore_error_fun); 227 | TEST_CHECK(!state("testf2()")); 228 | 229 | state["TestClass"].setClass(kaguya::UserdataMetatable() 230 | .setConstructors()); 231 | state["testf3"] = &proxy_class_test_func3; 232 | 233 | TEST_CHECK(state("testf3(TestClass.new('test'))")); 234 | 235 | #ifndef KAGUYA_NO_STD_VECTOR_TO_TABLE 236 | state["testf4"] = &proxy_class_test_func_array; 237 | TEST_CHECK(state("testf4({0,1,2,3})")); 238 | #endif 239 | } 240 | 241 | KAGUYA_TEST_GROUP_END(test_09_utility) 242 | -------------------------------------------------------------------------------- /include/kaguya/native_function_cxx11.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "kaguya/config.hpp" 10 | #include "kaguya/utility.hpp" 11 | #include "kaguya/object.hpp" 12 | 13 | namespace kaguya { 14 | namespace nativefunction { 15 | template struct index_tuple {}; 16 | 17 | template , 18 | bool flag = first >= last> 19 | struct index_range { 20 | using type = result; 21 | }; 22 | 23 | template 24 | struct index_range, false> 25 | : index_range > {}; 26 | 27 | template 28 | int _call_apply(lua_State *state, F &&f, index_tuple, 29 | util::FunctionSignatureType) { 30 | return util::push_args( 31 | state, util::invoke(f, lua_type_traits::get(state, Indexes)...)); 32 | } 33 | template 34 | int _call_apply(lua_State *state, F &&f, index_tuple, 35 | util::FunctionSignatureType) { 36 | KAGUYA_UNUSED(state); 37 | util::invoke(f, lua_type_traits::get(state, Indexes)...); 38 | return 0; 39 | } 40 | 41 | inline bool all_true() { return true; } 42 | template 43 | bool all_true(Arg f, Args... args) { // check from backward and lazy evaluation 44 | return all_true(args...) && bool(f); 45 | } 46 | 47 | inline void join(std::string &, const char *) {} 48 | template 49 | void join(std::string &result, const char *delim, const Arg &str, 50 | const Args &... args) { 51 | result += str; 52 | result += delim; 53 | join(result, delim, args...); 54 | } 55 | 56 | template struct _wcheckeval { 57 | _wcheckeval(lua_State *s, int i, bool opt) 58 | : state(s), index(i), opt_arg(opt) {} 59 | lua_State *state; 60 | int index; 61 | bool opt_arg; 62 | operator bool() { 63 | return (opt_arg && lua_isnoneornil(state, index)) || 64 | lua_type_traits::checkType(state, index); 65 | } 66 | }; 67 | 68 | template struct _scheckeval { 69 | _scheckeval(lua_State *s, int i, bool opt) 70 | : state(s), index(i), opt_arg(opt) {} 71 | lua_State *state; 72 | int index; 73 | bool opt_arg; 74 | operator bool() { 75 | return (opt_arg && lua_isnoneornil(state, index)) || 76 | lua_type_traits::strictCheckType(state, index); 77 | } 78 | }; 79 | 80 | template 81 | bool _ctype_apply(lua_State *state, index_tuple, 82 | util::TypeTuple, int opt_count) { 83 | KAGUYA_UNUSED(state); 84 | KAGUYA_UNUSED(opt_count); 85 | return all_true(_wcheckeval( 86 | state, Indexes, sizeof...(Indexes) - opt_count < Indexes)...); 87 | } 88 | template 89 | bool _sctype_apply(lua_State *state, index_tuple, 90 | util::TypeTuple, int opt_count) { 91 | KAGUYA_UNUSED(state); 92 | KAGUYA_UNUSED(opt_count); 93 | return all_true(_scheckeval( 94 | state, Indexes, sizeof...(Indexes) - opt_count < Indexes)...); 95 | } 96 | 97 | template 98 | std::string _type_name_apply(index_tuple, util::TypeTuple, 99 | int opt_count) { 100 | KAGUYA_UNUSED(opt_count); 101 | std::string result; 102 | const int max_arg = sizeof...(Args); 103 | join(result, ",", 104 | (((max_arg - opt_count < int(Indexes)) ? std::string("[OPT]") 105 | : std::string("")) + 106 | util::pretty_name(typeid(Args)))...); 107 | return result; 108 | } 109 | 110 | template int call(lua_State *state, F &&f) { 111 | typedef typename traits::decay::type ftype; 112 | typedef typename util::FunctionSignature::type fsigtype; 113 | typedef typename index_range<1, fsigtype::argument_count + 1>::type index; 114 | return _call_apply(state, f, index(), fsigtype()); 115 | } 116 | template 117 | bool checkArgTypes(lua_State *state, const F &, int opt_count = 0) { 118 | typedef typename traits::decay::type ftype; 119 | typedef typename util::FunctionSignature::type fsigtype; 120 | typedef typename index_range<1, fsigtype::argument_count + 1>::type index; 121 | typedef typename fsigtype::argument_type_tuple argument_type_tuple; 122 | return _ctype_apply(state, index(), argument_type_tuple(), opt_count); 123 | } 124 | template 125 | bool strictCheckArgTypes(lua_State *state, const F &, int opt_count = 0) { 126 | typedef typename traits::decay::type ftype; 127 | typedef typename util::FunctionSignature::type fsigtype; 128 | typedef typename index_range<1, fsigtype::argument_count + 1>::type index; 129 | typedef typename fsigtype::argument_type_tuple argument_type_tuple; 130 | return _sctype_apply(state, index(), argument_type_tuple(), opt_count); 131 | } 132 | 133 | template std::string argTypesName(const F &, int opt_count = 0) { 134 | typedef typename traits::decay::type ftype; 135 | typedef typename util::FunctionSignature::type fsigtype; 136 | typedef typename index_range<1, fsigtype::argument_count + 1>::type index; 137 | typedef typename fsigtype::argument_type_tuple argument_type_tuple; 138 | return _type_name_apply(index(), argument_type_tuple(), opt_count); 139 | } 140 | template int minArgCount(const F &) { 141 | typedef typename traits::decay::type ftype; 142 | typedef typename util::FunctionSignature::type fsigtype; 143 | return fsigtype::argument_count; 144 | } 145 | template int maxArgCount(const F &) { 146 | typedef typename traits::decay::type ftype; 147 | typedef typename util::FunctionSignature::type fsigtype; 148 | return fsigtype::argument_count; 149 | } 150 | 151 | // for constructor 152 | template struct ConstructorFunctor; 153 | 154 | template 155 | struct ConstructorFunctor > { 156 | typedef util::FunctionSignatureType signature_type; 157 | typedef typename index_range<1, sizeof...(Args) + 1>::type get_index; 158 | 159 | template 160 | int invoke(lua_State *L, index_tuple) const { 161 | typedef ObjectWrapper wrapper_type; 162 | void *storage = lua_newuserdata(L, sizeof(wrapper_type)); 163 | try { 164 | new (storage) wrapper_type(lua_type_traits::get(L, Indexes)...); 165 | } catch (...) { 166 | lua_pop(L, 1); 167 | throw; 168 | } 169 | 170 | class_userdata::setmetatable(L); 171 | return 1; 172 | } 173 | 174 | int operator()(lua_State *L) const { return invoke(L, get_index()); } 175 | 176 | bool checkArgTypes(lua_State *L, int opt_count = 0) const { 177 | return _ctype_apply(L, get_index(), 178 | typename signature_type::argument_type_tuple(), 179 | opt_count); 180 | } 181 | bool strictCheckArgTypes(lua_State *L, int opt_count = 0) const { 182 | return _sctype_apply(L, get_index(), 183 | typename signature_type::argument_type_tuple(), 184 | opt_count); 185 | } 186 | std::string argTypesName(int opt_count = 0) const { 187 | return _type_name_apply( 188 | get_index(), typename signature_type::argument_type_tuple(), opt_count); 189 | } 190 | }; 191 | 192 | template struct ConstructorFunction; 193 | template 194 | struct ConstructorFunction { 195 | typedef ConstructorFunctor > 196 | type; 197 | }; 198 | template 199 | struct ConstructorFunction // class type check version 201 | { 202 | typedef ConstructorFunctor > 203 | type; 204 | }; 205 | } 206 | using nativefunction::ConstructorFunction; 207 | } 208 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " singlehtml to make a single large HTML file" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and a HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " applehelp to make an Apple Help Book" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " epub3 to make an epub3" 31 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 33 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 34 | @echo " text to make text files" 35 | @echo " man to make manual pages" 36 | @echo " texinfo to make Texinfo files" 37 | @echo " info to make Texinfo files and run them through makeinfo" 38 | @echo " gettext to make PO message catalogs" 39 | @echo " changes to make an overview of all changed/added/deprecated items" 40 | @echo " xml to make Docutils-native XML files" 41 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 42 | @echo " linkcheck to check all external links for integrity" 43 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 44 | @echo " coverage to run coverage check of the documentation (if enabled)" 45 | @echo " dummy to check syntax errors of document sources" 46 | 47 | .PHONY: clean 48 | clean: 49 | rm -rf $(BUILDDIR)/* 50 | 51 | .PHONY: html 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | .PHONY: dirhtml 58 | dirhtml: 59 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 62 | 63 | .PHONY: singlehtml 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | .PHONY: pickle 70 | pickle: 71 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 72 | @echo 73 | @echo "Build finished; now you can process the pickle files." 74 | 75 | .PHONY: json 76 | json: 77 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 78 | @echo 79 | @echo "Build finished; now you can process the JSON files." 80 | 81 | .PHONY: htmlhelp 82 | htmlhelp: 83 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 84 | @echo 85 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 86 | ".hhp project file in $(BUILDDIR)/htmlhelp." 87 | 88 | .PHONY: qthelp 89 | qthelp: 90 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 91 | @echo 92 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 93 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 94 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Kaguya.qhcp" 95 | @echo "To view the help file:" 96 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Kaguya.qhc" 97 | 98 | .PHONY: applehelp 99 | applehelp: 100 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 101 | @echo 102 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 103 | @echo "N.B. You won't be able to view it unless you put it in" \ 104 | "~/Library/Documentation/Help or install it in your application" \ 105 | "bundle." 106 | 107 | .PHONY: devhelp 108 | devhelp: 109 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 110 | @echo 111 | @echo "Build finished." 112 | @echo "To view the help file:" 113 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Kaguya" 114 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Kaguya" 115 | @echo "# devhelp" 116 | 117 | .PHONY: epub 118 | epub: 119 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 120 | @echo 121 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 122 | 123 | .PHONY: epub3 124 | epub3: 125 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 126 | @echo 127 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 128 | 129 | .PHONY: latex 130 | latex: 131 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 132 | @echo 133 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 134 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 135 | "(use \`make latexpdf' here to do that automatically)." 136 | 137 | .PHONY: latexpdf 138 | latexpdf: 139 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 140 | @echo "Running LaTeX files through pdflatex..." 141 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 142 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 143 | 144 | .PHONY: latexpdfja 145 | latexpdfja: 146 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 147 | @echo "Running LaTeX files through platex and dvipdfmx..." 148 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 149 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 150 | 151 | .PHONY: text 152 | text: 153 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 154 | @echo 155 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 156 | 157 | .PHONY: man 158 | man: 159 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 160 | @echo 161 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 162 | 163 | .PHONY: texinfo 164 | texinfo: 165 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 166 | @echo 167 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 168 | @echo "Run \`make' in that directory to run these through makeinfo" \ 169 | "(use \`make info' here to do that automatically)." 170 | 171 | .PHONY: info 172 | info: 173 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 174 | @echo "Running Texinfo files through makeinfo..." 175 | make -C $(BUILDDIR)/texinfo info 176 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 177 | 178 | .PHONY: gettext 179 | gettext: 180 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 181 | @echo 182 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 183 | 184 | .PHONY: changes 185 | changes: 186 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 187 | @echo 188 | @echo "The overview file is in $(BUILDDIR)/changes." 189 | 190 | .PHONY: linkcheck 191 | linkcheck: 192 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 193 | @echo 194 | @echo "Link check complete; look for any errors in the above output " \ 195 | "or in $(BUILDDIR)/linkcheck/output.txt." 196 | 197 | .PHONY: doctest 198 | doctest: 199 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 200 | @echo "Testing of doctests in the sources finished, look at the " \ 201 | "results in $(BUILDDIR)/doctest/output.txt." 202 | 203 | .PHONY: coverage 204 | coverage: 205 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 206 | @echo "Testing of coverage in the sources finished, look at the " \ 207 | "results in $(BUILDDIR)/coverage/python.txt." 208 | 209 | .PHONY: xml 210 | xml: 211 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 212 | @echo 213 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 214 | 215 | .PHONY: pseudoxml 216 | pseudoxml: 217 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 218 | @echo 219 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 220 | 221 | .PHONY: dummy 222 | dummy: 223 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 224 | @echo 225 | @echo "Build finished. Dummy builder generates no files." 226 | -------------------------------------------------------------------------------- /test/test_08_optional.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | KAGUYA_TEST_GROUP_START(test_08_optional) 4 | 5 | using namespace kaguya_test_util; 6 | 7 | KAGUYA_TEST_FUNCTION_DEF(optional_construct)(kaguya::State &) { 8 | kaguya::optional opt1 = 1; 9 | TEST_EQUAL(1, *opt1); 10 | 11 | kaguya::optional opt2 = std::string("abc"); 12 | TEST_EQUAL("abc", *opt2); 13 | 14 | TEST_EQUAL(std::string("abc"), opt2.value_or("def")); 15 | 16 | const kaguya::optional opt3 = opt2; 17 | TEST_EQUAL("abc", *opt2); 18 | TEST_EQUAL("abc", *opt3); 19 | std::string value("data"); 20 | TEST_CHECK(opt2 = value); 21 | } 22 | 23 | KAGUYA_TEST_FUNCTION_DEF(optional_copy)(kaguya::State &) { 24 | kaguya::optional s1 = "abc", s2; // constructor 25 | 26 | TEST_EQUAL(std::string("def"), s2.value_or("def")); 27 | TEST_CHECK((s2 = s1)); 28 | TEST_CHECK((s1 = "def")); 29 | 30 | TEST_EQUAL(std::string("def"), s1.value_or("abc")); 31 | TEST_EQUAL(std::string("abc"), s2.value_or("def")); 32 | TEST_CHECK(s1); 33 | TEST_CHECK(s2); 34 | TEST_EQUAL(std::string("abc"), *s2); 35 | TEST_EQUAL(std::string("def"), *s1); 36 | 37 | TEST_CHECK(!(s2 = kaguya::optional())); 38 | TEST_CHECK(!s2); 39 | 40 | TEST_CHECK(s2 = s1); 41 | TEST_EQUAL(std::string("def"), *s2); 42 | TEST_CHECK(s2 = "data"); 43 | TEST_EQUAL(std::string("data"), *s2); 44 | 45 | kaguya::optional csnullopt; 46 | TEST_CHECK(!(s2 = csnullopt)); 47 | TEST_CHECK(!(s2 = csnullopt)); 48 | TEST_CHECK(!s2); 49 | 50 | kaguya::nullopt_t nullopt; 51 | TEST_CHECK(!(s2 = nullopt)); 52 | TEST_CHECK(!s2); 53 | } 54 | 55 | KAGUYA_TEST_FUNCTION_DEF(optional_ref)(kaguya::State &) { 56 | const std::string &str = "abc"; 57 | kaguya::optional s1 = str; // constructor 58 | TEST_EQUAL(std::string("abc"), *s1); 59 | 60 | TEST_EQUAL(std::string("abc"), s1.value_or("def")); 61 | 62 | const kaguya::optional s2 = str; // constructor 63 | TEST_CHECK(s2); 64 | TEST_EQUAL(std::string("abc"), *s2); 65 | TEST_EQUAL(std::string("abc"), s1.value_or("def")); 66 | 67 | kaguya::optional csnullopt; 68 | TEST_CHECK(!(s1 = csnullopt)); 69 | TEST_CHECK(!s1); 70 | 71 | TEST_CHECK(s1 = str); 72 | TEST_CHECK(s1); 73 | 74 | kaguya::nullopt_t nullopt; 75 | TEST_CHECK(!(s1 = nullopt)); 76 | TEST_CHECK(!s1); 77 | } 78 | 79 | KAGUYA_TEST_FUNCTION_DEF(optional_value_error)(kaguya::State &) { 80 | kaguya::optional s1; 81 | 82 | TEST_CHECK(!s1); 83 | TEST_EQUAL(std::string("def"), s1.value_or("def")); 84 | try { 85 | s1.value(); 86 | } catch (const kaguya::bad_optional_access &) { 87 | return; 88 | } 89 | TEST_CHECK(false); 90 | } 91 | KAGUYA_TEST_FUNCTION_DEF(optional_value_error2)(kaguya::State &) { 92 | kaguya::optional s1; 93 | 94 | TEST_CHECK(!s1); 95 | TEST_EQUAL(std::string("def"), s1.value_or("def")); 96 | try { 97 | s1.value(); 98 | } catch (const kaguya::bad_optional_access &) { 99 | return; 100 | } 101 | TEST_CHECK(false); 102 | } 103 | KAGUYA_TEST_FUNCTION_DEF(optional_value_error3)(kaguya::State &) { 104 | const kaguya::optional s1; 105 | 106 | TEST_CHECK(!s1); 107 | TEST_EQUAL(std::string("def"), s1.value_or("def")); 108 | 109 | bool catch_except = false; 110 | try { 111 | s1.value(); 112 | } catch (const kaguya::bad_optional_access &) { 113 | catch_except = true; 114 | } 115 | TEST_CHECK(catch_except); 116 | } 117 | KAGUYA_TEST_FUNCTION_DEF(optional_value_error4)(kaguya::State &) { 118 | const kaguya::optional s1; 119 | 120 | TEST_CHECK(!s1); 121 | TEST_EQUAL(std::string("def"), s1.value_or("def")); 122 | bool catch_except = false; 123 | try { 124 | s1.value(); 125 | } catch (const kaguya::bad_optional_access &) { 126 | catch_except = true; 127 | } 128 | TEST_CHECK(catch_except); 129 | } 130 | 131 | #if KAGUYA_USE_CPP11 132 | struct MoveOnlyClass { 133 | MoveOnlyClass(int i) : member(i) {} 134 | int member; 135 | 136 | MoveOnlyClass(MoveOnlyClass &&src) : member(src.member) {} 137 | MoveOnlyClass &operator=(MoveOnlyClass &&src) { 138 | member = src.member; 139 | return *this; 140 | } 141 | 142 | private: 143 | MoveOnlyClass(); 144 | MoveOnlyClass(const MoveOnlyClass &); 145 | MoveOnlyClass &operator=(const MoveOnlyClass &); 146 | }; 147 | 148 | KAGUYA_TEST_FUNCTION_DEF(optional_move)(kaguya::State &) { 149 | kaguya::optional s1 = MoveOnlyClass(43); 150 | kaguya::optional s2; // constructor 151 | s2 = std::move(s1); 152 | s1 = MoveOnlyClass(12); 153 | TEST_EQUAL(43, s2->member); 154 | TEST_EQUAL(12, s1->member); 155 | } 156 | #endif 157 | 158 | template 159 | void optional_type_test( 160 | const typename kaguya::traits::decay::type &init_value, 161 | const typename kaguya::traits::decay::type &other_value) { 162 | typedef kaguya::optional test_type; 163 | 164 | test_type init_v_opt(init_value); 165 | test_type other_v_opt(other_value); 166 | test_type nullopt_v_opt; 167 | 168 | TEST_EQUAL(init_v_opt == other_v_opt, init_value == other_value); 169 | TEST_EQUAL(init_v_opt != other_v_opt, init_value != other_value); 170 | TEST_EQUAL(init_v_opt < other_v_opt, init_value < other_value); 171 | TEST_EQUAL(init_v_opt > other_v_opt, init_value > other_value); 172 | TEST_EQUAL(init_v_opt <= other_v_opt, init_value <= other_value); 173 | TEST_EQUAL(init_v_opt >= other_v_opt, init_value >= other_value); 174 | 175 | TEST_EQUAL(init_v_opt == nullopt_v_opt, false); 176 | TEST_EQUAL(init_v_opt != nullopt_v_opt, true); 177 | TEST_EQUAL(init_v_opt < nullopt_v_opt, false); 178 | TEST_EQUAL(init_v_opt > nullopt_v_opt, true); 179 | TEST_EQUAL(init_v_opt <= nullopt_v_opt, false); 180 | TEST_EQUAL(init_v_opt >= nullopt_v_opt, true); 181 | 182 | TEST_EQUAL(nullopt_v_opt == nullopt_v_opt, true); 183 | TEST_EQUAL(nullopt_v_opt != nullopt_v_opt, false); 184 | TEST_EQUAL(nullopt_v_opt < nullopt_v_opt, false); 185 | TEST_EQUAL(nullopt_v_opt > nullopt_v_opt, false); 186 | TEST_EQUAL(nullopt_v_opt <= nullopt_v_opt, true); 187 | TEST_EQUAL(nullopt_v_opt >= nullopt_v_opt, true); 188 | 189 | test_type opt1 = init_value; 190 | TEST_EQUAL(init_value, opt1.value()); 191 | TEST_EQUAL(init_value, *opt1); 192 | TEST_EQUAL(init_value, opt1.value_or(other_value)); 193 | TEST_CHECK(!(opt1 = nullopt_v_opt)); 194 | TEST_EQUAL(other_value, opt1.value_or(other_value)); 195 | TEST_CHECK(!(opt1 = nullopt_v_opt)); 196 | 197 | opt1 = init_value; 198 | TEST_EQUAL(init_value, opt1.value()); 199 | TEST_EQUAL(init_value, *opt1); 200 | TEST_EQUAL(init_value, opt1.value_or(T(other_value))); 201 | TEST_CHECK(!(opt1 = nullopt_v_opt)); 202 | TEST_EQUAL(other_value, opt1.value_or(T(other_value))); 203 | TEST_CHECK(!(opt1 = nullopt_v_opt)); 204 | 205 | bool except_catch = false; 206 | try { 207 | opt1.value(); 208 | } catch (const kaguya::bad_optional_access &) { 209 | except_catch = true; 210 | } 211 | TEST_CHECK(except_catch); 212 | 213 | TEST_CHECK(opt1 = test_type(init_value)); 214 | TEST_EQUAL(init_value, *opt1); 215 | TEST_CHECK(opt1 = test_type(other_value)); 216 | TEST_EQUAL(other_value, *opt1); 217 | 218 | TEST_CHECK(opt1 = test_type(T(init_value))); 219 | TEST_EQUAL(init_value, *opt1); 220 | TEST_CHECK(opt1 = T(init_value)); 221 | TEST_EQUAL(init_value, *opt1); 222 | 223 | TEST_CHECK(opt1 = init_v_opt); 224 | TEST_EQUAL(init_value, *opt1); 225 | TEST_CHECK(opt1 = other_v_opt); 226 | TEST_EQUAL(other_value, *opt1); 227 | 228 | TEST_CHECK(opt1 = init_value); 229 | TEST_EQUAL(init_value, *opt1); 230 | TEST_CHECK(opt1 = other_value); 231 | TEST_EQUAL(other_value, *opt1); 232 | 233 | const test_type copt1 = init_value; 234 | TEST_CHECK(copt1); 235 | TEST_EQUAL(init_value, *copt1); 236 | 237 | TEST_EQUAL(init_value, copt1.value_or(other_value)); 238 | 239 | const test_type copt2; 240 | TEST_CHECK(!copt2); 241 | except_catch = false; 242 | try { 243 | copt2.value(); 244 | } catch (const kaguya::bad_optional_access &) { 245 | except_catch = true; 246 | } 247 | TEST_CHECK(except_catch); 248 | } 249 | 250 | KAGUYA_TEST_FUNCTION_DEF(optional_type)(kaguya::State &) { 251 | optional_type_test(1, 4); 252 | optional_type_test(1, 4); 253 | optional_type_test(1, 4); 254 | optional_type_test(1, 4); 255 | optional_type_test("abc", "def"); 256 | optional_type_test("abc", "def"); 257 | optional_type_test("abc", "def"); 258 | } 259 | 260 | KAGUYA_TEST_GROUP_END(test_08_optional) 261 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Kaguya.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Kaguya.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /include/kaguya/another_binding_api.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | 7 | #include "kaguya/kaguya.hpp" 8 | 9 | /// @addtogroup another_binding_api 10 | /// @brief Boost.python like binding API.(experimental) 11 | /// this api is not multi-thread-safe. 12 | /// @{ 13 | 14 | #if defined(KAGUYA_DYNAMIC_LIB) 15 | #if defined(_WIN32) || defined(_WIN64) 16 | #define KAGUYA_EXPORT extern "C" __declspec(dllexport) 17 | #else 18 | #define KAGUYA_EXPORT extern "C" __attribute__((visibility("default"))) 19 | #endif 20 | #else 21 | #define KAGUYA_EXPORT 22 | #endif 23 | 24 | /// @brief start define binding 25 | #define KAGUYA_BINDINGS(MODULE_NAME) \ 26 | \ 27 | void KAGUYA_PP_CAT(kaguya_bind_internal_, MODULE_NAME)(); \ 28 | \ 29 | KAGUYA_EXPORT int \ 30 | KAGUYA_PP_CAT(luaopen_, MODULE_NAME)(lua_State * L) { \ 31 | return kaguya::detail::bind_internal( \ 32 | L, &KAGUYA_PP_CAT(kaguya_bind_internal_, MODULE_NAME)); \ 33 | } \ 34 | \ 35 | void KAGUYA_PP_CAT(kaguya_bind_internal_, MODULE_NAME)() 36 | 37 | namespace kaguya { 38 | namespace detail { 39 | struct scope_stack { 40 | LuaTable current_scope() { 41 | return !stack.empty() ? stack.back() : LuaTable(); 42 | } 43 | static scope_stack &instance() { 44 | static scope_stack instance_; 45 | return instance_; 46 | } 47 | void push(const LuaTable &table) { stack.push_back(table); } 48 | void pop() { stack.pop_back(); } 49 | 50 | private: 51 | scope_stack() {} 52 | scope_stack(const scope_stack &); 53 | scope_stack &operator=(const scope_stack &); 54 | 55 | std::vector stack; 56 | }; 57 | } 58 | 59 | /// @ingroup another_binding_api 60 | /// @brief binding scope 61 | struct scope { 62 | scope(const std::string &name) : pushed_(true) { 63 | detail::scope_stack &stack = detail::scope_stack::instance(); 64 | LuaTable current = stack.current_scope(); 65 | if (!current[name]) { 66 | current[name] = NewTable(); 67 | } 68 | scope_table_ = current[name]; 69 | stack.push(scope_table_); 70 | } 71 | scope(const LuaTable &t) : pushed_(true) { 72 | scope_table_ = t; 73 | detail::scope_stack::instance().push(scope_table_); 74 | } 75 | scope() : pushed_(false) { 76 | detail::scope_stack &stack = detail::scope_stack::instance(); 77 | scope_table_ = stack.current_scope(); 78 | } 79 | 80 | TableKeyReferenceProxy attr(const std::string &name) { 81 | return scope_table_.operator[](name); 82 | } 83 | LuaTable table() { return scope_table_; } 84 | 85 | ~scope() { 86 | if (pushed_) { 87 | detail::scope_stack::instance().pop(); 88 | } 89 | } 90 | 91 | private: 92 | LuaTable scope_table_; 93 | bool pushed_; 94 | }; 95 | 96 | namespace detail { 97 | inline int bind_internal(lua_State *L, void (*bindfn)()) { 98 | int count = lua_gettop(L); 99 | kaguya::State state(L); 100 | LuaTable l = state.newTable(); 101 | l.push(); 102 | scope scope(l); 103 | bindfn(); 104 | return lua_gettop(L) - count; 105 | } 106 | } 107 | 108 | /// @ingroup another_binding_api 109 | /// @brief define class binding 110 | template 111 | struct class_ : private UserdataMetatable { 112 | class_(const std::string &name) : name_(name) {} 113 | ~class_() { 114 | LuaTable scope = detail::scope_stack::instance().current_scope(); 115 | if (scope) { 116 | scope[name_].setClass(*this); 117 | } 118 | } 119 | 120 | #if KAGUYA_USE_CPP11 121 | template class_ &constructor() { 122 | this->template setConstructors(); 123 | return *this; 124 | } 125 | 126 | template class_ &constructors() { 127 | this->template setConstructors(); 128 | return *this; 129 | } 130 | #else 131 | class_ &constructor() { 132 | this->template setConstructors(); 133 | return *this; 134 | } 135 | 136 | #define KAGUYA_ADD_CON_FN_DEF(N) \ 137 | template class_ &constructor() { \ 138 | this->template setConstructors(); \ 140 | return *this; \ 141 | } 142 | 143 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_ADD_CON_FN_DEF) 144 | #undef KAGUYA_ADD_CON_FN_DEF 145 | 146 | class_ &constructors() { 147 | this->template setConstructors(); 148 | return *this; 149 | } 150 | 151 | #define KAGUYA_ADD_CONS_FN_DEF(N) \ 152 | template class_ &constructors() { \ 153 | this->template setConstructors(); \ 154 | return *this; \ 155 | } 156 | 157 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_ADD_CONS_FN_DEF) 158 | #undef KAGUYA_ADD_CONS_FN_DEF 159 | #endif 160 | 161 | /// @ingroup another_binding_api 162 | /// @brief function binding 163 | template class_ &function(const char *name, F f) { 164 | this->addFunction(name, f); 165 | return *this; 166 | } 167 | 168 | template 169 | class_ &function(const char *name, FunctionInvokerType f) { 170 | this->addStaticField(name, f); 171 | return *this; 172 | } 173 | 174 | /// @ingroup another_binding_api 175 | /// @brief property binding 176 | template class_ &property(const char *name, F f) { 177 | this->addProperty(name, f); 178 | return *this; 179 | } 180 | 181 | /// @ingroup another_binding_api 182 | /// @brief property binding with getter and sette function 183 | template 184 | class_ &property(const char *name, Getter getter, Setter setter) { 185 | this->addProperty(name, getter, setter); 186 | return *this; 187 | } 188 | 189 | /// @brief class function binding 190 | template class_ &class_function(const char *name, F f) { 191 | this->addStaticFunction(name, f); 192 | return *this; 193 | } 194 | 195 | template 196 | class_ &class_function(const char *name, FunctionInvokerType f) { 197 | this->addStaticField(name, f); 198 | return *this; 199 | } 200 | 201 | /// @ingroup another_binding_api 202 | /// @brief function binding 203 | template class_ &def(const char *name, F f) { 204 | this->addFunction(name, f); 205 | return *this; 206 | } 207 | 208 | /// @ingroup another_binding_api 209 | /// @brief property binding with getter and sette function 210 | template 211 | class_ &add_property(const char *name, Getter getter, Setter setter) { 212 | property(name, getter, setter); 213 | return *this; 214 | } 215 | 216 | /// @ingroup another_binding_api 217 | /// @brief property binding 218 | template class_ &add_property(const char *name, F f) { 219 | property(name, f); 220 | return *this; 221 | } 222 | 223 | /// @ingroup another_binding_api 224 | /// @brief static property binding 225 | template 226 | class_ &add_static_property(const char *name, Data data) { 227 | this->addStaticField(name, data); 228 | return *this; 229 | } 230 | 231 | private: 232 | std::string name_; 233 | }; 234 | 235 | template struct enum_ { 236 | enum_(const std::string &name) : enum_scope_table_(scope(name).table()) {} 237 | enum_ &value(const char *name, EnumType data) { 238 | enum_scope_table_[name] = data; 239 | return *this; 240 | } 241 | 242 | private: 243 | LuaTable enum_scope_table_; 244 | }; 245 | 246 | /// @ingroup another_binding_api 247 | /// @brief function binding 248 | template void function(const char *name, F f) { 249 | LuaTable scope = detail::scope_stack::instance().current_scope(); 250 | if (scope) { 251 | scope[name] = kaguya::function(f); 252 | } 253 | } 254 | template 255 | void function(const char *name, FunctionInvokerType f) { 256 | LuaTable scope = detail::scope_stack::instance().current_scope(); 257 | if (scope) { 258 | scope[name] = f; 259 | } 260 | } 261 | 262 | /// @ingroup another_binding_api 263 | /// @brief function binding 264 | template void def(const char *name, F f) { 265 | kaguya::function(name, f); 266 | } 267 | 268 | /// @ingroup another_binding_api 269 | /// @brief function binding 270 | template void constant(const char *name, T v) { 271 | LuaTable scope = detail::scope_stack::instance().current_scope(); 272 | if (scope) { 273 | scope[name] = v; 274 | } 275 | } 276 | } 277 | /// @} 278 | -------------------------------------------------------------------------------- /include/kaguya/detail/lua_ref_impl.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "kaguya/config.hpp" 14 | #include "kaguya/error_handler.hpp" 15 | #include "kaguya/type.hpp" 16 | #include "kaguya/utility.hpp" 17 | 18 | namespace kaguya { 19 | /// @brief StackTop tag type 20 | struct StackTop {}; 21 | 22 | namespace Ref { 23 | /// @brief NoMainCheck tag type 24 | struct NoMainCheck {}; 25 | 26 | /// @brief reference to Lua stack value 27 | class StackRef { 28 | protected: 29 | lua_State *state_; 30 | int stack_index_; 31 | mutable bool pop_; 32 | #if KAGUYA_USE_CPP11 33 | StackRef(StackRef &&src) 34 | : state_(src.state_), stack_index_(src.stack_index_), pop_(src.pop_) { 35 | src.pop_ = false; 36 | } 37 | StackRef &operator=(StackRef &&src) { 38 | state_ = src.state_; 39 | stack_index_ = src.stack_index_; 40 | pop_ = src.pop_; 41 | 42 | src.pop_ = false; 43 | return *this; 44 | } 45 | 46 | StackRef(const StackRef &src) = delete; 47 | StackRef &operator=(const StackRef &src) = delete; 48 | #else 49 | StackRef(const StackRef &src) 50 | : state_(src.state_), stack_index_(src.stack_index_), pop_(src.pop_) { 51 | src.pop_ = false; 52 | } 53 | StackRef &operator=(const StackRef &src) { 54 | if (this != &src) { 55 | state_ = src.state_; 56 | stack_index_ = src.stack_index_; 57 | pop_ = src.pop_; 58 | 59 | src.pop_ = false; 60 | } 61 | return *this; 62 | } 63 | #endif 64 | StackRef(lua_State *s, int index) 65 | : state_(s), stack_index_(lua_absindex(s, index)), pop_(true) {} 66 | StackRef(lua_State *s, int index, bool pop) 67 | : state_(s), stack_index_(lua_absindex(s, index)), pop_(pop) {} 68 | StackRef() : state_(0), stack_index_(0), pop_(false) {} 69 | ~StackRef() { 70 | if (state_ && pop_) { 71 | if (lua_gettop(state_) >= stack_index_) { 72 | lua_settop(state_, stack_index_ - 1); 73 | } 74 | } 75 | } 76 | 77 | public: 78 | bool isNilref() const { 79 | return state_ == 0 || lua_type(state_, stack_index_) == LUA_TNIL; 80 | } 81 | 82 | int push() const { 83 | lua_pushvalue(state_, stack_index_); 84 | return 1; 85 | } 86 | int push(lua_State *state) const { 87 | lua_pushvalue(state_, stack_index_); 88 | if (state_ != state) { 89 | lua_pushvalue(state_, stack_index_); 90 | lua_xmove(state_, state, 1); 91 | } 92 | return 1; 93 | } 94 | 95 | int pushStackIndex(lua_State *state) const { 96 | if (state_ != state) { 97 | lua_pushvalue(state_, stack_index_); 98 | lua_xmove(state_, state, 1); 99 | return lua_gettop(state); 100 | } else { 101 | return stack_index_; 102 | } 103 | } 104 | lua_State *state() const { return state_; } 105 | }; 106 | 107 | /// @brief Reference to Lua value. Retain reference by LUA_REGISTRYINDEX 108 | class RegistoryRef { 109 | public: 110 | #if KAGUYA_USE_SHARED_LUAREF 111 | struct RefHolder { 112 | struct RefDeleter { 113 | RefDeleter(lua_State *L) : state_(L) {} 114 | void operator()(int *ref) { 115 | luaL_unref(state_, LUA_REGISTRYINDEX, *ref); 116 | delete ref; 117 | } 118 | lua_State *state_; 119 | }; 120 | RefHolder(lua_State *L, int ref) 121 | : state_(L), ref_(new int(ref), RefDeleter(L)) {} 122 | 123 | RefHolder(const RefHolder &src) : state_(src.state_), ref_(src.ref_) {} 124 | RefHolder &operator=(const RefHolder &src) { 125 | state_ = src.state_; 126 | ref_ = src.ref_; 127 | return *this; 128 | } 129 | #if KAGUYA_USE_RVALUE_REFERENCE 130 | RefHolder(RefHolder &&src) : state_(0), ref_() { swap(src); } 131 | RefHolder &operator=(RefHolder &&src) throw() { 132 | swap(src); 133 | return *this; 134 | } 135 | #endif 136 | void swap(RefHolder &other) throw() { 137 | std::swap(state_, other.state_); 138 | std::swap(ref_, other.ref_); 139 | } 140 | int ref() const { 141 | if (state_ && ref_) { 142 | return *ref_; 143 | } 144 | return LUA_REFNIL; 145 | } 146 | void reset() { ref_.reset(); } 147 | lua_State *state() const { return state_; } 148 | 149 | private: 150 | lua_State *state_; 151 | standard::shared_ptr ref_; 152 | }; 153 | #else 154 | struct RefHolder { 155 | RefHolder(lua_State *L, int ref) : state_(L), ref_(ref) {} 156 | RefHolder(const RefHolder &src) : state_(src.state_), ref_(LUA_REFNIL) { 157 | if (state_) { 158 | lua_rawgeti(state_, LUA_REGISTRYINDEX, src.ref_); 159 | ref_ = luaL_ref(state_, LUA_REGISTRYINDEX); 160 | } 161 | } 162 | RefHolder &operator=(const RefHolder &src) { 163 | reset(); 164 | state_ = src.state_; 165 | if (state_) { 166 | lua_rawgeti(state_, LUA_REGISTRYINDEX, src.ref_); 167 | ref_ = luaL_ref(state_, LUA_REGISTRYINDEX); 168 | } else { 169 | ref_ = LUA_REFNIL; 170 | } 171 | return *this; 172 | } 173 | #if KAGUYA_USE_RVALUE_REFERENCE 174 | RefHolder(RefHolder &&src) throw() : state_(src.state_), ref_(src.ref_) { 175 | src.ref_ = LUA_REFNIL; 176 | } 177 | RefHolder &operator=(RefHolder &&src) throw() { 178 | swap(src); 179 | return *this; 180 | } 181 | #endif 182 | void swap(RefHolder &other) throw() { 183 | std::swap(state_, other.state_); 184 | std::swap(ref_, other.ref_); 185 | } 186 | int ref() const { 187 | if (state_) { 188 | return ref_; 189 | } 190 | return LUA_REFNIL; 191 | } 192 | void reset() { 193 | if (ref_ != LUA_REFNIL && state_) { 194 | luaL_unref(state_, LUA_REGISTRYINDEX, ref_); 195 | ref_ = LUA_REFNIL; 196 | } 197 | } 198 | ~RefHolder() { reset(); } 199 | 200 | lua_State *state() const { return state_; } 201 | 202 | private: 203 | lua_State *state_; 204 | int ref_; 205 | }; 206 | #endif 207 | RegistoryRef(const RegistoryRef &src) : ref_(src.ref_) {} 208 | RegistoryRef &operator=(const RegistoryRef &src) { 209 | if (this != &src) { 210 | ref_ = src.ref_; 211 | } 212 | return *this; 213 | } 214 | 215 | static int ref_from_stacktop(lua_State *state) { 216 | if (state) { 217 | return luaL_ref(state, LUA_REGISTRYINDEX); 218 | } else { 219 | return LUA_REFNIL; 220 | } 221 | } 222 | #if KAGUYA_USE_RVALUE_REFERENCE 223 | RegistoryRef(RegistoryRef &&src) throw() : ref_(0, LUA_REFNIL) { swap(src); } 224 | RegistoryRef &operator=(RegistoryRef &&src) throw() { 225 | swap(src); 226 | return *this; 227 | } 228 | #endif 229 | 230 | RegistoryRef() : ref_(0, LUA_REFNIL) {} 231 | RegistoryRef(lua_State *state) : ref_(state, LUA_REFNIL) {} 232 | 233 | RegistoryRef(lua_State *state, StackTop, NoMainCheck) 234 | : ref_(state, ref_from_stacktop(state)) {} 235 | 236 | RegistoryRef(lua_State *state, StackTop) 237 | : ref_(util::toMainThread(state), ref_from_stacktop(state)) {} 238 | 239 | void swap(RegistoryRef &other) throw() { ref_.swap(other.ref_); } 240 | 241 | template 242 | RegistoryRef(lua_State *state, const T &v, NoMainCheck) 243 | : ref_(0, LUA_REFNIL) { 244 | if (!state) { 245 | return; 246 | } 247 | util::ScopedSavedStack save(state); 248 | util::one_push(state, v); 249 | ref_ = RefHolder(state, ref_from_stacktop(state)); 250 | } 251 | template 252 | RegistoryRef(lua_State *state, const T &v) : ref_(0, LUA_REFNIL) { 253 | if (!state) { 254 | return; 255 | } 256 | util::ScopedSavedStack save(state); 257 | util::one_push(state, v); 258 | ref_ = RefHolder(util::toMainThread(state), ref_from_stacktop(state)); 259 | } 260 | #if KAGUYA_USE_CPP11 261 | template 262 | RegistoryRef(lua_State *state, T &&v, NoMainCheck) : ref_(0, LUA_REFNIL) { 263 | if (!state) { 264 | return; 265 | } 266 | util::ScopedSavedStack save(state); 267 | util::one_push(state, standard::forward(v)); 268 | ref_ = RefHolder(state, ref_from_stacktop(state)); 269 | } 270 | template 271 | RegistoryRef(lua_State *state, T &&v) : ref_(0, LUA_REFNIL) { 272 | if (!state) { 273 | return; 274 | } 275 | util::ScopedSavedStack save(state); 276 | util::one_push(state, standard::forward(v)); 277 | ref_ = RefHolder(util::toMainThread(state), ref_from_stacktop(state)); 278 | } 279 | #endif 280 | ~RegistoryRef() { 281 | try { 282 | unref(); 283 | } catch (...) { 284 | } // can't throw at Destructor 285 | } 286 | 287 | /// @brief push to Lua stack 288 | int push() const { return push(ref_.state()); } 289 | /// @brief push to Lua stack 290 | int push(lua_State *state) const { 291 | if (isNilref()) { 292 | lua_pushnil(state); 293 | return 1; 294 | } 295 | #if LUA_VERSION_NUM >= 502 296 | if (state != ref_.state()) { // state check 297 | assert(util::toMainThread(state) == util::toMainThread(ref_.state())); 298 | } 299 | #endif 300 | lua_rawgeti(state, LUA_REGISTRYINDEX, ref_.ref()); 301 | return 1; 302 | } 303 | 304 | int pushStackIndex(lua_State *state) const { 305 | push(state); 306 | return lua_gettop(state); 307 | } 308 | lua_State *state() const { return ref_.state(); } 309 | 310 | bool isNilref() const { return ref_.ref() == LUA_REFNIL; } 311 | 312 | void unref() { ref_.reset(); } 313 | 314 | private: 315 | RefHolder ref_; 316 | }; 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /include/kaguya/utility_cxx03.hpp: -------------------------------------------------------------------------------- 1 | // Copyright satoren 2 | // Distributed under the Boost Software License, Version 1.0. (See 3 | // accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt) 5 | #pragma once 6 | 7 | #include 8 | 9 | #include "kaguya/config.hpp" 10 | 11 | namespace kaguya { 12 | namespace util { 13 | ///! 14 | struct null_type {}; 15 | 16 | #define KAGUYA_PP_STRUCT_TDEF_REP(N) KAGUYA_PP_CAT(typename A, N) = null_type 17 | #define KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT(N) \ 18 | KAGUYA_PP_REPEAT_ARG(N, KAGUYA_PP_STRUCT_TDEF_REP) 19 | 20 | template 21 | struct TypeTuple {}; 22 | 23 | template struct TypeTupleSize; 24 | 25 | #define KAGUYA_TYPE_TUPLE_SIZE_DEF(N) \ 26 | template \ 27 | struct TypeTupleSize > { \ 28 | static const size_t value = N; \ 29 | }; 30 | 31 | KAGUYA_TYPE_TUPLE_SIZE_DEF(0) 32 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_TYPE_TUPLE_SIZE_DEF) 33 | #undef KAGUYA_TYPE_TUPLE_SIZE_DEF 34 | 35 | template struct CFuntionType; 36 | #define KAGUYA_CFUNCTION_TYPE_DEF(N) \ 37 | template \ 38 | struct CFuntionType > { \ 39 | typedef Ret (*type)(KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)); \ 40 | }; 41 | 42 | KAGUYA_CFUNCTION_TYPE_DEF(0) 43 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_CFUNCTION_TYPE_DEF) 44 | #undef KAGUYA_CFUNCTION_TYPE_DEF 45 | 46 | template 48 | struct FunctionSignatureType { 49 | typedef Ret result_type; 50 | typedef TypeTuple 51 | argument_type_tuple; 52 | static const size_t argument_count = 53 | TypeTupleSize::value; 54 | typedef typename CFuntionType::type c_function_type; 55 | }; 56 | 57 | template struct FunctionSignature; 58 | 59 | #define KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF(N) \ 60 | template \ 61 | struct FunctionSignature { \ 62 | typedef FunctionSignatureType \ 64 | type; \ 65 | }; \ 66 | template \ 67 | struct FunctionSignature { \ 69 | typedef FunctionSignatureType< \ 70 | Ret, const T & KAGUYA_PP_TEMPLATE_ARG_REPEAT_CONCAT(N)> \ 71 | type; \ 72 | }; 73 | 74 | #define KAGUYA_FUNCTION_SIGNATURE_DEF(N) \ 75 | template \ 76 | struct FunctionSignature { \ 77 | typedef FunctionSignatureType \ 78 | type; \ 79 | }; \ 80 | template \ 81 | struct FunctionSignature { \ 82 | typedef FunctionSignatureType \ 83 | type; \ 84 | }; \ 85 | template \ 86 | struct FunctionSignature< \ 87 | standard::function > { \ 88 | typedef FunctionSignatureType \ 89 | type; \ 90 | }; 91 | 92 | KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF(0) 93 | KAGUYA_PP_REPEAT_DEF(KAGUYA_PP_DEC(KAGUYA_FUNCTION_MAX_ARGS), 94 | KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF) 95 | #undef KAGUYA_MEMBER_FUNCTION_SIGNATURE_DEF 96 | KAGUYA_FUNCTION_SIGNATURE_DEF(0) 97 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_FUNCTION_SIGNATURE_DEF) 98 | #undef KAGUYA_FUNCTION_SIGNATURE_DEF 99 | 100 | template struct FunctionResultType { 101 | typedef typename FunctionSignature::type::result_type type; 102 | }; 103 | 104 | template 105 | struct TypeIndexGet {}; 106 | 107 | #define KAGUYA_TYPE_INDEX_GET_DEF(N) \ 108 | template \ 110 | struct TypeIndexGet< \ 111 | remain, TypeTuple, true> { \ 112 | typedef arg type; \ 113 | }; \ 114 | template \ 116 | struct TypeIndexGet< \ 117 | remain, TypeTuple, false> \ 118 | : TypeIndexGet > {}; 120 | 121 | // KAGUYA_TYPE_INDEX_GET_DEF(0); 122 | KAGUYA_PP_REPEAT_DEF(KAGUYA_PP_DEC(KAGUYA_FUNCTION_MAX_ARGS), 123 | KAGUYA_TYPE_INDEX_GET_DEF) 124 | #undef KAGUYA_TYPE_INDEX_GET_DEF 125 | 126 | template struct ArgumentType { 127 | typedef typename TypeIndexGet< 128 | N, typename FunctionSignature::type::argument_type_tuple>::type type; 129 | }; 130 | 131 | namespace detail { 132 | 133 | #define KAGUYA_INVOKE_HELPER_DEF(N) \ 134 | template \ 136 | typename FunctionResultType::type invoke_helper( \ 137 | typename FunctionResultType::type (T::*f)( \ 138 | KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)), \ 139 | ThisType this_ KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \ 140 | return (this_.*f)(KAGUYA_PP_ARG_REPEAT(N)); \ 141 | } \ 142 | template \ 144 | typename FunctionResultType::type invoke_helper( \ 145 | typename FunctionResultType::type (T::*f)( \ 146 | KAGUYA_PP_TEMPLATE_ARG_REPEAT(N)) const, \ 147 | ThisType this_ KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \ 148 | return (this_.*f)(KAGUYA_PP_ARG_REPEAT(N)); \ 149 | } \ 150 | template \ 151 | typename FunctionResultType::type invoke_helper( \ 152 | F f KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \ 153 | return f(KAGUYA_PP_ARG_REPEAT(N)); \ 154 | } 155 | 156 | KAGUYA_INVOKE_HELPER_DEF(0) 157 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_INVOKE_HELPER_DEF) 158 | #undef KAGUYA_INVOKE_HELPER_DEF 159 | } 160 | 161 | #define KAGUYA_INVOKE_DEF(N) \ 162 | template \ 163 | typename FunctionResultType::type invoke( \ 164 | F f KAGUYA_PP_ARG_DEF_REPEAT_CONCAT(N)) { \ 165 | return detail::invoke_helper( \ 166 | f KAGUYA_PP_ARG_REPEAT_CONCAT(N)); \ 167 | } 168 | 169 | KAGUYA_INVOKE_DEF(0) 170 | KAGUYA_PP_REPEAT_DEF(KAGUYA_FUNCTION_MAX_ARGS, KAGUYA_INVOKE_DEF) 171 | #undef KAGUYA_INVOKE_DEF 172 | 173 | #undef KAGUYA_PP_STRUCT_TDEF_REP 174 | #undef KAGUYA_PP_STRUCT_TEMPLATE_DEF_REPEAT 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /test/test_01_primitive.cpp: -------------------------------------------------------------------------------- 1 | #include "kaguya/kaguya.hpp" 2 | #include 3 | #include "test_util.hpp" 4 | #include 5 | 6 | KAGUYA_TEST_GROUP_START(test_01_primitive) 7 | 8 | using namespace kaguya_test_util; 9 | 10 | KAGUYA_TEST_FUNCTION_DEF(bool_get)(kaguya::State &state) { 11 | state("value = true"); 12 | TEST_EQUAL(state["value"], true); 13 | } 14 | KAGUYA_TEST_FUNCTION_DEF(int_get)(kaguya::State &state) { 15 | state("value = 3"); 16 | TEST_EQUAL(state["value"], int(3)); 17 | } 18 | KAGUYA_TEST_FUNCTION_DEF(string_get)(kaguya::State &state) { 19 | state("value = 'test'"); 20 | TEST_EQUAL(state["value"], "test"); 21 | TEST_EQUAL(state["value"], std::string("test")); 22 | } 23 | KAGUYA_TEST_FUNCTION_DEF(table_get1)(kaguya::State &state) { 24 | state("value = {1,32,'teststr'}"); 25 | 26 | TEST_EQUAL(state["value"][1], 1); 27 | TEST_EQUAL(state["value"][2], 32); 28 | TEST_EQUAL(state["value"][3], "teststr"); 29 | } 30 | KAGUYA_TEST_FUNCTION_DEF(table_get2)(kaguya::State &state) { 31 | state("value={out=32,str='gjgj'}"); 32 | state("value['in'] = 'test'"); 33 | kaguya::LuaRef value = state["value"]; 34 | 35 | TEST_EQUAL(value["str"], "gjgj"); 36 | TEST_EQUAL(value["in"], "test"); 37 | TEST_EQUAL(value["out"], "32"); 38 | } 39 | 40 | KAGUYA_TEST_FUNCTION_DEF(bool_set)(kaguya::State &state) { 41 | state["value"] = true; 42 | TEST_EQUAL(state["value"], true); 43 | TEST_CHECK(state["value"]); 44 | TEST_CHECK(state("assert(value == true)")); 45 | state["value"] = false; 46 | TEST_EQUAL(state["value"], false); 47 | TEST_CHECK(!state["value"]); 48 | TEST_CHECK(state("assert(value == false)")); 49 | } 50 | KAGUYA_TEST_FUNCTION_DEF(int_set)(kaguya::State &state) { 51 | state["value"] = 3; 52 | TEST_EQUAL(state["value"], 3); 53 | TEST_CHECK(state["value"]); 54 | TEST_CHECK(state("assert(value == 3)")); 55 | state["value"] = 0; 56 | TEST_EQUAL(state["value"], 0); 57 | TEST_CHECK(state["value"]); 58 | TEST_CHECK(state("assert(value == 0)")); 59 | } 60 | KAGUYA_TEST_FUNCTION_DEF(short_set)(kaguya::State &state) { 61 | state["value"] = short(3); 62 | TEST_EQUAL(state["value"], short(3)); 63 | TEST_CHECK(state["value"]); 64 | TEST_CHECK(state("assert(value == 3)")); 65 | state["value"] = short(0); 66 | TEST_EQUAL(state["value"], short(0)); 67 | TEST_CHECK(state["value"]); 68 | TEST_CHECK(state("assert(value == 0)")); 69 | } 70 | 71 | KAGUYA_TEST_FUNCTION_DEF(char_set)(kaguya::State &state) { 72 | state["value"] = char(3); 73 | TEST_EQUAL(state["value"], char(3)); 74 | TEST_CHECK(state["value"]); 75 | TEST_CHECK(state("assert(value == 3)")); 76 | state["value"] = char(0); 77 | TEST_EQUAL(state["value"], char(0)); 78 | TEST_CHECK(state["value"]); 79 | TEST_CHECK(state("assert(value == 0)")); 80 | } 81 | KAGUYA_TEST_FUNCTION_DEF(float_set)(kaguya::State &state) { 82 | state["value"] = 5.5f; 83 | TEST_EQUAL(state["value"], 5.5f); 84 | TEST_CHECK(state["value"]); 85 | TEST_CHECK(state("assert(value == 5.5,value)")); 86 | } 87 | 88 | KAGUYA_TEST_FUNCTION_DEF(double_set)(kaguya::State &state) { 89 | state["value"] = 5.5; 90 | TEST_EQUAL(state["value"], 5.5); 91 | TEST_CHECK(state["value"]); 92 | TEST_CHECK(state("assert(value == 5.5,value)")); 93 | } 94 | 95 | KAGUYA_TEST_FUNCTION_DEF(string_set)(kaguya::State &state) { 96 | state["value"] = "test"; 97 | TEST_EQUAL(state["value"], "test"); 98 | TEST_CHECK(state["value"]); 99 | TEST_CHECK(state("assert(value == 'test')")); 100 | state["value"] = "test2"; 101 | TEST_EQUAL(state["value"], "test2"); 102 | TEST_CHECK(state["value"]); 103 | TEST_CHECK(state("assert(value == 'test2')")); 104 | state["value"] = ""; 105 | TEST_EQUAL(state["value"], ""); 106 | TEST_CHECK(state["value"]); 107 | TEST_CHECK(state("assert(value == '')")); 108 | 109 | state["value"] = "false"; 110 | TEST_EQUAL(state["value"], "false"); 111 | TEST_CHECK(state["value"]); 112 | TEST_CHECK(state("assert(value == 'false')")); 113 | 114 | state["value"] = std::string("test"); 115 | TEST_EQUAL(state["value"], std::string("test")); 116 | TEST_CHECK(state("assert(value == 'test')")); 117 | 118 | std::string org = std::string("t\0est", 5); 119 | state["value"] = org; 120 | TEST_EQUAL(state["value"], org); 121 | 122 | state["value"] = "t\0est"; 123 | TEST_EQUAL(state["value"].size(), 5); 124 | TEST_EQUAL(state["value"], std::string("t\0est", 5)); 125 | } 126 | KAGUYA_TEST_FUNCTION_DEF(table_set)(kaguya::State &state) { 127 | state["value"] = kaguya::NewTable(); 128 | state["value"]["abc"] = kaguya::NewTable(); 129 | state["value"]["abc"]["def"] = 7; 130 | state["value"]["abc"]["bbb"] = "test"; 131 | TEST_CHECK(state("assert(value.abc.def == 7 and value.abc.bbb == 'test')")); 132 | } 133 | 134 | KAGUYA_TEST_FUNCTION_DEF(nilAndNull)(kaguya::State &state) { 135 | // Nil and 0 resolve to different values 136 | state["value"] = (void *)0; 137 | TEST_CHECK(state("assert(value == nil)")); 138 | TEST_CHECK(state("assert(value ~= 0)")); 139 | state["value"] = kaguya::NilValue(); 140 | TEST_CHECK(state("assert(value == nil)")); 141 | TEST_CHECK(state("assert(value ~= 0)")); 142 | state["value"] = 0; 143 | TEST_CHECK(state("assert(value ~= nil)")); 144 | TEST_CHECK(state("assert(value == 0)")); 145 | 146 | state("value = 0"); 147 | TEST_CHECK(state["value"]); // !=nil && != false 148 | TEST_CHECK(!state["value"].isNilref()); 149 | TEST_CHECK(!state["value"].typeTest()); 150 | TEST_CHECK(state["value"].typeTest()); 151 | TEST_CHECK(state["value"].typeTest()); 152 | TEST_EQUAL(state["value"], 0); 153 | TEST_COMPARE_NE(state["value"], (void *)0); 154 | TEST_COMPARE_NE(state["value"], kaguya::NilValue()); 155 | #if KAGUYA_USE_CPP11 156 | TEST_COMPARE_NE(state["value"], nullptr); 157 | #endif 158 | 159 | state("value = nil"); 160 | TEST_CHECK(!state["value"]); 161 | TEST_CHECK(state["value"].isNilref()); 162 | TEST_CHECK(state["value"].typeTest()); 163 | TEST_CHECK(!state["value"].typeTest()); 164 | TEST_CHECK(!state["value"].typeTest()); 165 | TEST_EQUAL(state["value"], (void *)0); 166 | TEST_COMPARE_NE(state["value"], 0); 167 | TEST_EQUAL(state["value"], kaguya::NilValue()); 168 | #if KAGUYA_USE_CPP11 169 | TEST_EQUAL(state["value"], nullptr); 170 | #endif 171 | } 172 | 173 | KAGUYA_TEST_FUNCTION_DEF(optional_set)(kaguya::State &state) { 174 | state["value"] = kaguya::optional(5.5); 175 | TEST_EQUAL(state["value"], 5.5); 176 | TEST_CHECK(state["value"]); 177 | TEST_CHECK(state("assert(value == 5.5,value)")); 178 | { 179 | kaguya::optional v = 180 | state["value"].get >(); 181 | TEST_EQUAL(*v, 5.5); 182 | } 183 | state["value"] = kaguya::optional(); 184 | TEST_CHECK(state("assert(value == nil)")); 185 | { 186 | kaguya::optional v = 187 | state["value"].get >(); 188 | TEST_CHECK(!v); 189 | } 190 | 191 | state["value"] = kaguya::optional("test"); 192 | TEST_EQUAL(state["value"], "test"); 193 | TEST_CHECK(state["value"]); 194 | TEST_CHECK(state("assert(value == 'test')")); 195 | { 196 | kaguya::optional v = 197 | state["value"].get >(); 198 | TEST_CHECK(strcmp(*v, "test") == 0); 199 | } 200 | state["value"] = kaguya::optional(); 201 | TEST_CHECK(state("assert(value == nil)")); 202 | { 203 | kaguya::optional v = 204 | state["value"].get >(); 205 | TEST_CHECK(!v); 206 | } 207 | 208 | state["value"] = kaguya::optional("test"); 209 | TEST_EQUAL(state["value"], "test"); 210 | TEST_CHECK(state["value"]); 211 | TEST_CHECK(state("assert(value == 'test')")); 212 | { 213 | kaguya::optional v = 214 | state["value"].get >(); 215 | TEST_EQUAL(*v, "test"); 216 | } 217 | state["value"] = kaguya::optional(); 218 | TEST_CHECK(state("assert(value == nil)")); 219 | { 220 | kaguya::optional v = 221 | state["value"].get >(); 222 | TEST_CHECK(!v); 223 | } 224 | } 225 | enum testenum { Foo = 0, Bar = 1 }; 226 | 227 | KAGUYA_TEST_FUNCTION_DEF(enum_set)(kaguya::State &state) { 228 | state["value"] = Foo; 229 | TEST_EQUAL(state["value"], Foo); 230 | TEST_CHECK(state["value"]); 231 | TEST_CHECK(state("assert(value == 0)")); 232 | } 233 | KAGUYA_TEST_FUNCTION_DEF(enum_get)(kaguya::State &state) { 234 | state("value = 1"); 235 | TEST_EQUAL(state["value"], Bar); 236 | TEST_CHECK(state["value"]); 237 | TEST_CHECK(state("assert(value == 1)")); 238 | } 239 | 240 | KAGUYA_TEST_FUNCTION_DEF(minmax_overflow_check)(kaguya::State &state) { 241 | state["value"] = std::numeric_limits::min(); 242 | TEST_EQUAL(state["value"], std::numeric_limits::min()); 243 | state["value"] = std::numeric_limits::max(); 244 | TEST_EQUAL(state["value"], std::numeric_limits::max()); 245 | 246 | state["value"] = std::numeric_limits::min(); 247 | TEST_EQUAL(state["value"], std::numeric_limits::min()); 248 | state["value"] = std::numeric_limits::max(); 249 | TEST_EQUAL(state["value"], std::numeric_limits::max()); 250 | 251 | state["value"] = std::numeric_limits::min(); 252 | TEST_EQUAL(state["value"], std::numeric_limits::min()); 253 | state["value"] = std::numeric_limits::max(); 254 | TEST_EQUAL(state["value"], std::numeric_limits::max()); 255 | } 256 | 257 | KAGUYA_TEST_FUNCTION_DEF(map_set)(kaguya::State &state) { 258 | std::map setmap; 259 | setmap["3"] = 23232; 260 | setmap["4"] = 232; 261 | setmap["5"] = 23; 262 | state["value"] = setmap; 263 | TEST_CHECK(state["value"]); 264 | TEST_CHECK(state["value"] == setmap); 265 | 266 | std::vector v; 267 | TEST_CHECK(state["value"] != v); 268 | } 269 | 270 | KAGUYA_TEST_FUNCTION_DEF(vector_set)(kaguya::State &state) { 271 | std::vector setvec; 272 | setvec.push_back("342"); 273 | setvec.push_back("32"); 274 | state["value"] = setvec; 275 | TEST_CHECK(state["value"]); 276 | TEST_CHECK(state["value"] == setvec); 277 | 278 | std::map m; 279 | TEST_CHECK(state["value"] != m); 280 | } 281 | KAGUYA_TEST_FUNCTION_DEF(vector_set2)(kaguya::State &state) { 282 | std::vector > setvec; 283 | setvec.push_back(std::vector(12, "332")); 284 | setvec.push_back(std::vector(42, "3232")); 285 | state["value"] = setvec; 286 | TEST_CHECK(state["value"]); 287 | TEST_CHECK(state["value"] == setvec); 288 | 289 | std::map m; 290 | TEST_CHECK(state["value"] != m); 291 | } 292 | 293 | KAGUYA_TEST_GROUP_END(test_01_primitive) 294 | --------------------------------------------------------------------------------