1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 16:57:16 +01:00
SqMod/include/sqrat/sqratUtil.h
Sandu Liviu Catalin f51b4968ac Fix bug in plugin caused by not popping the closure from the stack after calling it.
This would've caused the plugin to run out of stack memory eventually.
2018-07-05 21:01:08 +03:00

1907 lines
74 KiB
C++

//
// SqratUtil: Squirrel Utilities
//
//
// Copyright (c) 2009 Brandon Jones
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
#if !defined(_SCRAT_UTIL_H_)
#define _SCRAT_UTIL_H_
#ifdef SQMOD_PLUGIN_API
#include <SqAPI.h>
#else
#include <squirrel.h>
#include <sqstdstring.h>
#endif // SQMOD_PLUGIN_API
#include <cassert>
#include <map>
#include <string.h>
#if defined(SCRAT_USE_CXX11_OPTIMIZATIONS)
#include <unordered_map>
#endif
namespace Sqrat {
/// @cond DEV
#if defined(SCRAT_USE_CXX11_OPTIMIZATIONS)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Define an unordered map for Sqrat to use based on whether SCRAT_USE_CXX11_OPTIMIZATIONS is defined or not
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Key, class T>
struct unordered_map {
typedef std::unordered_map<Key, T> type;
};
#else
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Define an unordered map for Sqrat to use based on whether SCRAT_USE_CXX11_OPTIMIZATIONS is defined or not
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Key, class T>
struct unordered_map {
typedef std::map<Key, T> type;
};
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Define an inline function to avoid MSVC's "conditional expression is constant" warning
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
template <typename T>
inline T _c_def(T value) { return value; }
#define SQRAT_CONST_CONDITION(value) _c_def(value)
#else
#define SQRAT_CONST_CONDITION(value) value
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Define helpers to create portable import / export macros
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if defined(SCRAT_EXPORT)
#if defined(_WIN32)
// Windows compilers need a specific keyword for export
#define SQRAT_API __declspec(dllexport)
#else
#if __GNUC__ >= 4
// GCC 4 has special keywords for showing/hiding symbols,
// the same keyword is used for both importing and exporting
#define SQRAT_API __attribute__ ((__visibility__ ("default")))
#else
// GCC < 4 has no mechanism to explicitly hide symbols, everything's exported
#define SQRAT_API
#endif
#endif
#elif defined(SCRAT_IMPORT)
#if defined(_WIN32)
// Windows compilers need a specific keyword for import
#define SQRAT_API __declspec(dllimport)
#else
#if __GNUC__ >= 4
// GCC 4 has special keywords for showing/hiding symbols,
// the same keyword is used for both importing and exporting
#define SQRAT_API __attribute__ ((__visibility__ ("default")))
#else
// GCC < 4 has no mechanism to explicitly hide symbols, everything's exported
#define SQRAT_API
#endif
#endif
#else
#define SQRAT_API
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Define macros for internal error handling
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if defined (SCRAT_NO_ERROR_CHECKING)
#define SQCATCH(vm) if (SQRAT_CONST_CONDITION(false))
#define SQCATCH_NOEXCEPT(vm) if (SQRAT_CONST_CONDITION(false))
#define SQCLEAR(vm)
#define SQRETHROW(vm)
#define SQTHROW(vm, err)
#define SQTRY()
#define SQWHAT(vm) _SC("")
#define SQWHAT_NOEXCEPT(vm) _SC("")
#elif defined (SCRAT_USE_EXCEPTIONS)
#define SQCATCH(vm) } catch (const ::Sqrat::Exception& e)
#define SQCATCH_NOEXCEPT(vm) if (SQRAT_CONST_CONDITION(false))
#define SQCLEAR(vm)
#ifdef _MSC_VER // avoid MSVC's "unreachable code" warning
#define SQRETHROW(vm) if (SQRAT_CONST_CONDITION(true)) throw
#define SQTHROW(vm, err) if (SQRAT_CONST_CONDITION(true)) throw ::Sqrat::Exception(err)
#else
#define SQRETHROW(vm) throw
#define SQTHROW(vm, err) throw ::Sqrat::Exception(err)
#endif
#define SQTRY() try {
#define SQWHAT(vm) e.Message().c_str()
#define SQWHAT_NOEXCEPT(vm) _SC("")
#else
#define SQCATCH(vm) if (SQRAT_CONST_CONDITION(false))
#define SQCATCH_NOEXCEPT(vm) if (Error::Occurred(vm))
#define SQCLEAR(vm) Error::Clear(vm)
#define SQRETHROW(vm)
#define SQTHROW(vm, err) Error::Throw(vm, err)
#define SQTRY()
#define SQWHAT(vm) _SC("")
#define SQWHAT_NOEXCEPT(vm) Error::Message(vm).c_str()
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Removes unused variable warnings in a way that Doxygen can understand
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
void SQUNUSED(const T&) {
}
/// @endcond
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Defines a string that is definitely compatible with the version of Squirrel being used (normally this is std::string)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef std::basic_string<SQChar> string;
/// @cond DEV
#ifdef SQUNICODE
/* from http://stackoverflow.com/questions/15333259/c-stdwstring-to-stdstring-quick-and-dirty-conversion-for-use-as-key-in,
only works for ASCII chars */
/**
* Convert a std::string into a std::wstring
*/
static std::wstring string_to_wstring(const std::string& str)
{
return std::wstring(str.begin(), str.end());
}
/**
* Convert a std::wstring into a std::string
*/
static std::string wstring_to_string(const std::wstring& wstr)
{
return std::string(wstr.begin(), wstr.end());
}
#endif // SQUNICODE
template <class T>
class SharedPtr;
template <class T>
class WeakPtr;
/// @endcond
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper class that defines a VM that can be used as a fallback VM in case no other one is given to a piece of code
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class DefaultVM {
private:
static HSQUIRRELVM& staticVm() {
static HSQUIRRELVM vm;
return vm;
}
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Gets the default VM
///
/// \return Default VM
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static HSQUIRRELVM Get() {
return staticVm();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Sets the default VM to a given VM
///
/// \param vm New default VM
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void Set(HSQUIRRELVM vm) {
staticVm() = vm;
}
};
#if !defined (SCRAT_NO_ERROR_CHECKING) && !defined (SCRAT_USE_EXCEPTIONS)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// The class that must be used to deal with errors that Sqrat has
///
/// \remarks
/// When documentation in Sqrat says, "This function MUST have its error handled if it occurred," that
/// means that after the function has been run, you must call Error::Occurred to see if the function
/// ran successfully. If the function did not run successfully, then you MUST either call Error::Clear
/// or Error::Message to clear the error buffer so new ones may occur and Sqrat does not get confused.
///
/// \remarks
/// Any error thrown inside of a bound C++ function will be thrown in the given Squirrel VM and
/// automatically handled.
///
/// \remarks
/// If compiling with SCRAT_USE_EXCEPTIONS defined, Sqrat will throw exceptions instead of using this
/// class to handle errors. This means that functions must be enclosed in try blocks that catch
/// Sqrat::Exception instead of checking for errors with Error::Occurred.
///
/// \remarks
/// If compiling with SCRAT_NO_ERROR_CHECKING defined, Sqrat will run significantly faster,
/// but it will no longer check for errors and the Error class itself will not be defined.
/// In this mode, a Squirrel script may crash the C++ application if errors occur in it.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Error {
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Clears the error associated with a given VM
///
/// \param vm Target VM
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void Clear(HSQUIRRELVM vm) {
sq_pushregistrytable(vm);
sq_pushstring(vm, "__error", -1);
sq_rawdeleteslot(vm, -2, false);
sq_pop(vm, 1);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Clears the error associated with a given VM and returns the associated error message
///
/// \param vm Target VM
///
/// \return String containing a nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static string Message(HSQUIRRELVM vm) {
sq_pushregistrytable(vm);
sq_pushstring(vm, "__error", -1);
if (SQ_SUCCEEDED(sq_rawget(vm, -2))) {
string** ud;
sq_getuserdata(vm, -1, (SQUserPointer*)&ud, NULL);
sq_pop(vm, 1);
string err = **ud;
sq_pushstring(vm, "__error", -1);
sq_rawdeleteslot(vm, -2, false);
sq_pop(vm, 1);
return err;
}
sq_pushstring(vm, "__error", -1);
sq_rawdeleteslot(vm, -2, false);
sq_pop(vm, 1);
return string(_SC("an unknown error has occurred"));
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns whether a Sqrat error has occurred with a given VM
///
/// \param vm Target VM
///
/// \return True if an error has occurred, otherwise false
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static bool Occurred(HSQUIRRELVM vm) {
sq_pushregistrytable(vm);
sq_pushstring(vm, "__error", -1);
if (SQ_SUCCEEDED(sq_rawget(vm, -2))) {
sq_pop(vm, 2);
return true;
}
sq_pop(vm, 1);
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Raises an error in a given VM with a given error message
///
/// \param vm Target VM
/// \param err A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void Throw(HSQUIRRELVM vm, const string& err) {
sq_pushregistrytable(vm);
sq_pushstring(vm, "__error", -1);
if (SQ_FAILED(sq_rawget(vm, -2))) {
sq_pushstring(vm, "__error", -1);
string** ud = reinterpret_cast<string**>(sq_newuserdata(vm, sizeof(string*)));
*ud = new string(err);
sq_setreleasehook(vm, -1, &error_cleanup_hook);
sq_rawset(vm, -3);
sq_pop(vm, 1);
return;
}
sq_pop(vm, 2);
}
private:
Error() {}
static SQInteger error_cleanup_hook(SQUserPointer ptr, SQInteger size) {
SQUNUSED(size);
string** ud = reinterpret_cast<string**>(ptr);
delete *ud;
return 0;
}
};
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Tells Sqrat whether Squirrel error handling should be used
///
/// \remarks
/// If true, if a runtime error occurs during the execution of a call, the VM will invoke its error handler.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ErrorHandling {
private:
static bool& errorHandling() {
static bool eh = true;
return eh;
}
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns whether Squirrel error handling is enabled
///
/// \return True if error handling is enabled, otherwise false
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static bool IsEnabled() {
return errorHandling();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Enables or disables Squirrel error handling
///
/// \param enable True to enable, false to disable
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void Enable(bool enable) {
errorHandling() = enable;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Sqrat exception class
///
/// \remarks
/// Used only when SCRAT_USE_EXCEPTIONS is defined (see Sqrat::Error)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Exception {
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an exception
///
/// \param msg A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Exception(const SQChar * msg) noexcept : message(msg) {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an exception
///
/// \param msg A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit Exception(string && msg) noexcept : message(msg) {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an exception
///
/// \param msg A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit Exception(const string& msg) noexcept : message(msg) {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param ex Exception to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Exception(const Exception& ex) noexcept : message(ex.message) {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns a string identifying the exception
///
/// \return A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const string& Message() const noexcept {
return message;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns a C string identifying the exception
///
/// \return A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const SQChar * what() const noexcept {
return message.c_str();
}
private:
string message;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns a string that has been formatted to give a nice type error message (for usage with Class::SquirrelFunc)
///
/// \param vm VM the error occurred with
/// \param idx Index on the stack of the argument that had a type error
/// \param expectedType The name of the type that the argument should have been
///
/// \return String containing a nice type error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline string FormatTypeError(HSQUIRRELVM vm, SQInteger idx, const string& expectedType) {
string err = _SC("wrong type (") + expectedType + _SC(" expected");
#if (SQUIRREL_VERSION_NUMBER>= 200) && (SQUIRREL_VERSION_NUMBER < 300) // Squirrel 2.x
err = err + _SC(")");
#else // Squirrel 3.x
if (SQ_SUCCEEDED(sq_typeof(vm, idx))) {
const SQChar* actualType;
sq_tostring(vm, -1);
sq_getstring(vm, -1, &actualType);
sq_pop(vm, 2);
err = err + _SC(", got ") + actualType + _SC(")");
} else {
err = err + _SC(", got unknown)");
}
#endif
return err;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns the last error that occurred with a Squirrel VM (not associated with Sqrat errors)
///
/// \param vm Target VM
///
/// \return String containing a nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline string LastErrorString(HSQUIRRELVM vm) {
const SQChar* sqErr;
SQInteger size;
sq_getlasterror(vm);
if (sq_gettype(vm, -1) == OT_NULL) {
sq_pop(vm, 1);
return string();
}
sq_tostring(vm, -1);
sq_getstringandsize(vm, -1, &sqErr, &size);
sq_pop(vm, 2);
return string(sqErr, size);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Used internally to store the counters of managed pointers.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SqReferenceCounter {
typedef unsigned int ValueType; ///< The type of value that is used to represent a count.
ValueType mHard; ///< Strong reference count. If equal to zero, the object has been destroyed.
ValueType mSoft; ///< Weak reference count. If equal to zero, the counter has been destroyed.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqReferenceCounter()
: mHard(0), mSoft(0)
{ }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Construct with specific counts
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqReferenceCounter(ValueType hard, ValueType soft)
: mHard(hard), mSoft(soft)
{ }
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// A smart pointer that retains shared ownership of an object through a pointer (see std::shared_ptr)
///
/// \tparam T Type of pointer
///
/// \remarks
/// SharedPtr exists to automatically delete an object when all references to it are destroyed.
///
/// \remarks
/// std::shared_ptr was not used because it is a C++11 feature.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class T>
class SharedPtr
{
template <class U>
friend class SharedPtr;
template <class U>
friend class WeakPtr;
typedef SqReferenceCounter Counter;
private:
T* m_Ptr;
Counter* m_Ref;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs with explicit pointer and counter.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr(T * ptr, Counter * ref)
: m_Ptr(ptr)
, m_Ref(ref)
{
if (m_Ptr != NULL)
{
++(m_Ref->mHard);
++(m_Ref->mSoft);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns a new pointer.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Assign(T * ptr) noexcept
{
if (m_Ptr != ptr)
{
Reset();
if (ptr != NULL)
{
m_Ptr = ptr;
m_Ref = new Counter(1,1);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns a new pointer and counter.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Assign(T * ptr, Counter * ref) noexcept
{
if (m_Ptr != ptr)
{
Reset();
if (ptr != NULL)
{
m_Ptr = ptr;
m_Ref = ref;
++(m_Ref->mHard);
++(m_Ref->mSoft);
}
}
}
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs a new SharedPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr()
: m_Ptr(NULL)
, m_Ref(NULL)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs a new SharedPtr from an object allocated with the new operator
///
/// \param ptr Should be the return value from a call to the new operator
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr(T* ptr)
: m_Ptr(NULL)
, m_Ref(NULL)
{
Assign(ptr);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs a new SharedPtr from an object allocated with the new operator
///
/// \param ptr Should be the return value from a call to the new operator
///
/// \tparam U Type of pointer (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
SharedPtr(U* ptr)
: m_Ptr(NULL)
, m_Ref(NULL)
{
Assign(static_cast<T*>(ptr));
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy SharedPtr to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr(const SharedPtr<T>& copy)
: SharedPtr(copy.m_Ptr, copy.m_Ref)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy SharedPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
SharedPtr(const SharedPtr<U>& copy)
: SharedPtr(static_cast<T*>(copy.m_Ptr), copy.m_Ref)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor
///
/// \param other SharedPtr to move
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr(SharedPtr<T>&& other)
: m_Ptr(other.m_Ptr)
, m_Ref(other.m_Ref)
{
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor
///
/// \param other SharedPtr to move
///
/// \tparam U Type of pointer (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
SharedPtr(SharedPtr<U>&& other)
: m_Ptr(static_cast<T*>(other.m_Ptr))
, m_Ref(other.m_Ref)
{
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy WeakPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr(const WeakPtr<T>& copy)
: SharedPtr(copy.m_Ptr, copy.m_Ref)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy WeakPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
SharedPtr(const WeakPtr<U>& copy)
: SharedPtr(static_cast<T*>(copy.m_Ptr), copy.m_Ref)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructs the owned object if no more SharedPtr link to it
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~SharedPtr()
{
Reset();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the SharedPtr
///
/// \param copy SharedPtr to copy
///
/// \return The SharedPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr<T>& operator=(const SharedPtr<T>& copy)
{
Assign(copy.m_Ptr, copy.m_Ref);
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the SharedPtr
///
/// \param copy SharedPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/// \return The SharedPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
SharedPtr<T>& operator=(const SharedPtr<U>& copy)
{
Assign(static_cast<T*>(copy.m_Ptr), copy.m_Ref);
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the SharedPtr
///
/// \param other SharedPtr to move
///
/// \return The SharedPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr<T>& operator=(SharedPtr<T>&& other)
{
if (m_Ptr != other.m_Ptr)
{
Reset();
m_Ptr = other.m_Ptr;
m_Ref = other.m_Ref;
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the SharedPtr
///
/// \param other SharedPtr to move
///
/// \tparam U Type of pointer (usually doesnt need to be defined explicitly)
///
/// \return The SharedPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
SharedPtr<T>& operator=(SharedPtr<U>&& other)
{
if (m_Ptr != static_cast<T*>(other.m_Ptr))
{
Reset();
m_Ptr = static_cast<T*>(other.m_Ptr);
m_Ref = other.m_Ref;
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Sets up a new object to be managed by the SharedPtr
///
/// \param ptr Should be the return value from a call to the new operator
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Init(T* ptr)
{
Assign(ptr);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Sets up a new object to be managed by the SharedPtr
///
/// \param ptr Should be the return value from a call to the new operator
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
void Init(U* ptr)
{
Assign(static_cast<T*>(ptr));
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Clears the owned object for this SharedPtr and deletes it if no more SharedPtr link to it
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Reset()
{
if (m_Ptr != NULL)
{
--(m_Ref->mHard);
if (m_Ref->mHard == 0)
{
delete m_Ptr;
}
--(m_Ref->mSoft);
if (m_Ref->mSoft == 0)
{
delete m_Ref;
}
m_Ptr = NULL;
m_Ref = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Checks if there is an associated managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator bool () const
{
return m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Checks if there is NOT an associated managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool operator!() const
{
return !m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another SharedPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename U>
bool operator ==(const SharedPtr<U>& right) const
{
return m_Ptr == right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another SharedPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool operator ==(const SharedPtr<T>& right) const
{
return m_Ptr == right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename U>
bool friend operator ==(const SharedPtr<T>& left, const U* right)
{
return left.m_Ptr == right;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool friend operator ==(const SharedPtr<T>& left, const T* right)
{
return left.m_Ptr == right;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename U>
bool friend operator ==(const U* left, const SharedPtr<T>& right)
{
return left == right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool friend operator ==(const T* left, const SharedPtr<T>& right)
{
return left == right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another SharedPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename U>
bool operator !=(const SharedPtr<U>& right) const
{
return m_Ptr != right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another SharedPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool operator !=(const SharedPtr<T>& right) const
{
return m_Ptr != right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename U>
bool friend operator !=(const SharedPtr<T>& left, const U* right)
{
return left.m_Ptr != right;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool friend operator !=(const SharedPtr<T>& left, const T* right)
{
return left.m_Ptr != right;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename U>
bool friend operator !=(const U* left, const SharedPtr<T>& right)
{
return left != right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compares with another pointer
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool friend operator !=(const T* left, const SharedPtr<T>& right)
{
return left != right.m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Dereferences pointer to the managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
T& operator*() const
{
assert(m_Ptr != NULL); // fails when dereferencing a null SharedPtr
return *m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Dereferences pointer to the managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
T* operator->() const
{
assert(m_Ptr != NULL); // fails when dereferencing a null SharedPtr
return m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Gets the underlying pointer
///
/// \return Pointer to the managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
T* Get() const
{
return m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Gets the number of references to the underlying pointer
///
/// \return Number of references
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Counter::ValueType Count() const
{
return m_Ref ? m_Ref->mHard : 0;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// A smart pointer that retains a non-owning ("weak") reference to an object that is managed by SharedPtr (see std::weak_ptr)
///
/// \tparam T Type of pointer
///
/// \remarks
/// WeakPtr exists for when an object that may be deleted at any time needs to be accessed if it exists.
///
/// \remarks
/// std::weak_ptr was not used because it is a C++11 feature.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class T>
class WeakPtr
{
template <class U>
friend class SharedPtr;
typedef SqReferenceCounter Counter;
private:
T* m_Ptr;
Counter* m_Ref;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs with explicit pointer and counter.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr(T * ptr, Counter * ref)
: m_Ptr(ptr)
, m_Ref(ref)
{
if (m_Ptr != NULL)
{
++(m_Ref->mSoft);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Initializes the pointer and counter.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Initialize(T * ptr, Counter * ref) noexcept
{
if (ptr != NULL)
{
m_Ptr = ptr;
m_Ref = ref;
++(m_Ref->mSoft);
}
else
{
m_Ptr = NULL;
m_Ref = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns a new pointer and counter.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Assign(T * ptr, Counter * ref) noexcept
{
if (m_Ptr != ptr)
{
Reset();
if (ptr != NULL)
{
m_Ptr = ptr;
m_Ref = ref;
++(m_Ref->mSoft);
}
}
}
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs a new WeakPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr()
: m_Ptr(NULL)
, m_Ref(NULL)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy WeakPtr to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr(const WeakPtr<T>& copy)
{
Initialize(copy.m_Ptr, copy.m_Ref);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy WeakPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
WeakPtr(const WeakPtr<U>& copy)
{
Initialize(static_cast<T*>(copy.m_Ptr), copy.m_Ref);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor
///
/// \param other WeakPtr to move
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr(WeakPtr<T>&& other)
: m_Ptr(other.m_Ptr)
, m_Ref(other.m_Ref)
{
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor
///
/// \param other WeakPtr to move
///
/// \tparam U Type of pointer (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
WeakPtr(WeakPtr<U>&& other)
: m_Ptr(static_cast<T*>(other.m_Ptr))
, m_Ref(other.m_Ref)
{
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy SharedPtr to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr(const SharedPtr<T>& copy)
{
Initialize(copy.m_Ptr, copy.m_Ref);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy SharedPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
WeakPtr(const SharedPtr<U>& copy)
{
Initialize(static_cast<T*>(copy.m_Ptr), copy.m_Ref);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructs the WeakPtr but has no influence on the object that was managed
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~WeakPtr()
{
Reset();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the WeakPtr
///
/// \param copy WeakPtr to copy
///
/// \return The WeakPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr<T>& operator=(const WeakPtr<T>& copy)
{
Assign(copy.m_Ptr, copy.m_Ref);
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the WeakPtr
///
/// \param copy WeakPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/// \return The WeakPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
WeakPtr<T>& operator=(const WeakPtr<U>& copy)
{
Assign(static_cast<T*>(copy.m_Ptr), copy.m_Ref);
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the WeakPtr
///
/// \param other WeakPtr to move
///
/// \return The WeakPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr<T>& operator=(WeakPtr<T>&& other)
{
if (m_Ptr != other.m_Ptr)
{
Reset();
m_Ptr = other.m_Ptr;
m_Ref = other.m_Ref;
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the WeakPtr
///
/// \param other WeakPtr to move
///
/// \tparam U Type of pointer (usually doesnt need to be defined explicitly)
///
/// \return The WeakPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
WeakPtr<T>& operator=(WeakPtr<U>&& other)
{
if (m_Ptr != static_cast<T*>(other.m_Ptr))
{
Reset();
m_Ptr = static_cast<T*>(other.m_Ptr);
m_Ref = other.m_Ref;
other.m_Ptr = NULL;
other.m_Ref = NULL;
}
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the SharedPtr
///
/// \param copy SharedPtr to copy
///
/// \return The WeakPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr<T>& operator=(const SharedPtr<T>& copy)
{
Assign(copy.m_Ptr, copy.m_Ref);
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Assigns the SharedPtr
///
/// \param copy SharedPtr to copy
///
/// \tparam U Type of copy (usually doesnt need to be defined explicitly)
///
/// \return The WeakPtr itself
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class U>
WeakPtr<T>& operator=(const SharedPtr<U>& copy)
{
Assign(static_cast<T*>(copy.m_Ptr), copy.m_Ref);
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Checks whether the managed object exists
///
/// \return True if the managed object does not exist, false otherwise
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Expired() const
{
return (m_Ptr == NULL || m_Ref->mHard == 0);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Creates a new SharedPtr that shares ownership of the managed object
///
/// \return A SharedPtr which shares ownership of the managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr<T> Lock() const
{
return SharedPtr<T>(m_Ptr, m_Ref);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Clears the associated object for this WeakPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Reset()
{
if (m_Ptr != NULL)
{
--(m_Ref->mSoft);
if (m_Ref->mSoft == 0)
{
delete m_Ref;
}
m_Ptr = NULL;
m_Ref = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Gets the number of weak references to the underlying pointer
///
/// \return Number of references
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Counter::ValueType Count() const
{
return m_Ref ? m_Ref->mSoft : 0;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper structure for popping elements from the stack.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct SqPopGuard
{
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
SQInteger mNum; // The number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuard(HSQUIRRELVM vm, SQInteger num)
: mVM(vm), mNum(num)
{
//...
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor. Pops the specified elements from the stack.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~SqPopGuard()
{
sq_pop(mVM, mNum);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Increment the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuard & operator ++ ()
{
++mNum;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Decrement the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuard & operator -- ()
{
--mNum;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Increase the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuard & operator += (SQInteger n)
{
mNum += n;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Decrease the number of elements to be popped.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqPopGuard & operator -= (SQInteger n)
{
mNum -= n;
return *this;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Implements RAII to restore the VM stack to it's initial size on function exit.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct StackGuard
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard()
: m_VM(DefaultVM::Get()), m_Top(sq_gettop(m_VM))
{
/* ... */
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard(HSQUIRRELVM vm)
: m_VM(vm), m_Top(sq_gettop(vm))
{
/* ... */
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard(const StackGuard &) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard(StackGuard &&) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~StackGuard()
{
Restore();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard & operator = (const StackGuard &) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackGuard & operator = (StackGuard &&) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Restore the stack to what was known to be.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Restore() const
{
// Retrieve the new stack top
const SQInteger top = sq_gettop(m_VM);
// Did the stack size change?
if (top > m_Top)
{
sq_pop(m_VM, top - m_Top); // Trim the stack
}
}
private:
HSQUIRRELVM m_VM; ///< The VM where the stack should be restored.
SQInteger m_Top; ///< The top of the stack when this instance was created.
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper structure for retrieving a value from the stack as a string or a formatted string.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct StackStrF
{
const SQChar * mPtr; ///< Pointer to the C string that was retrieved.
SQInteger mLen; ///< The string length if it could be retrieved.
SQRESULT mRes; ///< The result of the retrieval attempts.
HSQOBJECT mObj; ///< Strong reference to the string object.
HSQUIRRELVM mVM; ///< The associated virtual machine.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF()
: mPtr(_SC(""))
, mLen(0)
, mRes(SQ_OK)
, mObj()
, mVM(DefaultVM::Get())
{
// Reset the converted value object
sq_resetobject(&mObj);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compile time string constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template < size_t N > StackStrF(const SQChar(&str)[N])
: mPtr(str)
, mLen(N)
, mRes(SQ_OK)
, mObj()
, mVM(DefaultVM::Get())
{
// Reset the converted value object
sq_resetobject(&mObj);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF(HSQUIRRELVM vm, SQInteger idx, bool fmt = false, bool dummy = false)
: mPtr(nullptr)
, mLen(-1)
, mRes(SQ_OK)
, mObj()
, mVM(vm)
{
// Reset the converted value object
sq_resetobject(&mObj);
// is this a dummy request?
if (dummy)
{
// Since this is a dummy then avoid making it look like a failure
mPtr = _SC("");
mLen = 0;
// We're not supposed to proceed with this!
return;
}
// Grab the top of the stack
const SQInteger top = sq_gettop(vm);
// Was the string or value specified?
if (top <= (idx - 1))
{
mRes = sq_throwerror(vm, "Missing string or value");
}
// Do we have enough values to call the format function and are we allowed to?
else if (fmt && (top - 1) >= idx)
{
// Pointer to the generated string
SQChar * str = nullptr;
// Attempt to generate the specified string format
mRes = sqstd_format(vm, idx, &mLen, &str);
// Did the format succeeded but ended up with a null string pointer?
if (SQ_SUCCEEDED(mRes) && !str)
{
mRes = sq_throwerror(vm, "Unable to generate the string");
}
else
{
mPtr = const_cast< const SQChar * >(str);
}
}
// Is the value on the stack an actual string?
else if (sq_gettype(vm, idx) == OT_STRING)
{
// Obtain a reference to the string object
mRes = sq_getstackobj(vm, idx, &mObj);
// Could we retrieve the object from the stack?
if (SQ_SUCCEEDED(mRes))
{
// Keep a strong reference to the object
sq_addref(vm, &mObj);
// Attempt to retrieve the string value from the stack
mRes = sq_getstringandsize(vm, idx, &mPtr, &mLen);
}
// Did the retrieval succeeded but ended up with a null string pointer?
if (SQ_SUCCEEDED(mRes) && !mPtr)
{
mRes = sq_throwerror(vm, "Unable to retrieve the string");
}
}
// We have to try and convert it to string
else
{
// Attempt to convert the value from the stack to a string
mRes = sq_tostring(vm, idx);
// Could we convert the specified value to string?
if (SQ_SUCCEEDED(mRes))
{
// Obtain a reference to the resulted object
mRes = sq_getstackobj(vm, -1, &mObj);
// Could we retrieve the object from the stack?
if (SQ_SUCCEEDED(mRes))
{
// Keep a strong reference to the object
sq_addref(vm, &mObj);
// Attempt to obtain the string pointer
mRes = sq_getstringandsize(vm, -1, &mPtr, &mLen);
}
}
// Pop a value from the stack regardless of the result
sq_pop(vm, 1);
// Did the retrieval succeeded but ended up with a null string pointer?
if (SQ_SUCCEEDED(mRes) && !mPtr)
{
mRes = sq_throwerror(vm, "Unable to retrieve the value");
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF(const StackStrF & o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF(StackStrF && o)
: mPtr(o.mPtr)
, mLen(o.mLen)
, mRes(o.mRes)
, mObj(o.mObj)
, mVM(o.mVM)
{
o.mPtr = nullptr;
o.mLen = 0;
o.mRes = SQ_OK;
o.mVM = nullptr;
sq_resetobject(&o.mObj);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~StackStrF()
{
if (mVM && !sq_isnull(mObj))
{
sq_release(mVM, &mObj);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF & operator = (const StackStrF & o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF & operator = (StackStrF && o) = delete;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// RAII approach to make sure an instance is deleted regardless of what exceptions are thrown.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template < typename T > struct DeleteGuard
{
private:
// --------------------------------------------------------------------------------------------
T * m_Ptr; // Pointer to the instance to manage.
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DeleteGuard(T * ptr)
: m_Ptr(ptr)
{
/* ... */
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DeleteGuard(const DeleteGuard & o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DeleteGuard(DeleteGuard && o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~DeleteGuard()
{
if (m_Ptr)
{
delete m_Ptr;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DeleteGuard & operator = (const DeleteGuard & o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DeleteGuard & operator = (DeleteGuard && o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Implicit conversion the managed instance type.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator T * () const
{
return m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Retrieve the managed instance.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
T * Get() const
{
return m_Ptr;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Release the managed instance.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Release()
{
m_Ptr = nullptr;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Helper structure used to make it easy to track instances of a certain type.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template < typename T > struct SqChainedInstances
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SqChainedInstances()
: m_Prev(nullptr), m_Next(nullptr)
{
//...
}
protected:
SqChainedInstances * m_Prev; // Previous instance in the chain.
SqChainedInstances * m_Next; // Next instance in the chain.
static SqChainedInstances * s_Head; // The head of the instance chain.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Attach the instance to the chain.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ChainInstance()
{
// Is there an existing head?
if (s_Head == nullptr)
{
// There was no existing head
m_Prev = m_Next = nullptr;
// We're the head
s_Head = this;
}
// Is there a preceding instance before the current head?
else if (s_Head->m_Prev == nullptr)
{
// Grab the current head as the next instance in the chain
m_Next = s_Head;
// Become the new head and the preceding instance of the current head
m_Next->m_Prev = s_Head = this;
}
else
{
// Grab the current head as the next instance in the chain
m_Next = s_Head;
// Become the new head and the next instance of the preceding instance of the current head
m_Next->m_Prev->m_Next = s_Head = this;
// Become the preceding instance of the current head
m_Next->m_Prev = this;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Detach the instance from the chain.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UnchainInstance()
{
// Is there an instance after us?
if (m_Next != nullptr)
{
// Link the next instance with the one before us
m_Next->m_Prev = m_Prev;
// Are we the current head?
if (s_Head == this)
{
s_Head = m_Next; // Make the next one the head
}
}
// Is there an instance before us?
if (m_Prev != nullptr)
{
// Link the previous instance with the one after us
m_Prev->m_Next = m_Next;
// Are we the current head?
if (s_Head == nullptr || s_Head == this)
{
// If there was no instance after us then make the previous one the head
s_Head = m_Prev;
}
}
// Are we the current and the only head?
else if (s_Head == this)
{
s_Head = nullptr; // No more instances of this type
}
}
};
template < typename T > SqChainedInstances< T > * SqChainedInstances< T >::s_Head = nullptr;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @cond DEV
/// Used internally to get and manipulate the underlying type of variables - retrieved from cppreference.com
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T> struct remove_const {typedef T type;};
template<class T> struct remove_const<const T> {typedef T type;};
template<class T> struct remove_volatile {typedef T type;};
template<class T> struct remove_volatile<volatile T> {typedef T type;};
template<class T> struct remove_cv {typedef typename remove_volatile<typename remove_const<T>::type>::type type;};
template<class T> struct is_pointer_helper {static constexpr bool value = false;};
template<class T> struct is_pointer_helper<T*> {static constexpr bool value = true;};
template<class T> struct is_pointer_helper<SharedPtr<T> > {static constexpr bool value = true;};
template<class T> struct is_pointer_helper<WeakPtr<T> > {static constexpr bool value = true;};
template<class T> struct is_pointer : is_pointer_helper<typename remove_cv<T>::type> {};
template<class T> struct is_reference {static constexpr bool value = false;};
template<class T> struct is_reference<T&> {static constexpr bool value = true;};
/// @endcond
}
#endif