diff --git a/cbp/Module.cbp b/cbp/Module.cbp index cb4a9a2b..a2028a33 100644 --- a/cbp/Module.cbp +++ b/cbp/Module.cbp @@ -431,6 +431,8 @@ + + diff --git a/source/Base/Shared.cpp b/source/Base/Shared.cpp index b140b0bb..e71dd490 100644 --- a/source/Base/Shared.cpp +++ b/source/Base/Shared.cpp @@ -5,16 +5,7 @@ #include "Library/String.hpp" // ------------------------------------------------------------------------------------------------ -#include "Base/AABB.hpp" -#include "Base/Circle.hpp" #include "Base/Color3.hpp" -#include "Base/Color4.hpp" -#include "Base/Quaternion.hpp" -#include "Base/Sphere.hpp" -#include "Base/Vector2.hpp" -#include "Base/Vector2i.hpp" -#include "Base/Vector3.hpp" -#include "Base/Vector4.hpp" // ------------------------------------------------------------------------------------------------ #include @@ -23,9 +14,6 @@ #include #include -// ------------------------------------------------------------------------------------------------ -#include - // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -67,123 +55,6 @@ Function & NullFunction() return f; } -// ------------------------------------------------------------------------------------------------ -Object BufferToStrObj(const Buffer & b) -{ - // Obtain the initial stack size - const StackGuard sg(DefaultVM::Get()); - // Push the string onto the stack - sq_pushstring(DefaultVM::Get(), b.Data(), b.Position()); - // Obtain the object from the stack and return it - return Var< Object >(DefaultVM::Get(), -1).value; -} - -// -------------------------------------------------------------------------------------------- -Object BufferToStrObj(const Buffer & b, Uint32 size) -{ - // Perform a range check on the specified buffer - if (size > b.Capacity()) - { - STHROWF("The specified buffer size is out of range: %u >= %u", size, b.Capacity()); - } - // Obtain the initial stack size - const StackGuard sg(DefaultVM::Get()); - // Push the string onto the stack - sq_pushstring(DefaultVM::Get(), b.Data(), size); - // Obtain the object from the stack and return it - return Var< Object >(DefaultVM::Get(), -1).value; -} - -// -------------------------------------------------------------------------------------------- -StackStrF::StackStrF(HSQUIRRELVM vm, SQInteger idx, bool fmt) - : mPtr(nullptr) - , mLen(-1) - , mRes(SQ_OK) - , mObj() - , mVM(vm) -{ - const Int32 top = sq_gettop(vm); - // Reset the converted value object - sq_resetobject(&mObj); - // Was the string or value specified? - if (top <= (idx - 1)) - { - mRes = sq_throwerror(vm, "Missing string or value"); - } - // Do we have enough values to call the format function and are we allowed to? - else if (top > idx && fmt) - { - // Pointer to the generated string - SStr str = nullptr; - // Attempt to generate the specified string format - mRes = sqstd_format(vm, idx, &mLen, &str); - // Did the format succeeded but ended up with a null string pointer? - if (SQ_SUCCEEDED(mRes) && !str) - { - mRes = sq_throwerror(vm, "Unable to generate the string"); - } - else - { - mPtr = const_cast< CSStr >(str); - } - } - // Is the value on the stack an actual string? - else if (sq_gettype(vm, idx) == OT_STRING) - { - // Obtain a reference to the string object - mRes = sq_getstackobj(vm, idx, &mObj); - // Could we retrieve the object from the stack? - if (SQ_SUCCEEDED(mRes)) - { - // Keep a strong reference to the object - sq_addref(vm, &mObj); - // Attempt to retrieve the string value from the stack - mRes = sq_getstring(vm, idx, &mPtr); - } - // Did the retrieval succeeded but ended up with a null string pointer? - if (SQ_SUCCEEDED(mRes) && !mPtr) - { - mRes = sq_throwerror(vm, "Unable to retrieve the string"); - } - } - // We have to try and convert it to string - else - { - // Attempt to convert the value from the stack to a string - mRes = sq_tostring(vm, idx); - // Could we convert the specified value to string? - if (SQ_SUCCEEDED(mRes)) - { - // Obtain a reference to the resulted object - mRes = sq_getstackobj(vm, -1, &mObj); - // Could we retrieve the object from the stack? - if (SQ_SUCCEEDED(mRes)) - { - // Keep a strong reference to the object - sq_addref(vm, &mObj); - // Attempt to obtain the string pointer - mRes = sq_getstring(vm, -1, &mPtr); - } - } - // Pop a value from the stack regardless of the result - sq_pop(vm, 1); - // Did the retrieval succeeded but ended up with a null string pointer? - if (SQ_SUCCEEDED(mRes) && !mPtr) - { - mRes = sq_throwerror(vm, "Unable to retrieve the value"); - } - } -} - -// ------------------------------------------------------------------------------------------------ -StackStrF::~StackStrF() -{ - if (mVM && !sq_isnull(mObj)) - { - sq_release(mVM, &mObj); - } -} - // ------------------------------------------------------------------------------------------------ bool SToB(CSStr str) { diff --git a/source/Base/Shared.hpp b/source/Base/Shared.hpp index 151467a7..ed28fce3 100644 --- a/source/Base/Shared.hpp +++ b/source/Base/Shared.hpp @@ -25,107 +25,6 @@ extern PluginFuncs* _Func; extern PluginCallbacks* _Clbk; extern PluginInfo* _Info; -/* ------------------------------------------------------------------------------------------------ - * 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; -}; - /* ------------------------------------------------------------------------------------------------ * Perform an equality comparison between two values taking into account floating point issues. */ @@ -218,31 +117,549 @@ template <> inline bool EpsGtEq(const Float64 a, const Float64 b) return !EpsEq(a, b) || (a - b) > 0.000000001d; } +/* ------------------------------------------------------------------------------------------------ + * +*/ +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); + } +}; + +// ------------------------------------------------------------------------------------------------ +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< Uint16 >(Max)) ? Max : static_cast< Int8 >(v); +} + +// ------------------------------------------------------------------------------------------------ +template <> template <> inline Int8 ConvTo< Int8 >::From< Uint32 >(Uint32 v) +{ + return (v >= static_cast< Uint32 >(Max)) ? Max : static_cast< Int8 >(v); +} + +// ------------------------------------------------------------------------------------------------ +template <> template <> inline Int8 ConvTo< Int8 >::From< Uint64 >(Uint64 v) +{ + return (v >= static_cast< Uint64 >(Max)) ? Max : static_cast< Int8 >(v); +} + +// ------------------------------------------------------------------------------------------------ +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< Uint32 >(Max)) ? Max : static_cast< Int16 >(v); +} + +// ------------------------------------------------------------------------------------------------ +template <> template <> inline Int16 ConvTo< Int16 >::From< Uint64 >(Uint64 v) +{ + return (v >= static_cast< Uint64 >(Max)) ? Max : static_cast< Int16 >(v); +} + +// ------------------------------------------------------------------------------------------------ +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< Uint64 >(Max)) ? Max : static_cast< Int32 >(v); +} + +// ------------------------------------------------------------------------------------------------ +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< Int32 >(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< Int64 >(Max)) + { + return Max; + } + return static_cast< Uint8 >(v); +} + +// ------------------------------------------------------------------------------------------------ +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< Int64 >(Max)) + { + return Max; + } + return static_cast< Uint16 >(v); +} + +// ------------------------------------------------------------------------------------------------ +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 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); +} + +// ------------------------------------------------------------------------------------------------ +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); +} + +// ------------------------------------------------------------------------------------------------ +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); +} + +// ------------------------------------------------------------------------------------------------ +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 signed long long 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< Uint64 >(Uint64 v) +{ + return (v >= static_cast< Uint64 >(Max)) ? Max : static_cast< Int64 >(v); +} + +/* ------------------------------------------------------------------------------------------------ + * Convert other numeric values to unsigned long long 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< 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 a 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< 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 a double 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); + } +}; + /* ------------------------------------------------------------------------------------------------ * Force a value to be within a certain range. */ template< typename T > inline T Clamp(T val, T min, T max) { - return val < min ? min : (val > max ? max : val); + // 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 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 val) +template < typename T, typename U > inline U ClampL(T v) { - // Is the specified value bellow the minimum? - if (val < std::numeric_limits< U >::min()) - { - return std::numeric_limits< U >::min(); - } - // Is the specified value above the maximum? - else if (val > std::numeric_limits< U >::max()) - { - return std::numeric_limits< U >::max(); - } - // Return the value as is - return static_cast< U >(val); + return ConvTo< U >::From(v); } /* ------------------------------------------------------------------------------------------------ @@ -289,42 +706,6 @@ Array & NullArray(); */ Function & NullFunction(); -/* ------------------------------------------------------------------------------------------------ - * Create a script string object from a buffer. -*/ -Object BufferToStrObj(const Buffer & b); - -/* ------------------------------------------------------------------------------------------------ - * Create a script string object from a portion of a buffer. -*/ -Object BufferToStrObj(const Buffer & b, Uint32 size); - -/* ------------------------------------------------------------------------------------------------ - * 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; -} - /* ------------------------------------------------------------------------------------------------ * Simple function to check whether the specified string can be considered as a boolean value */ diff --git a/source/Base/Stack.cpp b/source/Base/Stack.cpp new file mode 100644 index 00000000..fd4c70f3 --- /dev/null +++ b/source/Base/Stack.cpp @@ -0,0 +1,413 @@ +// ------------------------------------------------------------------------------------------------ +#include "Base/Stack.hpp" +#include "Base/Shared.hpp" +#include "Base/Buffer.hpp" +#include "Library/Numeric.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQInteger PopStackInteger(HSQUIRRELVM vm, SQInteger idx) +{ + // Identify which type must be extracted + switch (sq_gettype(vm, idx)) + { + case OT_INTEGER: + { + SQInteger val; + sq_getinteger(vm, idx, &val); + return val; + } break; + case OT_FLOAT: + { + SQFloat val; + sq_getfloat(vm, idx, &val); + return ConvTo< SQInteger >::From(val); + } break; + case OT_BOOL: + { + SQBool val; + sq_getbool(vm, idx, &val); + return static_cast< SQInteger >(val); + } break; + case OT_STRING: + { + CSStr val = nullptr; + // Attempt to retrieve and convert the string + if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0') + { + return ConvTo< SQInteger >::From(std::strtoll(val, nullptr, 10)); + } + } break; + case OT_ARRAY: + case OT_TABLE: + case OT_CLASS: + case OT_USERDATA: + { + return sq_getsize(vm, idx); + } break; + case OT_INSTANCE: + { + // Attempt to treat the value as a signed long instance + try + { + return ConvTo< SQInteger >::From(Var< const SLongInt & >(vm, idx).value.GetNum()); + } + catch (...) + { + // Just ignore it... + } + // Attempt to treat the value as a unsigned long instance + try + { + return ConvTo< SQInteger >::From(Var< const ULongInt & >(vm, idx).value.GetNum()); + } + catch (...) + { + // Just ignore it... + } + // Attempt to get the size of the instance as a fallback + return sq_getsize(vm, idx); + } break; + default: break; + } + // Default to 0 + return 0; +} + +// ------------------------------------------------------------------------------------------------ +SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx) +{ + // Identify which type must be extracted + switch (sq_gettype(vm, idx)) + { + case OT_FLOAT: + { + SQFloat val; + sq_getfloat(vm, idx, &val); + return val; + } break; + case OT_INTEGER: + { + SQInteger val; + sq_getinteger(vm, idx, &val); + return ConvTo< SQFloat >::From(val); + } break; + case OT_BOOL: + { + SQBool val; + sq_getbool(vm, idx, &val); + return ConvTo< SQFloat >::From(val); + } break; + case OT_STRING: + { + CSStr val = nullptr; + // Attempt to retrieve and convert the string + if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0') + { +#ifdef SQUSEDOUBLE + return std::strtod(val, nullptr); +#else + return std::strtof(val, nullptr); +#endif // SQUSEDOUBLE + } + } break; + case OT_ARRAY: + case OT_TABLE: + case OT_CLASS: + case OT_USERDATA: + { + return ConvTo< SQFloat >::From(sq_getsize(vm, idx)); + } break; + case OT_INSTANCE: + { + // Attempt to treat the value as a signed long instance + try + { + return ConvTo< SQFloat >::From(Var< const SLongInt & >(vm, idx).value.GetNum()); + } + catch (...) + { + // Just ignore it... + } + // Attempt to treat the value as a unsigned long instance + try + { + return ConvTo< SQFloat >::From(Var< const ULongInt & >(vm, idx).value.GetNum()); + } + catch (...) + { + // Just ignore it... + } + // Attempt to get the size of the instance as a fallback + return ConvTo< SQFloat >::From(sq_getsize(vm, idx)); + } break; + default: break; + } + // Default to 0 + return 0.0; +} + +// ------------------------------------------------------------------------------------------------ +Int64 PopStackLong(HSQUIRRELVM vm, SQInteger idx) +{ + // Identify which type must be extracted + switch (sq_gettype(vm, idx)) + { + case OT_INTEGER: + { + SQInteger val; + sq_getinteger(vm, idx, &val); + return static_cast< Int64 >(val); + } break; + case OT_FLOAT: + { + SQFloat val; + sq_getfloat(vm, idx, &val); + return ConvTo< Int64 >::From(val); + } break; + case OT_BOOL: + { + SQBool val; + sq_getbool(vm, idx, &val); + return static_cast< Int64 >(val); + } break; + case OT_STRING: + { + CSStr val = nullptr; + // Attempt to retrieve and convert the string + if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0') + { + return std::strtoll(val, nullptr, 10); + } + } break; + case OT_ARRAY: + case OT_TABLE: + case OT_CLASS: + case OT_USERDATA: + { + return static_cast< Int64 >(sq_getsize(vm, idx)); + } break; + case OT_INSTANCE: + { + // Attempt to treat the value as a signed long instance + try + { + return Var< const SLongInt & >(vm, idx).value.GetNum(); + } + catch (...) + { + // Just ignore it... + } + // Attempt to treat the value as a unsigned long instance + try + { + return ConvTo< Int64 >::From(Var< const ULongInt & >(vm, idx).value.GetNum()); + } + catch (...) + { + // Just ignore it... + } + // Attempt to get the size of the instance as a fallback + return static_cast< Int64 >(sq_getsize(vm, idx)); + } break; + default: break; + } + // Default to 0 + return 0; +} + +// ------------------------------------------------------------------------------------------------ +Uint64 PopStackULong(HSQUIRRELVM vm, SQInteger idx) +{ + // Identify which type must be extracted + switch (sq_gettype(vm, idx)) + { + case OT_INTEGER: + { + SQInteger val; + sq_getinteger(vm, idx, &val); + return ConvTo< Uint64 >::From(val); + } break; + case OT_FLOAT: + { + SQFloat val; + sq_getfloat(vm, idx, &val); + return ConvTo< Uint64 >::From(val); + } break; + case OT_BOOL: + { + SQBool val; + sq_getbool(vm, idx, &val); + return ConvTo< Uint64 >::From(val); + } break; + case OT_STRING: + { + CSStr val = nullptr; + // Attempt to retrieve and convert the string + if (SQ_SUCCEEDED(sq_getstring(vm, idx, &val)) && val != nullptr && *val != '\0') + { + return std::strtoull(val, nullptr, 10); + } + } break; + case OT_ARRAY: + case OT_TABLE: + case OT_CLASS: + case OT_USERDATA: + { + return ConvTo< Uint64 >::From(sq_getsize(vm, idx)); + } break; + case OT_INSTANCE: + { + // Attempt to treat the value as a signed long instance + try + { + return ConvTo< Uint64 >::From(Var< const SLongInt & >(vm, idx).value.GetNum()); + } + catch (...) + { + // Just ignore it... + } + // Attempt to treat the value as a unsigned long instance + try + { + return Var< const ULongInt & >(vm, idx).value.GetNum(); + } + catch (...) + { + // Just ignore it... + } + // Attempt to get the size of the instance as a fallback + return ConvTo< Uint64 >::From(sq_getsize(vm, idx)); + } break; + default: break; + } + // Default to 0 + return 0; +} + +// -------------------------------------------------------------------------------------------- +StackStrF::StackStrF(HSQUIRRELVM vm, SQInteger idx, bool fmt) + : mPtr(nullptr) + , mLen(-1) + , mRes(SQ_OK) + , mObj() + , mVM(vm) +{ + const Int32 top = sq_gettop(vm); + // Reset the converted value object + sq_resetobject(&mObj); + // Was the string or value specified? + if (top <= (idx - 1)) + { + mRes = sq_throwerror(vm, "Missing string or value"); + } + // Do we have enough values to call the format function and are we allowed to? + else if (top > idx && fmt) + { + // Pointer to the generated string + SStr str = nullptr; + // Attempt to generate the specified string format + mRes = sqstd_format(vm, idx, &mLen, &str); + // Did the format succeeded but ended up with a null string pointer? + if (SQ_SUCCEEDED(mRes) && !str) + { + mRes = sq_throwerror(vm, "Unable to generate the string"); + } + else + { + mPtr = const_cast< CSStr >(str); + } + } + // Is the value on the stack an actual string? + else if (sq_gettype(vm, idx) == OT_STRING) + { + // Obtain a reference to the string object + mRes = sq_getstackobj(vm, idx, &mObj); + // Could we retrieve the object from the stack? + if (SQ_SUCCEEDED(mRes)) + { + // Keep a strong reference to the object + sq_addref(vm, &mObj); + // Attempt to retrieve the string value from the stack + mRes = sq_getstring(vm, idx, &mPtr); + } + // Did the retrieval succeeded but ended up with a null string pointer? + if (SQ_SUCCEEDED(mRes) && !mPtr) + { + mRes = sq_throwerror(vm, "Unable to retrieve the string"); + } + } + // We have to try and convert it to string + else + { + // Attempt to convert the value from the stack to a string + mRes = sq_tostring(vm, idx); + // Could we convert the specified value to string? + if (SQ_SUCCEEDED(mRes)) + { + // Obtain a reference to the resulted object + mRes = sq_getstackobj(vm, -1, &mObj); + // Could we retrieve the object from the stack? + if (SQ_SUCCEEDED(mRes)) + { + // Keep a strong reference to the object + sq_addref(vm, &mObj); + // Attempt to obtain the string pointer + mRes = sq_getstring(vm, -1, &mPtr); + } + } + // Pop a value from the stack regardless of the result + sq_pop(vm, 1); + // Did the retrieval succeeded but ended up with a null string pointer? + if (SQ_SUCCEEDED(mRes) && !mPtr) + { + mRes = sq_throwerror(vm, "Unable to retrieve the value"); + } + } +} + +// ------------------------------------------------------------------------------------------------ +StackStrF::~StackStrF() +{ + if (mVM && !sq_isnull(mObj)) + { + sq_release(mVM, &mObj); + } +} + +// ------------------------------------------------------------------------------------------------ +Object BufferToStrObj(const Buffer & b) +{ + // Obtain the initial stack size + const StackGuard sg(DefaultVM::Get()); + // Push the string onto the stack + sq_pushstring(DefaultVM::Get(), b.Data(), b.Position()); + // Obtain the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// -------------------------------------------------------------------------------------------- +Object BufferToStrObj(const Buffer & b, Uint32 size) +{ + // Perform a range check on the specified buffer + if (size > b.Capacity()) + { + STHROWF("The specified buffer size is out of range: %u >= %u", size, b.Capacity()); + } + // Obtain the initial stack size + const StackGuard sg(DefaultVM::Get()); + // Push the string onto the stack + sq_pushstring(DefaultVM::Get(), b.Data(), size); + // Obtain the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ + + +} // Namespace:: SqMod diff --git a/source/Base/Stack.hpp b/source/Base/Stack.hpp new file mode 100644 index 00000000..5324fa4f --- /dev/null +++ b/source/Base/Stack.hpp @@ -0,0 +1,172 @@ +#ifndef _BASE_STACK_HPP_ +#define _BASE_STACK_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "SqBase.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * 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 PopStackLong(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); + +/* ------------------------------------------------------------------------------------------------ + * Create a script string object from a buffer. +*/ +Object BufferToStrObj(const Buffer & b); + +/* ------------------------------------------------------------------------------------------------ + * Create a script string object from a portion of a buffer. +*/ +Object BufferToStrObj(const Buffer & b, Uint32 size); + +/* ------------------------------------------------------------------------------------------------ + * 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; +}; + +/* ------------------------------------------------------------------------------------------------ + * 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; +} + +} // Namespace:: SqMod + +#endif // _BASE_STACK_HPP_ diff --git a/source/Command.cpp b/source/Command.cpp index 078791b1..957fe474 100644 --- a/source/Command.cpp +++ b/source/Command.cpp @@ -1,6 +1,7 @@ // ------------------------------------------------------------------------------------------------ #include "Command.hpp" #include "Core.hpp" +#include "Base/Stack.hpp" #include "Entity/Player.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Constants.cpp b/source/Constants.cpp index a528ec08..7b1b1abf 100644 --- a/source/Constants.cpp +++ b/source/Constants.cpp @@ -38,6 +38,20 @@ void Register_Constants(HSQUIRRELVM vm) .Const(_SC("MaxFloat"), std::numeric_limits< SQFloat >::max()) .Const(_SC("MinFloat32"), std::numeric_limits< Float32 >::min()) .Const(_SC("MaxFloat32"), std::numeric_limits< Float32 >::max()) + .Const(_SC("FpNormal"), FP_NORMAL) + .Const(_SC("FpSubnormal"), FP_SUBNORMAL) + .Const(_SC("FpZero"), FP_ZERO) + .Const(_SC("FpInfinite"), FP_INFINITE) + .Const(_SC("FpNan"), FP_NAN) +#ifdef SQUSEDOUBLE + .Const(_SC("HugeVal"), HUGE_VAL) +#else + .Const(_SC("HugeVal"), HUGE_VALF) +#endif // SQUSEDOUBLE + .Const(_SC("Infinity"), static_cast< float >(INFINITY)) + .Const(_SC("Inf"), static_cast< float >(INFINITY)) + .Const(_SC("Nan"), static_cast< float >(NAN)) + ); ConstTable(vm).Enum(_SC("SqArchitectre"), Enumeration(vm) diff --git a/source/Entity/Blip.cpp b/source/Entity/Blip.cpp index d7a8a5ea..34b1cd8b 100644 --- a/source/Entity/Blip.cpp +++ b/source/Entity/Blip.cpp @@ -1,5 +1,6 @@ // ------------------------------------------------------------------------------------------------ #include "Entity/Blip.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Entity/Checkpoint.cpp b/source/Entity/Checkpoint.cpp index 00cb9a6a..8546a141 100644 --- a/source/Entity/Checkpoint.cpp +++ b/source/Entity/Checkpoint.cpp @@ -3,6 +3,7 @@ #include "Entity/Player.hpp" #include "Base/Color4.hpp" #include "Base/Vector3.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Entity/Forcefield.cpp b/source/Entity/Forcefield.cpp index 404319af..4b69115b 100644 --- a/source/Entity/Forcefield.cpp +++ b/source/Entity/Forcefield.cpp @@ -3,6 +3,7 @@ #include "Entity/Player.hpp" #include "Base/Color3.hpp" #include "Base/Vector3.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Entity/Keybind.cpp b/source/Entity/Keybind.cpp index 070638b9..208e79e7 100644 --- a/source/Entity/Keybind.cpp +++ b/source/Entity/Keybind.cpp @@ -1,5 +1,6 @@ // ------------------------------------------------------------------------------------------------ #include "Entity/Keybind.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ @@ -288,4 +289,4 @@ void Register_CKeybind(HSQUIRRELVM vm) ); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Object.cpp b/source/Entity/Object.cpp index b085c0ae..4c430b0b 100644 --- a/source/Entity/Object.cpp +++ b/source/Entity/Object.cpp @@ -3,6 +3,7 @@ #include "Entity/Player.hpp" #include "Base/Quaternion.hpp" #include "Base/Vector3.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Entity/Pickup.cpp b/source/Entity/Pickup.cpp index cd124db5..c91c24ff 100644 --- a/source/Entity/Pickup.cpp +++ b/source/Entity/Pickup.cpp @@ -2,6 +2,7 @@ #include "Entity/Pickup.hpp" #include "Entity/Player.hpp" #include "Base/Vector3.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ @@ -490,4 +491,4 @@ void Register_CPickup(HSQUIRRELVM vm) ); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Player.cpp b/source/Entity/Player.cpp index f691809d..b06832f4 100644 --- a/source/Entity/Player.cpp +++ b/source/Entity/Player.cpp @@ -3,6 +3,7 @@ #include "Entity/Vehicle.hpp" #include "Base/Color3.hpp" #include "Base/Vector3.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Entity/Sprite.cpp b/source/Entity/Sprite.cpp index 41397fdc..14be71a4 100644 --- a/source/Entity/Sprite.cpp +++ b/source/Entity/Sprite.cpp @@ -2,6 +2,7 @@ #include "Entity/Sprite.hpp" #include "Entity/Player.hpp" #include "Base/Vector2i.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Entity/Textdraw.cpp b/source/Entity/Textdraw.cpp index be7f25de..190f89ad 100644 --- a/source/Entity/Textdraw.cpp +++ b/source/Entity/Textdraw.cpp @@ -2,6 +2,7 @@ #include "Entity/Textdraw.hpp" #include "Entity/Player.hpp" #include "Base/Vector2i.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Entity/Vehicle.cpp b/source/Entity/Vehicle.cpp index bd1c792b..c7802fc2 100644 --- a/source/Entity/Vehicle.cpp +++ b/source/Entity/Vehicle.cpp @@ -3,6 +3,7 @@ #include "Entity/Player.hpp" #include "Base/Quaternion.hpp" #include "Base/Vector4.hpp" +#include "Base/Stack.hpp" #include "Core.hpp" // ------------------------------------------------------------------------------------------------ diff --git a/source/Library/Chrono.cpp b/source/Library/Chrono.cpp index a2c29627..622e1d1a 100644 --- a/source/Library/Chrono.cpp +++ b/source/Library/Chrono.cpp @@ -173,7 +173,7 @@ extern void Register_ChronoTime(HSQUIRRELVM vm, Table & cns); extern void Register_ChronoTimer(HSQUIRRELVM vm, Table & cns); extern void Register_ChronoTimestamp(HSQUIRRELVM vm, Table & cns); -// ------------------------------------------------------------------------------------------------ +// ================================================================================================ void Register_Chrono(HSQUIRRELVM vm) { Table cns(vm); diff --git a/source/Library/Crypt.cpp b/source/Library/Crypt.cpp index a6cd7f20..7acc7e9e 100644 --- a/source/Library/Crypt.cpp +++ b/source/Library/Crypt.cpp @@ -1,6 +1,7 @@ // ------------------------------------------------------------------------------------------------ #include "Library/Crypt.hpp" #include "Base/Shared.hpp" +#include "Base/Stack.hpp" // ------------------------------------------------------------------------------------------------ #include diff --git a/source/Library/Math.cpp b/source/Library/Math.cpp index e69de29b..b3990a7e 100644 --- a/source/Library/Math.cpp +++ b/source/Library/Math.cpp @@ -0,0 +1,1142 @@ +// ------------------------------------------------------------------------------------------------ +#include "Library/Math.hpp" +#include "Library/Numeric.hpp" +#include "Base/Stack.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqDiv(HSQUIRRELVM vm) +{ + // The return type of the function +#ifdef _SQ64 + typedef std::lldiv_t DivT; +#else + typedef std::div_t DivT; +#endif // _SQ64 + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + const DivT r = std::div(PopStackInteger(vm, 2), PopStackInteger(vm, 3)); + // Create a new table on the stack + sq_newtable(vm); + // Push the quotient index + sq_pushstring(vm, _SC("quot"), -1); + // Push the quotient value + sq_pushinteger(vm, r.quot); + // Attempt to create the array element + if (SQ_FAILED(sq_rawset(vm, -3))) + { + return sq_throwerror(vm, "Unable to insert the quotient element"); + } + // Push the remainder index + sq_pushstring(vm, _SC("rem"), -1); + // Push the remainder value + sq_pushinteger(vm, r.rem); + // Attempt to create the array element + if (SQ_FAILED(sq_rawset(vm, -3))) + { + return sq_throwerror(vm, "Unable to insert the remainder element"); + } + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqRemainder(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Are we both arguments floats? + if ((sq_gettype(vm, 2) == OT_FLOAT) && sq_gettype(vm, 3) == OT_FLOAT) + { + sq_pushfloat(vm, std::remainder(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + } + // Are we both arguments integers? + else if ((sq_gettype(vm, 2) == OT_INTEGER) && sq_gettype(vm, 3) == OT_INTEGER) + { + sq_pushinteger(vm, std::remainder(PopStackInteger(vm, 2), PopStackInteger(vm, 3))); + } + // Is the first argument float? + else if ((sq_gettype(vm, 2) == OT_FLOAT)) + { + sq_pushfloat(vm, std::remainder(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + } + // Is the first argument integer? + else if ((sq_gettype(vm, 2) == OT_INTEGER)) + { + sq_pushinteger(vm, std::remainder(PopStackInteger(vm, 2), PopStackInteger(vm, 3))); + } + // Default to both arhuments as float so we don't loos precision from the float one + else + { + sq_pushfloat(vm, std::remainder(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + } + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqFma(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 3) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::fma(PopStackFloat(vm, 2), PopStackFloat(vm, 3), PopStackFloat(vm, 4))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqMax(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::fmax(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqMin(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::fmin(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqDim(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::fdim(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqNan(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Attempt to generate the string value + StackStrF val(vm, 2); + // Have we failed to retrieve the string? + if (SQ_FAILED(val.mRes)) + { + return val.mRes; // Propagate the error! + } + // Fetch the arguments from the stack and perform the requested operation +#ifdef _SQ64 + sq_pushfloat(vm, std::nan(val.mPtr)); +#else + sq_pushfloat(vm, std::nanf(val.mPtr)); +#endif // _SQ64 + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqNanL(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Attempt to generate the string value + StackStrF val(vm, 2); + // Have we failed to retrieve the string? + if (SQ_FAILED(val.mRes)) + { + return val.mRes; // Propagate the error! + } + // Fetch the arguments from the stack and perform the requested operation + try + { + Var< SLongInt * >::push(vm, new SLongInt(std::nanl(val.mPtr))); + } + catch (const Sqrat::Exception & e) + { + return sq_throwerror(vm, e.Message().c_str()); + } + catch (const std::exception e) + { + return sq_throwerror(vm, e.what()); + } + catch (...) + { + return sq_throwerror(vm, _SC("Failed to create a long integer instance")); + } + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqExp(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::exp(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqExp2(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::exp2(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqExpm1(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::expm1(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqLog(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::log(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqLog10(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::log10(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqLog2(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::log2(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqLog1p(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::log1p(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqPow(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::pow(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqSqrt(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::sqrt(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqCbrt(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::cbrt(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqHypot(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::hypot(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqSin(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::sin(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqCos(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::cos(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqTan(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::tan(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqAsin(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::asin(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqAcos(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::acos(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqAtan(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::atan(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqAtan2(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::atan2(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqSinh(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::sinh(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqCosh(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::cosh(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqTanh(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::tanh(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqAsinh(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::asinh(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqAcosh(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::acosh(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqAtanh(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::atanh(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqErf(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::erf(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqErfc(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::erfc(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqTgamma(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::tgamma(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqLgamma(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::lgamma(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqCeil(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::ceil(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqFloor(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::floor(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqTrunc(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::trunc(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqRound(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::round(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqRoundI(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + if (sq_gettype(vm, 2) == OT_FLOAT) + { + sq_pushinteger(vm, ConvTo< SQInteger >::From(std::llround(PopStackFloat(vm, 2)))); + } + else + { + sq_pushinteger(vm, ConvTo< SQInteger >::From(std::llround(PopStackInteger(vm, 2)))); + } + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqRoundL(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + try + { + if (sq_gettype(vm, 2) == OT_FLOAT) + { + Var< SLongInt * >::push(vm, new SLongInt(std::llround(PopStackFloat(vm, 2)))); + } + else + { + Var< SLongInt * >::push(vm, new SLongInt(std::llround(PopStackInteger(vm, 2)))); + } + } + catch (const Sqrat::Exception & e) + { + return sq_throwerror(vm, e.Message().c_str()); + } + catch (const std::exception e) + { + return sq_throwerror(vm, e.what()); + } + catch (...) + { + return sq_throwerror(vm, _SC("Failed to create a long integer instance")); + } + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqNearByInt(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::nearbyint(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqFrexp(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Where the exponent is retrieved + Int32 expv = 0; + // Fetch the arguments from the stack and perform the requested operation + const SQFloat sigv = std::frexp(PopStackFloat(vm, 2), &expv); + // Create a new table on the stack + sq_newtable(vm); + // Push the significand index + sq_pushstring(vm, _SC("sig"), -1); + // Push the significand value + sq_pushfloat(vm, sigv); + // Attempt to create the array element + if (SQ_FAILED(sq_rawset(vm, -3))) + { + return sq_throwerror(vm, "Unable to insert the significand element"); + } + // Push the exponent index + sq_pushstring(vm, _SC("exp"), -1); + // Push the exponent value + sq_pushinteger(vm, expv); + // Attempt to create the array element + if (SQ_FAILED(sq_rawset(vm, -3))) + { + return sq_throwerror(vm, "Unable to insert the exponent element"); + } + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqLdexp(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::ldexp(PopStackFloat(vm, 2), PopStackInteger(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqModF(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Where the fractional part is retrieved + SQFloat intv = 0; + // Fetch the arguments from the stack and perform the requested operation + const SQFloat fracv = std::modf(PopStackFloat(vm, 2), &intv); + // Create a new table on the stack + sq_newtable(vm); + // Push the integral index + sq_pushstring(vm, _SC("integral"), -1); + // Push the integral value + sq_pushfloat(vm, intv); + // Attempt to create the array element + if (SQ_FAILED(sq_rawset(vm, -3))) + { + return sq_throwerror(vm, "Unable to insert the integral element"); + } + // Push the fractional index + sq_pushstring(vm, _SC("fractional"), -1); + // Push the fractional value + sq_pushfloat(vm, fracv); + // Attempt to create the array element + if (SQ_FAILED(sq_rawset(vm, -3))) + { + return sq_throwerror(vm, "Unable to insert the fractional element"); + } + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqScalbn(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation +#ifdef _SQ64 + sq_pushfloat(vm, std::scalbln(PopStackFloat(vm, 2), PopStackInteger(vm, 3))); +#else + sq_pushfloat(vm, std::scalbn(PopStackFloat(vm, 2), PopStackInteger(vm, 3))); +#endif // _SQ64 + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIlogb(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushinteger(vm, std::ilogb(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqLogb(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::logb(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqNextAfter(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::nextafter(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqNextForward(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::nexttoward(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqCopySign(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushfloat(vm, std::copysign(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqFpClassify(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushinteger(vm, std::fpclassify(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsFinite(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isfinite(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsInf(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isinf(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsNan(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isnan(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsNormal(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isnormal(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqSignBit(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 1) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::signbit(PopStackFloat(vm, 2))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsGreater(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isgreater(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsGreaterEqual(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isgreaterequal(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsLess(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isless(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsLessEqual(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::islessequal(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsLessGreater(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::islessgreater(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ------------------------------------------------------------------------------------------------ +static SQInteger SqIsUnordered(HSQUIRRELVM vm) +{ + // Do we have the correct number of arguments? + if (sq_gettop(vm) <= 2) + { + return sq_throwerror(vm, "Wrong number of arguments"); + } + // Fetch the arguments from the stack and perform the requested operation + sq_pushbool(vm, std::isunordered(PopStackFloat(vm, 2), PopStackFloat(vm, 3))); + // Specify that we have a value on the stack + return 1; +} + +// ================================================================================================ +void Register_Math(HSQUIRRELVM vm) +{ + Table mns(vm); + + mns + .SquirrelFunc(_SC("Div"), &SqDiv) + .SquirrelFunc(_SC("Remainder"), &SqRemainder) + .SquirrelFunc(_SC("Fma"), &SqFma) + .SquirrelFunc(_SC("Max"), &SqMax) + .SquirrelFunc(_SC("Min"), &SqMin) + .SquirrelFunc(_SC("Dim"), &SqDim) + .SquirrelFunc(_SC("Nan"), &SqNan) + .SquirrelFunc(_SC("NanL"), &SqNanL) + .SquirrelFunc(_SC("Exp"), &SqExp) + .SquirrelFunc(_SC("Exp2"), &SqExp2) + .SquirrelFunc(_SC("Expm1"), &SqExpm1) + .SquirrelFunc(_SC("Log"), &SqLog) + .SquirrelFunc(_SC("Log10"), &SqLog10) + .SquirrelFunc(_SC("Log2"), &SqLog2) + .SquirrelFunc(_SC("Log1p"), &SqLog1p) + .SquirrelFunc(_SC("Pow"), &SqPow) + .SquirrelFunc(_SC("Sqrt"), &SqSqrt) + .SquirrelFunc(_SC("Cbrt"), &SqCbrt) + .SquirrelFunc(_SC("Hypot"), &SqHypot) + .SquirrelFunc(_SC("Sin"), &SqSin) + .SquirrelFunc(_SC("Cos"), &SqCos) + .SquirrelFunc(_SC("Tan"), &SqTan) + .SquirrelFunc(_SC("Asin"), &SqAsin) + .SquirrelFunc(_SC("Acos"), &SqAcos) + .SquirrelFunc(_SC("Atan"), &SqAtan) + .SquirrelFunc(_SC("Atan2"), &SqAtan2) + .SquirrelFunc(_SC("Sinh"), &SqSinh) + .SquirrelFunc(_SC("Cosh"), &SqCosh) + .SquirrelFunc(_SC("Tanh"), &SqTanh) + .SquirrelFunc(_SC("Asinh"), &SqAsinh) + .SquirrelFunc(_SC("Acosh"), &SqAcosh) + .SquirrelFunc(_SC("Atanh"), &SqAtanh) + .SquirrelFunc(_SC("Erf"), &SqErf) + .SquirrelFunc(_SC("Erfc"), &SqErfc) + .SquirrelFunc(_SC("Tgamma"), &SqTgamma) + .SquirrelFunc(_SC("Lgamma"), &SqLgamma) + .SquirrelFunc(_SC("Ceil"), &SqCeil) + .SquirrelFunc(_SC("Floor"), &SqFloor) + .SquirrelFunc(_SC("Trunc"), &SqTrunc) + .SquirrelFunc(_SC("Round"), &SqRound) + .SquirrelFunc(_SC("RoundI"), &SqRoundI) + .SquirrelFunc(_SC("RoundL"), &SqRoundL) + .SquirrelFunc(_SC("NearByInt"), &SqNearByInt) + .SquirrelFunc(_SC("Frexp"), &SqFrexp) + .SquirrelFunc(_SC("Ldexp"), &SqLdexp) + .SquirrelFunc(_SC("ModF"), &SqModF) + .SquirrelFunc(_SC("Scalbn"), &SqScalbn) + .SquirrelFunc(_SC("Ilogb"), &SqIlogb) + .SquirrelFunc(_SC("Logb"), &SqLogb) + .SquirrelFunc(_SC("NextAfter"), &SqNextAfter) + .SquirrelFunc(_SC("NextForward"), &SqNextForward) + .SquirrelFunc(_SC("CopySign"), &SqCopySign) + .SquirrelFunc(_SC("FpClassify"), &SqFpClassify) + .SquirrelFunc(_SC("IsFinite"), &SqIsFinite) + .SquirrelFunc(_SC("IsInf"), &SqIsInf) + .SquirrelFunc(_SC("IsNan"), &SqIsNan) + .SquirrelFunc(_SC("IsNormal"), &SqIsNormal) + .SquirrelFunc(_SC("SignBit"), &SqSignBit) + .SquirrelFunc(_SC("IsGreater"), &SqIsGreater) + .SquirrelFunc(_SC("IsGreaterEqual"), &SqIsGreaterEqual) + .SquirrelFunc(_SC("IsLess"), &SqIsLess) + .SquirrelFunc(_SC("IsLessEqual"), &SqIsLessEqual) + .SquirrelFunc(_SC("IsLessGreater"), &SqIsLessGreater) + .SquirrelFunc(_SC("IsUnordered"), &SqIsUnordered); + + RootTable(vm).Bind(_SC("SqMath"), mns); +} + + +} // Namespace:: SqMod diff --git a/source/Library/Math.hpp b/source/Library/Math.hpp index e69de29b..6adc5428 100644 --- a/source/Library/Math.hpp +++ b/source/Library/Math.hpp @@ -0,0 +1,12 @@ +#ifndef _LIBRARY_MATH_HPP_ +#define _LIBRARY_MATH_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Base/Shared.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +} // Namespace:: SqMod + +#endif // _LIBRARY_MATH_HPP_ diff --git a/source/Library/Numeric.cpp b/source/Library/Numeric.cpp index 1491fdc8..2c6efc8a 100644 --- a/source/Library/Numeric.cpp +++ b/source/Library/Numeric.cpp @@ -54,7 +54,7 @@ LongInt< Uint64 > & LongInt< Uint64 >::operator = (CSStr text) // ------------------------------------------------------------------------------------------------ CSStr LongInt< Uint64 >::ToString() { - if (snprintf(m_Text, sizeof(m_Text), "%llu", m_Data) < 0) + if (std::snprintf(m_Text, sizeof(m_Text), "%llu", m_Data) < 0) { m_Text[0] = 0; } @@ -82,6 +82,12 @@ void Register_Numeric(HSQUIRRELVM vm) .Func(_SC("_tostring"), &SLongInt::ToString) .Func(_SC("_typename"), &SLongInt::Typename) .Func(_SC("_cmp"), &SLongInt::Cmp) + /* Core Functions */ + .Func(_SC("tointeger"), &SLongInt::ToSqInteger) + .Func(_SC("tofloat"), &SLongInt::ToSqFloat) + .Func(_SC("tostring"), &SLongInt::ToSqString) + .Func(_SC("tobool"), &SLongInt::ToSqBool) + .Func(_SC("tochar"), &SLongInt::ToSqChar) /* Metamethods */ .Func< SLongInt (SLongInt::*)(const SLongInt &) const >(_SC("_add"), &SLongInt::operator +) .Func< SLongInt (SLongInt::*)(const SLongInt &) const >(_SC("_sub"), &SLongInt::operator -) @@ -112,6 +118,12 @@ void Register_Numeric(HSQUIRRELVM vm) .Func(_SC("_tostring"), &ULongInt::ToString) .Func(_SC("_typename"), &ULongInt::Typename) .Func(_SC("_cmp"), &ULongInt::Cmp) + /* Core Functions */ + .Func(_SC("tointeger"), &ULongInt::ToSqInteger) + .Func(_SC("tofloat"), &ULongInt::ToSqFloat) + .Func(_SC("tostring"), &ULongInt::ToSqString) + .Func(_SC("tobool"), &ULongInt::ToSqBool) + .Func(_SC("tochar"), &ULongInt::ToSqChar) /* Metamethods */ .Func< ULongInt (ULongInt::*)(const ULongInt &) const >(_SC("_add"), &ULongInt::operator +) .Func< ULongInt (ULongInt::*)(const ULongInt &) const >(_SC("_sub"), &ULongInt::operator -) diff --git a/source/Library/Numeric.hpp b/source/Library/Numeric.hpp index 68c3cbe1..abb3130e 100644 --- a/source/Library/Numeric.hpp +++ b/source/Library/Numeric.hpp @@ -199,7 +199,7 @@ public: */ SQInteger GetSNum() const { - return (SQInteger)(m_Data); + return ClampL< Type, SQInteger >(m_Data); } /* -------------------------------------------------------------------------------------------- @@ -222,6 +222,46 @@ public: void Random(Type n); void Random(Type m, Type n); + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel integer. + */ + SQInteger ToSqInteger() const + { + return ClampL< Type, SQInteger >(m_Data); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel float. + */ + SQFloat ToSqFloat() const + { + return ClampL< Float64, SQFloat >(static_cast< Float64 >(m_Data)); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel string. + */ + CSStr ToSqString() + { + return ToString(); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel boolean. + */ + bool ToSqBool() const + { + return (m_Data > 0); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel character. + */ + SQChar ToSqChar() const + { + return ClampL< Type, SQChar >(m_Data); + } + private: // -------------------------------------------------------------------------------------------- @@ -441,6 +481,46 @@ public: void Random(Type n); void Random(Type m, Type n); + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel integer. + */ + SQInteger ToSqInteger() const + { + return ClampL< Type, SQInteger >(m_Data); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel float. + */ + SQFloat ToSqFloat() const + { + return ClampL< Float64, SQFloat >(static_cast< Float64 >(m_Data)); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel string. + */ + CSStr ToSqString() + { + return ToString(); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel boolean. + */ + bool ToSqBool() const + { + return (m_Data > 0); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert the long integer to a squirrel character. + */ + SQChar ToSqChar() const + { + return ClampL< Type, SQChar >(m_Data); + } + private: // -------------------------------------------------------------------------------------------- diff --git a/source/Library/String.cpp b/source/Library/String.cpp index 40f54848..9d4f9b90 100644 --- a/source/Library/String.cpp +++ b/source/Library/String.cpp @@ -2,6 +2,7 @@ #include "Library/String.hpp" #include "Base/Shared.hpp" #include "Base/Buffer.hpp" +#include "Base/Stack.hpp" // ------------------------------------------------------------------------------------------------ #include diff --git a/source/Library/SysEnv.cpp b/source/Library/SysEnv.cpp index 58ac320f..8d6fc49a 100644 --- a/source/Library/SysEnv.cpp +++ b/source/Library/SysEnv.cpp @@ -1,5 +1,6 @@ // ------------------------------------------------------------------------------------------------ #include "Library/SysEnv.hpp" +#include "Base/Stack.hpp" // ------------------------------------------------------------------------------------------------ #include diff --git a/source/Library/SysPath.cpp b/source/Library/SysPath.cpp index c0fc0eb5..b4d5a519 100644 --- a/source/Library/SysPath.cpp +++ b/source/Library/SysPath.cpp @@ -1,6 +1,7 @@ // ------------------------------------------------------------------------------------------------ #include "Library/SysPath.hpp" #include "Library/SysEnv.hpp" +#include "Base/Stack.hpp" // ------------------------------------------------------------------------------------------------ #include diff --git a/source/Register.cpp b/source/Register.cpp index 908de542..0dffc171 100644 --- a/source/Register.cpp +++ b/source/Register.cpp @@ -37,6 +37,7 @@ extern void Register_Entity(HSQUIRRELVM vm); extern void Register_Chrono(HSQUIRRELVM vm); extern void Register_Crypt(HSQUIRRELVM vm); extern void Register_Numeric(HSQUIRRELVM vm); +extern void Register_Math(HSQUIRRELVM vm); extern void Register_Random(HSQUIRRELVM vm); extern void Register_String(HSQUIRRELVM vm); extern void Register_SysEnv(HSQUIRRELVM vm); @@ -82,6 +83,7 @@ bool RegisterAPI(HSQUIRRELVM vm) Register_Crypt(vm); Register_Random(vm); Register_Numeric(vm); + Register_Math(vm); Register_String(vm); Register_SysEnv(vm); Register_SysPath(vm); diff --git a/source/Routine.cpp b/source/Routine.cpp index ccda3299..46059451 100644 --- a/source/Routine.cpp +++ b/source/Routine.cpp @@ -1,5 +1,6 @@ // ------------------------------------------------------------------------------------------------ #include "Routine.hpp" +#include "Base/Stack.hpp" #include "Library/Chrono.hpp" // ------------------------------------------------------------------------------------------------