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

1995 lines
78 KiB
C
Raw Normal View History

2015-11-01 09:06:54 +01:00
//
// 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_
2016-02-23 16:48:30 +01:00
#ifdef SQMOD_PLUGIN_API
#include <SqAPI.h>
2016-02-23 16:48:30 +01:00
#else
#include <squirrel.h>
#include <sqstdstring.h>
2016-02-23 16:48:30 +01:00
#endif // SQMOD_PLUGIN_API
2015-11-01 09:06:54 +01:00
#include <cassert>
#include <map>
#include <string.h>
#if defined(SCRAT_USE_CXX11_OPTIMIZATIONS)
#include <unordered_map>
#endif
namespace Sqrat {
#if defined(__GNUC__)
#define SQ_UNREACHABLE __builtin_unreachable();
#elif defined(_MSVC)
static _Noreturn void unreachable() { return; }
#define SQ_UNREACHABLE unreachable();
#else
#define SQ_UNREACHABLE assert(0);
#endif
2015-11-01 09:06:54 +01:00
/// @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)
2015-11-01 09:06:54 +01:00
#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)
2015-11-01 09:06:54 +01:00
#else
#define SQRETHROW(vm) throw
#define SQTHROW(vm, err) throw ::Sqrat::Exception(err)
2015-11-01 09:06:54 +01:00
#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
2018-07-31 16:41:46 +02:00
// 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
2015-11-01 09:06:54 +01:00
class DefaultVM {
private:
static HSQUIRRELVM& StaticVM() {
2015-11-01 09:06:54 +01:00
static HSQUIRRELVM vm;
return vm;
}
public:
2018-07-31 16:41:46 +02:00
// Gets the default VM (copy)
static HSQUIRRELVM Get() {
2018-07-31 16:41:46 +02:00
return StaticVM();
2015-11-01 09:06:54 +01:00
}
2018-07-31 16:41:46 +02:00
// Gets the default VM (reference)
static HSQUIRRELVM & Get_() {
2018-07-31 16:41:46 +02:00
return StaticVM();
}
// Sets the default VM to a given VM
2015-11-01 09:06:54 +01:00
static void Set(HSQUIRRELVM vm) {
2018-07-31 16:41:46 +02:00
StaticVM() = vm;
2015-11-01 09:06:54 +01:00
}
};
#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) : message(msg) {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an exception
///
/// \param msg A nice error message
/// \param len Length of the message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Exception(const SQChar * msg, SQInteger len) : message(msg, len > 0 ? len : 0) {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an exception
///
/// \param msg A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit Exception(string && msg) : message(msg) {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an exception
///
/// \param msg A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit Exception(const string& msg) : message(msg) {}
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param ex Exception to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Exception(const Exception& ex) : message(ex.message) {}
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns a string identifying the exception
///
/// \return A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const string& Message() const {
2015-11-01 09:06:54 +01:00
return message;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns a C string identifying the exception
///
/// \return A nice error message
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const SQChar * what() const {
return message.c_str();
}
2015-11-01 09:06:54 +01:00
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;
2015-11-01 09:06:54 +01:00
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);
2015-11-01 09:06:54 +01:00
sq_pop(vm, 2);
return string(sqErr, size);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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)
{ }
};
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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;
2015-11-01 09:06:54 +01:00
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)
{
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)
{
if (m_Ptr != ptr)
{
Reset();
if (ptr != NULL)
{
m_Ptr = ptr;
m_Ref = ref;
++(m_Ref->mHard);
++(m_Ref->mSoft);
}
}
}
2015-11-01 09:06:54 +01:00
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs a new SharedPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr()
: m_Ptr(NULL)
, m_Ref(NULL)
2015-11-01 09:06:54 +01:00
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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)
2015-11-01 09:06:54 +01:00
{
Assign(ptr);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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)
2015-11-01 09:06:54 +01:00
{
Assign(static_cast<T*>(ptr));
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy SharedPtr to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SharedPtr(const SharedPtr<T>& copy)
: SharedPtr(copy.m_Ptr, copy.m_Ref)
2015-11-01 09:06:54 +01:00
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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)
2015-11-01 09:06:54 +01:00
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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)
{
}
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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)
2015-11-01 09:06:54 +01:00
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
2015-11-01 09:06:54 +01:00
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);
2015-11-01 09:06:54 +01:00
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;
}
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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));
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
2015-11-01 09:06:54 +01:00
if (m_Ref->mHard == 0)
2015-11-01 09:06:54 +01:00
{
delete m_Ptr;
}
--(m_Ref->mSoft);
if (m_Ref->mSoft == 0)
2015-11-01 09:06:54 +01:00
{
delete m_Ref;
2015-11-01 09:06:54 +01:00
}
m_Ptr = NULL;
m_Ref = NULL;
2015-11-01 09:06:54 +01:00
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Checks if there is an associated managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator bool () const
{
return m_Ptr;
}
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Checks if there is NOT an associated managed object
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool operator!() const
{
return !m_Ptr;
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
2015-11-01 09:06:54 +01:00
///
/// \return Number of references
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Counter::ValueType Count() const
2015-11-01 09:06:54 +01:00
{
return m_Ref ? m_Ref->mHard : 0;
2015-11-01 09:06:54 +01:00
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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;
2015-11-01 09:06:54 +01:00
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)
{
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)
{
if (m_Ptr != ptr)
{
Reset();
if (ptr != NULL)
{
m_Ptr = ptr;
m_Ref = ref;
++(m_Ref->mSoft);
}
}
}
2015-11-01 09:06:54 +01:00
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructs a new WeakPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr()
: m_Ptr(NULL)
, m_Ref(NULL)
2015-11-01 09:06:54 +01:00
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
///
/// \param copy WeakPtr to copy
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WeakPtr(const WeakPtr<T>& copy)
{
Initialize(copy.m_Ptr, copy.m_Ref);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
}
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
2015-11-01 09:06:54 +01:00
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);
2015-11-01 09:06:54 +01:00
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;
}
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
2015-11-01 09:06:54 +01:00
///
/// \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);
2015-11-01 09:06:54 +01:00
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);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
2015-11-01 09:06:54 +01:00
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Clears the associated object for this WeakPtr
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Reset()
{
if (m_Ptr != NULL)
{
--(m_Ref->mSoft);
2015-11-01 09:06:54 +01:00
if (m_Ref->mSoft == 0)
2015-11-01 09:06:54 +01:00
{
delete m_Ref;
2015-11-01 09:06:54 +01:00
}
m_Ptr = NULL;
m_Ref = NULL;
2015-11-01 09:06:54 +01:00
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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;
}
2015-11-01 09:06:54 +01:00
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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 function to transform a negative index into a positive index.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline SQInteger IndexAbs(SQInteger top, SQInteger idx)
{
return (idx <= -1) ? (top + idx + 1) : idx;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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.
SQInteger mIdx; ///< The index where the string should be retrieved from.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Default constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF()
: mPtr(_SC(""))
, mLen(0)
, mRes(SQ_OK)
, mObj()
, mVM(nullptr)
, mIdx(-1)
{
sq_resetobject(&mObj); // Reset the converted value object
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Compile time string constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template < size_t N > StackStrF(const SQChar(&str)[N])
: mPtr(str)
, mLen(N)
, mRes(SQ_OK)
, mObj()
, mVM(nullptr)
, mIdx(-1)
{
sq_resetobject(&mObj); // Reset the converted value object
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Base constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF(HSQUIRRELVM vm, SQInteger idx)
2018-10-23 21:28:09 +02:00
: mPtr(_SC(""))
2018-07-30 19:40:52 +02:00
, mLen(SQ_ERROR)
, mRes(SQ_OK)
, mObj()
, mVM(vm)
, mIdx(idx)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy constructor. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF(const StackStrF & o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move constructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF(StackStrF && o)
: mPtr(o.mPtr)
, mLen(o.mLen)
, mRes(o.mRes)
, mObj(o.mObj)
, mVM(o.mVM)
, mIdx(o.mIdx)
{
2018-10-23 21:28:09 +02:00
o.mPtr = _SC("");
o.mLen = 0;
o.mRes = SQ_OK;
o.mVM = nullptr;
o.mIdx = -1;
sq_resetobject(&o.mObj);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Destructor.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~StackStrF()
{
2018-10-23 21:28:09 +02:00
if (!sq_isnull(mObj))
{
2018-10-23 21:28:09 +02:00
sq_release(mVM ? mVM : DefaultVM::Get(), &mObj);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copy assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF & operator = (const StackStrF & o) = delete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Move assignment operator. (disabled)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
StackStrF & operator = (StackStrF && o) = delete;
2018-10-23 21:28:09 +02:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Release any object references.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Release()
{
if (!sq_isnull(mObj))
{
sq_release(mVM ? mVM : DefaultVM::Get(), &mObj);
}
mPtr = _SC("");
mLen = 0;
mRes = SQ_OK;
mVM = nullptr;
mIdx = -1;
sq_resetobject(&mObj);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actual implementation.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SQRESULT Proc(bool fmt = false, SQInteger top = -1)
{
// If there's no virtual machine, just ignore the request
if (mVM == nullptr)
{
return SQ_OK;
}
// Release the converted value object
else if (!sq_isnull(mObj))
{
sq_release(mVM, &mObj);
}
// Reset the converted value object
sq_resetobject(&mObj);
// Grab the top of the stack, if necessary
if (top < 0)
{
top = sq_gettop(mVM);
}
// Make the stack index absolute
mIdx = IndexAbs(top, mIdx);
// Was the string or value specified?
if (top <= (mIdx - 1))
{
mRes = sq_throwerror(mVM, "Missing string or value");
}
2018-07-30 19:40:52 +02:00
// If null was specified then treat it as a dummy
else if (sq_gettype(mVM, mIdx) == OT_NULL)
{
// Default to an empty string and ignore formatting even if possible
mPtr = _SC("");
mLen = 0;
mRes = SQ_OK;
}
// Do we have enough values to call the format function and are we allowed to?
else if (fmt && (top - 1) >= mIdx)
{
// Pointer to the generated string
SQChar * str = nullptr;
// Attempt to generate the specified string format
mRes = sqstd_format(mVM, mIdx, &mLen, &str);
// Did the format succeeded but ended up with a null string pointer?
if (SQ_SUCCEEDED(mRes) && !str)
{
mRes = sq_throwerror(mVM, "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(mVM, mIdx) == OT_STRING)
{
// Obtain a reference to the string object
mRes = sq_getstackobj(mVM, mIdx, &mObj);
// Could we retrieve the object from the stack?
if (SQ_SUCCEEDED(mRes))
{
// Keep a strong reference to the object
sq_addref(mVM, &mObj);
// Attempt to retrieve the string value from the stack
mRes = sq_getstringandsize(mVM, mIdx, &mPtr, &mLen);
}
// Did the retrieval succeeded but ended up with a null string pointer?
if (SQ_SUCCEEDED(mRes) && !mPtr)
{
mRes = sq_throwerror(mVM, "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(mVM, mIdx);
// Could we convert the specified value to string?
if (SQ_SUCCEEDED(mRes))
{
// Obtain a reference to the resulted object
mRes = sq_getstackobj(mVM, -1, &mObj);
// Could we retrieve the object from the stack?
if (SQ_SUCCEEDED(mRes))
{
// Keep a strong reference to the object
sq_addref(mVM, &mObj);
// Attempt to obtain the string pointer
mRes = sq_getstringandsize(mVM, -1, &mPtr, &mLen);
}
}
// Pop a value from the stack regardless of the result
sq_pop(mVM, 1);
// Did the retrieval succeeded but ended up with a null string pointer?
if (SQ_SUCCEEDED(mRes) && !mPtr)
{
mRes = sq_throwerror(mVM, "Unable to retrieve the value");
}
}
return mRes;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Throws the current error in a given VM as a program exception.
///
/// \param vm Target VM
/// \param keep Whether to clear the error from the VM
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline void ErrorToException(HSQUIRRELVM vm, bool keep = false) {
// Get the error object on the stack
sq_getlasterror(vm);
// See if there's an actual error
if (sq_gettype(vm, -1) == OT_NULL) {
sq_poptop(vm); // Pop the object from the stack
return; // Done here!
}
StackStrF s(vm, -1);
// Attempt to the the object as a string
if (SQ_FAILED(s.Proc(false))) {
sq_poptop(vm); // Pop the object from the stack
throw ::Sqrat::Exception(_SC("Unidentifiable script object used as error."));
}
sq_poptop(vm); // Pop the object from the stack
// Should the error be kept in the VM?
if (!keep) {
sq_reseterror(vm);
}
// Throw the error message
throw ::Sqrat::Exception(s.mPtr, s.mLen);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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;
2015-11-01 09:06:54 +01:00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @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;};
2015-11-01 09:06:54 +01:00
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;};
2015-11-01 09:06:54 +01:00
/// @endcond
}
#endif