diff --git a/libs/lua/LuaBridge/detail/TypeTraits.h b/libs/lua/LuaBridge/detail/TypeTraits.h index acfce6c373..5ef4205ffd 100644 --- a/libs/lua/LuaBridge/detail/TypeTraits.h +++ b/libs/lua/LuaBridge/detail/TypeTraits.h @@ -89,14 +89,6 @@ struct TypeTraits static const bool value = sizeof (test >(0)) == sizeof (yes); }; - /** Determine if T is an enum */ - template - class isEnum - { - public: - static const bool value = std::is_enum::value; - }; - /** Determine if T is const qualified. */ diff --git a/libs/lua/LuaBridge/detail/Userdata.h b/libs/lua/LuaBridge/detail/Userdata.h index 11e048d0e6..aceb4317df 100644 --- a/libs/lua/LuaBridge/detail/Userdata.h +++ b/libs/lua/LuaBridge/detail/Userdata.h @@ -555,23 +555,27 @@ public: }; //---------------------------------------------------------------------------- -// -// SFINAE helpers. -// -// non-const objects template struct UserdataSharedHelper { +private: + typedef typename TypeTraits::removeConst < typename ContainerTraits ::Type>::Type T; +public: + static void push (lua_State* L, C const& c) { if (ContainerTraits ::get (c) != 0) { new (lua_newuserdata (L, sizeof (UserdataShared ))) UserdataShared (c); - lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); + if constexpr (makeObjectConst) { + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getConstKey ()); + } else { + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); + } // If this goes off it means the class T is unregistered! assert (lua_istable (L, -1)); lua_setmetatable (L, -2); @@ -587,7 +591,11 @@ struct UserdataSharedHelper if (t) { new (lua_newuserdata (L, sizeof (UserdataShared ))) UserdataShared (t); - lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); + if constexpr (makeObjectConst) { + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getConstKey ()); + } else { + lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getClassKey ()); + } // If this goes off it means the class T is unregistered! assert (lua_istable (L, -1)); lua_setmetatable (L, -2); @@ -599,132 +607,84 @@ struct UserdataSharedHelper } }; -// const objects -template -struct UserdataSharedHelper -{ - typedef typename TypeTraits::removeConst < - typename ContainerTraits ::Type>::Type T; - - static void push (lua_State* L, C const& c) - { - if (ContainerTraits ::get (c) != 0) - { - new (lua_newuserdata (L, sizeof (UserdataShared ))) UserdataShared (c); - lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getConstKey ()); - // If this goes off it means the class T is unregistered! - assert (lua_istable (L, -1)); - lua_setmetatable (L, -2); - } - else - { - lua_pushnil (L); - } - } - - static void push (lua_State* L, T* const t) - { - if (t) - { - new (lua_newuserdata (L, sizeof (UserdataShared ))) UserdataShared (t); - lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo ::getConstKey ()); - // If this goes off it means the class T is unregistered! - assert (lua_istable (L, -1)); - lua_setmetatable (L, -2); - } - else - { - lua_pushnil (L); - } - } -}; - -/** - Pass by container. - - The container controls the object lifetime. Typically this will be a - lifetime shared by C++ and Lua using a reference count. Because of type - erasure, containers like std::shared_ptr will not work. Containers must - either be of the intrusive variety, or in the style of the RefCountedPtr - type provided by LuaBridge (that uses a global hash table). -*/ -template -struct StackHelper -{ - static inline void push (lua_State* L, C const& c) - { - UserdataSharedHelper ::Type>::value>::push (L, c); - } - - typedef typename TypeTraits::removeConst < - typename ContainerTraits ::Type>::Type T; - - static inline C get (lua_State* L, int index) - { - return Userdata::get (L, index, true); - } -}; - -/** - Pass by value. - - Lifetime is managed by Lua. A C++ function which accesses a pointer or - reference to an object outside the activation record in which it was - retrieved may result in undefined behavior if Lua garbage collected it. -*/ -template -struct StackHelper -{ - static inline void push (lua_State* L, T const& t) - { - UserdataValue ::push (L, t); - } - - static inline T const& get (lua_State* L, int index) - { - return *Userdata::get (L, index, true); - } -}; - -template -struct StackHelper -{ - static inline void push (lua_State* L, T const& t) - { - int v = static_cast (t); - lua_pushinteger (L, static_cast (v)); - } - - static inline T get (lua_State* L, int index) - { - int v = static_cast (luaL_checkinteger (L, index)); - return T (v); - } -}; - //============================================================================== /** Lua stack conversions for class objects passed by value. */ + template struct Stack { +private: + + /** + * Pass by container. + * + * The container controls the object lifetime. Typically this will be a + * lifetime shared by C++ and Lua using a reference count. Because of type + * erasure, containers like std::shared_ptr will not work. Containers must + * either be of the intrusive variety, or in the style of the RefCountedPtr + * type provided by LuaBridge (that uses a global hash table). + */ + + static constexpr bool passByContainer = TypeTraits::isContainer::value; + + /** + * Pass by value. + * + * Lifetime is managed by Lua. A C++ function which accesses a pointer or + * reference to an object outside the activation record in which it was + * retrieved may result in undefined behavior if Lua garbage collected it. + */ + + static constexpr bool passByValueNotEnum = !passByContainer && !std::is_enum_v; + static constexpr bool passByValueEnum = !passByContainer && std::is_enum_v; + public: + static inline void push (lua_State* L, T const& t) { - StackHelper ::value, - TypeTraits::isEnum::value>::push (L, t); + if constexpr (passByValueNotEnum) { + + UserdataValue ::push (L, t); + + } else if constexpr (passByValueEnum) { + + int v = static_cast (t); + lua_pushinteger (L, static_cast (v)); + + } else { + + UserdataSharedHelper ::Type>::value>::push (L, t); + + } } - static inline T get (lua_State* L, int index) + static inline + std::conditional_t + get (lua_State* L, int index) { - return StackHelper ::value, - TypeTraits::isEnum::value>::get (L, index); + if constexpr (passByValueNotEnum) { + + return *Userdata::get (L, index, true); + + } else if constexpr (passByValueEnum) { + + int v = static_cast (luaL_checkinteger (L, index)); + return T (v); + + } else { + + typedef typename TypeTraits::removeConst < + typename ContainerTraits ::Type>::Type U; + + return Userdata::get (L, index, true); + + } } + }; //------------------------------------------------------------------------------ @@ -830,60 +790,50 @@ struct Stack } }; -template -struct RefStackHelper -{ - typedef C return_type; - - static inline void push (lua_State* L, C const& t) - { - UserdataSharedHelper ::Type>::value>::push (L, t); - } - - typedef typename TypeTraits::removeConst < - typename ContainerTraits ::Type>::Type T; - - static return_type get (lua_State* L, int index) - { - return Userdata::get (L, index, true); - } -}; - -template -struct RefStackHelper -{ - typedef T const& return_type; - - static inline void push (lua_State* L, T const& t) - { - UserdataPtr::push (L, &t); - } - - static return_type get (lua_State* L, int index) - { - T const* const t = Userdata::get (L, index, true); - - if (!t) - luaL_error (L, "nil passed to reference"); - return *t; - } - -}; - // reference to const template struct Stack { - typedef RefStackHelper ::value> helper_t; +private: + + static constexpr bool passByContainer = TypeTraits::isContainer::value; + +public: static inline void push (lua_State* L, T const& t) { - helper_t::push (L, t); + if constexpr (passByContainer) { + + UserdataSharedHelper ::Type>::value>::push (L, t); + + } else { + + UserdataPtr::push (L, &t); + + } } - static typename helper_t::return_type get (lua_State* L, int index) + static + std::conditional_t + get (lua_State* L, int index) { - return helper_t::get (L, index); + if constexpr (passByContainer) { + + typedef typename TypeTraits::removeConst < + typename ContainerTraits ::Type>::Type U; + + return Userdata::get (L, index, true); + + } else { + + T const* const t = Userdata::get (L, index, true); + + if (!t) + luaL_error (L, "nil passed to reference"); + return *t; + + } } + };