#ifndef _BASE_UTILITY_HPP_ #define _BASE_UTILITY_HPP_ // ------------------------------------------------------------------------------------------------ #ifdef SQMOD_PLUGIN_API #include #include #else #include #include #endif // SQMOD_PLUGIN_API // ------------------------------------------------------------------------------------------------ #include #include #include // ------------------------------------------------------------------------------------------------ #include // ------------------------------------------------------------------------------------------------ namespace SqMod { /* ------------------------------------------------------------------------------------------------ * Forward declarations. */ class Buffer; /* ------------------------------------------------------------------------------------------------ * Proxies to communicate with the server. */ extern PluginFuncs* _Func; extern PluginCallbacks* _Clbk; extern PluginInfo* _Info; /* ------------------------------------------------------------------------------------------------ * Retrieve the temporary buffer. */ SStr GetTempBuff(); /* ------------------------------------------------------------------------------------------------ * Retrieve the size of the temporary buffer. */ Uint32 GetTempBuffSize(); /* ------------------------------------------------------------------------------------------------ * Output a message only if the _DEBUG was defined. */ void OutputDebug(const char * msg, ...); /* ------------------------------------------------------------------------------------------------ * Output a formatted user message to the console. */ void OutputMessage(const char * msg, ...); /* ------------------------------------------------------------------------------------------------ * Output a formatted error message to the console. */ void OutputError(const char * msg, ...); /* ------------------------------------------------------------------------------------------------ * Generate a formatted string and throw it as a sqrat exception. */ void SqThrowF(CCStr str, ...); /* ------------------------------------------------------------------------------------------------ * Quickly generate a formatted string on a small static buffer without any memory allocations. * NOTE: This does throw an exception in case of failure. */ CSStr FmtStr(CSStr str, ...); /* ------------------------------------------------------------------------------------------------ * Quickly generate a formatted string on a small static buffer without any memory allocations. * NOTE: This does not throw an exception in case of failure. */ CSStr ToStrF(CCStr str, ...); /* ------------------------------------------------------------------------------------------------ * Generate a formatted string on a temporary buffer and return the string but not the buffer. * NOTE: This does not throw an exception in case of failure. */ CSStr ToStringF(CCStr str, ...); /* ------------------------------------------------------------------------------------------------ * Simple function to check whether the specified string can be considered as a boolean value */ bool SToB(CSStr str); /* ------------------------------------------------------------------------------------------------ * Retrieve a reference to a null script object. */ Object & NullObject(); /* ------------------------------------------------------------------------------------------------ * Retrieve a reference to a null/empty script table. */ Table & NullTable(); /* ------------------------------------------------------------------------------------------------ * Retrieve a reference to a null/empty script array. */ Array & NullArray(); /* ------------------------------------------------------------------------------------------------ * Retrieve a reference to a null script function. */ Function & NullFunction(); /* ------------------------------------------------------------------------------------------------ * Retrieve a reference to a null string. */ String & NullString(); /* ------------------------------------------------------------------------------------------------ * Compute the next power of two for the specified number. */ inline Uint32 NextPow2(Uint32 num) { --num; num |= num >> 1; num |= num >> 2; num |= num >> 4; num |= num >> 8; num |= num >> 16; return ++num; } /* ------------------------------------------------------------------------------------------------ * Retrieve the maximum value of a fundamental type. */ template < typename T > constexpr T MaxOf() noexcept { return std::numeric_limits< T >::max(); } /* ------------------------------------------------------------------------------------------------ * Retrieve the minimum value of a fundamental type. */ template < typename T > constexpr T MinOf() noexcept { return std::numeric_limits< T >::min(); } /* ------------------------------------------------------------------------------------------------ * Perform an equality comparison between two values taking into account floating point issues. */ template< typename T > inline bool EpsEq(const T a, const T b) { return abs(a - b) <= 0; } template <> inline bool EpsEq(const Float32 a, const Float32 b) { return fabs(a - b) <= 0.000001f; } template <> inline bool EpsEq(const Float64 a, const Float64 b) { return fabs(a - b) <= 0.000000001d; } /* ------------------------------------------------------------------------------------------------ * Perform a less than comparison between two values taking into account floating point issues. */ template< typename T > inline bool EpsLt(const T a, const T b) { return !EpsEq(a, b) && (a < b); } template <> inline bool EpsLt(const Float32 a, const Float32 b) { return !EpsEq(a, b) && (a - b) < 0.000001f; } template <> inline bool EpsLt(const Float64 a, const Float64 b) { return !EpsEq(a, b) && (a - b) < 0.000000001d; } /* ------------------------------------------------------------------------------------------------ * Perform a greater than comparison between two values taking into account floating point issues. */ template< typename T > inline bool EpsGt(const T a, const T b) { return !EpsEq(a, b) && (a > b); } template <> inline bool EpsGt(const Float32 a, const Float32 b) { return !EpsEq(a, b) && (a - b) > 0.000001f; } template <> inline bool EpsGt(const Float64 a, const Float64 b) { return !EpsEq(a, b) && (a - b) > 0.000000001d; } /* ------------------------------------------------------------------------------------------------ * Perform a less than or equal comparison between two values taking into account * floating point issues. */ template< typename T > inline bool EpsLtEq(const T a, const T b) { return !EpsEq(a, b) || (a < b); } template <> inline bool EpsLtEq(const Float32 a, const Float32 b) { return !EpsEq(a, b) || (a - b) < 0.000001f; } template <> inline bool EpsLtEq(const Float64 a, const Float64 b) { return !EpsEq(a, b) || (a - b) < 0.000000001d; } /* ------------------------------------------------------------------------------------------------ * Perform a greater than or equal comparison between two values taking into account * floating point issues. */ template< typename T > inline bool EpsGtEq(const T a, const T b) { return !EpsEq(a, b) || (a > b); } template <> inline bool EpsGtEq(const Float32 a, const Float32 b) { return !EpsEq(a, b) || (a - b) > 0.000001f; } template <> inline bool EpsGtEq(const Float64 a, const Float64 b) { return !EpsEq(a, b) || (a - b) > 0.000000001d; } /* ------------------------------------------------------------------------------------------------ * Utility used to convert strings to numeric values and/or backwards. */ template < typename T > struct ConvNum; /* ------------------------------------------------------------------------------------------------ * Specializations for each numeric type conversion to string and/or backwards. */ template <> struct ConvNum< Int8 > { static CCStr ToStr(Int8 v); static Int8 FromStr(CCStr s); static Int8 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Uint8 > { static CCStr ToStr(Uint8 v); static Uint8 FromStr(CCStr s); static Uint8 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Int16 > { static CCStr ToStr(Int16 v); static Int16 FromStr(CCStr s); static Int16 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Uint16 > { static CCStr ToStr(Uint16 v); static Uint16 FromStr(CCStr s); static Uint16 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Int32 > { static CCStr ToStr(Int32 v); static Int32 FromStr(CCStr s); static Int32 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Uint32 > { static CCStr ToStr(Uint32 v); static Uint32 FromStr(CCStr s); static Uint32 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Int64 > { static CCStr ToStr(Int64 v); static Int64 FromStr(CCStr s); static Int64 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Uint64 > { static CCStr ToStr(Uint64 v); static Uint64 FromStr(CCStr s); static Uint64 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< LongI > { static CCStr ToStr(LongI v); static LongI FromStr(CCStr s); static LongI FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Ulong > { static CCStr ToStr(Ulong v); static Ulong FromStr(CCStr s); static Ulong FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Float32 > { static CCStr ToStr(Float32 v); static Float32 FromStr(CCStr s); static Float32 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< Float64 > { static CCStr ToStr(Float64 v); static Float64 FromStr(CCStr s); static Float64 FromStr(CCStr s, Int32 base); }; template <> struct ConvNum< bool > { static CCStr ToStr(bool v); static bool FromStr(CCStr s); static bool FromStr(CCStr s, Int32 base); }; /* ------------------------------------------------------------------------------------------------ * Utility used to cast between specialized types and perform proper conversion. */ template < typename T > struct ConvTo { // -------------------------------------------------------------------------------------------- static constexpr T Min = std::numeric_limits< T >::min(); static constexpr T Max = std::numeric_limits< T >::max(); // -------------------------------------------------------------------------------------------- template < typename U > static inline T From(U v) { if (v > Max) { return Max; } else if (v < Min) { return Min; } return static_cast< T >(v); } }; /* ------------------------------------------------------------------------------------------------ * Convert a string to 8/16/32 bit signed integers. */ template <> template <> inline Int8 ConvTo< Int8 >::From< CCStr >(CCStr v) { return ConvNum< Int8 >::FromStr(v); } template <> template <> inline Int16 ConvTo< Int16 >::From< CCStr >(CCStr v) { return ConvNum< Int16 >::FromStr(v); } template <> template <> inline Int32 ConvTo< Int32 >::From< CCStr >(CCStr v) { return ConvNum< Int32 >::FromStr(v); } /* ------------------------------------------------------------------------------------------------ * Convert a string to 8/16/32 bit unsigned integers. */ template <> template <> inline Uint8 ConvTo< Uint8 >::From< CCStr >(CCStr v) { return ConvNum< Uint8 >::FromStr(v); } template <> template <> inline Uint16 ConvTo< Uint16 >::From< CCStr >(CCStr v) { return ConvNum< Uint16 >::FromStr(v); } template <> template <> inline Uint32 ConvTo< Uint32 >::From< CCStr >(CCStr v) { return ConvNum< Uint32 >::FromStr(v); } /* ------------------------------------------------------------------------------------------------ * Convert to 8 bit signed integer from any unsigned integer. */ template <> template <> inline Int8 ConvTo< Int8 >::From< Uint8 >(Uint8 v) { return (v >= static_cast< Uint8 >(Max)) ? Max : static_cast< Int8 >(v); } template <> template <> inline Int8 ConvTo< Int8 >::From< Uint16 >(Uint16 v) { return (v >= static_cast< Uint8 >(Max)) ? Max : static_cast< Int8 >(v); } template <> template <> inline Int8 ConvTo< Int8 >::From< Uint32 >(Uint32 v) { return (v >= static_cast< Uint8 >(Max)) ? Max : static_cast< Int8 >(v); } template <> template <> inline Int8 ConvTo< Int8 >::From< Uint64 >(Uint64 v) { return (v >= static_cast< Uint8 >(Max)) ? Max : static_cast< Int8 >(v); } template <> template <> inline Int8 ConvTo< Int8 >::From< Ulong >(Ulong v) { return (v >= static_cast< Uint8 >(Max)) ? Max : static_cast< Int8 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to 16 bit signed integer from any unsigned integer. */ template <> template <> inline Int16 ConvTo< Int16 >::From< Uint8 >(Uint8 v) { return static_cast< Int16 >(v); } template <> template <> inline Int16 ConvTo< Int16 >::From< Uint16 >(Uint16 v) { return (v >= static_cast< Uint16 >(Max)) ? Max : static_cast< Int16 >(v); } template <> template <> inline Int16 ConvTo< Int16 >::From< Uint32 >(Uint32 v) { return (v >= static_cast< Uint16 >(Max)) ? Max : static_cast< Int16 >(v); } template <> template <> inline Int16 ConvTo< Int16 >::From< Uint64 >(Uint64 v) { return (v >= static_cast< Uint16 >(Max)) ? Max : static_cast< Int16 >(v); } template <> template <> inline Int16 ConvTo< Int16 >::From< Ulong >(Ulong v) { return (v >= static_cast< Uint16 >(Max)) ? Max : static_cast< Int16 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to 32 bit signed integer from any unsigned integer. */ template <> template <> inline Int32 ConvTo< Int32 >::From< Uint8 >(Uint8 v) { return static_cast< Int32 >(v); } template <> template <> inline Int32 ConvTo< Int32 >::From< Uint16 >(Uint16 v) { return static_cast< Int32 >(v); } template <> template <> inline Int32 ConvTo< Int32 >::From< Uint32 >(Uint32 v) { return (v >= static_cast< Uint32 >(Max)) ? Max : static_cast< Int32 >(v); } template <> template <> inline Int32 ConvTo< Int32 >::From< Uint64 >(Uint64 v) { return (v >= static_cast< Uint32 >(Max)) ? Max : static_cast< Int32 >(v); } template <> template <> inline Int32 ConvTo< Int32 >::From< Ulong >(Ulong v) { return (v >= static_cast< Uint32 >(Max)) ? Max : static_cast< Int32 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to 8 bit unsigned integer from any signed integer. */ template <> template <> inline Uint8 ConvTo< Uint8 >::From< Int8 >(Int8 v) { return (v <= 0) ? 0 : static_cast< Uint8 >(v); } template <> template <> inline Uint8 ConvTo< Uint8 >::From< Int16 >(Int16 v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int16 >(Max)) { return Max; } return static_cast< Uint8 >(v); } template <> template <> inline Uint8 ConvTo< Uint8 >::From< Int32 >(Int32 v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int16 >(Max)) { return Max; } return static_cast< Uint8 >(v); } template <> template <> inline Uint8 ConvTo< Uint8 >::From< Int64 >(Int64 v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int16 >(Max)) { return Max; } return static_cast< Uint8 >(v); } template <> template <> inline Uint8 ConvTo< Uint8 >::From< LongI >(LongI v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int16 >(Max)) { return Max; } return static_cast< Uint8 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to 16 bit unsigned integer from any signed integer. */ template <> template <> inline Uint16 ConvTo< Uint16 >::From< Int8 >(Int8 v) { return (v <= 0) ? 0 : static_cast< Uint16 >(v); } template <> template <> inline Uint16 ConvTo< Uint16 >::From< Int16 >(Int16 v) { return (v <= 0) ? 0 : static_cast< Uint16 >(v); } template <> template <> inline Uint16 ConvTo< Uint16 >::From< Int32 >(Int32 v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int32 >(Max)) { return Max; } return static_cast< Uint16 >(v); } template <> template <> inline Uint16 ConvTo< Uint16 >::From< Int64 >(Int64 v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int32 >(Max)) { return Max; } return static_cast< Uint16 >(v); } template <> template <> inline Uint16 ConvTo< Uint16 >::From< LongI >(LongI v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int32 >(Max)) { return Max; } return static_cast< Uint16 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to 32 bit unsigned integer from any signed integer. */ template <> template <> inline Uint32 ConvTo< Uint32 >::From< Int8 >(Int8 v) { return (v <= 0) ? 0 : static_cast< Uint32 >(v); } template <> template <> inline Uint32 ConvTo< Uint32 >::From< Int16 >(Int16 v) { return (v <= 0) ? 0 : static_cast< Uint32 >(v); } template <> template <> inline Uint32 ConvTo< Uint32 >::From< Int32 >(Int32 v) { return (v <= 0) ? 0 : static_cast< Uint32 >(v); } template <> template <> inline Uint32 ConvTo< Uint32 >::From< Int64 >(Int64 v) { if (v <= 0) { return 0; } else if (v >= static_cast< Int64 >(Max)) { return Max; } return static_cast< Uint32 >(v); } template <> template <> inline Uint32 ConvTo< Uint32 >::From< LongI >(LongI v) { #if (ULONG_MAX > UINT_MAX) if (v <= 0) { return 0; } else if (v >= static_cast< Int64 >(Max)) { return Max; } return static_cast< Uint32 >(v); #else return (v <= 0) ? 0 : static_cast< Uint32 >(v); #endif } /* ------------------------------------------------------------------------------------------------ * Convert to signed integer from 32 bit floating point number. */ template <> template <> inline Int8 ConvTo< Int8 >::From< Float32 >(Float32 v) { if (EpsLt(v, static_cast< Float32 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float32 >(Max))) { return Max; } return static_cast< Int8 >(v); } template <> template <> inline Int16 ConvTo< Int16 >::From< Float32 >(Float32 v) { if (EpsLt(v, static_cast< Float32 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float32 >(Max))) { return Max; } return static_cast< Int16 >(v); } template <> template <> inline Int32 ConvTo< Int32 >::From< Float32 >(Float32 v) { if (EpsLt(v, static_cast< Float32 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float32 >(Max))) { return Max; } return static_cast< Int32 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to signed integer from 64 bit floating point number. */ template <> template <> inline Int8 ConvTo< Int8 >::From< Float64 >(Float64 v) { if (EpsLt(v, static_cast< Float64 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float64 >(Max))) { return Max; } return static_cast< Int8 >(v); } template <> template <> inline Int16 ConvTo< Int16 >::From< Float64 >(Float64 v) { if (EpsLt(v, static_cast< Float64 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float64 >(Max))) { return Max; } return static_cast< Int16 >(v); } template <> template <> inline Int32 ConvTo< Int32 >::From< Float64 >(Float64 v) { if (EpsLt(v, static_cast< Float64 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float64 >(Max))) { return Max; } return static_cast< Int32 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to unsigned integer from 32 bit floating point number. */ template <> template <> inline Uint8 ConvTo< Uint8 >::From< Float32 >(Float32 v) { if (EpsLt(v, static_cast< Float32 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float32 >(Max))) { return Max; } return static_cast< Uint8 >(v); } template <> template <> inline Uint16 ConvTo< Uint16 >::From< Float32 >(Float32 v) { if (EpsLt(v, static_cast< Float32 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float32 >(Max))) { return Max; } return static_cast< Uint16 >(v); } template <> template <> inline Uint32 ConvTo< Uint32 >::From< Float32 >(Float32 v) { if (EpsLt(v, static_cast< Float32 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float32 >(Max))) { return Max; } return static_cast< Uint32 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert to unsigned integer from 64 bit floating point number. */ template <> template <> inline Uint8 ConvTo< Uint8 >::From< Float64 >(Float64 v) { if (EpsLt(v, static_cast< Float64 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float64 >(Max))) { return Max; } return static_cast< Uint8 >(v); } template <> template <> inline Uint16 ConvTo< Uint16 >::From< Float64 >(Float64 v) { if (EpsLt(v, static_cast< Float64 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float64 >(Max))) { return Max; } return static_cast< Uint16 >(v); } template <> template <> inline Uint32 ConvTo< Uint32 >::From< Float64 >(Float64 v) { if (EpsLt(v, static_cast< Float64 >(Min))) { return Min; } else if (EpsGt(v, static_cast< Float64 >(Max))) { return Max; } return static_cast< Uint32 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to 64 bit signed integer. */ template <> struct ConvTo< Int64 > { // -------------------------------------------------------------------------------------------- static constexpr Int64 Min = std::numeric_limits< Int64 >::min(); static constexpr Int64 Max = std::numeric_limits< Int64 >::max(); // -------------------------------------------------------------------------------------------- template < typename T > static inline Int64 From(T v) { return static_cast< Int64 >(v); } }; // ------------------------------------------------------------------------------------------------ template <> inline Int64 ConvTo< Int64 >::From< CCStr >(CCStr v) { return ConvNum< Int64 >::FromStr(v); } // ------------------------------------------------------------------------------------------------ template <> inline Int64 ConvTo< Int64 >::From< Uint64 >(Uint64 v) { return (v >= static_cast< Uint64 >(Max)) ? Max : static_cast< Int64 >(v); } #if (ULONG_MAX > UINT_MAX) // ------------------------------------------------------------------------------------------------ template <> inline Int64 ConvTo< Int64 >::From< Ulong >(Ulong v) { return (v >= static_cast< Ulong >(Max)) ? Max : static_cast< Int64 >(v); } #endif /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to 64 bit unsigned integer. */ template <> struct ConvTo< Uint64 > { // -------------------------------------------------------------------------------------------- static constexpr Uint64 Min = std::numeric_limits< Uint64 >::min(); static constexpr Uint64 Max = std::numeric_limits< Uint64 >::max(); // -------------------------------------------------------------------------------------------- template < typename T > static inline Uint64 From(T v) { return (v <= static_cast< T >(0)) ? 0 : static_cast< Uint64 >(v); } }; // ------------------------------------------------------------------------------------------------ template <> inline Uint64 ConvTo< Uint64 >::From< CCStr >(CCStr v) { return ConvNum< Uint64 >::FromStr(v); } // ------------------------------------------------------------------------------------------------ template <> inline Uint64 ConvTo< Uint64 >::From< Float32 >(Float32 v) { return From(ConvTo< Int64 >::From(v)); } // ------------------------------------------------------------------------------------------------ template <> inline Uint64 ConvTo< Uint64 >::From< Float64 >(Float64 v) { return From(ConvTo< Int64 >::From(v)); } /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to signed long integer. */ template <> struct ConvTo< LongI > { // -------------------------------------------------------------------------------------------- static constexpr LongI Min = std::numeric_limits< LongI >::min(); static constexpr LongI Max = std::numeric_limits< LongI >::max(); // -------------------------------------------------------------------------------------------- template < typename T > static inline LongI From(T v) { return static_cast< LongI >(v); } }; // ------------------------------------------------------------------------------------------------ template <> inline LongI ConvTo< LongI >::From< CCStr >(CCStr v) { return ConvNum< LongI >::FromStr(v); } // ------------------------------------------------------------------------------------------------ #if (ULONG_MAX <= UINT_MAX) template <> inline LongI ConvTo< LongI >::From< Uint32 >(Uint32 v) { return (v >= static_cast< Uint32 >(Max)) ? Max : static_cast< LongI >(v); } #endif // ------------------------------------------------------------------------------------------------ template <> inline LongI ConvTo< LongI >::From< Uint64 >(Uint64 v) { return (v >= static_cast< Uint64 >(Max)) ? Max : static_cast< LongI >(v); } // ------------------------------------------------------------------------------------------------ template <> inline LongI ConvTo< LongI >::From< Ulong >(Ulong v) { return (v >= static_cast< Ulong >(Max)) ? Max : static_cast< LongI >(v); } /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to unsigned long integer. */ template <> struct ConvTo< Ulong > { // -------------------------------------------------------------------------------------------- static constexpr Ulong Min = std::numeric_limits< Ulong >::min(); static constexpr Ulong Max = std::numeric_limits< Ulong >::max(); // -------------------------------------------------------------------------------------------- template < typename T > static inline Ulong From(T v) { return (v <= static_cast< T >(0)) ? 0 : static_cast< Ulong >(v); } }; // ------------------------------------------------------------------------------------------------ template <> inline Ulong ConvTo< Ulong >::From< CCStr >(CCStr v) { return ConvNum< Ulong >::FromStr(v); } // ------------------------------------------------------------------------------------------------ #if (ULONG_MAX <= UINT_MAX) template <> inline Ulong ConvTo< Ulong >::From< Int64 >(Int64 v) { if (v <= 0) { return Min; } else if (v >= static_cast< Int64 >(Max)) { return Max; } return static_cast< Ulong >(v); } template <> inline Ulong ConvTo< Ulong >::From< Uint64 >(Uint64 v) { return (v >= Max) ? Max : static_cast< Ulong >(v); } #endif // ------------------------------------------------------------------------------------------------ template <> inline Ulong ConvTo< Ulong >::From< Float32 >(Float32 v) { return From(ConvTo< LongI >::From(v)); } // ------------------------------------------------------------------------------------------------ template <> inline Ulong ConvTo< Ulong >::From< Float64 >(Float64 v) { return From(ConvTo< LongI >::From(v)); } /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to 32 bit floating point value. */ template <> struct ConvTo< Float32 > { // -------------------------------------------------------------------------------------------- static constexpr Float32 Min = std::numeric_limits< Float32 >::min(); static constexpr Float32 Max = std::numeric_limits< Float32 >::max(); // -------------------------------------------------------------------------------------------- template < typename T > static inline Float32 From(T v) { return static_cast< Float32 >(v); } }; // ------------------------------------------------------------------------------------------------ template <> inline Float32 ConvTo< Float32 >::From< CCStr >(CCStr v) { return ConvNum< Float32 >::FromStr(v); } // ------------------------------------------------------------------------------------------------ template <> inline Float32 ConvTo< Float32 >::From< Float64 >(Float64 v) { if (EpsGt(v, static_cast< Float64 >(Max))) { return Max; } else if (EpsLt(v, static_cast< Float64 >(Min))) { return Min; } return static_cast< Float32 >(v); } /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to 64 bit floating point value. */ template <> struct ConvTo< Float64 > { // -------------------------------------------------------------------------------------------- static constexpr Float64 Min = std::numeric_limits< Float64 >::min(); static constexpr Float64 Max = std::numeric_limits< Float64 >::max(); // -------------------------------------------------------------------------------------------- template < typename T > static inline Float64 From(T v) { return static_cast< Float64 >(v); } }; // ------------------------------------------------------------------------------------------------ template <> inline Float64 ConvTo< Float64 >::From< CCStr >(CCStr v) { return ConvNum< Float64 >::FromStr(v); } /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to boolean value. */ template <> struct ConvTo< bool > { // -------------------------------------------------------------------------------------------- template < typename T > static inline bool From(T v) { return static_cast< bool >(v); } }; // ------------------------------------------------------------------------------------------------ template <> inline bool ConvTo< bool >::From< CCStr >(CCStr v) { return ConvNum< bool >::FromStr(v); } /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to string value. */ template <> struct ConvTo< CStr > { // -------------------------------------------------------------------------------------------- template < typename T > static inline CStr From(T v) { return const_cast< CStr >(ConvNum< T >::ToStr(v)); } }; /* ------------------------------------------------------------------------------------------------ * Convert other numeric values to string value. */ template <> struct ConvTo< CCStr > { // -------------------------------------------------------------------------------------------- template < typename T > static inline CCStr From(T v) { return ConvNum< T >::ToStr(v); } }; /* ------------------------------------------------------------------------------------------------ * Force a value to be within a certain range. */ template< typename T, typename U, typename V > inline T Clamp(T val, U min, V max) { // Is the specified value bellow the minimum? if (val < min) { return min; } // Is the specified value above the maximum? else if (val > max) { return max; } // Return the value as is return val; } /* ------------------------------------------------------------------------------------------------ * Force a value to be higher then than the imposed limit. */ template< typename T, typename U > inline T ClampMin(T val, U min) { // Is the specified value bellow the minimum? if (val < min) { return min; } // Return the value as is return val; } /* ------------------------------------------------------------------------------------------------ * Force a value to be smaller then than the imposed limit. */ template< typename T, typename U > inline T ClampMax(T val, U max) { // Is the specified value above the maximum? if (val > max) { return max; } // Return the value as is return val; } /* ------------------------------------------------------------------------------------------------ * Force a value to be within a certain range. */ template<> inline Float32 Clamp(Float32 val, Float32 min, Float32 max) { // Is the specified value bellow the minimum? if (EpsLt(val, min)) { return min; } // Is the specified value above the maximum? else if (EpsGt(val, max)) { return max; } // Return the value as is return val; } /* ------------------------------------------------------------------------------------------------ * Force a value to be within a certain range. */ template<> inline Float64 Clamp(Float64 val, Float64 min, Float64 max) { // Is the specified value bellow the minimum? if (EpsLt(val, min)) { return min; } // Is the specified value above the maximum? else if (EpsGt(val, max)) { return max; } // Return the value as is return val; } /* ------------------------------------------------------------------------------------------------ * Force a value to be the boundaries of the specified type. */ template < typename T, typename U > inline U ClampL(T v) { return ConvTo< U >::From(v); } /* ------------------------------------------------------------------------------------------------ * Helper class allows the use of functions with ctype style as predicate for algorithms. */ struct IsCType { // ------------------------------------------------------------------------------------------------ typedef int (*CTypeFn)(int); // The signature of a ctype function. private: // ------------------------------------------------------------------------------------------------ CTypeFn m_Fn; // Pointer to the actual function that does the comparison. public: /* ------------------------------------------------------------------------------------------------ * Base constructor. */ IsCType(CTypeFn fn) : m_Fn(fn) { /* ... */ } /* ------------------------------------------------------------------------------------------------ * Function call operator. */ template < typename T > bool operator () (T c) { return (m_Fn(static_cast< int >(c)) != 0); } }; /* ------------------------------------------------------------------------------------------------ * Helper class allows the use of functions with ctype style as predicate for algorithms. */ struct IsNotCType { // ------------------------------------------------------------------------------------------------ typedef int (*CTypeFn)(int); // The signature of a ctype function. private: // ------------------------------------------------------------------------------------------------ CTypeFn m_Fn; // Pointer to the actual function that does the comparison. public: /* ------------------------------------------------------------------------------------------------ * Base constructor. */ IsNotCType(CTypeFn fn) : m_Fn(fn) { /* ... */ } /* ------------------------------------------------------------------------------------------------ * Function call operator. */ template < typename T > bool operator () (T c) { return (m_Fn(static_cast< int >(c)) == 0); } }; /* ------------------------------------------------------------------------------------------------ * Utility implementing RAII to toggle a bit mask on and off at all costs. */ template < typename T > struct BitGuard { private: /* ------------------------------------------------------------------------------------------------ * The lock to be toggled. */ T & m_Lock; /* ------------------------------------------------------------------------------------------------ * The mask to be applied. */ T m_Mask; public: /* ------------------------------------------------------------------------------------------------ * Base constructor. */ BitGuard(T & lock, T mask) : m_Lock(lock), m_Mask(mask) { // Apply the specified mask m_Lock |= m_Mask; } /* ------------------------------------------------------------------------------------------------ * Destructor. */ ~BitGuard() { // In case one of the bits was turned off in the meantime m_Lock |= m_Mask; // Now turn off all the bits in the mask m_Lock ^= m_Mask; } }; // ------------------------------------------------------------------------------------------------ typedef BitGuard< Uint8 > BitGuardU8; typedef BitGuard< Uint16 > BitGuardU16; typedef BitGuard< Uint32 > BitGuardU32; /* ------------------------------------------------------------------------------------------------ * 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() { sq_pop(m_VM, sq_gettop(m_VM) - m_Top); } /* -------------------------------------------------------------------------------------------- * Copy assignment operator. (disabled) */ StackGuard & operator = (const StackGuard &) = delete; /* -------------------------------------------------------------------------------------------- * Move assignment operator. (disabled) */ StackGuard & operator = (StackGuard &&) = delete; private: // -------------------------------------------------------------------------------------------- HSQUIRRELVM m_VM; // The VM where the stack should be restored. Int32 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 { // -------------------------------------------------------------------------------------------- CSStr 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. /* -------------------------------------------------------------------------------------------- * Base constructor. */ StackStrF(HSQUIRRELVM vm, SQInteger idx, bool fmt = true); /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ StackStrF(const StackStrF & o) = delete; /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ StackStrF(StackStrF && o) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~StackStrF(); /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ StackStrF & operator = (const StackStrF & o) = delete; /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ StackStrF & operator = (StackStrF && o) = delete; }; /* ------------------------------------------------------------------------------------------------ * Retrieve the string representation of a certain type. */ CSStr SqTypeName(SQObjectType type); /* ------------------------------------------------------------------------------------------------ * Retrieve the string representation of a certain type from a value on the stack. */ String SqTypeName(HSQUIRRELVM vm, SQInteger idx); /* ------------------------------------------------------------------------------------------------ * Create a script object from the specified value on the default VM. */ template < typename T > Object MakeObject(const T & v) { // Remember the current stack size const StackGuard sg; // Transform the specified value into a script object PushVar< T >(DefaultVM::Get(), v); // Get the object from the stack and return it return Var< Object >(DefaultVM::Get(), -1).value; } /* ------------------------------------------------------------------------------------------------ * Create a script object from the specified value on the specified VM. */ template < typename T > Object MakeObject(HSQUIRRELVM vm, const T & v) { // Remember the current stack size const StackGuard sg; // Transform the specified value into a script object PushVar< T >(vm, v); // Get the object from the stack and return it return Var< Object >(vm, -1).value; } /* ------------------------------------------------------------------------------------------------ * Create a script string instance from a buffer. */ Object BufferToStrObj(const Buffer & b); /* ------------------------------------------------------------------------------------------------ * Create a script string instance from a portion of a buffer. */ Object BufferToStrObj(const Buffer & b, Uint32 size); /* ------------------------------------------------------------------------------------------------ * Create a signed long integer instance from an integer. */ Object MakeSLongObj(Int64 value); /* ------------------------------------------------------------------------------------------------ * Create a unsigned long integer instance from an integer. */ Object MakeULongObj(Uint64 value); /* ------------------------------------------------------------------------------------------------ * Create a signed long integer instance from an integer. */ Object MakeSLongObj(HSQUIRRELVM vm, Int64 value); /* ------------------------------------------------------------------------------------------------ * Create a unsigned long integer instance from an integer. */ Object MakeULongObj(HSQUIRRELVM vm, Uint64 value); /* ------------------------------------------------------------------------------------------------ * Retrieve a signed 64 bit integer from an signed long integer instance. */ Int64 FetchSLongObjVal(const Object & value); /* ------------------------------------------------------------------------------------------------ * Retrieve a unsigned 64 bit integer from an unsigned long integer instance. */ Uint64 FetchULongObjVal(const Object & value); /* ------------------------------------------------------------------------------------------------ * Retrieve the date components from a date instance. */ SQRESULT FetchDateObjVal(const Object & value, Uint16 & year, Uint8 & month, Uint8 & day); /* ------------------------------------------------------------------------------------------------ * Retrieve the date components from a date instance as a string. */ CSStr FetchDateObjStr(const Object & value); /* ------------------------------------------------------------------------------------------------ * Retrieve the time components from a date instance. */ SQRESULT FetchTimeObjVal(const Object & value, Uint8 & hour, Uint8 & minute, Uint8 & second); /* ------------------------------------------------------------------------------------------------ * Retrieve the time components from a date instance. */ SQRESULT FetchTimeObjVal(const Object & value, Uint8 & hour, Uint8 & minute, Uint8 & second, Uint16 & millisecond); /* ------------------------------------------------------------------------------------------------ * Retrieve the time components from a date instance as a string. */ CSStr FetchTimeObjStr(const Object & value); /* ------------------------------------------------------------------------------------------------ * Retrieve the time components from a date instance as the number of seconds. */ Int32 FetchTimeObjSeconds(const Object & value); /* ------------------------------------------------------------------------------------------------ * Retrieve the date-time components from a date-time instance. */ SQRESULT FetchDatetimeObjVal(const Object & value, Uint16 & year, Uint8 & month, Uint8 & day, Uint8 & hour, Uint8 & minute, Uint8 & second); /* ------------------------------------------------------------------------------------------------ * Retrieve the date-time components from a date-time instance. */ SQRESULT FetchDatetimeObjVal(const Object & value, Uint16 & year, Uint8 & month, Uint8 & day, Uint8 & hour, Uint8 & minute, Uint8 & second, Uint16 & millisecond); /* ------------------------------------------------------------------------------------------------ * Retrieve the date-time components from a date-time instance as a string. */ CSStr FetchDatetimeObjStr(const Object & value); /* ------------------------------------------------------------------------------------------------ * Attempt to pop the value at the specified index on the stack as a native integer. */ SQInteger PopStackInteger(HSQUIRRELVM vm, SQInteger idx); /* ------------------------------------------------------------------------------------------------ * Attempt to pop the value at the specified index on the stack as a native float. */ SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx); /* ------------------------------------------------------------------------------------------------ * Attempt to pop the value at the specified index on the stack as a signed long integer. */ Int64 PopStackSLong(HSQUIRRELVM vm, SQInteger idx); /* ------------------------------------------------------------------------------------------------ * Attempt to pop the value at the specified index on the stack as an unsigned long integer. */ Uint64 PopStackULong(HSQUIRRELVM vm, SQInteger idx); // ------------------------------------------------------------------------------------------------ #ifdef SQMOD_PLUGIN_API /* ------------------------------------------------------------------------------------------------ * Validate the module API to make sure we don't run into issues. */ bool CheckModuleAPIVer(CCStr ver, CCStr mod); /* ------------------------------------------------------------------------------------------------ * Make sure that the module was loaded after the host plug-in. */ bool CheckModuleOrder(PluginFuncs * vcapi, Uint32 mod_id, CCStr mod); /* ------------------------------------------------------------------------------------------------ * Used by the modules to import the API from the host plug-in. */ void ImportModuleAPI(PluginFuncs * vcapi, CCStr mod); #endif // SQMOD_PLUGIN_API /* ------------------------------------------------------------------------------------------------ * Default class for checking if the argument on the stack matches the requested type. */ template < typename U > struct SqCmpArg { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INSTANCE); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { Var< U * > var(vm, 2); // Is this instance valid? if (!var.value) { STHROWF("No such instance"); } // Attempt to perform the comparison return val.Cmp(*var.value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < typename U > struct SqCmpArg< U * > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INSTANCE); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { Var< U * > var(vm, 2); // Is this instance valid? if (!var.value) { STHROWF("No such instance"); } // Attempt to perform the comparison return val.Cmp(var.value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < typename U > struct SqCmpArg< const U * > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INSTANCE); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { Var< const U * > var(vm, 2); // Is this instance valid? if (!var.value) { STHROWF("No such instance"); } // Attempt to perform the comparison return val.Cmp(*var.value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< std::nullptr_t > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_NULL); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM /*vm*/) { return val.Cmp(nullptr); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< char > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< char >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< signed char > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< signed char >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< unsigned char > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< unsigned char >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< signed short > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< signed short >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< unsigned short > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< unsigned short >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< signed int > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< signed int >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< unsigned int > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< unsigned int >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< signed long > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< signed long >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< unsigned long > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< unsigned long >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< signed long long > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< signed long long >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< unsigned long long > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_INTEGER); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< unsigned long long >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< float > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_FLOAT); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< float >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< double > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_FLOAT); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< double >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< bool > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_BOOL); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< bool >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< SQChar * > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_STRING); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< SQChar * >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< const SQChar * > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_STRING); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< const SQChar * >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< String > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_STRING); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< String >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< Table > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_TABLE); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< Table >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< Array > { static inline bool CanPop(HSQUIRRELVM vm) { return (sq_gettype(vm, 2) == OT_ARRAY); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< Array >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< Function > { static inline bool CanPop(HSQUIRRELVM vm) { const SQObjectType type = sq_gettype(vm, 2); return (type == OT_CLOSURE || type == OT_NATIVECLOSURE); } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< Function >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Specialization of the argument checking structure. */ template < > struct SqCmpArg< Object > { static inline bool CanPop(HSQUIRRELVM /*vm*/) { return true; // Objects can use any type. } template < typename T > static inline Int32 Compare(const T & val, HSQUIRRELVM vm) { return val.Cmp(Var< Object >(vm, 2).value); } }; /* ------------------------------------------------------------------------------------------------ * Common function used to compare one type of instance with a couple of other types. */ template < typename... Ts > struct SqCmpImpl; /* ------------------------------------------------------------------------------------------------ * Zeroth case of the comparison. No known comparison at this point. */ template < > struct SqCmpImpl< > { template < typename T > static Int32 Fn(const T & /*val*/, HSQUIRRELVM vm) { const String tn1(SqTypeName(vm, 1)); const String tn2(SqTypeName(vm, 2)); return sq_throwerror(vm, ToStrF("Unknown comparison between (%s) and (%s)", tn1.c_str(), tn2.c_str())); } }; /* ------------------------------------------------------------------------------------------------ * Argument pack type pealing. Attempt comparison with a specified type. */ template < typename U, typename... Ts > struct SqCmpImpl< U, Ts... > { template < typename T > static Int32 Fn(const T & val, HSQUIRRELVM vm) { typedef typename std::decay< U >::type ArgType; // Can the stack value be used with the current type? if (SqCmpArg< ArgType >::CanPop(vm)) { // If not an instance then don't use a try catch block if (sq_gettype(vm, 2) != OT_INSTANCE) { return SqCmpArg< ArgType >::Compare(val, vm); } // Instances require a try/catch block since we can't differentiate types try { return SqCmpArg< ArgType >::Compare(val, vm); } catch (const Sqrat::Exception & e) { // Probably the wrong type } catch (...) { // Something bad happened. At this point, we just don't want to let // exceptions propagate to the virtual machine and we must end here. // Either way, reaching this point is bad and we just shuved it under // the rug. This is bad practice but circumstances forced me. // Don't do this at home kids! return -1; } } // On to the next type return SqCmpImpl< Ts... >::Fn(val, vm); } }; /* ------------------------------------------------------------------------------------------------ * Squirrel function that forwards the call to the actual implementation. */ template < typename T, typename U, typename... Ts > SQInteger SqCmpFwd(HSQUIRRELVM vm) { // Make sure that there are enough parameters on the stack if (sq_gettop(vm) < 2) { return sq_throwerror(vm, "Insufficient parameters to perform comparison"); } // Attempt to grab a pointer to the base instance Var< T * > var(vm, 1); // Is this instance valid? if (!var.value) { return sq_throwerror(vm, "No such instance to compare"); } // Attempt to perform the comparison try { sq_pushinteger(vm, SqCmpImpl< U, Ts... >::Fn(*var.value, vm)); } catch (const Sqrat::Exception & e) { return sq_throwerror(vm, e.what()); } catch (...) { return sq_throwerror(vm, "Unknown error occurred during comparison"); } // At this point we should have an integer on the stack return 1; } } // Namespace:: SqMod #endif // _BASE_UTILITY_HPP_