diff --git a/include/sqrat/sqratMemberMethods.h b/include/sqrat/sqratMemberMethods.h index 3d5ae84b..c76d1f0e 100644 --- a/include/sqrat/sqratMemberMethods.h +++ b/include/sqrat/sqratMemberMethods.h @@ -52,7 +52,7 @@ template struct SqMemberProxy { M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; - R ret = (inst->*method)(a...); + R ret = (inst->*method)(std::forward< A >(a)...); PushVar(vm, ret); }); return 1; @@ -64,7 +64,7 @@ template struct SqMemberProxy { M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; - R ret = (inst->*method)(a...); + R ret = (inst->*method)(std::forward< A >(a)...); PushVar(vm, ret); }); return 1; @@ -83,7 +83,7 @@ template struct SqMemberProxy { M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; - R& ret = (inst->*method)(a...); + R& ret = (inst->*method)(std::forward< A >(a)...); PushVarR(vm, ret); }); return 1; @@ -95,7 +95,7 @@ template struct SqMemberProxy { M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; - R& ret = (inst->*method)(a...); + R& ret = (inst->*method)(std::forward< A >(a)...); PushVarR(vm, ret); }); return 1; @@ -114,7 +114,7 @@ template struct SqMemberProxy { M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; - (inst->*method)(a...); + (inst->*method)(std::forward< A >(a)...); }); return 0; } @@ -125,7 +125,7 @@ template struct SqMemberProxy { M* methodPtr; sq_getuserdata(vm, -1, reinterpret_cast(&methodPtr), nullptr); M method = *methodPtr; - (inst->*method)(a...); + (inst->*method)(std::forward< A >(a)...); }); return 0; } diff --git a/include/sqrat/sqratObject.h b/include/sqrat/sqratObject.h index d4032739..dddbd2fc 100644 --- a/include/sqrat/sqratObject.h +++ b/include/sqrat/sqratObject.h @@ -682,6 +682,32 @@ struct Var : Var {Var(HSQUIRRELVM vm, SQInteger idx) : Var struct Var : Var {Var(HSQUIRRELVM vm, SQInteger idx) : Var(vm, idx) {}}; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Create a script object from the specified value on the default VM. +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template < typename T > Object MakeObject(const T & v) +{ + // Remember the current stack size + const StackGuard sg; + // Transform the specified value into a script object + PushVar< T >(DefaultVM::Get(), v); + // Get the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Create a script object from the specified value on the specified VM. +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template < typename T > Object MakeObject(HSQUIRRELVM vm, const T & v) +{ + // Remember the current stack size + const StackGuard sg; + // Transform the specified value into a script object + PushVar< T >(vm, v); + // Get the object from the stack and return it + return Var< Object >(vm, -1).value; +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// A lightweight wrapper arround the Squirrel objects that implements RAII and still remains a POD type. /// @@ -799,6 +825,20 @@ struct LightObj { } } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Constructs an LightObj from a C++ instance wrapped inside a DeleteGuard + /// + /// \param instance Pointer to a C++ class instance that has been bound already + /// \param v VM that the object will exist in + /// + /// \tparam T Type of instance + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + LightObj(DeleteGuard guard, HSQUIRRELVM v = DefaultVM::Get()) : LightObj(guard.Get(), v) { + guard.Release(); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Destructor /// @@ -927,6 +967,45 @@ struct LightObj { sq_pop(vm,1); // pop table } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Casts the object to a certain C++ type + /// + /// \tparam T Type to cast to + /// + /// \return A copy of the value of the Object with the given type + /// + /// \remarks + /// This function MUST have its Error handled if it occurred. + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + T Cast() const { + HSQUIRRELVM vm = DefaultVM::Get(); + sq_pushobject(vm, mObj); + Var v(vm, -1); + sq_pop(vm, 1); + return v.value; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Casts the object to a certain C++ type instance + /// + /// \tparam T Type to cast to + /// + /// \return A pointer to the value of the Object with the given type + /// + /// \remarks + /// This function MUST have its Error handled if it occurred. + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + T * CastI() const { + HSQUIRRELVM vm = DefaultVM::Get(); + sq_pushobject(vm, mObj); + Var v(vm, -1); + sq_pop(vm, 1); + return v.value; + } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -974,6 +1053,84 @@ struct Var : Var {Var(HSQUIRRELVM vm, SQInteger idx) : Var< template<> struct Var : Var {Var(HSQUIRRELVM vm, SQInteger idx) : Var(vm, idx) {}}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Create a script object from the specified value on the default VM. +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template < typename T > LightObj MakeLightObj(const T & v) +{ + // Remember the current stack size + const StackGuard sg; + // Transform the specified value into a script object + PushVar< T >(DefaultVM::Get(), v); + // Get the object from the stack and return it + return Var< LightObj >(DefaultVM::Get(), -1).value; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Create a script object from the specified value on the specified VM. +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template < typename T > LightObj MakeLightObj(HSQUIRRELVM vm, const T & v) +{ + // Remember the current stack size + const StackGuard sg; + // Transform the specified value into a script object + PushVar< T >(vm, v); + // Get the object from the stack and return it + return Var< LightObj >(vm, -1).value; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Used to get and push pure script objects to and from the stack as references (HSQOBJECT is always a reference) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template<> +struct Var { + + HSQOBJECT value; ///< The actual value of get operations + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Attempts to get the value off the stack at idx as an HSQOBJECT + /// + /// \param vm Target VM + /// \param idx Index trying to be read + /// + /// \remarks + /// This function MUST have its Error handled if it occurred. + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Var(HSQUIRRELVM vm, SQInteger idx) { + if (SQ_FAILED(sq_getstackobj(vm, idx, &value))) { + sq_resetobject(&value); + } else { + sq_addref(vm, &value); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Called by Sqrat::PushVar to put an HSQOBJECT on the stack + /// + /// \param vm Target VM + /// \param value Value to push on to the VM's stack + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static void push(HSQUIRRELVM vm, const HSQOBJECT& value) { + sq_pushobject(vm, value); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Used to get and push pure script objects to and from the stack as references (HSQOBJECT is always a reference) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template<> +struct Var : Var {Var(HSQUIRRELVM vm, SQInteger idx) : Var(vm, idx) {}}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Used to get and push pure script objects to and from the stack as references (HSQOBJECT is always a reference) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template<> +struct Var : Var {Var(HSQUIRRELVM vm, SQInteger idx) : Var(vm, idx) {}}; + + } #endif diff --git a/include/sqrat/sqratUtil.h b/include/sqrat/sqratUtil.h index 50052262..a667c62b 100644 --- a/include/sqrat/sqratUtil.h +++ b/include/sqrat/sqratUtil.h @@ -1554,6 +1554,68 @@ inline SQInteger IndexAbs(SQInteger top, SQInteger idx) return (idx <= -1) ? (top + idx + 1) : idx; } +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Hashing utilities. +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +typedef const uint8_t * FnvHashData; + +static constexpr uint32_t FnvHashSeed32 = 2166136261u; +static constexpr uint32_t FnvHashPrime32 = 16777619u; +// Hash a single byte. +inline uint32_t Fnv1a32(uint8_t byte, uint32_t hash = FnvHashSeed32) +{ + return (byte ^ hash) * FnvHashPrime32; +} +// Hash an array of bytes. 32-bit variant. +inline uint32_t FnvHash32(FnvHashData data, size_t size, uint32_t hash = FnvHashSeed32) +{ + assert(data); + while (size--) + { + hash = Fnv1a32(*(data++), hash); + } + return hash; +} +static constexpr uint64_t FnvHashSeed64 = 14695981039346656037llu; +static constexpr uint64_t FnvHashPrime64 = 1099511628211llu; +// Hash a single byte. +inline uint64_t Fnv1a64(uint8_t byte, uint64_t hash = FnvHashSeed64) +{ + return (byte ^ hash) * FnvHashPrime64; +} +// Hash an array of bytes. 64-bit variant. +inline uint64_t FnvHash64(FnvHashData data, size_t size, uint64_t hash = FnvHashSeed64) +{ + assert(data); + while (size--) + { + hash = Fnv1a64(*(data++), hash); + } + return hash; +} +#ifdef _SQ64 + static constexpr size_t FnvHashSeed = FnvHashSeed64; + static constexpr size_t FnvHashPrime = FnvHashPrime64; +#else + static constexpr size_t FnvHashSeed = FnvHashSeed32; + static constexpr size_t FnvHashPrime = FnvHashPrime32; +#endif // _SQ64 +// Hash a single byte. +inline size_t Fnv1a(uint8_t byte, size_t hash = FnvHashSeed) +{ + return (byte ^ hash) * FnvHashPrime; +} + +// Hash an array of bytes. +inline size_t FnvHash(const uint8_t * data, size_t size, size_t hash = FnvHashSeed) { + assert(data); + while (size--) + { + hash = Fnv1a(*(data++), hash); + } + return hash; +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Helper structure for retrieving a value from the stack as a string or a formatted string. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1648,9 +1710,35 @@ struct StackStrF StackStrF & operator = (const StackStrF & o) = delete; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Move assignment operator. (disabled) + /// Move assignment operator. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - StackStrF & operator = (StackStrF && o) = delete; + StackStrF & operator = (StackStrF && o) + { + if (this != &o) + { + // Release + if (!sq_isnull(mObj)) + { + sq_release(mVM ? mVM : DefaultVM::Get(), &mObj); + sq_resetobject(&mObj); + } + // Replicate + mPtr = o.mPtr; + mLen = o.mLen; + mRes = o.mRes; + mObj = o.mObj; + mVM = o.mVM; + mIdx = o.mIdx; + // Own + o.mPtr = _SC(""); + o.mLen = 0; + o.mRes = SQ_OK; + o.mVM = nullptr; + o.mIdx = -1; + sq_resetobject(&o.mObj); + } + return *this; + } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Release any object references. @@ -1771,6 +1859,35 @@ struct StackStrF } return mRes; } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Compute the hash of the managed string using the FNV-1a algorithm. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t ToHash() const + { + return mLen ? FnvHash(reinterpret_cast< FnvHashData >(mPtr), static_cast< size_t >(mLen) * sizeof(SQChar)) : FnvHashSeed; + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Compute the string hash and cache it into the mRes member. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void CacheHash() + { + mRes = static_cast< SQInteger >(ToHash()); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Retrieve the cached string hash. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t GetHash() const + { + return static_cast< size_t >(mRes); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Compute the hash of the managed string, cashe it then retrieve it. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t HashIt() + { + CacheHash(); + return GetHash(); + } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1818,7 +1935,7 @@ public: ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Default constructor. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - DeleteGuard(T * ptr) + explicit DeleteGuard(T * ptr) : m_Ptr(ptr) { /* ... */ @@ -1830,9 +1947,13 @@ public: DeleteGuard(const DeleteGuard & o) = delete; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Move constructor. (disabled) + /// Move constructor. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - DeleteGuard(DeleteGuard && o) = delete; + DeleteGuard(DeleteGuard && o) + : m_Ptr(o.m_Ptr) + { + o.m_Ptr = nullptr; + } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Destructor. @@ -1878,6 +1999,16 @@ public: { m_Ptr = nullptr; } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Retrieve and release the managed instance. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + T * Grab() + { + T * ptr = m_Ptr; + m_Ptr = nullptr; + return ptr; + } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/sample/Module.cpp b/modules/sample/Module.cpp index ea2aac97..0ec47616 100644 --- a/modules/sample/Module.cpp +++ b/modules/sample/Module.cpp @@ -58,11 +58,11 @@ static bool OnSquirrelLoad() return false; } // Prevent common null objects from using dead virtual machines - NullObject().Release(); - NullTable().Release(); - NullArray().Release(); - NullLightObj().Release(); - NullFunction().ReleaseGently(); + NullObject() = Object(); + NullTable() = Table(); + NullArray() = Array(); + NullLightObj() = LightObj(); + NullFunction() = Function(); // Register the module API if (RegisterAPI(DefaultVM::Get())) { @@ -86,6 +86,7 @@ static void OnSquirrelTerminate() NullObject().Release(); NullTable().Release(); NullArray().Release(); + NullLightObj().Release(); NullFunction().ReleaseGently(); // Release script resources... } @@ -177,13 +178,13 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * functions, PluginCall { using namespace SqMod; // Output plug-in header - std::puts(""); + puts(""); OutputMessage("--------------------------------------------------------------------"); OutputMessage("Plug-in: %s", SQSAMPLE_NAME); OutputMessage("Author: %s", SQSAMPLE_AUTHOR); OutputMessage("Legal: %s", SQSAMPLE_COPYRIGHT); OutputMessage("--------------------------------------------------------------------"); - std::puts(""); + puts(""); // Make sure that the module was loaded after the host plug-in if (!CheckModuleOrder(functions, info->pluginId, SQSAMPLE_NAME)) { @@ -206,7 +207,7 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * functions, PluginCall // Notify that the plug-in was successfully loaded OutputMessage("Successfully loaded %s", SQSAMPLE_NAME); // Dummy spacing - std::puts(""); + puts(""); // Done! return SQMOD_SUCCESS; } diff --git a/shared/Base/Utility.hpp b/shared/Base/Utility.hpp index 3726b39d..bb5315a0 100644 --- a/shared/Base/Utility.hpp +++ b/shared/Base/Utility.hpp @@ -1457,109 +1457,6 @@ public: } }; -/* ------------------------------------------------------------------------------------------------ - * RAII approach to delete an instance of a class if not released. -*/ -template < typename T > class AutoDelete -{ -private: - - // -------------------------------------------------------------------------------------------- - T * m_Inst; // The managed instance. - -public: - - /* -------------------------------------------------------------------------------------------- - * Default constructor. - */ - AutoDelete(T * inst) - : m_Inst(inst) - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. (disabled) - */ - AutoDelete(const AutoDelete & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. (disabled) - */ - AutoDelete(AutoDelete && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Destructor. - */ - ~AutoDelete() - { - if (m_Inst) - { - delete m_Inst; - } - } - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) - */ - AutoDelete & operator = (const AutoDelete & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. (disabled) - */ - AutoDelete & operator = (AutoDelete && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Implicit cast to the managed instance. - */ - operator T * () - { - return m_Inst; - } - - /* -------------------------------------------------------------------------------------------- - * Implicit cast to the managed instance. - */ - operator const T * () const - { - return m_Inst; - } - - /* -------------------------------------------------------------------------------------------- - * Released the managed instance. - */ - void Release() - { - m_Inst = nullptr; - } - - /* -------------------------------------------------------------------------------------------- - * Released the managed instance. - */ - T * Grab() - { - T * ptr = m_Inst; - m_Inst = nullptr; - return ptr; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the managed instance. - */ - T * Get() - { - return m_Inst; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the managed instance. - */ - const T * Get() const - { - return m_Inst; - } -}; - /* ------------------------------------------------------------------------------------------------ * Retrieve the string representation of a certain type. */ @@ -1570,32 +1467,6 @@ CSStr SqTypeName(SQObjectType type); */ String SqTypeName(HSQUIRRELVM vm, SQInteger idx); -/* ------------------------------------------------------------------------------------------------ - * Create a script object from the specified value on the default VM. -*/ -template < typename T > Object MakeObject(const T & v) -{ - // Remember the current stack size - const StackGuard sg; - // Transform the specified value into a script object - PushVar< T >(DefaultVM::Get(), v); - // Get the object from the stack and return it - return Var< Object >(DefaultVM::Get(), -1).value; -} - -/* ------------------------------------------------------------------------------------------------ - * Create a script object from the specified value on the specified VM. -*/ -template < typename T > Object MakeObject(HSQUIRRELVM vm, const T & v) -{ - // Remember the current stack size - const StackGuard sg; - // Transform the specified value into a script object - PushVar< T >(vm, v); - // Get the object from the stack and return it - return Var< Object >(vm, -1).value; -} - /* ------------------------------------------------------------------------------------------------ * Create a script string instance from a buffer. */ diff --git a/source/Core/Events.inc b/source/Core/Events.inc index a4d2c322..11e79c51 100644 --- a/source/Core/Events.inc +++ b/source/Core/Events.inc @@ -1422,7 +1422,7 @@ void Core::EmitClientScriptData(Int32 player_id, const uint8_t * data, size_t si // Remember the current stack size const StackGuard sg; // Create a protected instance of a buffer wrapper - AutoDelete< SqBuffer > ad(new SqBuffer(std::move(b))); + DeleteGuard< SqBuffer > ad(new SqBuffer(std::move(b))); // Transform the pointer into a script object PushVar< SqBuffer * >(DefaultVM::Get(), ad.Get()); // The script took over the instance now diff --git a/source/Misc/Areas.cpp b/source/Misc/Areas.cpp index b99a0e56..34d1e221 100644 --- a/source/Misc/Areas.cpp +++ b/source/Misc/Areas.cpp @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------------------------ -#include "Areas.hpp" +#include "Misc/Areas.hpp" // ------------------------------------------------------------------------------------------------ #include diff --git a/source/Misc/Command.cpp b/source/Misc/Command.cpp index 9c92f2ae..37f9c981 100644 --- a/source/Misc/Command.cpp +++ b/source/Misc/Command.cpp @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------------------------ -#include "Command.hpp" +#include "Misc/Command.hpp" // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -161,7 +161,7 @@ Object Manager::Create(StackStrF & name, StackStrF & spec, Array & tags, Uint8 m // Create the command listener { // Create a new instance of this class and make sure it can't get leaked due to exceptions - AutoDelete< Listener > ad(new Listener(name, spec, tags, min, max, auth, prot, assoc)); + DeleteGuard< Listener > ad(new Listener(name, spec, tags, min, max, auth, prot, assoc)); // Transform the instance into a script object obj = Object(ad.Get()); // Validate the obtained script object diff --git a/source/Misc/Routine.cpp b/source/Misc/Routine.cpp index f7de0d2a..e31d3764 100644 --- a/source/Misc/Routine.cpp +++ b/source/Misc/Routine.cpp @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------------------------ -#include "Routine.hpp" +#include "Misc/Routine.hpp" #include "Library/Chrono.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Misc/Signal.cpp b/source/Misc/Signal.cpp index 37e85dbc..9f0898ad 100644 --- a/source/Misc/Signal.cpp +++ b/source/Misc/Signal.cpp @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------------------------ -#include "Signal.hpp" +#include "Misc/Signal.hpp" // ------------------------------------------------------------------------------------------------ namespace SqMod {