From 1a9c7484b1f3dfc9206cf403d3f8b28c42a183e8 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 11 Mar 2016 11:34:44 -0500 Subject: [PATCH] Fix up the API; prepare for release. --- bootstrap.py | 2 + sol.hpp | 1 + sol/coroutine.hpp | 18 ++-- sol/demangle.hpp | 62 +++++++++++- sol/function.hpp | 2 +- sol/function_types_allocator.hpp | 18 ++-- sol/function_types_core.hpp | 14 +-- sol/function_types_overload.hpp | 16 +-- sol/function_types_usertype.hpp | 2 +- sol/inheritance.hpp | 126 ++++++++++++++++------- sol/object.hpp | 20 +--- sol/protected_function.hpp | 12 +-- sol/protected_function_result.hpp | 40 ++++++-- sol/raii.hpp | 2 +- sol/reference.hpp | 18 ++-- sol/stack.hpp | 156 +++++++++++++++------------- sol/state.hpp | 2 +- sol/state_view.hpp | 163 ++++++++++++++++-------------- sol/table_core.hpp | 76 ++++++++++++-- sol/traits.hpp | 53 +++++++--- sol/types.hpp | 37 ++++--- sol/usertype.hpp | 31 +++--- sol/usertype_traits.hpp | 8 +- tests.cpp | 93 +++++++++++++++-- 24 files changed, 655 insertions(+), 317 deletions(-) diff --git a/bootstrap.py b/bootstrap.py index acc4fa68..aaf66cbd 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -39,6 +39,7 @@ cxx = os.environ.get('CXX', "g++") parser = argparse.ArgumentParser() parser.add_argument('--debug', action='store_true', help='compile with debug flags') parser.add_argument('--cxx', metavar='', help='compiler name to use (default: env.CXX=%s)' % cxx, default=cxx) +parser.add_argument('--cxx-flags', help='additional flags passed to the compiler', default='') parser.add_argument('--ci', action='store_true', help=argparse.SUPPRESS) parser.add_argument('--testing', action='store_true', help=argparse.SUPPRESS) parser.add_argument('--lua-lib', help='lua library name (without the lib on *nix).', default='lua') @@ -55,6 +56,7 @@ args = parser.parse_args() include = [ '.', './include' ] depends = [os.path.join('Catch', 'include')] cxxflags = [ '-Wall', '-Wextra', '-pedantic', '-pedantic-errors', '-std=c++14' ] +cxxflags.extend([p for p in re.split("( |\\\".*?\\\"|'.*?')", args.cxx_flags) if p.strip()]) ldflags = [] script_dir = os.path.dirname(os.path.realpath(sys.argv[0])) sol_dir = os.path.join(script_dir, 'sol') diff --git a/sol.hpp b/sol.hpp index 2534e646..9b00fad4 100644 --- a/sol.hpp +++ b/sol.hpp @@ -24,6 +24,7 @@ #include "sol/state.hpp" #include "sol/object.hpp" +#include "sol/userdata.hpp" #include "sol/function.hpp" #include "sol/coroutine.hpp" diff --git a/sol/coroutine.hpp b/sol/coroutine.hpp index cbfd0b5f..4d74a40a 100644 --- a/sol/coroutine.hpp +++ b/sol/coroutine.hpp @@ -71,26 +71,26 @@ private: } public: - coroutine(lua_State* L, int index = -1) : reference(L, index) {} - coroutine() = default; - coroutine(const coroutine&) = default; - coroutine& operator=(const coroutine&) = default; + coroutine(lua_State* L, int index = -1) noexcept : reference(L, index) {} + coroutine() noexcept = default; + coroutine(const coroutine&) noexcept = default; + coroutine& operator=(const coroutine&) noexcept = default; - call_status status() const { + call_status status() const noexcept { return stats; } - bool error() const { + bool error() const noexcept { call_status cs = status(); return cs != call_status::ok && cs != call_status::yielded; } - bool runnable () const { + bool runnable () const noexcept { return valid() && (status() == call_status::yielded); } - explicit operator bool() const { + explicit operator bool() const noexcept { return runnable(); } @@ -107,7 +107,7 @@ public: template decltype(auto) call( Args&&... args ) { push(); - int pushcount = stack::push_args( lua_state(), std::forward( args )... ); + int pushcount = stack::multi_push( lua_state(), std::forward( args )... ); return invoke( types( ), std::index_sequence_for(), pushcount ); } }; diff --git a/sol/demangle.hpp b/sol/demangle.hpp index 8c766d7c..b6843f5c 100644 --- a/sol/demangle.hpp +++ b/sol/demangle.hpp @@ -32,6 +32,7 @@ namespace sol { namespace detail { +#ifndef SOL_NO_RTTI #ifdef _MSC_VER inline std::string get_type_name(const std::type_info& id) { return id.name(); @@ -49,9 +50,66 @@ inline std::string get_type_name(const std::type_info& id) { #else #error Compiler not supported for demangling #endif // compilers +#else +#ifdef _MSC_VER +template +inline std::string get_type_name() { + std::string name = __FUNCSIG__; + std::size_t start = name.find_last_of('<'); + std::size_t end = name.find_last_of('>'); + if (end == std::string::npos) + end = name.size(); + if (start == std::string::npos) + start = 0; + if (start < name.size() - 1) + start += 1; + name = name.substr(start, end - start); + return name; +} -inline std::string demangle(const std::type_info& id) { - std::string realname = get_type_name(id); +#elif defined(__GNUC__) +template +inline std::string get_type_name() { + std::string name = __PRETTY_FUNCTION__; + std::size_t start = name.find_first_of('='); + std::size_t end = name.find_last_of(';'); + if (end == std::string::npos) + end = name.size(); + if (start == std::string::npos) + start = 0; + if (start < name.size() - 1) + start += 2; + name = name.substr(start, end - start); + return name; +} +#elif defined(__clang__) +template +inline std::string get_type_name() { + std::string name = __PRETTY_FUNCTION__; + std::size_t start = name.find_last_of('['); + start = name.find_first_of('=', start); + std::size_t end = name.find_last_of(']'); + if (end == std::string::npos) + end = name.size(); + if (start == std::string::npos) + start = 0; + if (start < name.size() - 1) + start += 1; + name = name.substr(start, end - start); + return name; +} +#else +#error Compiler not supported for demangling +#endif // compilers +#endif // No Runtime Type information + +template +inline std::string demangle() { +#ifndef SOL_NO_RTTI + std::string realname = get_type_name(typeid(T)); +#else + std::string realname = get_type_name(); +#endif // No Runtime Type Information const static std::array removals = {{ "struct ", "class " }}; const static std::array replacements = {{ "::", "_" }}; for(std::size_t r = 0; r < removals.size(); ++r) { diff --git a/sol/function.hpp b/sol/function.hpp index 1748a0d9..7d2992f0 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -92,7 +92,7 @@ public: template decltype(auto) call( Args&&... args ) const { push( ); - int pushcount = stack::push_args( lua_state( ), std::forward( args )... ); + int pushcount = stack::multi_push( lua_state( ), std::forward( args )... ); return invoke( types( ), std::index_sequence_for(), pushcount ); } }; diff --git a/sol/function_types_allocator.hpp b/sol/function_types_allocator.hpp index 39f9e6c6..ffda154d 100644 --- a/sol/function_types_allocator.hpp +++ b/sol/function_types_allocator.hpp @@ -41,10 +41,10 @@ struct constructor_match { constructor_match(T* obj) : obj(obj) {} - template - int operator()(meta::Bool, types, Index, types r, types a, lua_State* L, int, int start) const { + template + int operator()(types, Index, types r, types a, lua_State* L, int, int start) const { default_construct func{}; - return stack::call_into_lua(r, a, func, L, start, obj); + return stack::call_into_lua(r, a, func, L, start, obj); } }; } // detail @@ -86,11 +86,7 @@ inline int construct(lua_State* L) { template inline int destruct(lua_State* L) { - userdata udata = stack::get(L, 1); - // The first sizeof(T*) bytes are the reference: the rest is - // the actual data itself (if there is a reference at all) - T** pobj = reinterpret_cast(udata.value); - T*& obj = *pobj; + T* obj = stack::get>(L, 1); std::allocator alloc{}; alloc.destroy(obj); return 0; @@ -109,8 +105,8 @@ struct usertype_constructor_function : base_function { usertype_constructor_function(Functions... fxs) : overloads(fxs...) {} - template - int call(meta::Bool, types, Index, types r, types a, lua_State* L, int, int start) { + template + int call(types, Index, types r, types a, lua_State* L, int, int start) { static const auto& meta = usertype_traits::metatable; T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); T*& referencepointer = *pointerpointer; @@ -120,7 +116,7 @@ struct usertype_constructor_function : base_function { userdataref.pop(); auto& func = std::get(overloads); - stack::call_into_lua(r, a, func, L, start, function_detail::implicit_wrapper(obj)); + stack::call_into_lua(r, a, func, L, start, function_detail::implicit_wrapper(obj)); userdataref.push(); luaL_getmetatable(L, &meta[0]); diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index d26da485..f887bc87 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -205,10 +205,10 @@ static void func_gc(std::true_type, lua_State*) { template static void func_gc(std::false_type, lua_State* L) { for (std::size_t i = 0; i < limit; ++i) { - upvalue up = stack::get(L, static_cast(i + 1)); - if (up.value == nullptr) + void* value = stack::get(L, up_value_index(static_cast(i + 1))); + if (value == nullptr) continue; - base_function* obj = static_cast(up.value); + base_function* obj = static_cast(value); std::allocator alloc{}; alloc.destroy(obj); alloc.deallocate(obj, 1); @@ -216,19 +216,21 @@ static void func_gc(std::false_type, lua_State* L) { } inline int call(lua_State* L) { - void** pinheritancedata = static_cast(stack::get(L, 1).value); + void* ludata = stack::get(L, up_value_index(1)); + void** pinheritancedata = static_cast(ludata); return base_call(L, *pinheritancedata); } inline int gc(lua_State* L) { - void** pudata = static_cast(stack::get(L, 1).value); + void* udata = stack::get(L, 1); + void** pudata = static_cast(udata); return base_gc(L, *pudata); } template inline int usertype_call(lua_State* L) { // Zero-based template parameter, but upvalues start at 1 - return base_call(L, stack::get(L, I + 1)); + return base_call(L, stack::get(L, up_value_index(static_cast(I + 1)))); } template diff --git a/sol/function_types_overload.hpp b/sol/function_types_overload.hpp index 7fcf564f..c8a5fe69 100644 --- a/sol/function_types_overload.hpp +++ b/sol/function_types_overload.hpp @@ -57,10 +57,10 @@ inline int overload_match_arity(types, std::index_sequence if (traits::arity != fxarity) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } - if (sizeof...(Fxs) != 0 && !function_detail::check_types(args_type(), args_indices(), L, start)) { + if (!function_detail::check_types(args_type(), args_indices(), L, start)) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } - return matchfx(meta::Bool(), types(), Index(), return_types(), args_type(), L, fxarity, start, std::forward(args)...); + return matchfx(types(), Index(), return_types(), args_type(), L, fxarity, start, std::forward(args)...); } } // internals @@ -93,10 +93,10 @@ struct overloaded_function : base_function { } - template - int call(meta::Bool, types, Index, types r, types a, lua_State* L, int, int start) { + template + int call(types, Index, types r, types a, lua_State* L, int, int start) { auto& func = std::get(overloads); - return stack::call_into_lua(r, a, func, L, start); + return stack::call_into_lua(r, a, func, L, start); } virtual int operator()(lua_State* L) override { @@ -113,11 +113,11 @@ struct usertype_overloaded_function : base_function { usertype_overloaded_function(std::tuple set) : overloads(std::move(set)) {} - template - int call(meta::Bool, types, Index, types r, types a, lua_State* L, int, int start) { + template + int call(types, Index, types r, types a, lua_State* L, int, int start) { auto& func = std::get(overloads); func.item = detail::ptr(stack::get(L, 1)); - return stack::call_into_lua(r, a, func, L, start); + return stack::call_into_lua(r, a, func, L, start); } virtual int operator()(lua_State* L) override { diff --git a/sol/function_types_usertype.hpp b/sol/function_types_usertype.hpp index 84d0f914..69913fd8 100644 --- a/sol/function_types_usertype.hpp +++ b/sol/function_types_usertype.hpp @@ -151,7 +151,7 @@ struct usertype_indexing_function : base_function { if (functionpair != functions.end()) { std::pair& target = functionpair->second; if (target.first) { - stack::push(L, target.second); + stack::push(L, target.second); stack::push(L, c_closure(usertype_call<0>, 1)); return 1; } diff --git a/sol/inheritance.hpp b/sol/inheritance.hpp index 6db04f74..49b58993 100644 --- a/sol/inheritance.hpp +++ b/sol/inheritance.hpp @@ -23,6 +23,9 @@ #define SOL_INHERITANCE_HPP #include "types.hpp" +#if defined(SOL_NO_RTTI) && defined(SOL_NO_EXCEPTIONS) +#include +#endif // No Runtime Type Information and No Exceptions namespace sol { template @@ -30,53 +33,69 @@ struct base_list { }; template using bases = base_list; -const auto base_classes = bases<>(); +typedef bases<> base_classes_tag; +const auto base_classes = base_classes_tag(); namespace detail { +#if defined(SOL_NO_RTTI) && defined(SOL_NO_EXCEPTIONS) +inline std::size_t unique_id () { + static std::atomic x(0); + return ++x; +} + +template +struct id_for { + static const std::size_t value; +}; + +template +const std::size_t id_for::value = unique_id(); +#endif // No Runtime Type Information / No Exceptions + const auto& base_class_check_key = u8"♡o。.(✿ฺ。 ✿ฺ)"; const auto& base_class_cast_key = u8"(◕‿◕✿)"; #ifndef SOL_NO_EXCEPTIONS - template - void throw_as(void* p) { - throw static_cast(p); +template +void throw_as(void* p) { + throw static_cast(p); +} + +using throw_cast = decltype(&throw_as); + +template +inline T* catch_cast(void* p, throw_cast f) { + try { + f(static_cast(p)); } - - using throw_cast = decltype(&throw_as); - - template - T* catch_cast(void* p, throw_cast f) { - try { - f(static_cast(p)); - } - catch (T* ptr) { - return ptr; - } - catch (...) { - return static_cast(p); - } + catch (T* ptr) { + return ptr; + } + catch (...) { return static_cast(p); } + return static_cast(p); +} - template - bool catch_check(throw_cast f) { - try { - f( nullptr ); - } - catch (T*) { - return true; - } - catch (...) { - return false; - } +template +inline bool catch_check(throw_cast f) { + try { + f( nullptr ); + } + catch (T*) { + return true; + } + catch (...) { return false; } + return false; +} #elif !defined(SOL_NO_RTTI) template struct inheritance { - static bool type_check(types<>, const std::type_info& typeinfo) { + static bool type_check(types<>, const std::type_info&) { return false; } @@ -89,26 +108,61 @@ struct inheritance { return ti != typeid(T) || type_check(types(), ti); } - static void* type_cast(types<>, T*, const std::type_info& typeinfo) { + static void* type_cast(types<>, T*, const std::type_info& ti) { return nullptr; } template static void* type_cast(types, T* data, const std::type_info& ti) { // Make sure to convert to T first, and then dynamic cast to the proper type - return ti != typeid(Base) ? type_check(types(), ti) : dynamic_cast(static_cast(data)); + return ti != typeid(Base) ? type_cast(types(), data, ti) : static_cast(dynamic_cast(static_cast(data))); } - static void* cast(void* data, const std::type_info& ti) { - return ti != typeid(T) ? type_check(types(), ti) : static_cast(data); + static void* cast(void* voiddata, const std::type_info& ti) { + T* data = static_cast(voiddata); + return static_cast(ti != typeid(T) ? type_cast(types(), data, ti) : data); } }; using inheritance_check_function = decltype(&inheritance::check); using inheritance_cast_function = decltype(&inheritance::cast); -#endif // No Runtime Type Information +#else +template +struct inheritance { + static bool type_check(types<>, std::size_t) { + return false; + } -} // usertype_detail + template + static bool type_check(types, std::size_t ti) { + return ti != id_for::value || type_check(types(), ti); + } + + static bool check(std::size_t ti) { + return ti != id_for::value || type_check(types(), ti); + } + + static void* type_cast(types<>, T*, std::size_t) { + return nullptr; + } + + template + static void* type_cast(types, T* data, std::size_t ti) { + // Make sure to convert to T first, and then dynamic cast to the proper type + return ti != id_for::value ? type_cast(types(), data, ti) : static_cast(static_cast(data)); + } + + static void* cast(void* voiddata, std::size_t ti) { + T* data = static_cast(voiddata); + return static_cast(ti != id_for::value ? type_cast(types(), data, ti) : data); + } +}; + +using inheritance_check_function = decltype(&inheritance::check); +using inheritance_cast_function = decltype(&inheritance::cast); +#endif // No Exceptions and/or No Runtime Type Information + +} // detail } // sol #endif // SOL_INHERITANCE_HPP diff --git a/sol/object.hpp b/sol/object.hpp index 034cb03e..47ac6736 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -30,8 +30,7 @@ namespace sol { class object : public reference { public: - object(lua_State* L, int index = -1): reference(L, index) {} - object() = default; + using reference::reference; template decltype(auto) as() const { @@ -41,21 +40,10 @@ public: template bool is() const { - if (!reference::valid()) + if (!valid()) return false; - auto expected = type_of(); - auto actual = get_type(); - return (expected == actual) || (expected == type::poly); - } - - bool valid() const { - if (!reference::valid()) - return false; - return !this->is(); - } - - explicit operator bool() { - return valid(); + auto pp = stack::push_pop(*this); + return stack::check(lua_state(), -1, no_panic); } }; diff --git a/sol/protected_function.hpp b/sol/protected_function.hpp index f7538199..ecb65f08 100644 --- a/sol/protected_function.hpp +++ b/sol/protected_function.hpp @@ -93,17 +93,17 @@ private: int returncount = 0; call_status code = call_status::ok; #ifndef SOL_NO_EXCEPTIONS - auto onexcept = [&](const char* error) { + auto onexcept = [&](const char* error) { h.stackindex = 0; if (h.target.valid()) { h.target.push(); stack::push(lua_state(), error); lua_call(lua_state(), 1, 1); } - else { + else { stack::push(lua_state(), error); - } - }; + } + }; try { #endif // No Exceptions code = static_cast(luacall(n, LUA_MULTRET, h)); @@ -132,7 +132,7 @@ private: } public: - sol::reference error_handler; + reference error_handler; protected_function() = default; protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) { @@ -157,7 +157,7 @@ public: decltype(auto) call(Args&&... args) const { handler h(error_handler); push(); - int pushcount = stack::push_args(lua_state(), std::forward(args)...); + int pushcount = stack::multi_push(lua_state(), std::forward(args)...); return invoke(types(), std::index_sequence_for(), pushcount, h); } }; diff --git a/sol/protected_function_result.hpp b/sol/protected_function_result.hpp index 129784cf..1fa2fa6c 100644 --- a/sol/protected_function_result.hpp +++ b/sol/protected_function_result.hpp @@ -34,16 +34,16 @@ private: int index; int returncount; int popcount; - call_status error; + call_status err; public: protected_function_result() = default; - protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) { + protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), err(error) { } protected_function_result(const protected_function_result&) = default; protected_function_result& operator=(const protected_function_result&) = default; - protected_function_result(protected_function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), error(o.error) { + protected_function_result(protected_function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { // Must be manual, otherwise destructor will screw us // return count being 0 is enough to keep things clean // but will be thorough @@ -51,14 +51,14 @@ public: o.index = 0; o.returncount = 0; o.popcount = 0; - o.error = call_status::runtime; + o.err = call_status::runtime; } protected_function_result& operator=(protected_function_result&& o) { L = o.L; index = o.index; returncount = o.returncount; popcount = o.popcount; - error = o.error; + err = o.err; // Must be manual, otherwise destructor will screw us // return count being 0 is enough to keep things clean // but will be thorough @@ -66,12 +66,16 @@ public: o.index = 0; o.returncount = 0; o.popcount = 0; - o.error = call_status::runtime; + o.err = call_status::runtime; return *this; } + call_status error() const { + return err; + } + bool valid() const { - return error == call_status::ok; + return error() == call_status::ok; } template @@ -83,6 +87,28 @@ public: stack::remove(L, index, popcount); } }; + +struct protected_result { +private: + protected_function_result result; + +public: + template + protected_result( Args&&... args ) : result(std::forward(args)...) { + } + + bool valid() const { + return result.valid(); + } + + explicit operator bool () const { + return valid(); + } + + protected_function_result& operator* () { + return result; + } +}; } // sol #endif // SOL_FUNCTION_RESULT_HPP diff --git a/sol/raii.hpp b/sol/raii.hpp index b6666a92..548c46c8 100644 --- a/sol/raii.hpp +++ b/sol/raii.hpp @@ -50,7 +50,7 @@ struct constructor_wrapper : std::tuple { }; template -constructor_wrapper constructor(Functions&&... functions) { +constructor_wrapper initializers(Functions&&... functions) { return constructor_wrapper(std::forward(functions)...); } diff --git a/sol/reference.hpp b/sol/reference.hpp index 5c8a1c34..cb53a623 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -52,7 +52,7 @@ private: lua_State* L = nullptr; // non-owning int ref = LUA_NOREF; - int copy() const { + int copy() const noexcept { if (ref == LUA_NOREF) return LUA_NOREF; push(); @@ -60,7 +60,7 @@ private: } protected: - reference(lua_State* L, detail::global_tag) : L(L) { + reference(lua_State* L, detail::global_tag) noexcept : L(L) { lua_pushglobaltable(L); ref = luaL_ref(L, LUA_REGISTRYINDEX); } @@ -68,12 +68,12 @@ protected: public: reference() noexcept = default; - reference(lua_State* L, int index = -1): L(L) { + reference(lua_State* L, int index = -1) noexcept : L(L) { lua_pushvalue(L, index); ref = luaL_ref(L, LUA_REGISTRYINDEX); } - virtual ~reference() { + virtual ~reference() noexcept { luaL_unref(L, LUA_REGISTRYINDEX, ref); } @@ -115,19 +115,19 @@ public: lua_pop(lua_state( ), n); } - int get_index() const { + int registry_index() const noexcept { return ref; } - bool valid () const { - return !(ref == LUA_NOREF); + bool valid () const noexcept { + return !(ref == LUA_NOREF || ref == LUA_REFNIL); } - explicit operator bool () const { + explicit operator bool () const noexcept { return valid(); } - type get_type() const { + type get_type() const noexcept { push(); int result = lua_type(L, -1); lua_pop(L, 1); diff --git a/sol/stack.hpp b/sol/stack.hpp index 5a4afc20..ab71e5af 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -24,6 +24,7 @@ #include "error.hpp" #include "reference.hpp" +#include "userdata.hpp" #include "tuple.hpp" #include "traits.hpp" #include "usertype_traits.hpp" @@ -60,13 +61,13 @@ inline int push(lua_State* L, Arg&& arg, Args&&... args) { return pusher>{}.push(L, std::forward(arg), std::forward(args)...); } -inline int push_args(lua_State*) { +inline int multi_push(lua_State*) { // do nothing return 0; } template -inline int push_args(lua_State* L, T&& t, Args&&... args) { +inline int multi_push(lua_State* L, T&& t, Args&&... args) { int pushcount = push(L, std::forward(t)); void(sol::detail::swallow{(pushcount += sol::stack::push(L, std::forward(args)), 0)... }); return pushcount; @@ -92,8 +93,8 @@ bool check(lua_State* L, int index, Handler&& handler) { } template -bool check(lua_State* L, int index) { - auto handler = type_panic; +bool check(lua_State* L, int index = -1) { + auto handler = no_panic; return check(L, index, handler); } @@ -130,10 +131,10 @@ static int push_upvalues(lua_State* L, TCont&& cont) { int n = 0; for(auto& c : cont) { if(releasemem) { - stack::push(L, c.release()); + stack::push(L, c.release()); } else { - stack::push(L, c.get()); + stack::push(L, c.get()); } ++n; } @@ -144,7 +145,7 @@ template struct userdata_pusher { template static void push (lua_State* L, Key&& metatablekey, Args&&... args) { - // Basically, we store all user0data like this: + // Basically, we store all user-data like this: // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new // data in the first sizeof(T*) bytes, and then however many bytes it takes to // do the actual object. Things that are std::ref or plain T* are stored as @@ -255,26 +256,19 @@ struct getter::value>> { }; template<> -struct getter { - static userdata get(lua_State* L, int index = -1) { +struct getter { + static userdata_value get(lua_State* L, int index = -1) { return{ lua_touserdata(L, index) }; } }; template<> -struct getter { - static light_userdata get(lua_State* L, int index = -1) { +struct getter { + static light_userdata_value get(lua_State* L, int index = -1) { return{ lua_touserdata(L, index) }; } }; -template<> -struct getter { - static upvalue get(lua_State* L, int index = 1) { - return{ lua_touserdata(L, lua_upvalueindex(index)) }; - } -}; - template<> struct getter { static void* get(lua_State* L, int index = -1) { @@ -286,24 +280,36 @@ template struct getter { static T* get_no_nil(lua_State* L, int index = -1) { void** pudata = static_cast(lua_touserdata(L, index)); - void* udata = *pudata; + void* udata = *pudata; + return get_no_nil_from(L, udata, index); + } + + static T* get_no_nil_from(lua_State* L, void* udata, int index = -1) { #ifndef SOL_NO_EXCEPTIONS - if (luaL_getmetafield(L, -1, &detail::base_class_check_key[0]) != 0) { - void* basecastdata = stack::get(L); - detail::throw_cast basecast = (detail::throw_cast)basecastdata; + if (luaL_getmetafield(L, index, &detail::base_class_check_key[0]) != 0) { + void* basecastdata = stack::get(L); + detail::throw_cast basecast = (detail::throw_cast)basecastdata; // use the casting function to properly adjust the pointer for the desired T - udata = detail::catch_cast( udata, basecast ); - lua_pop(L, 1); - } + udata = detail::catch_cast(udata, basecast); + lua_pop(L, 1); + } #elif !defined(SOL_NO_RTTI) - if (luaL_getmetafield(L, -1, &detail::base_class_check_key[0]) != 0) { - detail::inheritance_cast_function ic = (detail::inheritance_cast_function)stack::get(L); + if (luaL_getmetafield(L, index, &detail::base_class_cast_key[0]) != 0) { + void* basecastdata = stack::get(L); + detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata; // use the casting function to properly adjust the pointer for the desired T udata = ic(udata, typeid(T)); - lua_pop(L, 1); - } + lua_pop(L, 1); + } #else - // Lol, inheritance could never work like this + // Lol, you motherfucker + if (luaL_getmetafield(L, index, &detail::base_class_cast_key[0]) != 0) { + void* basecastdata = stack::get(L); + detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata; + // use the casting function to properly adjust the pointer for the desired T + udata = ic(udata, detail::id_for::value); + lua_pop(L, 1); + } #endif // No Runtime Type Information || Exceptions T* obj = static_cast(udata); return obj; @@ -313,7 +319,14 @@ struct getter { type t = type_of(L, index); if (t == type::nil) return nullptr; - return get_no_nil(L, index); + return get_no_nil(L, index); + } +}; + +template +struct getter> { + static T* get(lua_State* L, int index = -1) { + return getter::get_no_nil(L, index); } }; @@ -421,7 +434,7 @@ struct checker { } }; -template +template struct checker { template static bool check (lua_State* L, type indextype, int index, const Handler& handler) { @@ -429,6 +442,8 @@ struct checker { handler(L, index, type::userdata, indextype); return false; } + if (meta::Or, std::is_same>::value) + return true; if (lua_getmetatable(L, index) == 0) { handler(L, index, type::userdata, indextype); return false; @@ -442,20 +457,34 @@ struct checker { } bool success = lua_rawequal(L, -1, -2) == 1; #ifndef SOL_NO_EXCEPTIONS - if (!success) { + if (!success) { lua_getfield(L, -2, &detail::base_class_check_key[0]); - void* basecastdata = stack::get(L); - detail::throw_cast basecast = (detail::throw_cast)basecastdata; - success |= detail::catch_check(basecast); - lua_pop(L, 1); - } + void* basecastdata = stack::get(L); + detail::throw_cast basecast = (detail::throw_cast)basecastdata; + success |= detail::catch_check(basecast); + lua_pop(L, 1); + } #elif !defined(SOL_NO_RTTI) - if (!success) { + if (!success) { lua_getfield(L, -2, &detail::base_class_check_key[0]); - detail::inheritance_check_function ic = (detail::inheritance_check_function)stack::get(L); - success |= ic(typeid(T)); - lua_pop(L, 1); - } + if (stack::get(L) != type::nil) { + void* basecastdata = stack::get(L); + detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; + success |= ic(typeid(T)); + } + lua_pop(L, 1); + } +#else + // Topkek + if (!success) { + lua_getfield(L, -2, &detail::base_class_check_key[0]); + if (stack::get(L) != type::nil) { + void* basecastdata = stack::get(L); + detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; + success |= ic(detail::id_for::value); + } + lua_pop(L, 1); + } #endif // No Runtime Type Information || Exceptions lua_pop(L, 2); return success; @@ -522,30 +551,25 @@ struct pusher, std::is_unsigne }; template -struct pusher, meta::Not>>::value>> { +struct pusher, meta::Not>, meta::Not>>::value>> { static int push(lua_State* L, const T& cont) { lua_createtable(L, static_cast(cont.size()), 0); + int tableindex = lua_gettop(L); unsigned index = 1; for(auto&& i : cont) { - // push the index - pusher{}.push(L, index++); - // push the value - pusher>{}.push(L, i); - // set the table - lua_settable(L, -3); + set_field(L, index++, i, tableindex); } return 1; } }; template -struct pusher, meta::has_key_value_pair>::value>> { +struct pusher, meta::has_key_value_pair, meta::Not>>::value>> { static int push(lua_State* L, const T& cont) { lua_createtable(L, static_cast(cont.size()), 0); + int tableindex = lua_gettop(L); for(auto&& pair : cont) { - pusher>{}.push(L, pair.first); - pusher>{}.push(L, pair.second); - lua_settable(L, -3); + set_field(L, pair.first, pair.second, tableindex); } return 1; } @@ -556,6 +580,10 @@ struct pusher::value>> { static int push(lua_State*, T& ref) { return ref.push(); } + + static int push(lua_State*, T&& ref) { + return ref.push(); + } }; template @@ -621,24 +649,16 @@ struct pusher { }; template<> -struct pusher { - static int push(lua_State* L, upvalue upv) { - lua_pushlightuserdata(L, upv); - return 1; - } -}; - -template<> -struct pusher { - static int push(lua_State* L, light_userdata userdata) { +struct pusher { + static int push(lua_State* L, light_userdata_value userdata) { lua_pushlightuserdata(L, userdata); return 1; } }; template<> -struct pusher { - static int push(lua_State* L, userdata data) { +struct pusher { + static int push(lua_State* L, userdata_value data) { void** ud = static_cast(lua_newuserdata(L, sizeof(void*))); *ud = data.value; return 1; @@ -782,7 +802,7 @@ inline int push_as_upvalues(lua_State* L, T& item) { std::memcpy(&data[0], std::addressof(item), itemsize); int pushcount = 0; for(auto&& v : data) { - pushcount += push(L, upvalue(v)); + pushcount += push(L, light_userdata_value(v)); } return pushcount; } @@ -793,7 +813,7 @@ inline std::pair get_as_upvalues(lua_State* L, int index = 1) { typedef std::array data_t; data_t voiddata{ {} }; for(std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { - voiddata[i] = get(L, index++); + voiddata[i] = get(L, up_value_index(index++)); } return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); } diff --git a/sol/state.hpp b/sol/state.hpp index f9f4277f..955975bf 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -32,7 +32,7 @@ public: state(lua_CFunction panic = detail::atpanic) : unique_base(luaL_newstate(), lua_close), state_view(unique_base::get()) { set_panic(panic); - stack::luajit_exception_handler(unique_base::get()); + stack::luajit_exception_handler(unique_base::get()); } using state_view::get; diff --git a/sol/state_view.hpp b/sol/state_view.hpp index c6cb7027..ad5690a1 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -31,6 +31,7 @@ namespace detail { inline int atpanic(lua_State* L) { #ifdef SOL_NO_EXCEPTIONS (void)L; + return -1; #else const char* message = lua_tostring(L, -1); std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic"; @@ -57,12 +58,12 @@ class state_view { private: lua_State* L; table reg; - global_table globals; + global_table global; public: state_view(lua_State* L): L(L), reg(L, LUA_REGISTRYINDEX), - globals(L, detail::global_) { + global(L, detail::global_) { } @@ -142,81 +143,30 @@ public: } } - void open_file(const std::string& filename) { + void script_file(const std::string& filename) { if(luaL_dofile(L, filename.c_str())) { lua_error(L); } } - template - decltype(auto) get(Keys&&... keys) const { - return globals.get(std::forward(keys)...); + table_iterator begin () const { + return global.begin(); } - template - state_view& set(Args&&... args) { - globals.set(std::forward(args)...); - return *this; + table_iterator end() const { + return global.end(); } - template - decltype(auto) traverse_get(Keys&&... keys) const { - return globals.traverse_get(std::forward(keys)...); + table_iterator cbegin() const { + return global.cbegin(); } - template - state_view& traverse_set(Args&&... args) { - globals.traverse_set(std::forward(args)...); - return *this; + table_iterator cend() const { + return global.cend(); } - template - state_view& set_usertype(usertype& user) { - return set_usertype(usertype_traits::name, user); - } - - template - state_view& set_usertype(Key&& key, usertype& user) { - globals.set_usertype(std::forward(key), user); - return *this; - } - - template - state_view& new_usertype(const std::string& name, Args&&... args) { - usertype utype(std::forward(args)...); - set_usertype(name, utype); - return *this; - } - - template - state_view& new_usertype(const std::string& name, Args&&... args) { - constructors> ctor{}; - return new_usertype(name, ctor, std::forward(args)...); - } - - template - state_view& new_usertype(const std::string& name, constructors ctor, Args&&... args) { - usertype utype(ctor, std::forward(args)...); - set_usertype(name, utype); - return *this; - } - - template - void for_each(Fx&& fx) { - globals.for_each(std::forward(fx)); - } - - template - table create_table(T&& key, int narr = 0, int nrec = 0) { - lua_createtable(L, narr, nrec); - table result(L); - lua_pop(L, 1); - globals.set(std::forward(key), result); - return result; - } - - global_table global() const { - return globals; + global_table globals() const { + return global; } table registry() const { @@ -227,45 +177,110 @@ public: lua_atpanic(L, panic); } - template - proxy operator[](T&& key) { - return globals[std::forward(key)]; + template + decltype(auto) get(Keys&&... keys) const { + return global.get(std::forward(keys)...); + } + + template + state_view& set(Args&&... args) { + global.set(std::forward(args)...); + return *this; + } + + template + decltype(auto) traverse_get(Keys&&... keys) const { + return global.traverse_get(std::forward(keys)...); + } + + template + state_view& traverse_set(Args&&... args) { + global.traverse_set(std::forward(args)...); + return *this; } template - proxy operator[](T&& key) const { - return globals[std::forward(key)]; + state_view& set_usertype(usertype& user) { + return set_usertype(usertype_traits::name, user); + } + + template + state_view& set_usertype(Key&& key, usertype& user) { + global.set_usertype(std::forward(key), user); + return *this; + } + + template + state_view& new_usertype(const std::string& name, Args&&... args) { + global.new_usertype(name, std::forward(args)...); + return *this; + } + + template + state_view& new_usertype(const std::string& name, Args&&... args) { + global.new_usertype(name, std::forward(args)...); + return *this; + } + + template + state_view& new_usertype(const std::string& name, constructors ctor, Args&&... args) { + global.new_usertype(name, ctor, std::forward(args)...); + return *this; + } + + template + void for_each(Fx&& fx) { + global.for_each(std::forward(fx)); + } + + template + proxy operator[](T&& key) { + return global[std::forward(key)]; + } + + template + proxy operator[](T&& key) const { + return global[std::forward(key)]; } template state_view& set_function(Key&& key, R fun_ptr(Args...)){ - globals.set_function(std::forward(key), fun_ptr); + global.set_function(std::forward(key), fun_ptr); return *this; } template state_view& set_function(Key&& key, Sig* fun_ptr){ - globals.set_function(std::forward(key), fun_ptr); + global.set_function(std::forward(key), fun_ptr); return *this; } template state_view& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) { - globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); + global.set_function(std::forward(key), mem_ptr, std::forward(obj)); return *this; } template state_view& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) { - globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); + global.set_function(std::forward(key), mem_ptr, std::forward(obj)); return *this; } template state_view& set_function(Key&& key, Fx&& fx) { - globals.set_function(std::forward(key), std::forward(fx)); + global.set_function(std::forward(key), std::forward(fx)); return *this; } + + static inline table create_table(lua_State* L, int narr = 0, int nrec = 0) { + return global_table::create(L, narr, nrec); + } + + template + static inline table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + return global_table::create(L, narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); + } }; } // sol diff --git a/sol/table_core.hpp b/sol/table_core.hpp index b27df384..df8d46d5 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -26,6 +26,7 @@ #include "stack.hpp" #include "function_types.hpp" #include "usertype.hpp" +#include "table_iterator.hpp" namespace sol { template @@ -36,6 +37,31 @@ class table_core : public reference { template using is_global = meta::And, meta::is_c_str...>; + template + void for_each(std::true_type, Fx&& fx) const { + auto pp = stack::push_pop( *this ); + stack::push( lua_state( ), nil ); + while ( lua_next( this->lua_state( ), -2 ) ) { + sol::object key( lua_state( ), -2 ); + sol::object value( lua_state( ), -1 ); + std::pair keyvalue(key, value); + fx( keyvalue ); + lua_pop( lua_state( ), 1 ); + } + } + + template + void for_each(std::false_type, Fx&& fx) const { + auto pp = stack::push_pop( *this ); + stack::push( lua_state( ), nil ); + while ( lua_next( this->lua_state( ), -2 ) ) { + sol::object key( lua_state( ), -2 ); + sol::object value( lua_state( ), -1 ); + fx( key, value ); + lua_pop( lua_state( ), 1 ); + } + } + template auto tuple_get( types, std::index_sequence, Keys&& keys ) const -> decltype(stack::pop>(nullptr)){ @@ -85,11 +111,27 @@ class table_core : public reference { public: table_core( ) noexcept : reference( ) { } - table_core( const table_core& global ) : reference( global ) { } + table_core( const table_core& global ) noexcept : reference( global ) { } table_core( lua_State* L, int index = -1 ) : reference( L, index ) { type_assert( L, index, type::table ); } + table_iterator begin () const { + return table_iterator(*this); + } + + table_iterator end() const { + return table_iterator(); + } + + table_iterator cbegin() const { + return begin(); + } + + table_iterator cend() const { + return end(); + } + template decltype(auto) get( Keys&&... keys ) const { return tuple_get( types( ), std::index_sequence_for( ), std::forward_as_tuple(std::forward(keys)...)); @@ -126,16 +168,30 @@ public: return set(std::forward(key), user); } + template + table_core& new_usertype(const std::string& name, Args&&... args) { + usertype utype(std::forward(args)...); + set_usertype(name, utype); + return *this; + } + + template + table_core& new_usertype(const std::string& name, Args&&... args) { + constructors> ctor{}; + return new_usertype(name, ctor, std::forward(args)...); + } + + template + table_core& new_usertype(const std::string& name, constructors ctor, Args&&... args) { + usertype utype(ctor, std::forward(args)...); + set_usertype(name, utype); + return *this; + } + template void for_each( Fx&& fx ) const { - auto pp = stack::push_pop( *this ); - stack::push( lua_state( ), nil ); - while ( lua_next( this->lua_state( ), -2 ) ) { - sol::object key( lua_state( ), -2 ); - sol::object value( lua_state( ), -1 ); - fx( key, value ); - lua_pop( lua_state( ), 1 ); - } + typedef meta::is_callable )> is_paired; + for_each(is_paired(), std::forward(fx)); } size_t size( ) const { @@ -221,6 +277,8 @@ public: template static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { + if (narr == 0) narr = static_cast(meta::count_if_pack::value); + if (nrec == 0) nrec = static_cast(( sizeof...(Args) + 2 ) - narr); lua_createtable(L, narr, nrec); table result(L); result.set(std::forward(key), std::forward(value), std::forward(args)...); diff --git a/sol/traits.hpp b/sol/traits.hpp index e8153c41..548eb7ad 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -135,6 +135,16 @@ using at_in_pack_t = typename at_in_pack::type; template struct at_in_pack : std::conditional> {}; +namespace meta_detail { + template class Pred, typename... Ts> + struct count_if_pack {}; + template class Pred, typename T, typename... Ts> + struct count_if_pack : std::conditional_t, count_if_pack(Pred::value), Pred, Ts...>> { }; +} // meta_detail + +template class Pred, typename... Ts> +struct count_if_pack : meta_detail::count_if_pack<0, Pred, Ts...> { }; + template struct return_type { typedef std::tuple type; @@ -153,7 +163,22 @@ struct return_type<> { template using return_type_t = typename return_type::type; -namespace detail { +namespace meta_detail { +template struct always_true : std::true_type {}; +struct is_callable_tester { + template + always_true()(std::declval()...))> static test(int); + template + std::false_type static test(...); +}; +} // meta_detail + +template +struct is_callable; +template +struct is_callable : decltype(meta_detail::is_callable_tester::test(0)) {}; + +namespace meta_detail { template>::value> struct is_function_impl : std::is_function> {}; @@ -186,15 +211,15 @@ struct check_deducible_signature { using type = std::is_void(0))>; }; -} // detail +} // meta_detail template -struct has_deducible_signature : detail::check_deducible_signature::type { }; +struct has_deducible_signature : meta_detail::check_deducible_signature::type { }; template -struct Function : Bool::value> {}; +struct Function : Bool::value> {}; -namespace detail { +namespace meta_detail { template::value> struct fx_traits; @@ -263,10 +288,10 @@ struct fx_traits { using arg = std::tuple_element_t; }; -} // detail +} // meta_detail template -struct function_traits : detail::fx_traits> {}; +struct function_traits : meta_detail::fx_traits> {}; template using function_args_t = typename function_traits::args_type; @@ -277,7 +302,7 @@ using function_signature_t = typename function_traits::signature_type template using function_return_t = typename function_traits::return_type; -namespace detail { +namespace meta_detail { template::value> struct callable_traits : function_traits { @@ -299,10 +324,10 @@ struct callable_traits { template using arg = std::tuple_element_t; }; -} // detail +} // meta_detail template -struct callable_traits : detail::callable_traits> { +struct callable_traits : meta_detail::callable_traits> { }; @@ -339,7 +364,7 @@ using is_string_constructible = Or, const char*>, st template using is_c_str = Or>, char*>, std::is_same, std::string>>; -namespace detail { +namespace meta_detail { template , std::tuple>> = 0> decltype(auto) force_tuple(T&& x) { return std::forward_as_tuple(x); @@ -349,11 +374,11 @@ template (x); } -} // detail +} // meta_detail template decltype(auto) tuplefy(X&&... x ) { - return std::tuple_cat(detail::force_tuple(x)...); + return std::tuple_cat(meta_detail::force_tuple(x)...); } } // meta namespace detail { @@ -411,7 +436,7 @@ template inline T* ptr(T* val) { return val; } -} // detail +} // meta_detail } // sol #endif // SOL_TRAITS_HPP diff --git a/sol/types.hpp b/sol/types.hpp index 7c5093c1..d9d9fc53 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -87,27 +87,27 @@ const nil_t nil {}; inline bool operator==(nil_t, nil_t) { return true; } inline bool operator!=(nil_t, nil_t) { return false; } -struct void_type : types {}; // This is important because it allows myobject.call( Void, ... ) to work -const void_type Void {}; +template +struct non_null {}; template struct function_sig {}; -struct upvalue { +struct up_value_index { + int index; + up_value_index(int idx) : index(lua_upvalueindex(idx)) {} + operator int() const { return index; } +}; + +struct light_userdata_value { void* value; - upvalue(void* data) : value(data) {} + light_userdata_value(void* data) : value(data) {} operator void*() const { return value; } }; -struct light_userdata { +struct userdata_value { void* value; - light_userdata(void* data) : value(data) {} - operator void*() const { return value; } -}; - -struct userdata { - void* value; - userdata(void* data) : value(data) {} + userdata_value(void* data) : value(data) {} operator void*() const { return value; } }; @@ -161,7 +161,7 @@ inline int type_panic(lua_State* L, int index, type expected, type actual) { } // Specify this function as the handler for lua::check if you know there's nothing wrong -inline int no_panic(lua_State*, int, type, type) { +inline int no_panic(lua_State*, int, type, type) noexcept { return 0; } @@ -202,6 +202,8 @@ class protected_function; class coroutine; class thread; class object; +class userdata; +class light_userdata; template struct lua_type_of : std::integral_constant {}; @@ -230,9 +232,18 @@ struct lua_type_of : std::integral_constant { } template <> struct lua_type_of : std::integral_constant {}; +template <> +struct lua_type_of : std::integral_constant {}; + +template <> +struct lua_type_of : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; +template <> +struct lua_type_of : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; diff --git a/sol/usertype.hpp b/sol/usertype.hpp index 4579d76f..491a6e05 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -121,12 +121,12 @@ inline void push_metatable(lua_State* L, bool needsindexfunction, Funcs&& funcs, int metatableindex = lua_gettop(L); #if !defined(SOL_NO_EXCEPTIONS) || !defined(SOL_NO_RTTI) if (baseclasscheck != nullptr) { - stack::push(L, light_userdata(baseclasscheck)); - lua_setfield(L, metatableindex, &detail::base_class_check_key[0]); + stack::push(L, light_userdata_value(baseclasscheck)); + lua_setfield(L, metatableindex, &detail::base_class_check_key[0]); } if (baseclasscast != nullptr) { - stack::push(L, light_userdata(baseclasscast)); - lua_setfield(L, metatableindex, &detail::base_class_cast_key[0]); + stack::push(L, light_userdata_value(baseclasscast)); + lua_setfield(L, metatableindex, &detail::base_class_cast_key[0]); } #endif // No Exceptions || RTTI if (funcs.size() < 1 && metafunctable.size() < 2) { @@ -342,17 +342,24 @@ private: } template - void build_function_tables(bases<>, bases, Args&&... args) { + void build_function_tables(base_classes_tag, bases, Args&&... args) { + build_function_tables(std::forward(args)...); + if (sizeof...(Bases) < 1) + return; #ifndef SOL_NO_EXCEPTIONS - static_assert(sizeof(void*) <= sizeof(detail::throw_cast), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscast = (void*)&detail::throw_as; + static_assert(sizeof(void*) <= sizeof(detail::throw_cast), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); + baseclasscast = (void*)&detail::throw_as; #elif !defined(SOL_NO_RTTI) - static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = (void*)&detail::userdata_check::check; - baseclasscast = (void*)&detail::userdata_check::cast; + static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); + static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); + baseclasscheck = (void*)&detail::inheritance::check; + baseclasscast = (void*)&detail::inheritance::cast; +#else + static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); + static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); + baseclasscheck = (void*)&detail::inheritance::check; + baseclasscast = (void*)&detail::inheritance::cast; #endif // No Runtime Type Information vs. Throw-Style Inheritance - build_function_tables(std::forward(args)...); } template diff --git a/sol/usertype_traits.hpp b/sol/usertype_traits.hpp index 5fc7dc6b..1bb4d36b 100644 --- a/sol/usertype_traits.hpp +++ b/sol/usertype_traits.hpp @@ -35,16 +35,16 @@ struct usertype_traits { }; template -const std::string usertype_traits::name = detail::demangle(typeid(T)); +const std::string usertype_traits::name = detail::demangle(); template -const std::string usertype_traits::metatable = std::string("sol.").append(detail::demangle(typeid(T))); +const std::string usertype_traits::metatable = std::string("sol.").append(detail::demangle()); template -const std::string usertype_traits::variable_metatable = std::string("sol.").append(detail::demangle(typeid(T))).append(".variables"); +const std::string usertype_traits::variable_metatable = std::string("sol.").append(detail::demangle()).append(".variables"); template -const std::string usertype_traits::gc_table = std::string("sol.").append(detail::demangle(typeid(T))).append(".\xE2\x99\xBB"); +const std::string usertype_traits::gc_table = std::string("sol.").append(detail::demangle().append(".\xE2\x99\xBB")); } diff --git a/tests.cpp b/tests.cpp index ad8dc6fb..73a810ad 100644 --- a/tests.cpp +++ b/tests.cpp @@ -1,5 +1,6 @@ #define CATCH_CONFIG_MAIN #define SOL_CHECK_ARGUMENTS + #include #include #include @@ -546,6 +547,17 @@ TEST_CASE("tables/variables", "Check if tables and variables work as intended") REQUIRE_NOTHROW(lua.script("assert(os.name == \"windows\")")); } +TEST_CASE("tables/create", "Check if creating a table is kosher") { + sol::state lua; + lua["testtable"] = sol::table::create(lua.lua_state(), 0, 0, "Woof", "Bark", 1, 2, 3, 4); + sol::object testobj = lua["testtable"]; + REQUIRE(testobj.is()); + sol::table testtable = testobj.as(); + REQUIRE((testtable["Woof"] == std::string("Bark"))); + REQUIRE((testtable[1] == 2)); + REQUIRE((testtable[3] == 4)); +} + TEST_CASE("tables/functions-variables", "Check if tables and function calls work as intended") { sol::state lua; lua.open_libraries(sol::lib::base, sol::lib::os); @@ -754,7 +766,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works REQUIRE(b == 20.4); }; - REQUIRE_NOTHROW(assert1(lua.global())); + REQUIRE_NOTHROW(assert1(lua.globals())); } TEST_CASE("tables/usertype", "Show that we can create classes from usertype and use them") { @@ -771,7 +783,7 @@ TEST_CASE("tables/usertype", "Show that we can create classes from usertype and sol::object a = lua.get("a"); sol::object b = lua.get("b"); sol::object c = lua.get("c"); - REQUIRE((a.is())); + REQUIRE((a.is())); auto atype = a.get_type(); auto btype = b.get_type(); auto ctype = c.get_type(); @@ -839,7 +851,7 @@ TEST_CASE("tables/usertype-utility", "Show internal management of classes regist sol::object a = lua.get("a"); sol::object b = lua.get("b"); sol::object c = lua.get("c"); - REQUIRE((a.is())); + REQUIRE((a.is())); auto atype = a.get_type(); auto btype = b.get_type(); auto ctype = c.get_type(); @@ -941,8 +953,7 @@ TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a l sol::table tbl = lua[ "arr" ]; std::size_t tablesize = 4; std::size_t iterations = 0; - tbl.for_each( - [&iterations](sol::object key, sol::object value) { + auto fx = [&iterations](sol::object key, sol::object value) { ++iterations; sol::type keytype = key.get_type(); switch (keytype) { @@ -973,8 +984,72 @@ TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a l default: break; } - } - ); + }; + auto fxpair = [&fx](std::pair kvp) { fx(kvp.first, kvp.second); }; + tbl.for_each( fx ); + REQUIRE(iterations == tablesize); + + iterations = 0; + tbl.for_each( fxpair ); + REQUIRE(iterations == tablesize); +} + +TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a lua table") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.script("arr = {\n" + "[0] = \"Hi\",\n" + "[1] = 123.45,\n" + "[2] = \"String value\",\n" + // Does nothing + //"[3] = nil,\n" + //"[nil] = 3,\n" + "[\"WOOF\"] = 123,\n" + "}"); + sol::table tbl = lua[ "arr" ]; + std::size_t tablesize = 4; + std::size_t iterations = 0; + + int begintop = 0; + int endtop = 0; + { + stack_guard s(lua.lua_state(), begintop, endtop); + for (auto& kvp : tbl) { + [&iterations](sol::object key, sol::object value) { + ++iterations; + sol::type keytype = key.get_type(); + switch (keytype) { + case sol::type::number: + switch (key.as()) { + case 0: + REQUIRE((value.as() == "Hi")); + break; + case 1: + REQUIRE((value.as() == 123.45)); + break; + case 2: + REQUIRE((value.as() == "String value")); + break; + case 3: + REQUIRE((value.is())); + break; + } + break; + case sol::type::string: + if (key.as() == "WOOF") { + REQUIRE((value.as() == 123)); + } + break; + case sol::type::nil: + REQUIRE((value.as() == 3)); + break; + default: + break; + } + }(kvp.first, kvp.second); + } + } REQUIRE(begintop == endtop); REQUIRE(iterations == tablesize); } @@ -1365,7 +1440,7 @@ TEST_CASE("usertype/private-constructible", "Check to make sure special snowflak lua.open_libraries(sol::lib::base); lua.new_usertype("factory_test", - "new", sol::constructor(factory_test::save), + "new", sol::initializers(factory_test::save), "__gc", sol::destructor(factory_test::kill), "a", &factory_test::a ); @@ -1470,7 +1545,7 @@ end lua.script(script); sol::thread runner = sol::thread::create(lua.lua_state()); sol::state_view runnerstate = runner.state(); - sol::coroutine cr = lua["loop"]; + sol::coroutine cr = runnerstate["loop"]; int counter; for (counter = 20; counter < 31 && cr; ++counter) {