mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2026-07-09 10:07:10 +02:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d15f4b6e9 | |||
| c0d142ab34 | |||
| f77ec9482f | |||
| 4fc1e892f7 | |||
| 015047a935 | |||
| bc1fc1d245 | |||
| 2a069f3040 | |||
| d295828545 | |||
| 483ac37bdb | |||
| 78dc76e6b4 | |||
| e29070af49 | |||
| 1f25b3ea60 | |||
| 52cfa235be | |||
| ec7f1183d8 | |||
| a788e059a5 | |||
| 5f20ffc4de | |||
| 08106156c4 | |||
| 60119ff8fa | |||
| f4720ae77a | |||
| c9fb257f48 | |||
| 475a428366 | |||
| 42ac0e32b7 | |||
| 3e75e36cdf | |||
| ac7d18f297 | |||
| 39473a68f4 | |||
| 5a57bf2fbf | |||
| 15e85f1394 | |||
| e8fa9e0259 | |||
| c551390999 | |||
| 804a5abb29 | |||
| 68551e4466 | |||
| 4618577ae4 | |||
| 2f428962c8 | |||
| 34a78dc166 | |||
| 49df7b75ee | |||
| 0d927f5d72 | |||
| 44243aadd2 | |||
| aa3952fd45 | |||
| ebe60ebf4b | |||
| fa9c3a5821 | |||
| f238588abe | |||
| 39524098f1 | |||
| ea63899c9a | |||
| 8f11e08150 | |||
| b8b5e89216 | |||
| 87387999f3 | |||
| d6a56feb87 | |||
| 9c94fb7afc | |||
| 2f3684e251 | |||
| 7afc05e52b | |||
| eca11b73ba | |||
| 5c54dc6a95 | |||
| 9330cd4eb3 | |||
| 7576409ceb | |||
| f278d151d6 | |||
| b3b57d5b2b | |||
| c4130c589f | |||
| 2d24860905 | |||
| eb90d9bc99 | |||
| b87e68b9fc | |||
| a1a71ee031 | |||
| c4b9b4c0a5 | |||
| b3f9f9e47a | |||
| a2421afca1 | |||
| e2cbd7d5cf | |||
| 2725387112 | |||
| 7248351469 | |||
| e253dc2038 | |||
| 38f0a53cd8 | |||
| 1c7fee69ea | |||
| 2b85b3a035 | |||
| 11fb1fa25c |
+2
-2
@@ -3,7 +3,7 @@ project(SqMod)
|
||||
|
||||
# This plug-in only works on 64-bit
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
message(FATAL_ERROR "SqMod does not support 32-but platforms anymore.")
|
||||
message(FATAL_ERROR "SqMod does not support 32-bit platforms anymore.")
|
||||
endif()
|
||||
|
||||
# Tell CMake where to find our scripts
|
||||
@@ -18,7 +18,7 @@ option(ENABLE_BUILTIN_MYSQL_C "Enable built-in MySQL connector library" OFF)
|
||||
#option(FORCE_32BIT_BIN "Create a 32-bit executable binary if the compiler defaults to 64-bit." OFF)
|
||||
# This option should only be available in certain conditions
|
||||
if(WIN32 AND MINGW)
|
||||
option(COPY_DEPENDENCIES "Copy deppendent DLLs into the deps folder." OFF)
|
||||
option(COPY_DEPENDENCIES "Copy dependent DLLs into the deps folder." OFF)
|
||||
endif()
|
||||
|
||||
# C++14 is mandatory
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
@@ -300,6 +301,21 @@ String AABB::ToString() const
|
||||
return fmt::format("{},{},{},{},{},{}", min.x, min.y, min.z, max.x, max.y, max.z);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AABB::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{min:{{x:{},y:{},z:{}}},max:{{x:{},y:{},z:{}}},",
|
||||
min.x, min.y, min.z, max.x, max.y, max.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{min:[{},{},{}],max:[{},{},{}]}},",
|
||||
min.x, min.y, min.z, max.x, max.y, max.z);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AABB::SetStr(SQChar delim, StackStrF & values)
|
||||
{
|
||||
@@ -793,6 +809,7 @@ void Register_AABB(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &AABB::ToString)
|
||||
.Func(_SC("_tojson"), &AABB::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
|
||||
|
||||
@@ -304,6 +304,11 @@ struct AABB
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set the values extracted from the specified string using the specified delimiter.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -360,6 +361,19 @@ String Circle::ToString() const
|
||||
return fmt::format("{},{},{}", pos.x, pos.y, rad);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Circle::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},r:{}}},", pos.x, pos.y, rad);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{}],", pos.x, pos.y, rad);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Circle::SetRadius(Value nr)
|
||||
{
|
||||
@@ -552,6 +566,7 @@ void Register_Circle(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Circle::ToString)
|
||||
.Func(_SC("_toJSON"), &Circle::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
|
||||
|
||||
@@ -341,6 +341,11 @@ struct Circle
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set the specified radius.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -481,6 +482,19 @@ String Color3::ToString() const
|
||||
return fmt::format("{},{},{}", r, g, b);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Color3::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{r:{},g:{},b:{}}},", r, g, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{}],", r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Color3::SetScalar(Value ns)
|
||||
{
|
||||
@@ -741,6 +755,7 @@ void Register_Color3(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Color3::ToString)
|
||||
.Func(_SC("_tojson"), &Color3::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
|
||||
|
||||
@@ -405,6 +405,11 @@ struct Color3
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set all components to the specified scalar value.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -506,6 +507,19 @@ String Color4::ToString() const
|
||||
return fmt::format("{},{},{},{}", r, g, b, a);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Color4::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{r:{},g:{},b:{},a:{}}},", r, g, b, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Color4::SetScalar(Value ns)
|
||||
{
|
||||
@@ -781,6 +795,7 @@ void Register_Color4(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Color4::ToString)
|
||||
.Func(_SC("_tojson"), &Color4::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
|
||||
|
||||
@@ -405,6 +405,11 @@ struct Color4
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set all components to the specified scalar value.
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -349,6 +350,19 @@ String Quaternion::ToString() const
|
||||
return fmt::format("{},{},{},{}", x, y, z, w);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Quaternion::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{},w:{}}},", x, y, z, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", x, y, z, w);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Quaternion::SetScalar(Value ns)
|
||||
{
|
||||
@@ -775,6 +789,7 @@ void Register_Quaternion(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Quaternion::ToString)
|
||||
.Func(_SC("_tojson"), &Quaternion::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
|
||||
|
||||
@@ -296,6 +296,11 @@ struct Quaternion
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set all components to the specified scalar value.
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct CtxJSON;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Helper constants used by the bas types.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -360,6 +361,19 @@ String Sphere::ToString() const
|
||||
return fmt::format("{},{},{},{}", pos.x, pos.y, pos.z, rad);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Sphere::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{},r:{}}},", pos.x, pos.y, pos.z, rad);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", pos.x, pos.y, pos.z, rad);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Sphere::SetRadius(Value nr)
|
||||
{
|
||||
@@ -527,6 +541,7 @@ void Register_Sphere(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Sphere::ToString)
|
||||
.Func(_SC("_tojson"), &Sphere::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
|
||||
|
||||
@@ -341,6 +341,11 @@ struct Sphere
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set the specified radius.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -295,6 +296,19 @@ String Vector2::ToString() const
|
||||
return fmt::format("{},{}", x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector2::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{}}},", x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{}],", x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector2::SetScalar(Value ns)
|
||||
{
|
||||
@@ -428,6 +442,7 @@ void Register_Vector2(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Vector2::ToString)
|
||||
.Func(_SC("_tojson"), &Vector2::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
|
||||
|
||||
@@ -285,6 +285,11 @@ struct Vector2
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set all components to the specified scalar value.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -441,6 +442,19 @@ String Vector2i::ToString() const
|
||||
return fmt::format("{},{}", x, y);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector2i::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{}}},", x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{}],", x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector2i::SetScalar(Value ns)
|
||||
{
|
||||
@@ -574,6 +588,7 @@ void Register_Vector2i(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Vector2i::ToString)
|
||||
.Func(_SC("_tojson"), &Vector2i::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
|
||||
|
||||
@@ -390,6 +390,11 @@ struct Vector2i
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set all components to the specified scalar value.
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -331,6 +332,19 @@ String Vector3::ToString() const
|
||||
return fmt::format("{},{},{}", x, y, z);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector3::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{}}},", x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{}],", x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector3::SetScalar(Value ns)
|
||||
{
|
||||
@@ -696,6 +710,7 @@ void Register_Vector3(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Vector3::ToString)
|
||||
.Func(_SC("_tojson"), &Vector3::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
|
||||
|
||||
@@ -297,6 +297,11 @@ struct Vector3
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set all components to the specified scalar value.
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Base/DynArg.hpp"
|
||||
#include "Core/Buffer.hpp"
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Library/JSON.hpp"
|
||||
#include "Library/Numeric/Random.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -344,6 +345,19 @@ String Vector4::ToString() const
|
||||
return fmt::format("{},{},{},{}", x, y, z, w);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector4::ToJSON(CtxJSON & ctx) const
|
||||
{
|
||||
if (ctx.mObjectOverArray)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "{{x:{},y:{},z:{},w:{}}},", x, y, z, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::format_to(std::back_inserter(ctx.mOutput), "[{},{},{},{}],", x, y, z, w);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Vector4::SetScalar(Value ns)
|
||||
{
|
||||
@@ -526,6 +540,7 @@ void Register_Vector4(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
|
||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||
.Func(_SC("_tostring"), &Vector4::ToString)
|
||||
.Func(_SC("_tojson"), &Vector4::ToJSON)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
|
||||
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
|
||||
|
||||
@@ -295,6 +295,11 @@ struct Vector4
|
||||
*/
|
||||
SQMOD_NODISCARD String ToString() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Used by the script engine to convert an instance of this type to a JSON string.
|
||||
*/
|
||||
void ToJSON(CtxJSON & ctx) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set all components to the specified scalar value.
|
||||
*/
|
||||
|
||||
+22
-9
@@ -1,5 +1,7 @@
|
||||
# Create the Squirrel module
|
||||
add_library(SqModule MODULE SqBase.hpp Main.cpp
|
||||
# SDK
|
||||
SDK/sqmod.h
|
||||
# VCMP
|
||||
VCMP/vcmp.h
|
||||
VCMP/vcmp20.h
|
||||
@@ -80,6 +82,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
|
||||
Library/Numeric.cpp Library/Numeric.hpp
|
||||
Library/Numeric/Math.cpp Library/Numeric/Math.hpp
|
||||
Library/Numeric/Random.cpp Library/Numeric/Random.hpp
|
||||
Library/RegEx.cpp Library/RegEx.hpp
|
||||
Library/String.cpp Library/String.hpp
|
||||
Library/System.cpp Library/System.hpp
|
||||
Library/System/Dir.cpp Library/System/Dir.hpp
|
||||
@@ -106,7 +109,6 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
|
||||
PocoLib/Crypto.cpp PocoLib/Crypto.hpp
|
||||
PocoLib/Data.cpp PocoLib/Data.hpp
|
||||
PocoLib/Net.cpp PocoLib/Net.hpp
|
||||
PocoLib/RegEx.cpp PocoLib/RegEx.hpp
|
||||
PocoLib/Register.cpp PocoLib/Register.hpp
|
||||
PocoLib/Time.cpp PocoLib/Time.hpp
|
||||
PocoLib/Util.cpp PocoLib/Util.hpp
|
||||
@@ -114,6 +116,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
|
||||
Core.cpp Core.hpp
|
||||
Logger.cpp Logger.hpp
|
||||
Register.cpp
|
||||
Exports.cpp
|
||||
)
|
||||
# Various definitions required by the plug-in
|
||||
target_compile_definitions(SqModule PRIVATE SCRAT_USE_EXCEPTIONS=1)
|
||||
@@ -132,7 +135,7 @@ if(WIN32 OR MINGW)
|
||||
target_link_libraries(SqModule wsock32 ws2_32 shlwapi)
|
||||
endif()
|
||||
# Link to base libraries
|
||||
target_link_libraries(SqModule Squirrel fmt::fmt SimpleINI TinyDir xxHash ConcurrentQueue SAJSON CPR UTF8Lib PUGIXML CivetWeb maxminddb libzmq-static)
|
||||
target_link_libraries(SqModule RPMalloc Squirrel fmt::fmt SimpleINI TinyDir xxHash ConcurrentQueue SAJSON CPR UTF8Lib PUGIXML CivetWeb maxminddb libzmq-static)
|
||||
# Link to POCO libraries
|
||||
target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net)
|
||||
# Does POCO have SQLite support?
|
||||
@@ -201,8 +204,18 @@ else(WIN32)
|
||||
endif(WIN32)
|
||||
# Include current directory in the search path
|
||||
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/SDK)
|
||||
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/VCMP)
|
||||
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/Sqrat)
|
||||
# Include PCRE directory in the header search path
|
||||
if (POCO_UNBUNDLED)
|
||||
find_package(PCRE REQUIRED)
|
||||
target_link_libraries(SqModule PRIVATE Pcre::Pcre)
|
||||
else()
|
||||
# Get the foundation source folder path
|
||||
get_target_property(POCO_FOUNDATION_SOURCE_DIR Foundation SOURCE_DIR)
|
||||
target_include_directories(SqModule PRIVATE "${POCO_FOUNDATION_SOURCE_DIR}/src")
|
||||
endif()
|
||||
# Copy module into the plug-ins folder
|
||||
add_custom_command(TARGET SqModule POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:SqModule> "${PROJECT_SOURCE_DIR}/bin/plugins")
|
||||
# Copy several dependent DLLs on windows to make distribution easier (used mainly by people that distribute builds)
|
||||
@@ -213,12 +226,12 @@ if(WIN32 AND MINGW AND COPY_DEPENDENCIES)
|
||||
endif()
|
||||
# Make sure the deps folder exists
|
||||
file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
# Copy dependencies into the plug-ins folder (only so it can be distributed with the DLL)
|
||||
# Copy dependencies into the deps folder (only so it can be distributed with the DLL)
|
||||
file(COPY "${MINGW_BIN_PATH}/zlib1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libpq.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libzstd.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libpsl-5.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libffi-7.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libffi-8.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libcurl-4.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libssh2-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libidn2-0.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
@@ -236,17 +249,17 @@ if(WIN32 AND MINGW AND COPY_DEPENDENCIES)
|
||||
file(COPY "${MINGW_BIN_PATH}/libp11-kit-0.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libbrotlidec.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libbrotlicommon.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libunistring-2.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libunistring-5.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libnghttp2-14.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libwinpthread-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libstdc++-6.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT FORCE_32BIT_BIN)
|
||||
file(COPY "${MINGW_BIN_PATH}/libgcc_s_seh-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libssl-1_1-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libcrypto-1_1-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libssl-3-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libcrypto-3-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
else()
|
||||
file(COPY "${MINGW_BIN_PATH}/libssl-1_1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libcrypto-1_1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libssl-3.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
file(COPY "${MINGW_BIN_PATH}/libcrypto-3.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
endif()
|
||||
if(POCO_UNBUNDLED)
|
||||
file(COPY "${MINGW_BIN_PATH}/libexpat-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||
|
||||
+115
-8
@@ -161,6 +161,7 @@ Core::Core() noexcept
|
||||
, m_Scripts()
|
||||
, m_PendingScripts()
|
||||
, m_Options()
|
||||
, m_ExtCommands{nullptr, nullptr, nullptr, nullptr}
|
||||
, m_Blips()
|
||||
, m_Checkpoints()
|
||||
, m_KeyBinds()
|
||||
@@ -441,9 +442,9 @@ bool Core::Execute()
|
||||
m_LockPostLoadSignal = false;
|
||||
m_LockUnloadSignal = false;
|
||||
|
||||
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to register their API");
|
||||
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins that the API is being registered");
|
||||
// Tell modules to do their monkey business
|
||||
//_Func->SendPluginCommand(0xDEADBABE, "");
|
||||
_Func->SendPluginCommand(SQMOD_LOAD_CMD, SQMOD_HOST_NAME);
|
||||
|
||||
// Load pending scripts while we're in the bounds of the allowed recursiveness
|
||||
for (unsigned levels = 0; !m_PendingScripts.empty() && (levels < 8); ++levels)
|
||||
@@ -511,9 +512,9 @@ void Core::Terminate(bool shutdown)
|
||||
// Clear the callbacks
|
||||
ResetSignalPair(mOnUnload);
|
||||
|
||||
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to release their resources");
|
||||
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to release their resources");
|
||||
// Tell modules to do their monkey business
|
||||
//_Func->SendPluginCommand(0xDEADC0DE, "");
|
||||
_Func->SendPluginCommand(SQMOD_TERMINATE_CMD, SQMOD_HOST_NAME);
|
||||
}
|
||||
|
||||
cLogDbg(m_Verbosity >= 1, "Clearing the entity containers");
|
||||
@@ -596,9 +597,9 @@ void Core::Terminate(bool shutdown)
|
||||
HSQUIRRELVM sq_vm = m_VM;
|
||||
m_VM = nullptr;
|
||||
|
||||
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing");
|
||||
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing");
|
||||
// Tell modules to do their monkey business
|
||||
//_Func->SendPluginCommand(0xBAAAAAAD, "");
|
||||
_Func->SendPluginCommand(SQMOD_CLOSING_CMD, SQMOD_HOST_NAME);
|
||||
// Release any callbacks from the logger
|
||||
Logger::Get().Release();
|
||||
cLogDbg(m_Verbosity >= 2, "Closing Virtual Machine");
|
||||
@@ -629,9 +630,9 @@ void Core::Terminate(bool shutdown)
|
||||
// Destroy the VM context, if any
|
||||
delete ctx;
|
||||
|
||||
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to release the virtual machine");
|
||||
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine was closed");
|
||||
// Tell modules to do their monkey business
|
||||
//_Func->SendPluginCommand(0xDEADBEAF, "");
|
||||
_Func->SendPluginCommand(SQMOD_RELEASED_CMD, SQMOD_HOST_NAME);
|
||||
}
|
||||
|
||||
OutputMessage("Squirrel plug-in was successfully terminated");
|
||||
@@ -904,6 +905,81 @@ String Core::FetchCodeLine(const SQChar * src, SQInteger line, bool trim)
|
||||
return script->FetchLine(line, trim);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int32_t Core::RegisterExtCommand(ExtPluginCommand_t fn)
|
||||
{
|
||||
ExtPluginCommand_t * slot = nullptr;
|
||||
// Find a free slot or matching function pointer in the pool
|
||||
for (size_t i = 0; i < m_ExtCommands.max_size(); ++i)
|
||||
{
|
||||
// Is this slot available and are we still looking for a slot?
|
||||
if (m_ExtCommands[i] == nullptr && slot == nullptr)
|
||||
{
|
||||
slot = &m_ExtCommands[i]; // Found a slot
|
||||
}
|
||||
// We keep looking for duplicates even if we found the slot
|
||||
else if (m_ExtCommands[i] == fn)
|
||||
{
|
||||
return 0; // Already registered
|
||||
}
|
||||
}
|
||||
// Do we have a free slot?
|
||||
if (slot != nullptr)
|
||||
{
|
||||
*slot = fn; // Use this slot
|
||||
return 1; // Successfully registered
|
||||
}
|
||||
// No space in the pool
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int32_t Core::UnregisterExtCommand(ExtPluginCommand_t fn)
|
||||
{
|
||||
// Find the matching function pointer
|
||||
for (size_t i = 0; i < m_ExtCommands.max_size(); ++i)
|
||||
{
|
||||
// Is this the same pointer?
|
||||
if (m_ExtCommands[i] != nullptr && m_ExtCommands[i] == fn)
|
||||
{
|
||||
// Forget about it
|
||||
m_ExtCommands[i] = nullptr;
|
||||
return 1; // Successfully unregistered
|
||||
}
|
||||
}
|
||||
// No space
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int32_t Core::SendExtCommand(int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size)
|
||||
{
|
||||
int32_t count = 0;
|
||||
// Send the command to all registered function pointers
|
||||
for (size_t i = 0; i < m_ExtCommands.max_size(); ++i)
|
||||
{
|
||||
if (m_ExtCommands[i] != nullptr)
|
||||
{
|
||||
const int32_t r = m_ExtCommands[i](target, req, tag, data, size);
|
||||
// Command processed
|
||||
++count;
|
||||
// Command failed?
|
||||
if (r < 0)
|
||||
{
|
||||
LogErr("External command failed (%i): target(%i), req(%i), tag(%i), data(%p), size (%zu)",
|
||||
r, target, req, tag, data, size);
|
||||
}
|
||||
// Command consumed?
|
||||
else if (r > 0)
|
||||
{
|
||||
break; // This function pointer requested exclusive access over this command
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return how many function pointers received this command
|
||||
return count;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end)
|
||||
{
|
||||
@@ -2371,6 +2447,8 @@ void Core::InitEvents()
|
||||
InitSignalPair(mOnServerOption, m_Events, "ServerOption");
|
||||
InitSignalPair(mOnScriptReload, m_Events, "ScriptReload");
|
||||
InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded");
|
||||
InitSignalPair(mOnExtCommandReply, m_Events, "ExtCommandReply");
|
||||
InitSignalPair(mOnExtCommandEvent, m_Events, "ExtCommandEvent");
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::DropEvents()
|
||||
@@ -2516,6 +2594,8 @@ void Core::DropEvents()
|
||||
ResetSignalPair(mOnServerOption);
|
||||
ResetSignalPair(mOnScriptReload);
|
||||
ResetSignalPair(mOnScriptLoaded);
|
||||
ResetSignalPair(mOnExtCommandReply);
|
||||
ResetSignalPair(mOnExtCommandEvent);
|
||||
m_Events.Release();
|
||||
}
|
||||
|
||||
@@ -2861,6 +2941,31 @@ static LightObj & SqGetClientDataBuffer()
|
||||
return Core::Get().GetClientDataBuffer();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqSendExtCommand(int32_t target, int32_t req, int32_t tag, SqBuffer & buffer)
|
||||
{
|
||||
// Default to an empty/null buffer
|
||||
const uint8_t * data = nullptr;
|
||||
size_t size = 0;
|
||||
// Does the buffer actually point to anything?
|
||||
if (buffer.GetRef())
|
||||
{
|
||||
data = buffer.GetRef()->Begin< uint8_t >();
|
||||
size = buffer.GetRef()->PositionAs< size_t >();
|
||||
}
|
||||
// Forward the request
|
||||
return Core::Get().SendExtCommand(target, req, tag, data, size);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqSendExtCommandStr(int32_t target, int32_t req, int32_t tag, StackStrF & str)
|
||||
{
|
||||
// Forward the request
|
||||
return Core::Get().SendExtCommand(target, req, tag,
|
||||
reinterpret_cast< const uint8_t * >(str.mPtr),
|
||||
str.mLen <= 0 ? 0 : static_cast< size_t >(str.mLen));
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
void Register_Core(HSQUIRRELVM vm)
|
||||
{
|
||||
@@ -2910,6 +3015,8 @@ void Register_Core(HSQUIRRELVM vm)
|
||||
.Func(_SC("DestroyPickup"), &SqDelPickup)
|
||||
.Func(_SC("DestroyVehicle"), &SqDelVehicle)
|
||||
.Func(_SC("ClientDataBuffer"), &SqGetClientDataBuffer)
|
||||
.Func(_SC("SendExtCommand"), &SqSendExtCommand)
|
||||
.FmtFunc(_SC("SendExtCommandStr"), &SqSendExtCommandStr)
|
||||
.Func(_SC("OnPreLoad"), &SqGetPreLoadEvent)
|
||||
.Func(_SC("OnPostLoad"), &SqGetPostLoadEvent)
|
||||
.Func(_SC("OnUnload"), &SqGetUnloadEvent)
|
||||
|
||||
+105
-5
@@ -9,6 +9,9 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <unordered_map>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "SDK/sqmod.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
@@ -56,6 +59,8 @@ public:
|
||||
typedef std::vector< ScriptSrc > Scripts; // List of loaded scripts.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::unordered_map< String, String > Options; // List of custom options.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef std::array< ExtPluginCommand_t, 4 > ExtCommands; // 4 external command parsers should be enough.
|
||||
|
||||
private:
|
||||
|
||||
@@ -68,6 +73,7 @@ private:
|
||||
Scripts m_Scripts; // Loaded scripts objects.
|
||||
Scripts m_PendingScripts; // Pending scripts objects.
|
||||
Options m_Options; // Custom configuration options.
|
||||
ExtCommands m_ExtCommands; // External command parsers pointers.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Blips m_Blips; // Blips pool.
|
||||
@@ -399,6 +405,23 @@ public:
|
||||
*/
|
||||
SQMOD_NODISCARD String FetchCodeLine(const SQChar * src, SQInteger line, bool trim = true);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Register a pointer to a function used to processes commands from script.
|
||||
* Returns -1 it failed (no free slot), 0 if it was already registered and 1 if it succeeded.
|
||||
*/
|
||||
int32_t RegisterExtCommand(ExtPluginCommand_t fn);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Remove a pointer to a function used to processes commands from script.
|
||||
* Returns -1 it failed (no free slot) and 1 if it succeeded.
|
||||
*/
|
||||
int32_t UnregisterExtCommand(ExtPluginCommand_t fn);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Send a command to all functions currently registered to receive them.
|
||||
*/
|
||||
int32_t SendExtCommand(int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size);
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -710,6 +733,16 @@ public:
|
||||
*/
|
||||
void EmitClientScriptData(int32_t player_id, const uint8_t * data, size_t size);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Send a response to the script that may have resulted from a previous command.
|
||||
*/
|
||||
void EmitExtCommandReply(int32_t sender, int32_t tag, const uint8_t * data, size_t size);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Forward an event to the script from an external plug-in.
|
||||
*/
|
||||
void EmitExtCommandEvent(int32_t sender, int32_t tag, const uint8_t * data, size_t size);
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -864,6 +897,8 @@ public:
|
||||
SignalPair mOnServerOption{};
|
||||
SignalPair mOnScriptReload{};
|
||||
SignalPair mOnScriptLoaded{};
|
||||
SignalPair mOnExtCommandReply{};
|
||||
SignalPair mOnExtCommandEvent{};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -993,28 +1028,93 @@ template < class F > inline void ForeachActivePickup(F f) { ForeachActiveEntity(
|
||||
template < class F > inline void ForeachActivePlayer(F f) { ForeachActiveEntity(Core::Get().GetPlayers(), std::forward< F >(f)); }
|
||||
template < class F > inline void ForeachActiveVehicle(F f) { ForeachActiveEntity(Core::Get().GetVehicles(), std::forward< F >(f)); }
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Process the identifier of each player slot.
|
||||
*/
|
||||
template < class F > inline void ForeachPlayerSlot(F f) {
|
||||
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||
f(i);
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Process the identifier of each player slot and count processed players.
|
||||
*/
|
||||
template < class F > SQMOD_NODISCARD inline int32_t ForeachPlayerSlotCount(F f) {
|
||||
int32_t c = 0;
|
||||
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||
if (f(i)) ++c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Process the identifier of each player slot until a certain criteria is met.
|
||||
*/
|
||||
template < class F > SQMOD_NODISCARD inline int32_t ForeachPlayerSlotUntil(F f) {
|
||||
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||
if (f(i)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Process the identifier of each connected player.
|
||||
*/
|
||||
template < class F > inline void ForeachConnectedPlayer(F f) {
|
||||
for (int32_t i = 0, n = _Func->GetMaxPlayers(); i < n; ++i) f(i);
|
||||
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||
if (_Func->IsPlayerConnected(i) != 0) f(i);
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Process the identifier of each connected player and count processed players.
|
||||
*/
|
||||
template < class F > SQMOD_NODISCARD inline int32_t ForeachConnectedPlayerCount(F f) {
|
||||
int32_t c = 0;
|
||||
for (int32_t i = 0, n = _Func->GetMaxPlayers(); i < n; ++i)
|
||||
if (f(i)) ++c;
|
||||
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||
if (_Func->IsPlayerConnected(i) != 0 && f(i)) ++c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Process the identifier of each connected player until a certain criteria is met.
|
||||
*/
|
||||
template < class F > SQMOD_NODISCARD inline int32_t ForeachConnectedPlayerUntil(F f) {
|
||||
for (int32_t i = 0, n = _Func->GetMaxPlayers(); i < n; ++i)
|
||||
if (f(i)) return i;
|
||||
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||
if (_Func->IsPlayerConnected(i) != 0 && f(i)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Used to select entity instances based on type.
|
||||
*/
|
||||
template < class > struct EntityInstSelect;
|
||||
// Specialization for blips.
|
||||
template < > struct EntityInstSelect< CBlip > {
|
||||
static BlipInst & Get(int32_t id) { return Core::Get().GetBlip(id); }
|
||||
};
|
||||
// Specialization for checkpoints.
|
||||
template < > struct EntityInstSelect< CCheckpoint > {
|
||||
static CheckpointInst & Get(int32_t id) { return Core::Get().GetCheckpoint(id); }
|
||||
};
|
||||
// Specialization for keybinds.
|
||||
template < > struct EntityInstSelect< CKeyBind > {
|
||||
static KeyBindInst & Get(int32_t id) { return Core::Get().GetKeyBind(id); }
|
||||
};
|
||||
// Specialization for objects.
|
||||
template < > struct EntityInstSelect< CObject > {
|
||||
static ObjectInst & Get(int32_t id) { return Core::Get().GetObj(id); }
|
||||
};
|
||||
// Specialization for pickups.
|
||||
template < > struct EntityInstSelect< CPickup > {
|
||||
static PickupInst & Get(int32_t id) { return Core::Get().GetPickup(id); }
|
||||
};
|
||||
// Specialization for players.
|
||||
template < > struct EntityInstSelect< CPlayer > {
|
||||
static PlayerInst & Get(int32_t id) { return Core::Get().GetPlayer(id); }
|
||||
};
|
||||
// Specialization for vehicles.
|
||||
template < > struct EntityInstSelect< CVehicle > {
|
||||
static VehicleInst & Get(int32_t id) { return Core::Get().GetVehicle(id); }
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
+33
-5
@@ -161,7 +161,7 @@ bool Area::IsInside(float x, float y) const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AreaManager::AreaManager(size_t sz) noexcept
|
||||
: m_Queue(), m_ProcList(), m_Grid{}
|
||||
: m_Queue(), m_ProcList(), m_Grid{}, m_Cells{}
|
||||
{
|
||||
// Negative half grid size (left)
|
||||
int l = (-GRIDH * CELLD);
|
||||
@@ -171,21 +171,30 @@ AreaManager::AreaManager(size_t sz) noexcept
|
||||
int r = (l + CELLD);
|
||||
// Positive half grid size (top)
|
||||
int t = abs(l);
|
||||
// Row/Column of the grid
|
||||
int row = 0, col = 0;
|
||||
// Initialize the grid cells
|
||||
for (auto & a : m_Grid)
|
||||
{
|
||||
// Reset the column
|
||||
col = 0;
|
||||
// Process row
|
||||
for (auto & c : a)
|
||||
{
|
||||
auto & cx = m_Cells[row][col];
|
||||
// Grab a reference to the cell
|
||||
// Configure the range of the cell
|
||||
c.mL = static_cast< float >(l);
|
||||
c.mB = static_cast< float >(b);
|
||||
c.mR = static_cast< float >(r);
|
||||
c.mT = static_cast< float >(t);
|
||||
c.mL = cx.mL = static_cast< float >(l);
|
||||
c.mB = cx.mB = static_cast< float >(b);
|
||||
c.mR = cx.mR = static_cast< float >(r);
|
||||
c.mT = cx.mT = static_cast< float >(t);
|
||||
// Reserve area memory if requested
|
||||
c.mAreas.reserve(sz);
|
||||
// Reset the locks on this area
|
||||
c.mLocks = 0;
|
||||
// Set the row and column
|
||||
c.mRow = row;
|
||||
c.mCol = col++;
|
||||
// Advance the left side
|
||||
l = r;
|
||||
// Advance the right side
|
||||
@@ -203,6 +212,8 @@ AreaManager::AreaManager(size_t sz) noexcept
|
||||
t -= CELLD;
|
||||
}
|
||||
}
|
||||
// Advance row
|
||||
++row;
|
||||
}
|
||||
// Reserve some space in the queue
|
||||
m_Queue.reserve(128);
|
||||
@@ -340,6 +351,21 @@ void AreaManager::RemoveArea(Area & a)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Vector2i AreaManager::LocateCell(float x, float y)
|
||||
{
|
||||
for (int r = 0; r < GRIDN; ++r)
|
||||
{
|
||||
for (int c = 0; c < GRIDN; ++c)
|
||||
{
|
||||
auto & bb = m_Cells[r][c];
|
||||
// Check whether point is inside cell
|
||||
if (bb.mL <= x && bb.mR >= x && bb.mB <= y && bb.mT >= y)
|
||||
{
|
||||
return {r, c}; // Is inside
|
||||
}
|
||||
}
|
||||
}
|
||||
// Point is out of bounds
|
||||
return {NOCELL, NOCELL};
|
||||
/*
|
||||
// Transform the world coordinates into a cell coordinates
|
||||
// and cast to integral after rounding the value
|
||||
int xc = static_cast< int >(std::round(x / CELLD));
|
||||
@@ -364,6 +390,7 @@ Vector2i AreaManager::LocateCell(float x, float y)
|
||||
}
|
||||
// Return the identified cell row and column
|
||||
return {GRIDH+xc, GRIDH-yc};
|
||||
*/
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -469,6 +496,7 @@ void Register_Areas(HSQUIRRELVM vm)
|
||||
.Func(_SC("TestEx"), &Area::TestEx)
|
||||
.Func(_SC("Manage"), &Area::Manage)
|
||||
.Func(_SC("Unmanage"), &Area::Unmanage)
|
||||
.CbFunc(_SC("EachCell"), &Area::EachCell)
|
||||
// Static Functions
|
||||
.StaticFunc(_SC("GlobalTest"), &Areas_TestPoint)
|
||||
.StaticFunc(_SC("GlobalTestEx"), &Areas_TestPointEx)
|
||||
|
||||
+28
-4
@@ -29,15 +29,25 @@ struct AreaCell
|
||||
Areas mAreas; // Areas that intersect with the cell.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
int mLocks; // The amount of locks on the cell.
|
||||
int mRow; // Row location in the grid.
|
||||
int mCol; // Column location in the grid.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
AreaCell()
|
||||
: mL(0), mB(0), mR(0), mT(0), mAreas(0), mLocks(0)
|
||||
: mL(0), mB(0), mR(0), mT(0), mAreas(0), mLocks(0), mRow(0), mCol(0)
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Show information (mainly for debug purposes).
|
||||
*/
|
||||
String Dump()
|
||||
{
|
||||
return fmt::format("({} : {} | {} : {}) {} : {}", mL, mB, mR, mT, mRow, mCol);
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -454,6 +464,17 @@ struct Area
|
||||
*/
|
||||
bool Unmanage();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all managed cells through a functor.
|
||||
*/
|
||||
void EachCell(Function & fn) const
|
||||
{
|
||||
for (const auto & e : mCells)
|
||||
{
|
||||
fn.Execute(static_cast< SQInteger >(e->mRow), static_cast< SQInteger >(e->mCol));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -610,7 +631,10 @@ private:
|
||||
ProcList m_ProcList; // Actions ready to be completed.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
AreaCell m_Grid[GRIDN][GRIDN]; // A grid of area lists.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
struct {
|
||||
float mL, mB, mR, mT;
|
||||
} m_Cells[GRIDN][GRIDN];
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -664,7 +688,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Clear all cell lists and release any script references.
|
||||
*/
|
||||
static Vector2i LocateCell(float x, float y);
|
||||
Vector2i LocateCell(float x, float y);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Test a point to see whether it intersects with any areas
|
||||
@@ -679,7 +703,7 @@ public:
|
||||
return; // Not our problem
|
||||
}
|
||||
// Retrieve a reference to the identified cell
|
||||
AreaCell & c = m_Grid[cc.y][cc.x];
|
||||
AreaCell & c = m_Grid[cc.x][cc.y];
|
||||
// Is this cell empty?
|
||||
if (c.mAreas.empty())
|
||||
{
|
||||
|
||||
+21
-21
@@ -285,13 +285,13 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Make sure that the specified element is withing buffer range
|
||||
else if (n > (m_Cap - sizeof(T)))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Element of size (%d) at index (%u) is out of buffer capacity (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Element of size ({}) at index ({}) is out of buffer capacity ({})"),
|
||||
sizeof(T), n, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -306,13 +306,13 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Make sure that the specified element is withing buffer range
|
||||
else if (n > (m_Cap - sizeof(T)))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Element of size (%d) at index (%u) is out of buffer capacity (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Element of size ({}) at index ({}) is out of buffer capacity ({})"),
|
||||
sizeof(T), n, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -359,7 +359,7 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -374,7 +374,7 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -389,7 +389,7 @@ public:
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host two elements of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host two elements of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -404,7 +404,7 @@ public:
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host two elements of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host two elements of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -419,7 +419,7 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -434,7 +434,7 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -449,7 +449,7 @@ public:
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host two elements of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host two elements of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -464,7 +464,7 @@ public:
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host two elements of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host two elements of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -540,7 +540,7 @@ public:
|
||||
// Make sure that at least one element of this type exists after the cursor
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Element of size ({}) starting at ({}) exceeds buffer capacity ({})"),
|
||||
sizeof(T), m_Cur, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -555,7 +555,7 @@ public:
|
||||
// Make sure that at least one element of this type exists after the cursor
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Element of size ({}) starting at ({}) exceeds buffer capacity ({})"),
|
||||
sizeof(T), m_Cur, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -570,7 +570,7 @@ public:
|
||||
// The cursor must have at least one element of this type behind
|
||||
if (m_Cur < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Cannot read an element of size (%u) before the cursor at (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Cannot read an element of size ({}) before the cursor at ({})"),
|
||||
sizeof(T), m_Cur);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -585,7 +585,7 @@ public:
|
||||
// The cursor must have at least one element of this type behind
|
||||
if (m_Cur < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Cannot read an element of size (%u) before the cursor at (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Cannot read an element of size ({}) before the cursor at ({})"),
|
||||
sizeof(T), m_Cur);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -600,13 +600,13 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// There must be buffer left for at least two elements of this type after the cursor
|
||||
else if ((m_Cur + (sizeof(T) * 2)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Element of size ({}) starting at ({}) exceeds buffer capacity ({})"),
|
||||
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -621,13 +621,13 @@ public:
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of (%u) is unable to host an element of size (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Buffer capacity of ({}) is unable to host an element of size ({})"),
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// There must be buffer left for at least two elements of this type after the cursor
|
||||
else if ((m_Cur + (sizeof(T) * 2)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)"),
|
||||
ThrowMemExcept(fmt::runtime("Element of size ({}) starting at ({}) exceeds buffer capacity ({})"),
|
||||
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
@@ -708,7 +708,7 @@ public:
|
||||
// See if the requested capacity doesn't exceed the limit
|
||||
if (n > Max< T >())
|
||||
{
|
||||
ThrowMemExcept(fmt::runtime("Requested buffer of (%u) elements exceeds the (%u) limit"), n, Max< T >());
|
||||
ThrowMemExcept(fmt::runtime("Requested buffer of ({}) elements exceeds the ({}) limit"), n, Max< T >());
|
||||
}
|
||||
// Is there an existing buffer?
|
||||
else if (n && !m_Cap)
|
||||
|
||||
@@ -248,6 +248,14 @@ String SqTypeName(HSQUIRRELVM vm, SQInteger idx)
|
||||
return String(val.mPtr, static_cast< size_t >(val.mLen));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
String SqTypeName(HSQUIRRELVM vm, LightObj & obj)
|
||||
{
|
||||
const StackGuard sg(vm);
|
||||
sq_pushobject(vm, obj);
|
||||
return SqTypeName(vm, -1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj BufferToStrObj(const Buffer & b)
|
||||
{
|
||||
|
||||
+97
-2
@@ -40,6 +40,7 @@
|
||||
#include <sqratTable.h>
|
||||
#include <sqratUtil.h>
|
||||
#include <fmt/core.h>
|
||||
#include <rpmalloc.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
@@ -173,7 +174,7 @@ void OutputError(const char * msg, ...);
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Generate a formatted string and throw it as a Sqrat exception.
|
||||
*/
|
||||
template < class... Args > void SqThrowF(Args &&... args)
|
||||
template < class... Args > inline void SqThrowF(Args &&... args)
|
||||
{
|
||||
throw Sqrat::Exception(fmt::format(std::forward< Args >(args)...));
|
||||
}
|
||||
@@ -181,7 +182,7 @@ template < class... Args > void SqThrowF(Args &&... args)
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Generate a formatted string and throw it as a squirrel exception.
|
||||
*/
|
||||
template < class... Args > SQRESULT SqThrowErrorF(HSQUIRRELVM vm, Args &&... args)
|
||||
template < class... Args > inline SQRESULT SqThrowErrorF(HSQUIRRELVM vm, Args &&... args)
|
||||
{
|
||||
String msg;
|
||||
try
|
||||
@@ -241,6 +242,11 @@ SQMOD_NODISCARD const SQChar * SqTypeName(SQObjectType type);
|
||||
*/
|
||||
SQMOD_NODISCARD String SqTypeName(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Retrieve the string representation of a certain type from a script object.
|
||||
*/
|
||||
SQMOD_NODISCARD String SqTypeName(HSQUIRRELVM vm, LightObj & obj);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Create a script string instance from a buffer.
|
||||
*/
|
||||
@@ -266,4 +272,93 @@ SQMOD_NODISCARD SQFloat PopStackFloat(HSQUIRRELVM vm, SQInteger idx);
|
||||
*/
|
||||
SQMOD_NODISCARD bool SToB(const SQChar * str);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* RAII allocator initializer.
|
||||
*/
|
||||
struct RPMallocInit
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
RPMallocInit()
|
||||
{
|
||||
if (rpmalloc_initialize() != 0)
|
||||
{
|
||||
OutputError("Failed to initialize memory allocator");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor (disabled).
|
||||
*/
|
||||
RPMallocInit(const RPMallocInit &) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor (disabled).
|
||||
*/
|
||||
RPMallocInit(RPMallocInit &&) noexcept = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~RPMallocInit()
|
||||
{
|
||||
if (rpmalloc_is_thread_initialized()) rpmalloc_finalize();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator (disabled).
|
||||
*/
|
||||
RPMallocInit & operator = (const RPMallocInit &) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator (disabled).
|
||||
*/
|
||||
RPMallocInit & operator = (RPMallocInit &&) noexcept = delete;
|
||||
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* RAII allocator thread initializer.
|
||||
*/
|
||||
struct RPMallocThreadInit
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
RPMallocThreadInit()
|
||||
{
|
||||
rpmalloc_thread_initialize();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor (disabled).
|
||||
*/
|
||||
RPMallocThreadInit(const RPMallocThreadInit &) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor (disabled).
|
||||
*/
|
||||
RPMallocThreadInit(RPMallocThreadInit &&) noexcept = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~RPMallocThreadInit()
|
||||
{
|
||||
if (rpmalloc_is_thread_initialized()) rpmalloc_thread_finalize(1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator (disabled).
|
||||
*/
|
||||
RPMallocThreadInit & operator = (const RPMallocThreadInit &) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator (disabled).
|
||||
*/
|
||||
RPMallocThreadInit & operator = (RPMallocThreadInit &&) noexcept = delete;
|
||||
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
+41
-2
@@ -347,7 +347,7 @@ void Core::EmitIncomingConnection(char * player_name, size_t name_buffer_size, c
|
||||
// Release any stored buffer information
|
||||
m_IncomingNameBuffer = nullptr;
|
||||
m_IncomingNameCapacity = 0;
|
||||
// We catched the exception so we can release the assigned buffer
|
||||
// We caught the exception so we can release the assigned buffer
|
||||
throw; // re-throw it
|
||||
}
|
||||
// Release any stored buffer information
|
||||
@@ -392,7 +392,8 @@ void Core::EmitPlayerRequestSpawn(int32_t player_id)
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
if (IsOfficial())
|
||||
{
|
||||
ExecuteLegacyEvent(m_VM, _SC("onPlayerRequestSpawn"), _player.mLgObj);
|
||||
LightObj r = EvaluateLegacyEvent(m_VM, _SC("onPlayerRequestSpawn"), _player.mLgObj);
|
||||
SetState(r.IsNull() ? 1 : r.Cast< int32_t >());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2245,6 +2246,44 @@ void Core::EmitClientScriptData(int32_t player_id, const uint8_t * data, size_t
|
||||
m_ClientData.Release();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::EmitExtCommandReply(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
|
||||
{
|
||||
SQMOD_CO_EV_TRACEBACK("[TRACE<] Core::ExtCommandReply(%i, %i, %p, %zu)", sender, tag, data, size)
|
||||
// Don't even bother if there's no one listening
|
||||
if (!(mOnExtCommandReply.first->IsEmpty()))
|
||||
{
|
||||
// Allocate a buffer with the received size
|
||||
Buffer b(static_cast< Buffer::SzType >(size));
|
||||
// Replicate the data to the allocated buffer
|
||||
b.Write(0, reinterpret_cast< Buffer::ConstPtr >(data), static_cast< Buffer::SzType >(size));
|
||||
// Prepare an object for the obtained buffer
|
||||
LightObj obj(SqTypeIdentity< SqBuffer >{}, m_VM, std::move(b));
|
||||
// Forward the event call
|
||||
(*mOnExtCommandReply.first)(sender, tag, obj, size);
|
||||
}
|
||||
SQMOD_CO_EV_TRACEBACK("[TRACE>] Core::ExtCommandReply")
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Core::EmitExtCommandEvent(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
|
||||
{
|
||||
SQMOD_CO_EV_TRACEBACK("[TRACE<] Core::ExtCommandEvent(%i, %i, %p, %zu)", sender, tag, data, size)
|
||||
// Don't even bother if there's no one listening
|
||||
if (!(mOnExtCommandEvent.first->IsEmpty()))
|
||||
{
|
||||
// Allocate a buffer with the received size
|
||||
Buffer b(static_cast< Buffer::SzType >(size));
|
||||
// Replicate the data to the allocated buffer
|
||||
b.Write(0, reinterpret_cast< Buffer::ConstPtr >(data), static_cast< Buffer::SzType >(size));
|
||||
// Prepare an object for the obtained buffer
|
||||
LightObj obj(SqTypeIdentity< SqBuffer >{}, m_VM, std::move(b));
|
||||
// Forward the event call
|
||||
(*mOnExtCommandEvent.first)(sender, tag, obj, size);
|
||||
}
|
||||
SQMOD_CO_EV_TRACEBACK("[TRACE>] Core::ExtCommandEvent")
|
||||
}
|
||||
|
||||
#undef NULL_SQOBJ_ // don't need this anymore
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -1723,6 +1723,7 @@ void Register_Signal(HSQUIRRELVM vm)
|
||||
.SquirrelFunc(_SC("Eliminate"), &Signal::SqEliminate)
|
||||
.SquirrelFunc(_SC("EliminateThis"), &Signal::SqEliminateThis)
|
||||
.SquirrelFunc(_SC("EliminateFunc"), &Signal::SqEliminateFunc)
|
||||
.SquirrelFunc(_SC("Broadcast"), &Signal::SqEmit)
|
||||
.SquirrelFunc(_SC("Emit"), &Signal::SqEmit)
|
||||
.SquirrelFunc(_SC("Query"), &Signal::SqQuery)
|
||||
.SquirrelFunc(_SC("Consume"), &Signal::SqConsume)
|
||||
|
||||
@@ -103,7 +103,7 @@ void ThreadPool::Terminate(bool SQ_UNUSED_ARG(shutdown))
|
||||
// Is the item valid?
|
||||
if (item)
|
||||
{
|
||||
item->OnCompleted(); // Allow the item to finish itself
|
||||
[[maybe_unused]] auto _ = item->OnCompleted(true); // Allow the item to finish itself
|
||||
}
|
||||
// Item processed
|
||||
item.reset();
|
||||
@@ -125,7 +125,15 @@ void ThreadPool::Process()
|
||||
// Is the item valid?
|
||||
if (item)
|
||||
{
|
||||
item->OnCompleted(); // Allow the item to finish itself
|
||||
try {
|
||||
// Allow the item to finish itself
|
||||
if (item->OnCompleted(false))
|
||||
{
|
||||
Enqueue(std::move(item)); // Queue again
|
||||
}
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s completion stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,6 +146,8 @@ void ThreadPool::WorkerProc()
|
||||
bool retry = false;
|
||||
// Pointer to the dequeued item
|
||||
Item item;
|
||||
// Initialize third-party allocator for this thread
|
||||
auto rpmallocinit = std::make_unique< RPMallocThreadInit >();
|
||||
// Constantly process items from the queue
|
||||
while (true)
|
||||
{
|
||||
@@ -147,7 +157,11 @@ void ThreadPool::WorkerProc()
|
||||
// Is there an item that requested to try again?
|
||||
if (item)
|
||||
{
|
||||
try {
|
||||
item->OnAborted(true); // NOLINT(bugprone-use-after-move) There's an `if` condition above idiot!
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s cancelation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
}
|
||||
// Exit the loop
|
||||
break;
|
||||
@@ -173,15 +187,30 @@ void ThreadPool::WorkerProc()
|
||||
// Is there an item to be processed?
|
||||
if (item)
|
||||
{
|
||||
try {
|
||||
item->OnAborted(false); // It should mark itself as aborted somehow!
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s forced cancelation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
}
|
||||
// Exit the loop
|
||||
break;
|
||||
}
|
||||
bool r;
|
||||
// Attempt preparation
|
||||
try {
|
||||
r = item->OnPrepare();
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s preparation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
// Perform the task
|
||||
if (item->OnPrepare())
|
||||
if (r)
|
||||
{
|
||||
try {
|
||||
retry = item->OnProcess();
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s processing stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
}
|
||||
// The task was performed
|
||||
if (!retry)
|
||||
|
||||
+54
-11
@@ -55,6 +55,16 @@ struct ThreadPoolItem
|
||||
*/
|
||||
ThreadPoolItem & operator = (ThreadPoolItem && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide a name to what type of task this is. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD virtual const char * TypeName() noexcept { return "worker item"; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide unique information that may help identify the task. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD virtual const char * IdentifiableInfo() noexcept { return ""; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in worker thread by the thread pool after obtaining the task from the queue.
|
||||
* Must return true to indicate that the task can be performed. False indicates failure.
|
||||
@@ -69,8 +79,10 @@ struct ThreadPoolItem
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in main thread by the thread pool after the task was completed.
|
||||
* If it returns true then it will be put back into the queue to be processed again.
|
||||
* If the boolean parameter is true then the thread-pool is in the process of shutting down.
|
||||
*/
|
||||
virtual void OnCompleted() { }
|
||||
SQMOD_NODISCARD virtual bool OnCompleted(bool SQ_UNUSED_ARG(stop)) { return false; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Called in worker by the thread pool to let the task know that it will be aborted.
|
||||
@@ -98,13 +110,13 @@ private:
|
||||
* Destructor.
|
||||
*/
|
||||
~ThreadPool();
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
using Item = std::unique_ptr< ThreadPoolItem >; // Owning pointer of an item.
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
using Pool = std::vector< std::thread >; // Worker container.
|
||||
using Item = std::unique_ptr< ThreadPoolItem >; // Owning pointer of an item.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
using Finished = moodycamel::ConcurrentQueue< Item >; // Finished items.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@@ -171,9 +183,25 @@ public:
|
||||
void Process();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Queue an item to be processed.
|
||||
* Queue an item to be processed. Will take ownership of the given pointer!
|
||||
*/
|
||||
void Enqueue(ThreadPoolItem * item)
|
||||
{
|
||||
Enqueue(Item{item});
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Queue an item to be processed. Will take ownership of the given pointer!
|
||||
*/
|
||||
template < class T > void CastEnqueue(std::unique_ptr< T > && item)
|
||||
{
|
||||
Enqueue(Item{std::forward< std::unique_ptr< T > >(item)});
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Queue an item to be processed. Will take ownership of the given pointer!
|
||||
*/
|
||||
void Enqueue(Item && item)
|
||||
{
|
||||
// Only queue valid items
|
||||
if (!item || !m_Running) return;
|
||||
@@ -183,7 +211,7 @@ public:
|
||||
// Acquire a lock on the mutex
|
||||
std::unique_lock< std::mutex > lock(m_Mutex);
|
||||
// Push the item in the queue
|
||||
m_Queue.push(Item(item));
|
||||
m_Queue.push(std::forward< Item >(item));
|
||||
// Release the mutex before notifying
|
||||
lock.unlock();
|
||||
// Notify one thread that there's work
|
||||
@@ -191,16 +219,32 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
bool r;
|
||||
// Attempt preparation
|
||||
try {
|
||||
r = item->OnPrepare();
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s preparation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
// Perform the task in-place
|
||||
if (item->OnPrepare())
|
||||
if (r)
|
||||
{
|
||||
if (item->OnProcess())
|
||||
try {
|
||||
r = item->OnProcess();
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s processing stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
if (r)
|
||||
{
|
||||
try {
|
||||
item->OnAborted(true); // Not accepted in single thread
|
||||
} catch (const std::exception & e) {
|
||||
LogErr("Exception occured in %s cancelation stage [%s] for [%s]", item->TypeName(), e.what(), item->IdentifiableInfo());
|
||||
}
|
||||
}
|
||||
// Item was finished in main thread
|
||||
item->OnCompleted();
|
||||
}
|
||||
// Task is completed in processing stage
|
||||
m_Finished.enqueue(std::forward< Item >(item));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +255,6 @@ public:
|
||||
{
|
||||
return m_Threads.size();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -251,6 +251,20 @@ template < class Key, class T, class Pred = std::equal_to< Key > > struct VecMap
|
||||
return m_Storage.back().second;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieves a reference to the front of the container.
|
||||
* Available for internal use only.
|
||||
*/
|
||||
reference front() { return m_Storage.front(); }
|
||||
const_reference front() const { return m_Storage.front(); }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieves a reference to the back of the container.
|
||||
* Available for internal use only.
|
||||
*/
|
||||
reference back() { return m_Storage.back(); }
|
||||
const_reference back() const { return m_Storage.back(); }
|
||||
|
||||
private:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -468,6 +468,16 @@ void CCheckpoint::SetColorA(int32_t a) const
|
||||
// Perform the requested operation
|
||||
_Func->SetCheckPointColour(m_ID, r, g, b, a);
|
||||
}
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj & CCheckpoint::GetLegacyObject() const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Core::Get().GetCheckpoint(m_ID).mLgObj;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & Checkpoint_CreateEx1a(int32_t world, bool sphere, float x, float y, float z,
|
||||
@@ -517,6 +527,9 @@ void Register_CCheckpoint(HSQUIRRELVM vm)
|
||||
.Prop(_SC("Tag"), &CCheckpoint::GetTag, &CCheckpoint::SetTag)
|
||||
.Prop(_SC("Data"), &CCheckpoint::GetData, &CCheckpoint::SetData)
|
||||
.Prop(_SC("Active"), &CCheckpoint::IsActive)
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
.Prop(_SC("Legacy"), &CCheckpoint::GetLegacyObject)
|
||||
#endif
|
||||
// Core Methods
|
||||
.FmtFunc(_SC("SetTag"), &CCheckpoint::ApplyTag)
|
||||
.Func(_SC("CustomEvent"), &CCheckpoint::CustomEvent)
|
||||
|
||||
@@ -320,6 +320,12 @@ public:
|
||||
* Modify the alpha transparency of the managed checkpoint entity.
|
||||
*/
|
||||
void SetColorA(int32_t a) const;
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve legacy object instance for this entity.
|
||||
*/
|
||||
LightObj & GetLegacyObject() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -833,6 +833,16 @@ void CObject::RotateByEulerZ(float z) const
|
||||
// Perform the requested operation
|
||||
_Func->RotateObjectByEuler(m_ID, 0.0f, 0.0f, z, mRotateByEulerDuration);
|
||||
}
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj & CObject::GetLegacyObject() const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Core::Get().GetObj(m_ID).mLgObj;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & Object_CreateEx1a(int32_t model, int32_t world, float x, float y, float z,
|
||||
@@ -883,6 +893,9 @@ void Register_CObject(HSQUIRRELVM vm)
|
||||
.Prop(_SC("Tag"), &CObject::GetTag, &CObject::SetTag)
|
||||
.Prop(_SC("Data"), &CObject::GetData, &CObject::SetData)
|
||||
.Prop(_SC("Active"), &CObject::IsActive)
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
.Prop(_SC("Legacy"), &CObject::GetLegacyObject)
|
||||
#endif
|
||||
// Core Methods
|
||||
.FmtFunc(_SC("SetTag"), &CObject::ApplyTag)
|
||||
.Func(_SC("CustomEvent"), &CObject::CustomEvent)
|
||||
|
||||
@@ -499,6 +499,12 @@ public:
|
||||
* Modify the rotation on the z axis of the managed object entity.
|
||||
*/
|
||||
void RotateByEulerZ(float z) const;
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve legacy object instance for this entity.
|
||||
*/
|
||||
LightObj & GetLegacyObject() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -449,6 +449,16 @@ void CPickup::SetPositionZ(float z) const
|
||||
// Perform the requested operation
|
||||
_Func->SetPickupPosition(m_ID, z, y, z);
|
||||
}
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj & CPickup::GetLegacyObject() const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Core::Get().GetPickup(m_ID).mLgObj;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & Pickup_CreateEx1a(int32_t model, int32_t world, int32_t quantity,
|
||||
@@ -496,6 +506,9 @@ void Register_CPickup(HSQUIRRELVM vm)
|
||||
.Prop(_SC("Tag"), &CPickup::GetTag, &CPickup::SetTag)
|
||||
.Prop(_SC("Data"), &CPickup::GetData, &CPickup::SetData)
|
||||
.Prop(_SC("Active"), &CPickup::IsActive)
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
.Prop(_SC("Legacy"), &CPickup::GetLegacyObject)
|
||||
#endif
|
||||
// Core Methods
|
||||
.FmtFunc(_SC("SetTag"), &CPickup::ApplyTag)
|
||||
.Func(_SC("CustomEvent"), &CPickup::CustomEvent)
|
||||
|
||||
@@ -298,6 +298,12 @@ public:
|
||||
* Modify the position on the z axis of the managed pickup entity.
|
||||
*/
|
||||
void SetPositionZ(float z) const;
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve legacy object instance for this entity.
|
||||
*/
|
||||
LightObj & GetLegacyObject() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -2593,7 +2593,16 @@ SQInteger CPlayer::AnnounceEx(HSQUIRRELVM vm)
|
||||
// This function does not return a value
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj & CPlayer::GetLegacyObject() const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Core::Get().GetPlayer(m_ID).mLgObj;
|
||||
}
|
||||
#endif
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger Player_FindAuto(HSQUIRRELVM vm)
|
||||
{
|
||||
@@ -2793,6 +2802,9 @@ void Register_CPlayer(HSQUIRRELVM vm)
|
||||
.Prop(_SC("Tag"), &CPlayer::GetTag, &CPlayer::SetTag)
|
||||
.Prop(_SC("Data"), &CPlayer::GetData, &CPlayer::SetData)
|
||||
.Prop(_SC("Active"), &CPlayer::IsActive)
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
.Prop(_SC("Legacy"), &CPlayer::GetLegacyObject)
|
||||
#endif
|
||||
// Core Methods
|
||||
.FmtFunc(_SC("SetTag"), &CPlayer::ApplyTag)
|
||||
.Func(_SC("CustomEvent"), &CPlayer::CustomEvent)
|
||||
|
||||
@@ -1101,6 +1101,12 @@ public:
|
||||
* Send a formatted announcement message to the managed player entity.
|
||||
*/
|
||||
static SQInteger AnnounceEx(HSQUIRRELVM vm);
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve legacy object instance for this entity.
|
||||
*/
|
||||
LightObj & GetLegacyObject() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -2015,6 +2015,16 @@ void CVehicle::SetRelativeTurnSpeedZ(float z) const
|
||||
// Perform the requested operation
|
||||
_Func->SetVehicleTurnSpeed(m_ID, z, y, z, static_cast< uint8_t >(false), static_cast< uint8_t >(true));
|
||||
}
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj & CVehicle::GetLegacyObject() const
|
||||
{
|
||||
// Validate the managed identifier
|
||||
Validate();
|
||||
// Return the requested information
|
||||
return Core::Get().GetVehicle(m_ID).mLgObj;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & Vehicle_CreateEx1a(int32_t model, int32_t world, float x, float y, float z, float angle,
|
||||
@@ -2061,6 +2071,9 @@ void Register_CVehicle(HSQUIRRELVM vm)
|
||||
.Prop(_SC("ID"), &CVehicle::GetID)
|
||||
.Prop(_SC("Tag"), &CVehicle::GetTag, &CVehicle::SetTag)
|
||||
.Prop(_SC("Data"), &CVehicle::GetData, &CVehicle::SetData)
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
.Prop(_SC("Legacy"), &CVehicle::GetLegacyObject)
|
||||
#endif
|
||||
.Prop(_SC("Active"), &CVehicle::IsActive)
|
||||
// Core Methods
|
||||
.FmtFunc(_SC("SetTag"), &CVehicle::ApplyTag)
|
||||
|
||||
@@ -942,6 +942,12 @@ public:
|
||||
* Modify the relative turn velocity on the z axis of the managed vehicle entity.
|
||||
*/
|
||||
void SetRelativeTurnSpeedZ(float z) const;
|
||||
#ifdef VCMP_ENABLE_OFFICIAL
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve legacy object instance for this entity.
|
||||
*/
|
||||
LightObj & GetLegacyObject() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstring>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sqmod.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static int32_t RegisterCommandFn(ExtPluginCommand_t fn)
|
||||
{
|
||||
return Core::Get().RegisterExtCommand(fn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static int32_t UnregisterCommandFn(ExtPluginCommand_t fn)
|
||||
{
|
||||
return Core::Get().UnregisterExtCommand(fn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static int32_t SendCommandFn(int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size)
|
||||
{
|
||||
return Core::Get().SendExtCommand(target, req, tag, data, size);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static int32_t SendCommandReplyFn(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
|
||||
{
|
||||
// Mark the initialization as successful by default
|
||||
const CoreState cs(SQMOD_SUCCESS);
|
||||
// Forward the call to the script callbacks
|
||||
Core::Get().EmitExtCommandReply(sender, tag, data, size);
|
||||
// Return the last known plug-in state
|
||||
return Core::Get().GetState();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static int32_t SendCommandEventFn(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
|
||||
{
|
||||
// Mark the initialization as successful by default
|
||||
const CoreState cs(SQMOD_SUCCESS);
|
||||
// Forward the call to the script callbacks
|
||||
Core::Get().EmitExtCommandEvent(sender, tag, data, size);
|
||||
// Return the last known plug-in state
|
||||
return Core::Get().GetState();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const SQ_MOD_EXPORTS g_SqModExports{
|
||||
sizeof(SQ_MOD_EXPORTS),
|
||||
&RegisterCommandFn,
|
||||
&UnregisterCommandFn,
|
||||
&SendCommandFn,
|
||||
&SendCommandReplyFn,
|
||||
&SendCommandEventFn
|
||||
};
|
||||
|
||||
// The server needs a pointer to a pointer, and a persistent one
|
||||
static const SQ_MOD_EXPORTS * g_SqModExportsPtr = &g_SqModExports;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void InitExports()
|
||||
{
|
||||
// Tell the server about the pointer to the exports structure
|
||||
_Func->ExportFunctions(_Info->pluginId, reinterpret_cast< const void ** >(&g_SqModExportsPtr), sizeof(HSQ_MOD_EXPORTS));
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -47,9 +47,11 @@ struct CpBaseAction : public ThreadPoolItem
|
||||
~CpBaseAction() override = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Task completed callback.
|
||||
* Invoked in main thread by the thread pool after the task was completed.
|
||||
* If it returns true then it will be put back into the queue to be processed again.
|
||||
* If the boolean parameter is trye then the thread-pool is in the process of shutting down.
|
||||
*/
|
||||
void OnCompleted() override
|
||||
SQMOD_NODISCARD bool OnCompleted(bool SQ_UNUSED_ARG(stop)) override
|
||||
{
|
||||
// Is there a callback?
|
||||
if (!mCallback.IsNull())
|
||||
@@ -58,6 +60,8 @@ struct CpBaseAction : public ThreadPoolItem
|
||||
}
|
||||
// Unlock the session
|
||||
mInstance->mPending = nullptr;
|
||||
// Don't re-queue
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <Poco/Checksum.h>
|
||||
#include <Poco/Base32Encoder.h>
|
||||
#include <Poco/Base32Decoder.h>
|
||||
#include <Poco/Base64Encoder.h>
|
||||
#include <Poco/Base64Decoder.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sstream>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
@@ -30,7 +37,7 @@ SQInteger SqBuffer::WriteRawString(StackStrF & val) const
|
||||
}
|
||||
// Calculate the string length
|
||||
Buffer::SzType length = ConvTo< Buffer::SzType >::From(val.mLen);
|
||||
// Write the the string contents
|
||||
// Write the string contents
|
||||
m_Buffer->AppendS(val.mPtr, length);
|
||||
// Return the length of the written string
|
||||
return val.mLen;
|
||||
@@ -224,7 +231,7 @@ AABB SqBuffer::ReadAABB() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< AABB >(1);
|
||||
// Return the requested information
|
||||
return AABB(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -237,7 +244,7 @@ Circle SqBuffer::ReadCircle() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Circle >(1);
|
||||
// Return the requested information
|
||||
return Circle(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -250,7 +257,7 @@ Color3 SqBuffer::ReadColor3() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Color3 >(1);
|
||||
// Return the requested information
|
||||
return Color3(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -263,7 +270,7 @@ Color4 SqBuffer::ReadColor4() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Color4 >(1);
|
||||
// Return the requested information
|
||||
return Color4(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -276,7 +283,7 @@ Quaternion SqBuffer::ReadQuaternion() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Quaternion >(1);
|
||||
// Return the requested information
|
||||
return Quaternion(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -289,7 +296,7 @@ Sphere SqBuffer::ReadSphere() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Sphere >(1);
|
||||
// Return the requested information
|
||||
return Sphere(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -302,7 +309,7 @@ Vector2 SqBuffer::ReadVector2() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Vector2 >(1);
|
||||
// Return the requested information
|
||||
return Vector2(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -315,7 +322,7 @@ Vector2i SqBuffer::ReadVector2i() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Vector2i >(1);
|
||||
// Return the requested information
|
||||
return Vector2i(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -328,7 +335,7 @@ Vector3 SqBuffer::ReadVector3() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Vector3 >(1);
|
||||
// Return the requested information
|
||||
return Vector3(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -341,7 +348,34 @@ Vector4 SqBuffer::ReadVector4() const
|
||||
// Advance the buffer cursor
|
||||
m_Buffer->Advance< Vector4 >(1);
|
||||
// Return the requested information
|
||||
return Vector4(value);
|
||||
return {value};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern SQInteger SqFromNativeJSON(HSQUIRRELVM vm, const char * data, size_t size);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger SqBuffer::GetJSON(HSQUIRRELVM vm) const
|
||||
{
|
||||
// Remember the current stack size
|
||||
const SQInteger top = sq_gettop(vm);
|
||||
// Was the JSON string size specified?
|
||||
if (top < 2)
|
||||
{
|
||||
return sq_throwerror(vm, _SC("Please specify the size of the JSON string to parse"));
|
||||
}
|
||||
// Do we even point to a valid buffer?
|
||||
if (!m_Buffer)
|
||||
{
|
||||
return sq_throwerror(vm, _SC("Invalid memory buffer reference"));
|
||||
}
|
||||
// Validate the buffer itself
|
||||
else if (!(*m_Buffer))
|
||||
{
|
||||
return sq_throwerror(vm, _SC("Invalid memory buffer"));
|
||||
}
|
||||
// Attempt to create the JSON object and push it on the stack
|
||||
return SqFromNativeJSON(vm, &m_Buffer->Cursor< char >(), static_cast< size_t >(Var< SQInteger >{vm, 2}.value));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -352,7 +386,7 @@ SQInteger SqBuffer::GetCRC32(SQInteger n) const
|
||||
// Create the checksum computer
|
||||
Poco::Checksum c(Poco::Checksum::TYPE_CRC32);
|
||||
// Give it the data to process
|
||||
c.update(&m_Buffer->Cursor< char >(), n >= 0 ? static_cast< uint32_t >(n) : m_Buffer->Remaining());
|
||||
c.update(&m_Buffer->Cursor< char >(), ClampRemaining(n));
|
||||
// return the result
|
||||
return static_cast< SQInteger >(c.checksum());
|
||||
}
|
||||
@@ -365,12 +399,46 @@ SQInteger SqBuffer::GetADLER32(SQInteger n) const
|
||||
// Create the checksum computer
|
||||
Poco::Checksum c(Poco::Checksum::TYPE_ADLER32);
|
||||
// Give it the data to process
|
||||
c.update(&m_Buffer->Cursor< char >(), n >= 0 ? static_cast< uint32_t >(n) : m_Buffer->Remaining());
|
||||
c.update(&m_Buffer->Cursor< char >(), ClampRemaining(n));
|
||||
// return the result
|
||||
return static_cast< SQInteger >(c.checksum());
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqBuffer::GetBase32(SQInteger n) const
|
||||
{
|
||||
// Validate the managed buffer reference
|
||||
ValidateDeeper();
|
||||
// Create a string receiver
|
||||
std::ostringstream out;
|
||||
// Create the encoder
|
||||
Poco::Base32Encoder enc(out);
|
||||
// Encode the string
|
||||
enc.write(&m_Buffer->Cursor< char >(), ClampRemaining(n));
|
||||
// Close the encoder
|
||||
enc.close();
|
||||
// Return the resulted string
|
||||
return LightObj{out.str()};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqBuffer::GetBase64(SQInteger n) const
|
||||
{
|
||||
// Validate the managed buffer reference
|
||||
ValidateDeeper();
|
||||
// Create a string receiver
|
||||
std::ostringstream out;
|
||||
// Create the encoder
|
||||
Poco::Base64Encoder enc(out);
|
||||
// Encode the string
|
||||
enc.write(&m_Buffer->Cursor< char >(), ClampRemaining(n));
|
||||
// Close the encoder
|
||||
enc.close();
|
||||
// Return the resulted string
|
||||
return LightObj{out.str()};
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
void Register_Buffer(HSQUIRRELVM vm)
|
||||
{
|
||||
@@ -457,6 +525,9 @@ void Register_Buffer(HSQUIRRELVM vm)
|
||||
.Func(_SC("ReadVector4"), &SqBuffer::ReadVector4)
|
||||
.Func(_SC("CRC32"), &SqBuffer::GetCRC32)
|
||||
.Func(_SC("ADLER32"), &SqBuffer::GetADLER32)
|
||||
.Func(_SC("Base32"), &SqBuffer::GetBase32)
|
||||
.Func(_SC("Base64"), &SqBuffer::GetBase64)
|
||||
.SquirrelMethod< SqBuffer, &SqBuffer::GetJSON >(_SC("GetJSON"))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,24 @@ public:
|
||||
return *m_Buffer;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Limit the specified amount at to the range of the cursor and the end of the buffer.
|
||||
*/
|
||||
SQMOD_NODISCARD SzType ClampRemaining(SQInteger n) const
|
||||
{
|
||||
// Do we even specify a buffer amount?
|
||||
if (n >= 0)
|
||||
{
|
||||
// Is it within the range we currently have left?
|
||||
if (static_cast< SzType >(n) <= m_Buffer->Remaining())
|
||||
{
|
||||
return static_cast< SzType >(n);
|
||||
}
|
||||
}
|
||||
// Fall back to the actual remaining data
|
||||
return m_Buffer->Remaining();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a certain element type at the specified position.
|
||||
*/
|
||||
@@ -276,33 +294,41 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Reposition the edit cursor to the specified number of elements ahead.
|
||||
*/
|
||||
void Advance(SQInteger n) const
|
||||
SqBuffer & Advance(SQInteger n)
|
||||
{
|
||||
Valid().Advance(ConvTo< SzType >::From(n));
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Reposition the edit cursor to the specified number of elements behind.
|
||||
*/
|
||||
void Retreat(SQInteger n) const
|
||||
SqBuffer & Retreat(SQInteger n)
|
||||
{
|
||||
Valid().Retreat(ConvTo< SzType >::From(n));
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Reposition the edit cursor to a fixed position within the buffer.
|
||||
*/
|
||||
void Move(SQInteger n) const
|
||||
SqBuffer & Move(SQInteger n)
|
||||
{
|
||||
Valid().Move(ConvTo< SzType >::From(n));
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Append a value to the current cursor location and advance the cursor.
|
||||
*/
|
||||
void Push(SQInteger v) const
|
||||
SqBuffer & Push(SQInteger v)
|
||||
{
|
||||
Valid().Push(ConvTo< Value >::From(v));
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -396,15 +422,17 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Grow the size of the internal buffer by the specified amount of bytes.
|
||||
*/
|
||||
void Grow(SQInteger n) const
|
||||
SqBuffer & Grow(SQInteger n)
|
||||
{
|
||||
return Valid().Grow(ConvTo< SzType >::From(n) * sizeof(Value));
|
||||
Valid().Grow(ConvTo< SzType >::From(n) * sizeof(Value));
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Makes sure there is enough capacity to hold the specified element count.
|
||||
*/
|
||||
void Adjust(SQInteger n)
|
||||
SqBuffer & Adjust(SQInteger n)
|
||||
{
|
||||
// Validate the managed buffer reference
|
||||
Validate();
|
||||
@@ -420,6 +448,8 @@ public:
|
||||
{
|
||||
STHROWF("{}", e.what()); // Re-package
|
||||
}
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -752,6 +782,12 @@ public:
|
||||
*/
|
||||
SQMOD_NODISCARD Vector4 ReadVector4() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Transform a portion of the data in the buffer to a JSON object.
|
||||
* This has the benefit that a temporary string doesn't have to be created.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetJSON(HSQUIRRELVM vm) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Compute the CRC-32 checksums on the data in the buffer.
|
||||
*/
|
||||
@@ -761,6 +797,16 @@ public:
|
||||
* Compute the Adler-32 checksums on the data in the buffer.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetADLER32(SQInteger n) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Encode the specified range of data as base32 and return it.
|
||||
*/
|
||||
SQMOD_NODISCARD LightObj GetBase32(SQInteger n) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Encode the specified range of data as base64 and return it.
|
||||
*/
|
||||
SQMOD_NODISCARD LightObj GetBase64(SQInteger n) const;
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
+608
-5
@@ -2,6 +2,7 @@
|
||||
#include "Library/JSON.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sajson.h>
|
||||
#include <sqratConst.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -11,13 +12,10 @@
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqToJSON(HSQUIRRELVM vm) noexcept
|
||||
{
|
||||
return sq_throwerror(vm, _SC("Not implemented yet!"));
|
||||
}
|
||||
SQMOD_DECL_TYPENAME(SqCtxJSON, _SC("SqCtxJSON"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqFromJson_Push(HSQUIRRELVM vm, const sajson::value & node) noexcept
|
||||
static SQInteger SqFromJson_Push(HSQUIRRELVM vm, const sajson::value & node) noexcept // NOLINT(misc-no-recursion)
|
||||
{
|
||||
// Operation result
|
||||
SQInteger r = SQ_OK;
|
||||
@@ -151,11 +149,616 @@ static SQInteger SqFromJSON(HSQUIRRELVM vm) noexcept
|
||||
return SQ_SUCCEEDED(r) ? 1 : r;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQInteger SqFromNativeJSON(HSQUIRRELVM vm, const char * data, size_t size)
|
||||
{
|
||||
// Attempt to parse the specified JSON string
|
||||
const sajson::document & document = sajson::parse(sajson::dynamic_allocation(), sajson::string(data, size));
|
||||
// See if there was an error
|
||||
if (!document.is_valid())
|
||||
{
|
||||
return sq_throwerror(vm, document.get_error_message_as_cstring());
|
||||
}
|
||||
// Process the nodes that were parsed from the string
|
||||
SQInteger r = SqFromJson_Push(vm, document.get_root());
|
||||
// We either have a value to return or we propagate some error
|
||||
return SQ_SUCCEEDED(r) ? 1 : r;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::OpenArray()
|
||||
{
|
||||
// Add the array-begin character
|
||||
mOutput.push_back('[');
|
||||
// Go forward one level
|
||||
Advance();
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::CloseArray()
|
||||
{
|
||||
// If the last character is a comma then replace it
|
||||
if (mOutput.back() == ',')
|
||||
{
|
||||
mOutput.back() = ']';
|
||||
}
|
||||
// Append the array-end character
|
||||
else
|
||||
{
|
||||
mOutput.push_back(']');
|
||||
}
|
||||
// Move the comma after the closing character
|
||||
mOutput.push_back(',');
|
||||
// Go back one level
|
||||
Retreat();
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::ReopenArray()
|
||||
{
|
||||
// If the last character is a comma then remove it
|
||||
if (mOutput.back() == ',')
|
||||
{
|
||||
mOutput.pop_back();
|
||||
}
|
||||
// If the last character is the array-end character then replace it with a comma
|
||||
if (mOutput.back() == ']')
|
||||
{
|
||||
mOutput.back() = ',';
|
||||
}
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::OpenObject()
|
||||
{
|
||||
// Add the object-begin character
|
||||
mOutput.push_back('{');
|
||||
// Go forward one level
|
||||
Advance();
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::CloseObject()
|
||||
{
|
||||
// If the last character is a comma then replace it
|
||||
if (mOutput.back() == ',')
|
||||
{
|
||||
mOutput.back() = '}';
|
||||
}
|
||||
// Append the object-end character
|
||||
else
|
||||
{
|
||||
mOutput.push_back('}');
|
||||
}
|
||||
// Move the comma after the closing character
|
||||
mOutput.push_back(',');
|
||||
// Go back one level
|
||||
Retreat();
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::ReopenObject()
|
||||
{
|
||||
// If the last character is a comma then remove it
|
||||
if (mOutput.back() == ',')
|
||||
{
|
||||
mOutput.pop_back();
|
||||
}
|
||||
// If the last character is the object-end character then replace it with a comma
|
||||
if (mOutput.back() == '}')
|
||||
{
|
||||
mOutput.back() = ',';
|
||||
}
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::MakeKey()
|
||||
{
|
||||
// If the last character is a comma then replace it
|
||||
if (mOutput.back() == ',')
|
||||
{
|
||||
mOutput.back() = ':';
|
||||
}
|
||||
// Append the array-end character
|
||||
else
|
||||
{
|
||||
mOutput.push_back(':');
|
||||
}
|
||||
// Allow the hook to react
|
||||
if (mKeyHook)
|
||||
{
|
||||
mKeyHook(*this);
|
||||
}
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool CtxJSON::CheckWeakRefWrap(HSQUIRRELVM vm, SQInteger idx) noexcept
|
||||
{
|
||||
SQRESULT r = sq_getweakrefval(vm, idx);
|
||||
// Whether the type doesn't have to be wrapped
|
||||
bool w = true;
|
||||
// Attempt to grab the value pointed by the weak reference
|
||||
if (SQ_SUCCEEDED(r))
|
||||
{
|
||||
// Attempt to serialize the actual value
|
||||
w = sq_gettype(vm, -1) != OT_TABLE && sq_gettype(vm, -1) != OT_ARRAY && sq_gettype(vm, -1) == OT_INSTANCE;
|
||||
// Pop the referenced value
|
||||
sq_poptop(vm);
|
||||
}
|
||||
// Wrap the value by default
|
||||
return w;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::SerializeParams(HSQUIRRELVM vm)
|
||||
{
|
||||
bool wrap_everything_in_array = false;
|
||||
// Clear the output buffer if necessary
|
||||
mOutput.clear();
|
||||
mDepth = 0;
|
||||
// Fetch the number of objects on the stack
|
||||
const auto top = sq_gettop(vm);
|
||||
// If there's more than one argument then they all get wrapped inside an array
|
||||
// If there is one argument and is not an array, table or instance then do the same
|
||||
if (top > 2 || (sq_gettype(vm, 2) != OT_TABLE &&
|
||||
sq_gettype(vm, 2) != OT_ARRAY &&
|
||||
sq_gettype(vm, 2) != OT_INSTANCE &&
|
||||
CheckWeakRefWrap(vm, 2)))
|
||||
{
|
||||
wrap_everything_in_array = true;
|
||||
// Open an array
|
||||
OpenArray();
|
||||
}
|
||||
// Serialize every specified argument
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
if (SQRESULT r = SerializeAt(vm, i); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Was everything wrapped inside an array?
|
||||
if (wrap_everything_in_array)
|
||||
{
|
||||
CloseArray();
|
||||
}
|
||||
// Remove trailing separator, if any
|
||||
if (mOutput.back() == ',')
|
||||
{
|
||||
mOutput.pop_back();
|
||||
}
|
||||
// Push the output string on the stack
|
||||
sq_pushstring(vm, mOutput.c_str(), static_cast< SQInteger >(mOutput.size()));
|
||||
// Specify that we have a value on the stack
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::SerializeAt(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
|
||||
{
|
||||
// Identify object type
|
||||
switch (sq_gettype(vm, idx))
|
||||
{
|
||||
case OT_NULL: {
|
||||
PushNull();
|
||||
} break;
|
||||
case OT_INTEGER: {
|
||||
SQInteger v;
|
||||
// Attempt to retrieve the value from the stack
|
||||
if (SQRESULT r = sq_getinteger(vm, idx, &v); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
// Write the value in the output
|
||||
PushInteger(v);
|
||||
} break;
|
||||
case OT_FLOAT: {
|
||||
SQFloat v;
|
||||
// Attempt to retrieve the value from the stack
|
||||
if (SQRESULT r = sq_getfloat(vm, idx, &v); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
// Write the value in the output
|
||||
#ifdef SQUSEDOUBLE
|
||||
PushDouble(v);
|
||||
#else
|
||||
PushFloat(v);
|
||||
#endif
|
||||
} break;
|
||||
case OT_BOOL: {
|
||||
SQBool v;
|
||||
// Attempt to retrieve the value from the stack
|
||||
if (SQRESULT r = sq_getbool(vm, idx, &v); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
// Write the value in the output
|
||||
PushBool(v != SQFalse);
|
||||
} break;
|
||||
case OT_STRING: {
|
||||
const SQChar * v = nullptr;
|
||||
SQInteger n = 0;
|
||||
// Attempt to retrieve and convert the string
|
||||
if (SQRESULT r = sq_getstringandsize(vm, idx, &v, &n); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
// Write the value in the output
|
||||
PushString(v, static_cast< size_t >(n));
|
||||
} break;
|
||||
case OT_TABLE: {
|
||||
if (SQRESULT r = SerializeTable(vm, idx); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
} break;
|
||||
case OT_ARRAY: {
|
||||
if (SQRESULT r = SerializeArray(vm, idx); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
} break;
|
||||
case OT_INSTANCE: {
|
||||
if (SQRESULT r = SerializeInstance(vm, idx); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
} break;
|
||||
case OT_WEAKREF: {
|
||||
if (SQRESULT r = SerializeWeakRef(vm, idx); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
} break;
|
||||
case OT_USERDATA:
|
||||
case OT_CLOSURE:
|
||||
case OT_NATIVECLOSURE:
|
||||
case OT_GENERATOR:
|
||||
case OT_USERPOINTER:
|
||||
case OT_THREAD:
|
||||
case OT_FUNCPROTO:
|
||||
case OT_CLASS:
|
||||
case OT_OUTER:
|
||||
return sq_throwerrorf(vm, _SC("Type (%s) is not serializable"), SqTypeName(sq_gettype(vm, 2)));
|
||||
}
|
||||
// Serialization was successful
|
||||
return SQ_OK;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::SerializeArray(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
|
||||
{
|
||||
// Begin array scope
|
||||
OpenArray();
|
||||
// Push null to initiate iteration
|
||||
sq_pushnull(vm);
|
||||
// So we can use absolute stack indexes to avoid errors
|
||||
const auto top = sq_gettop(vm);
|
||||
// Start iterating the array at the specified position in the stack
|
||||
for(SQRESULT r = SQ_OK; SQ_SUCCEEDED(sq_next(vm, idx));)
|
||||
{
|
||||
// Attempt serialization of the currently iterated value
|
||||
r = SerializeAt(vm, top + 2);
|
||||
// Check for failures
|
||||
if (SQ_FAILED(r))
|
||||
{
|
||||
// Pop the null iterator, key and value from the stack
|
||||
sq_pop(vm, 3);
|
||||
// Propagate the error
|
||||
return r;
|
||||
}
|
||||
// Pop the key and value from the stack (i.e. cleanup after `sq_next`)
|
||||
sq_pop(vm, 2);
|
||||
}
|
||||
// Pop the null iterator
|
||||
sq_poptop(vm);
|
||||
// Close array scope
|
||||
CloseArray();
|
||||
// Serialization was successful
|
||||
return SQ_OK;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::SerializeTable(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
|
||||
{
|
||||
// Begin object scope
|
||||
OpenObject();
|
||||
// Push null to initiate iteration
|
||||
sq_pushnull(vm);
|
||||
// So we can use absolute stack indexes to avoid errors
|
||||
const auto top = sq_gettop(vm);
|
||||
// Start iterating the object at the specified position in the stack
|
||||
for(SQRESULT r = SQ_OK; SQ_SUCCEEDED(sq_next(vm, idx));)
|
||||
{
|
||||
if (sq_gettype(vm, -2) == OT_STRING)
|
||||
{
|
||||
// Attempt serialization of the currently iterated element key
|
||||
r = SerializeAt(vm, top + 1);
|
||||
// Can we proceed with the value?
|
||||
if (SQ_SUCCEEDED(r))
|
||||
{
|
||||
// Mark the value above as the key of this element and
|
||||
// attempt serialization of the currently iterated element value
|
||||
r = MakeKey().SerializeAt(vm, top + 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = sq_throwerror(vm, _SC("Only string values are accepted as object keys"));
|
||||
}
|
||||
// Check for failures
|
||||
if (SQ_FAILED(r))
|
||||
{
|
||||
// Pop the null iterator, key and value from the stack
|
||||
sq_pop(vm, 3);
|
||||
// Propagate the error
|
||||
return r;
|
||||
}
|
||||
// Pop the key and value from the stack (i.e. cleanup after `sq_next`)
|
||||
sq_pop(vm, 2);
|
||||
}
|
||||
// Pop the null iterator
|
||||
sq_poptop(vm);
|
||||
// Close object scope
|
||||
CloseObject();
|
||||
// Serialization was successful
|
||||
return SQ_OK;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::SerializeInstance(HSQUIRRELVM vm, SQInteger idx)
|
||||
{
|
||||
sq_pushstring(vm, mMetaMethod.c_str(), static_cast< SQInteger >(mMetaMethod.size()));
|
||||
// Attempt to retrieve the meta-method from the instance
|
||||
if(SQRESULT r = sq_get(vm, idx); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
// Make sure this is actually a closure/function that we can invoke
|
||||
else if (const auto t = sq_gettype(vm, -1); t != OT_CLOSURE && t != OT_NATIVECLOSURE)
|
||||
{
|
||||
// Remove whatever is on the stack
|
||||
sq_poptop(vm);
|
||||
// Abort the operation as we can't do anything about it
|
||||
return sq_throwerrorf(vm, _SC("`_tojson` meta-method is not a closure for type (%s)"), SqTypeName(vm, idx).c_str());
|
||||
}
|
||||
// Push the instance itself the stack (the environment)
|
||||
sq_push(vm, idx);
|
||||
// Push this instance on the stack (the json context)
|
||||
ClassType< CtxJSON >::PushInstance(vm, this);
|
||||
// Invoke the function to perform the conversion in this context
|
||||
SQRESULT r = sq_call(vm, 2, SQFalse, SQFalse);
|
||||
// Remove the closure from the stack
|
||||
sq_poptop(vm);
|
||||
// Propagate the result, whatever that is
|
||||
return r;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::SerializeWeakRef(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-no-recursion)
|
||||
{
|
||||
SQRESULT r = sq_getweakrefval(vm, idx);
|
||||
// Attempt to grab the value pointed by the weak reference
|
||||
if (SQ_SUCCEEDED(r))
|
||||
{
|
||||
// Attempt to serialize the actual value
|
||||
r = SerializeAt(vm, sq_gettop(vm));
|
||||
// Pop the referenced value
|
||||
sq_poptop(vm);
|
||||
}
|
||||
// Propagate the error, if any
|
||||
return r;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::PushValues(HSQUIRRELVM vm)
|
||||
{
|
||||
// Fetch the number of objects on the stack
|
||||
const auto top = sq_gettop(vm);
|
||||
// Do we have a value?
|
||||
if (top < 2)
|
||||
{
|
||||
return sq_throwerror(vm, _SC("Must specify at least one value to be pushed"));
|
||||
}
|
||||
// Serialize every specified argument
|
||||
for (SQInteger i = 2; i <= top; ++i)
|
||||
{
|
||||
if (SQRESULT r = SerializeAt(vm, i); SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Allow chaining
|
||||
sq_push(vm, 1);
|
||||
// Specify that a value was returned
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQRESULT CtxJSON::PushElement(HSQUIRRELVM vm)
|
||||
{
|
||||
// Fetch the number of objects on the stack
|
||||
const auto top = sq_gettop(vm);
|
||||
// Do we have a value?
|
||||
if (top < 3)
|
||||
{
|
||||
return sq_throwerrorf(vm, _SC("Not enough parameters. Received %lld but %lld needed"), top-1, 2);
|
||||
}
|
||||
else if (sq_gettype(vm, 2) != OT_STRING)
|
||||
{
|
||||
return sq_throwerrorf(vm, _SC("Element key must be a string"));
|
||||
}
|
||||
// Attempt serialization of the currently iterated element key
|
||||
if (SQRESULT r = SerializeAt(vm, 2); SQ_SUCCEEDED(r))
|
||||
{
|
||||
// Mark the value above as the key of this element and
|
||||
// attempt serialization of the currently iterated element value
|
||||
r = MakeKey().SerializeAt(vm, 3);
|
||||
// Check for failures
|
||||
if (SQ_FAILED(r))
|
||||
{
|
||||
return r; // Propagate the error
|
||||
}
|
||||
}
|
||||
// Allow chaining
|
||||
sq_push(vm, 1);
|
||||
// Specify that a value was returned
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CtxJSON & CtxJSON::PushKey(StackStrF & key)
|
||||
{
|
||||
// Validate the string value
|
||||
if (key.mLen >= 0 && SQ_SUCCEEDED(key.mRes))
|
||||
{
|
||||
PushString(key.mPtr, static_cast< size_t >(key.mLen));
|
||||
MakeKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
STHROWF("Invalid object key");
|
||||
}
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CtxJSON::PushNull()
|
||||
{
|
||||
mOutput.append("null,");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CtxJSON::PushInteger(SQInteger value)
|
||||
{
|
||||
fmt::format_int f(value);
|
||||
// Append the formatted integer to the buffer
|
||||
mOutput.append(f.data(), f.size());
|
||||
mOutput.push_back(',');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CtxJSON::PushFloat(float value)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(mOutput), "{},", value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CtxJSON::PushDouble(double value)
|
||||
{
|
||||
fmt::format_to(std::back_inserter(mOutput), "{},", value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CtxJSON::PushBool(bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
mOutput.append("true,", 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
mOutput.append("false,", 6);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CtxJSON::PushString(const SQChar * str)
|
||||
{
|
||||
mOutput.push_back('"');
|
||||
mOutput.append(str);
|
||||
mOutput.push_back('"');
|
||||
mOutput.push_back(',');
|
||||
// Allow the hook to know
|
||||
mString.assign(str);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CtxJSON::PushString(const SQChar * str, size_t length)
|
||||
{
|
||||
mOutput.push_back('"');
|
||||
mOutput.append(str, length);
|
||||
mOutput.push_back('"');
|
||||
mOutput.push_back(',');
|
||||
// Allow the hook to know
|
||||
mString.assign(str, length);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqToJSON(HSQUIRRELVM vm) noexcept
|
||||
{
|
||||
// Make sure the instance is cleaned up even in the case of exceptions
|
||||
DeleteGuard< CtxJSON > sq_dg(new CtxJSON());
|
||||
// Remember the instance, so we don't have to cast the script object back
|
||||
auto ctx = sq_dg.Get();
|
||||
// Turn it into a script object because it may be passed as a parameter to `_tojson` meta-methods
|
||||
LightObj obj(sq_dg, vm);
|
||||
// Proceed with the serialization
|
||||
return ctx->SerializeParams(vm);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static SQInteger SqToCompactJSON(HSQUIRRELVM vm) noexcept
|
||||
{
|
||||
// Make sure the instance is cleaned up even in the case of exceptions
|
||||
DeleteGuard< CtxJSON > sq_dg(new CtxJSON(false));
|
||||
// Remember the instance, so we don't have to cast the script object back
|
||||
auto ctx = sq_dg.Get();
|
||||
// Turn it into a script object because it may be passed as a parameter to `_tojson` meta-methods
|
||||
LightObj obj(sq_dg, vm);
|
||||
// Proceed with the serialization
|
||||
return ctx->SerializeParams(vm);
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
void Register_JSON(HSQUIRRELVM vm)
|
||||
{
|
||||
RootTable(vm).SquirrelFunc(_SC("SqToJSON"), SqToJSON);
|
||||
RootTable(vm).SquirrelFunc(_SC("SqToCompactJSON"), SqToCompactJSON);
|
||||
RootTable(vm).SquirrelFunc(_SC("SqFromJSON"), SqFromJSON);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
RootTable(vm).Bind(_SC("SqCtxJSON"),
|
||||
Class< CtxJSON, NoCopy< CtxJSON > >(vm, SqCtxJSON::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< bool >()
|
||||
.Ctor< bool, StackStrF & >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqCtxJSON::Fn)
|
||||
// Properties
|
||||
.Prop(_SC("Output"), &CtxJSON::GetOutput)
|
||||
.Prop(_SC("Depth"), &CtxJSON::GetDepth)
|
||||
.Prop(_SC("OOA"), &CtxJSON::GetObjectOverArray, &CtxJSON::SetObjectOverArray)
|
||||
.Prop(_SC("ObjectOverArray"), &CtxJSON::GetObjectOverArray, &CtxJSON::SetObjectOverArray)
|
||||
// Member Methods
|
||||
.SquirrelMethod< CtxJSON, &CtxJSON::SerializeParams >(_SC("Serialize"))
|
||||
.SquirrelMethod< CtxJSON, &CtxJSON::PushValues >(_SC("PushValues"))
|
||||
.SquirrelMethod< CtxJSON, &CtxJSON::PushElement >(_SC("PushElement"))
|
||||
.Func(_SC("OpenArray"), &CtxJSON::OpenArray)
|
||||
.Func(_SC("CloseArray"), &CtxJSON::CloseArray)
|
||||
.Func(_SC("OpenObject"), &CtxJSON::OpenObject)
|
||||
.Func(_SC("CloseObject"), &CtxJSON::CloseObject)
|
||||
.Func(_SC("MakeKey"), &CtxJSON::MakeKey)
|
||||
.FmtFunc(_SC("PushKey"), &CtxJSON::PushKey)
|
||||
.Func(_SC("SetOOA"), &CtxJSON::SetObjectOverArray)
|
||||
.Func(_SC("SetObjectOverArray"), &CtxJSON::SetObjectOverArray)
|
||||
);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
+271
-2
@@ -5,12 +5,281 @@
|
||||
#include "Library/IO/Buffer.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sajson.h>
|
||||
#include <functional>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <fmt/args.h>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/xchar.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* JSON serializer. The generated JSON output is always minified for efficiency reasons.
|
||||
*/
|
||||
struct CtxJSON
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Output string.
|
||||
*/
|
||||
String mOutput{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Prefer a table with named members even when a simple array would do the job.
|
||||
* Take a Vector3 for example. Compact array [x, y, z] or named object {x: #.#, y: #.#, z: #.#}
|
||||
*/
|
||||
bool mObjectOverArray{true};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* How nested are we currently.
|
||||
*/
|
||||
uint32_t mDepth{0};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* The meta-method name to use on objects.
|
||||
*/
|
||||
String mMetaMethod{"_tojson"};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Last pushed string value. Can be used to heck for key name in the hook.
|
||||
*/
|
||||
String mString{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal utility used to monitor the existence of certain keys to allow overloading.
|
||||
*/
|
||||
std::function< void(CtxJSON&) > mKeyHook{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
CtxJSON() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
explicit CtxJSON(bool ooa)
|
||||
: CtxJSON()
|
||||
{
|
||||
mObjectOverArray = ooa;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
CtxJSON(bool ooa, StackStrF & mmname)
|
||||
: CtxJSON()
|
||||
{
|
||||
mObjectOverArray = ooa;
|
||||
// Allow custom metamethod names
|
||||
mMetaMethod.assign(mmname.mPtr, static_cast< size_t >(mmname.mLen));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal constructor.
|
||||
*/
|
||||
explicit CtxJSON(std::function< void(CtxJSON&) > && kh)
|
||||
: CtxJSON()
|
||||
{
|
||||
mKeyHook = std::move(kh);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
CtxJSON(const CtxJSON &) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
CtxJSON(CtxJSON &&) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~CtxJSON() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
CtxJSON & operator = (const CtxJSON &) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
CtxJSON & operator = (CtxJSON &&) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current depth.
|
||||
*/
|
||||
SQMOD_NODISCARD const String & GetOutput() const noexcept
|
||||
{
|
||||
return mOutput;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current depth.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetDepth() const noexcept
|
||||
{
|
||||
return mDepth;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve whether objects are preferred over arrays.
|
||||
*/
|
||||
SQMOD_NODISCARD bool GetObjectOverArray() const noexcept
|
||||
{
|
||||
return mObjectOverArray;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve whether objects are preferred over arrays.
|
||||
*/
|
||||
CtxJSON & SetObjectOverArray(bool toggle) noexcept
|
||||
{
|
||||
mObjectOverArray = toggle;
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Increase indentation by one level.
|
||||
*/
|
||||
void Advance() noexcept
|
||||
{
|
||||
++mDepth;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Decrease indentation by one level.
|
||||
*/
|
||||
void Retreat() noexcept
|
||||
{
|
||||
assert(mDepth > 0);
|
||||
if (mDepth) --mDepth;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Begin writing an array.
|
||||
*/
|
||||
CtxJSON & OpenArray();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Stop writing an array.
|
||||
*/
|
||||
CtxJSON & CloseArray();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Resume writing an array.
|
||||
*/
|
||||
CtxJSON & ReopenArray();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Begin writing an object.
|
||||
*/
|
||||
CtxJSON & OpenObject();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Stop writing an object.
|
||||
*/
|
||||
CtxJSON & CloseObject();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Resume writing an object.
|
||||
*/
|
||||
CtxJSON & ReopenObject();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Begin writing a key value.
|
||||
*/
|
||||
CtxJSON & MakeKey();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check whether the specified weak-ref points to a type of value that must be wrapped.
|
||||
*/
|
||||
SQMOD_NODISCARD static bool CheckWeakRefWrap(HSQUIRRELVM vm, SQInteger idx) noexcept;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize given arguments.
|
||||
*/
|
||||
SQRESULT SerializeParams(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize the value a specific position in the stack.
|
||||
*/
|
||||
SQRESULT SerializeAt(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize the array a specific position in the stack. Stack index must be absolute!
|
||||
*/
|
||||
SQRESULT SerializeArray(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize the table a specific position in the stack. Stack index must be absolute!
|
||||
*/
|
||||
SQRESULT SerializeTable(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize the instance a specific position in the stack. Stack index must be absolute!
|
||||
*/
|
||||
SQRESULT SerializeInstance(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize the weak-ref a specific position in the stack. Stack index must be absolute!
|
||||
*/
|
||||
SQRESULT SerializeWeakRef(HSQUIRRELVM vm, SQInteger idx);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize a value to the current container. It assumes an array or object is currently open.
|
||||
*/
|
||||
SQRESULT PushValues(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Serialize a key/value pair to the current object. It assumes an object is currently open.
|
||||
*/
|
||||
SQRESULT PushElement(HSQUIRRELVM vm);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Push a key in the output. It assumes an object was open and previous element closed properly.
|
||||
*/
|
||||
CtxJSON & PushKey(StackStrF & key);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a null value to the output.
|
||||
*/
|
||||
void PushNull();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write an integer value to the output.
|
||||
*/
|
||||
void PushInteger(SQInteger value);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a single precision floating point value to the output.
|
||||
*/
|
||||
void PushFloat(float value);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a double precision floating point value to the output.
|
||||
*/
|
||||
void PushDouble(double value);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a boolean value to the output.
|
||||
*/
|
||||
void PushBool(bool value);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a string value to the output.
|
||||
*/
|
||||
void PushString(const SQChar * str);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Write a string value to the output.
|
||||
*/
|
||||
void PushString(const SQChar * str, size_t length);
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
+419
-383
File diff suppressed because it is too large
Load Diff
+237
-179
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,8 @@ void InitializeNet()
|
||||
#endif
|
||||
#ifndef NO_SSL
|
||||
f |= MG_FEATURES_SSL;
|
||||
#else
|
||||
OutputMessage("Network compiled without SSL support.");
|
||||
#endif
|
||||
#ifndef NO_CGI
|
||||
f |= MG_FEATURES_CGI;
|
||||
@@ -89,6 +91,9 @@ WebSocketClient & WebSocketClient::Connect()
|
||||
{
|
||||
STHROWF("Connection failed: {}", err_buf);
|
||||
}
|
||||
// Reset memebrs
|
||||
mClosing.store(false);
|
||||
mClosed.store(false);
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
@@ -113,6 +118,9 @@ WebSocketClient & WebSocketClient::ConnectExt()
|
||||
{
|
||||
STHROWF("Connection failed: {}", err_buf);
|
||||
}
|
||||
// Reset memebrs
|
||||
mClosing.store(false);
|
||||
mClosed.store(false);
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
@@ -129,6 +137,11 @@ int WebSocketClient::DataHandler(int flags, char * data, size_t data_len) noexce
|
||||
{
|
||||
LogFtl("Failed to queue web-socket data");
|
||||
}
|
||||
// Should we auto-close the connection
|
||||
if (((flags & 0xF) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) && mAutoClose.load() == true)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Return 1 to keep the connection open
|
||||
return 1;
|
||||
}
|
||||
@@ -167,6 +180,7 @@ void Register_Net(HSQUIRRELVM vm)
|
||||
.Prop(_SC("OnClose"), &WebSocketClient::GetOnClose, &WebSocketClient::SetOnClose)
|
||||
.Prop(_SC("Valid"), &WebSocketClient::IsValid)
|
||||
.Prop(_SC("Closing"), &WebSocketClient::IsClosing)
|
||||
.Prop(_SC("AutoClose"), &WebSocketClient::GetAutoClose, &WebSocketClient::SetAutoClose)
|
||||
// Member Methods
|
||||
.FmtFunc(_SC("SetTag"), &WebSocketClient::ApplyTag)
|
||||
.FmtFunc(_SC("SetData"), &WebSocketClient::ApplyData)
|
||||
|
||||
+40
-9
@@ -154,6 +154,18 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
*/
|
||||
std::atomic< bool > mClosing{false};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Whether the closing callback was inoked (avoid recursive calls).
|
||||
*/
|
||||
std::atomic< bool > mClosed{false};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Whether to not keep the connection open after receiving the close event.
|
||||
* Internally this event is ignored but if set to true the connection is immediatelly closed
|
||||
* in the internal event handler, before the event may reach the script callback.
|
||||
*/
|
||||
std::atomic< bool > mAutoClose{false};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Server host to connect to, i.e. "echo.websocket.org" or "192.168.1.1" or "localhost".
|
||||
*/
|
||||
@@ -179,7 +191,8 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
*/
|
||||
WebSocketClient()
|
||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
||||
, mPort(0), mSecure(false), mClosing(false), mHost(), mPath(), mOrigin(), mExtensions()
|
||||
, mPort(0), mSecure(false), mClosing(false), mClosed(false), mAutoClose(false)
|
||||
, mHost(), mPath(), mOrigin(), mExtensions()
|
||||
{
|
||||
ChainInstance(); // Remember this instance
|
||||
}
|
||||
@@ -189,7 +202,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
*/
|
||||
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path)
|
||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
||||
, mPort(port), mSecure(false), mClosing(false)
|
||||
, mPort(port), mSecure(false), mClosing(false), mClosed(false), mAutoClose(false)
|
||||
, mHost(host.mPtr, host.GetSize())
|
||||
, mPath(path.mPtr, path.GetSize())
|
||||
, mOrigin(), mExtensions()
|
||||
@@ -202,7 +215,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
*/
|
||||
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure)
|
||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
||||
, mPort(port), mSecure(secure), mClosing(false)
|
||||
, mPort(port), mSecure(secure), mClosing(false), mClosed(false), mAutoClose(false)
|
||||
, mHost(host.mPtr, host.GetSize())
|
||||
, mPath(path.mPtr, path.GetSize())
|
||||
, mOrigin(), mExtensions()
|
||||
@@ -215,7 +228,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
*/
|
||||
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure, StackStrF & origin)
|
||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
||||
, mPort(port), mSecure(secure), mClosing(false)
|
||||
, mPort(port), mSecure(secure), mClosing(false), mClosed(false), mAutoClose(false)
|
||||
, mHost(host.mPtr, host.GetSize())
|
||||
, mPath(path.mPtr, path.GetSize())
|
||||
, mOrigin(origin.mPtr, origin.GetSize())
|
||||
@@ -229,7 +242,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
*/
|
||||
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure, StackStrF & origin, StackStrF & ext)
|
||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
||||
, mPort(port), mSecure(secure), mClosing(false)
|
||||
, mPort(port), mSecure(secure), mClosing(false), mClosed(false), mAutoClose(false)
|
||||
, mHost(host.mPtr, host.GetSize())
|
||||
, mPath(path.mPtr, path.GetSize())
|
||||
, mOrigin(origin.mPtr, origin.GetSize())
|
||||
@@ -289,6 +302,22 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
return mClosing.load();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve whether auto-closing is enabled or not.
|
||||
*/
|
||||
SQMOD_NODISCARD bool GetAutoClose() const
|
||||
{
|
||||
return mAutoClose.load();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify whether auto-closing is enabled or not.
|
||||
*/
|
||||
void SetAutoClose(bool toggle)
|
||||
{
|
||||
mAutoClose.store(toggle);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the associated user tag.
|
||||
*/
|
||||
@@ -648,7 +677,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Sends the contents of the given buffer through the socket as a single frame.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger SendOpCode(SqBuffer & buf, SQInteger opcode)
|
||||
SQMOD_NODISCARD SQInteger SendOpCode(SQInteger opcode)
|
||||
{
|
||||
return mg_websocket_client_write(Valid(), static_cast< int >(opcode), nullptr, 0);
|
||||
}
|
||||
@@ -706,9 +735,12 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
||||
}
|
||||
}
|
||||
// Is the server closing the connection?
|
||||
if (closing && !mOnClose.IsNull())
|
||||
if (closing && !mClosed.load() && !mOnClose.IsNull())
|
||||
{
|
||||
mOnClose.Execute(); // Let the user know
|
||||
// Let the user know
|
||||
mOnClose.Execute();
|
||||
// Prevent calling this callback again
|
||||
mClosed.store(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,5 +788,4 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Library/RegEx.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sqratConst.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(SqRxMatchTypename, _SC("SqRxMatch"))
|
||||
SQMOD_DECL_TYPENAME(SqRxMatchesTypename, _SC("SqRxMatches"))
|
||||
SQMOD_DECL_TYPENAME(SqRxInstanceTypename, _SC("SqRxInstance"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool RxInstance::STUDY = true;
|
||||
int RxInstance::OPTIONS = 0;
|
||||
int RxInstance::STUDY_OPTIONS = 0;
|
||||
|
||||
// ================================================================================================
|
||||
void Register_RegEx(HSQUIRRELVM vm)
|
||||
{
|
||||
RootTable(vm).Bind(SqRxMatchTypename::Str,
|
||||
Class< RxMatch >(vm, SqRxMatchTypename::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< SQInteger >()
|
||||
.Ctor< SQInteger, SQInteger >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqRxMatchTypename::Fn)
|
||||
// Properties
|
||||
.Prop(_SC("Offset"), &RxMatch::GetOffset, &RxMatch::SetOffset)
|
||||
.Prop(_SC("Length"), &RxMatch::GetLength, &RxMatch::SetLength)
|
||||
.Prop(_SC("End"), &RxMatch::GetEnd)
|
||||
// Member Methods
|
||||
.Func(_SC("SubStr"), &RxMatch::SubStr)
|
||||
);
|
||||
RootTable(vm).Bind(SqRxMatchesTypename::Str,
|
||||
Class< RxMatches >(vm, SqRxMatchesTypename::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqRxMatchesTypename::Fn)
|
||||
// Properties
|
||||
.Prop(_SC("Front"), &RxMatches::Front)
|
||||
.Prop(_SC("Back"), &RxMatches::Back)
|
||||
.Prop(_SC("Empty"), &RxMatches::Empty)
|
||||
.Prop(_SC("Size"), &RxMatches::Size)
|
||||
.Prop(_SC("Capacity"), &RxMatches::Capacity, &RxMatches::Reserve)
|
||||
// Member Methods
|
||||
.Func(_SC("Get"), &RxMatches::Get)
|
||||
.Func(_SC("Reserve"), &RxMatches::Reserve)
|
||||
.Func(_SC("Compact"), &RxMatches::Compact)
|
||||
.Func(_SC("Clear"), &RxMatches::Clear)
|
||||
.Func(_SC("Pop"), &RxMatches::Pop)
|
||||
.Func(_SC("EraseAt"), &RxMatches::EraseAt)
|
||||
.Func(_SC("EraseFrom"), &RxMatches::EraseFrom)
|
||||
.Func(_SC("Each"), &RxMatches::Each)
|
||||
.Func(_SC("EachRange"), &RxMatches::EachRange)
|
||||
.Func(_SC("While"), &RxMatches::While)
|
||||
.Func(_SC("WhileRange"), &RxMatches::WhileRange)
|
||||
.Func(_SC("SubStr"), &RxMatches::SubStr)
|
||||
);
|
||||
RootTable(vm).Bind(_SC("SqRx"),
|
||||
Class< RxInstance, NoCopy< RxInstance > >(vm, SqRxInstanceTypename::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< StackStrF & >()
|
||||
.Ctor< int, StackStrF & >()
|
||||
.Ctor< int, bool, StackStrF & >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqRxInstanceTypename::Fn)
|
||||
//.Func(_SC("_tostring"), &CPlayer::ToString)
|
||||
// Static Values
|
||||
.SetStaticValue(_SC("STUDY"), RxInstance::STUDY)
|
||||
.SetStaticValue(_SC("OPTIONS"), RxInstance::OPTIONS)
|
||||
.SetStaticValue(_SC("STUDY_OPTIONS"), RxInstance::STUDY_OPTIONS)
|
||||
// Properties
|
||||
.Prop(_SC("Valid"), &RxInstance::IsValid)
|
||||
.Prop(_SC("Studied"), &RxInstance::IsStudied)
|
||||
// Member Methods
|
||||
.FmtFunc(_SC("CompileF"), &RxInstance::Compile1)
|
||||
.FmtFunc(_SC("CompileExF"), &RxInstance::Compile2)
|
||||
.FmtFunc(_SC("TryCompileF"), &RxInstance::TryCompile1)
|
||||
.FmtFunc(_SC("TryCompileExF"), &RxInstance::TryCompile2)
|
||||
.FmtFunc(_SC("MatchFirst"), &RxInstance::MatchFirst)
|
||||
.FmtFunc(_SC("MatchFirstEx"), &RxInstance::MatchFirst_)
|
||||
.FmtFunc(_SC("MatchFirstFrom"), &RxInstance::MatchFirstFrom)
|
||||
.FmtFunc(_SC("MatchFirstFromEx"), &RxInstance::MatchFirstFrom_)
|
||||
.FmtFunc(_SC("Match"), &RxInstance::Match)
|
||||
.FmtFunc(_SC("MatchEx"), &RxInstance::Match_)
|
||||
.FmtFunc(_SC("MatchFrom"), &RxInstance::MatchFrom)
|
||||
.FmtFunc(_SC("MatchFromEx"), &RxInstance::MatchFrom_)
|
||||
.FmtFunc(_SC("Matches"), &RxInstance::Matches)
|
||||
.FmtFunc(_SC("MatchesEx"), &RxInstance::Matches_)
|
||||
.FmtFunc(_SC("MatchesEx2"), &RxInstance::MatchesEx)
|
||||
// Member Overloads
|
||||
.Overload(_SC("Compile"), &RxInstance::Compile1)
|
||||
.Overload(_SC("Compile"), &RxInstance::Compile2)
|
||||
.Overload(_SC("TryCompile"), &RxInstance::TryCompile1)
|
||||
.Overload(_SC("TryCompile"), &RxInstance::TryCompile2)
|
||||
.Overload(_SC("Study"), &RxInstance::Study0)
|
||||
.Overload(_SC("Study"), &RxInstance::Study1)
|
||||
);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ConstTable(vm).Enum(_SC("SqRxOption"), Enumeration(vm)
|
||||
.Const(_SC("Caseless"), static_cast< SQInteger >(PCRE_CASELESS))
|
||||
.Const(_SC("Multiline"), static_cast< SQInteger >(PCRE_MULTILINE))
|
||||
.Const(_SC("Dotall"), static_cast< SQInteger >(PCRE_DOTALL))
|
||||
.Const(_SC("Extended"), static_cast< SQInteger >(PCRE_EXTENDED))
|
||||
.Const(_SC("Anchored"), static_cast< SQInteger >(PCRE_ANCHORED))
|
||||
.Const(_SC("DollarEndOnly"), static_cast< SQInteger >(PCRE_DOLLAR_ENDONLY))
|
||||
.Const(_SC("Extra"), static_cast< SQInteger >(PCRE_EXTRA))
|
||||
.Const(_SC("NotBOL"), static_cast< SQInteger >(PCRE_NOTBOL))
|
||||
.Const(_SC("NotEOL"), static_cast< SQInteger >(PCRE_NOTEOL))
|
||||
.Const(_SC("UnGreedy"), static_cast< SQInteger >(PCRE_UNGREEDY))
|
||||
.Const(_SC("NotEmpty"), static_cast< SQInteger >(PCRE_NOTEMPTY))
|
||||
.Const(_SC("UTF8"), static_cast< SQInteger >(PCRE_UTF8))
|
||||
.Const(_SC("UTF16"), static_cast< SQInteger >(PCRE_UTF16))
|
||||
.Const(_SC("UTF32"), static_cast< SQInteger >(PCRE_UTF32))
|
||||
.Const(_SC("NoAutoCapture"), static_cast< SQInteger >(PCRE_NO_AUTO_CAPTURE))
|
||||
.Const(_SC("NoUTF8Check"), static_cast< SQInteger >(PCRE_NO_UTF8_CHECK))
|
||||
.Const(_SC("NoUTF16Check"), static_cast< SQInteger >(PCRE_NO_UTF16_CHECK))
|
||||
.Const(_SC("NoUTF32Check"), static_cast< SQInteger >(PCRE_NO_UTF32_CHECK))
|
||||
.Const(_SC("AutoCallout"), static_cast< SQInteger >(PCRE_AUTO_CALLOUT))
|
||||
.Const(_SC("PartialSoft"), static_cast< SQInteger >(PCRE_PARTIAL_SOFT))
|
||||
.Const(_SC("Partial"), static_cast< SQInteger >(PCRE_PARTIAL))
|
||||
.Const(_SC("NeverUTF"), static_cast< SQInteger >(PCRE_NEVER_UTF))
|
||||
.Const(_SC("DfaShortest"), static_cast< SQInteger >(PCRE_DFA_SHORTEST))
|
||||
.Const(_SC("NoAutoPossess"), static_cast< SQInteger >(PCRE_NO_AUTO_POSSESS))
|
||||
.Const(_SC("DfaRestart"), static_cast< SQInteger >(PCRE_DFA_RESTART))
|
||||
.Const(_SC("FirstLine"), static_cast< SQInteger >(PCRE_FIRSTLINE))
|
||||
.Const(_SC("DupNames"), static_cast< SQInteger >(PCRE_DUPNAMES))
|
||||
.Const(_SC("NewLineCR"), static_cast< SQInteger >(PCRE_NEWLINE_CR))
|
||||
.Const(_SC("NewLineLF"), static_cast< SQInteger >(PCRE_NEWLINE_LF))
|
||||
.Const(_SC("NewLineCRLF"), static_cast< SQInteger >(PCRE_NEWLINE_CRLF))
|
||||
.Const(_SC("NewLineAny"), static_cast< SQInteger >(PCRE_NEWLINE_ANY))
|
||||
.Const(_SC("NewLineAnyCRLF"), static_cast< SQInteger >(PCRE_NEWLINE_ANYCRLF))
|
||||
.Const(_SC("BsrAnyCRLF"), static_cast< SQInteger >(PCRE_BSR_ANYCRLF))
|
||||
.Const(_SC("BsrUnicode"), static_cast< SQInteger >(PCRE_BSR_UNICODE))
|
||||
.Const(_SC("JavaScriptCompat"), static_cast< SQInteger >(PCRE_JAVASCRIPT_COMPAT))
|
||||
.Const(_SC("NoStartOptimize"), static_cast< SQInteger >(PCRE_NO_START_OPTIMIZE))
|
||||
.Const(_SC("NoStartOptimise"), static_cast< SQInteger >(PCRE_NO_START_OPTIMISE))
|
||||
.Const(_SC("PartialHard"), static_cast< SQInteger >(PCRE_PARTIAL_HARD))
|
||||
.Const(_SC("NotEmptyAtStart"), static_cast< SQInteger >(PCRE_NOTEMPTY_ATSTART))
|
||||
.Const(_SC("UCP"), static_cast< SQInteger >(PCRE_UCP))
|
||||
);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ConstTable(vm).Enum(_SC("SqRxError"), Enumeration(vm)
|
||||
.Const(_SC("NoMatch"), static_cast< SQInteger >(PCRE_ERROR_NOMATCH))
|
||||
.Const(_SC("Null"), static_cast< SQInteger >(PCRE_ERROR_NULL))
|
||||
.Const(_SC("BadOption"), static_cast< SQInteger >(PCRE_ERROR_BADOPTION))
|
||||
.Const(_SC("BadMagic"), static_cast< SQInteger >(PCRE_ERROR_BADMAGIC))
|
||||
.Const(_SC("UnknownOpCode"), static_cast< SQInteger >(PCRE_ERROR_UNKNOWN_OPCODE))
|
||||
.Const(_SC("UnknownNode"), static_cast< SQInteger >(PCRE_ERROR_UNKNOWN_NODE))
|
||||
.Const(_SC("NoMemory"), static_cast< SQInteger >(PCRE_ERROR_NOMEMORY))
|
||||
.Const(_SC("NoSubstring"), static_cast< SQInteger >(PCRE_ERROR_NOSUBSTRING))
|
||||
.Const(_SC("MatchLimit"), static_cast< SQInteger >(PCRE_ERROR_MATCHLIMIT))
|
||||
.Const(_SC("Callout"), static_cast< SQInteger >(PCRE_ERROR_CALLOUT))
|
||||
.Const(_SC("BadUTF8"), static_cast< SQInteger >(PCRE_ERROR_BADUTF8))
|
||||
.Const(_SC("BadUTF16"), static_cast< SQInteger >(PCRE_ERROR_BADUTF16))
|
||||
.Const(_SC("BadUTF32"), static_cast< SQInteger >(PCRE_ERROR_BADUTF32))
|
||||
.Const(_SC("BadUTF8Offset"), static_cast< SQInteger >(PCRE_ERROR_BADUTF8_OFFSET))
|
||||
.Const(_SC("BadUTF16Offset"), static_cast< SQInteger >(PCRE_ERROR_BADUTF16_OFFSET))
|
||||
.Const(_SC("Partial"), static_cast< SQInteger >(PCRE_ERROR_PARTIAL))
|
||||
.Const(_SC("BadPartial"), static_cast< SQInteger >(PCRE_ERROR_BADPARTIAL))
|
||||
.Const(_SC("Internal"), static_cast< SQInteger >(PCRE_ERROR_INTERNAL))
|
||||
.Const(_SC("BadCount"), static_cast< SQInteger >(PCRE_ERROR_BADCOUNT))
|
||||
.Const(_SC("DfaUitem"), static_cast< SQInteger >(PCRE_ERROR_DFA_UITEM))
|
||||
.Const(_SC("DfaUcond"), static_cast< SQInteger >(PCRE_ERROR_DFA_UCOND))
|
||||
.Const(_SC("DfaUmLimit"), static_cast< SQInteger >(PCRE_ERROR_DFA_UMLIMIT))
|
||||
.Const(_SC("DfaWsSize"), static_cast< SQInteger >(PCRE_ERROR_DFA_WSSIZE))
|
||||
.Const(_SC("DfaRecurse"), static_cast< SQInteger >(PCRE_ERROR_DFA_RECURSE))
|
||||
.Const(_SC("RecursionLimit"), static_cast< SQInteger >(PCRE_ERROR_RECURSIONLIMIT))
|
||||
.Const(_SC("NullWsLimit"), static_cast< SQInteger >(PCRE_ERROR_NULLWSLIMIT))
|
||||
.Const(_SC("BadNewLine"), static_cast< SQInteger >(PCRE_ERROR_BADNEWLINE))
|
||||
.Const(_SC("BadOffset"), static_cast< SQInteger >(PCRE_ERROR_BADOFFSET))
|
||||
.Const(_SC("ShortUTF8"), static_cast< SQInteger >(PCRE_ERROR_SHORTUTF8))
|
||||
.Const(_SC("ShortUTF16"), static_cast< SQInteger >(PCRE_ERROR_SHORTUTF16))
|
||||
.Const(_SC("RecurseLoop"), static_cast< SQInteger >(PCRE_ERROR_RECURSELOOP))
|
||||
.Const(_SC("JitStackLimit"), static_cast< SQInteger >(PCRE_ERROR_JIT_STACKLIMIT))
|
||||
.Const(_SC("BadMode"), static_cast< SQInteger >(PCRE_ERROR_BADMODE))
|
||||
.Const(_SC("BadEndianness"), static_cast< SQInteger >(PCRE_ERROR_BADENDIANNESS))
|
||||
.Const(_SC("DfaBadRestart"), static_cast< SQInteger >(PCRE_ERROR_DFA_BADRESTART))
|
||||
.Const(_SC("JitBadOption"), static_cast< SQInteger >(PCRE_ERROR_JIT_BADOPTION))
|
||||
.Const(_SC("BadLength"), static_cast< SQInteger >(PCRE_ERROR_BADLENGTH))
|
||||
.Const(_SC("Unset"), static_cast< SQInteger >(PCRE_ERROR_UNSET))
|
||||
);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -0,0 +1,885 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#ifdef POCO_UNBUNDLED
|
||||
#include <pcre.h>
|
||||
#else
|
||||
#include "pcre_config.h"
|
||||
#include "pcre.h"
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <utility>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
struct RxMatch
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
SQInteger mOffset{0};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
SQInteger mLength{0};
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
RxMatch() noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Offset constructor.
|
||||
*/
|
||||
explicit RxMatch(SQInteger offset) noexcept
|
||||
: mOffset{offset}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
RxMatch(SQInteger offset, SQInteger length) noexcept
|
||||
: mOffset{offset}, mLength{length}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
RxMatch(const RxMatch & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
RxMatch(RxMatch && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
RxMatch & operator = (const RxMatch & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
RxMatch & operator = (RxMatch && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve offset.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetOffset() const noexcept
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify offset.
|
||||
*/
|
||||
void SetOffset(SQInteger value) noexcept
|
||||
{
|
||||
mOffset = value;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve length.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetLength() const noexcept
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify length.
|
||||
*/
|
||||
void SetLength(SQInteger value) noexcept
|
||||
{
|
||||
mLength = value;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve match end.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetEnd() const noexcept
|
||||
{
|
||||
return mOffset + mLength;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Extract a sub-string.
|
||||
*/
|
||||
[[nodiscard]] LightObj SubStr(StackStrF & str) const
|
||||
{
|
||||
if ((mOffset + mLength) > str.mLen)
|
||||
{
|
||||
STHROWF("Rx: Match is outside the range of the specified string.");
|
||||
}
|
||||
// Return the sub-string
|
||||
return LightObj{str.mPtr + mOffset, mLength};
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
struct RxMatches
|
||||
{
|
||||
using List = std::vector< RxMatch >;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal RegularExpression instance.
|
||||
*/
|
||||
List mList;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
RxMatches() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy list constructor.
|
||||
*/
|
||||
explicit RxMatches(const List & l) // NOLINT(modernize-pass-by-value)
|
||||
: mList{l}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move list constructor.
|
||||
*/
|
||||
explicit RxMatches(List && m) noexcept
|
||||
: mList{std::move(m)}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
RxMatches(const RxMatches & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
RxMatches(RxMatches && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
RxMatches & operator = (const RxMatches & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
RxMatches & operator = (RxMatches && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure an index is within range and return the container. Container must exist.
|
||||
*/
|
||||
List & ValidIdx(SQInteger i)
|
||||
{
|
||||
if (static_cast< size_t >(i) >= mList.size())
|
||||
{
|
||||
STHROWF("Invalid Regular Expression match list index({})", i);
|
||||
}
|
||||
return mList;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure an index is within range and return the container. Container must exist.
|
||||
*/
|
||||
SQMOD_NODISCARD const List & ValidIdx(SQInteger i) const
|
||||
{
|
||||
if (static_cast< size_t >(i) >= mList.size())
|
||||
{
|
||||
STHROWF("Invalid Regular Expression match list index({})", i);
|
||||
}
|
||||
return mList;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure a container instance is populated, then return it.
|
||||
*/
|
||||
SQMOD_NODISCARD List & ValidPop()
|
||||
{
|
||||
if (mList.empty())
|
||||
{
|
||||
STHROWF("Regular Expression match list container is empty");
|
||||
}
|
||||
return mList;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a value from the container.
|
||||
*/
|
||||
SQMOD_NODISCARD List::reference Get(SQInteger i)
|
||||
{
|
||||
return ValidIdx(i).at(ClampL< SQInteger, size_t >(i));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the first element in the container.
|
||||
*/
|
||||
SQMOD_NODISCARD List::reference Front()
|
||||
{
|
||||
return ValidPop().front();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the last element in the container.
|
||||
*/
|
||||
SQMOD_NODISCARD List::reference Back()
|
||||
{
|
||||
return mList.back();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if the container has no elements.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Empty() const
|
||||
{
|
||||
return mList.empty();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of elements in the container.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Size() const
|
||||
{
|
||||
return static_cast< SQInteger >(mList.size());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of elements that the container has currently allocated space for.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Capacity() const
|
||||
{
|
||||
return static_cast< SQInteger >(mList.capacity());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Increase the capacity of the container to a value that's greater or equal to the one specified.
|
||||
*/
|
||||
RxMatches & Reserve(SQInteger n)
|
||||
{
|
||||
mList.reserve(ClampL< SQInteger, size_t >(n));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Request the removal of unused capacity.
|
||||
*/
|
||||
void Compact()
|
||||
{
|
||||
mList.shrink_to_fit();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase all elements from the container.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Pop the last element in the container.
|
||||
*/
|
||||
void Pop()
|
||||
{
|
||||
ValidPop().pop_back();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase the element at a certain position.
|
||||
*/
|
||||
void EraseAt(SQInteger i)
|
||||
{
|
||||
mList.erase(ValidIdx(i).begin() + static_cast< size_t >(i)); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase a certain amount of elements starting from a specific position.
|
||||
*/
|
||||
void EraseFrom(SQInteger i, SQInteger n)
|
||||
{
|
||||
mList.erase(ValidIdx(i).begin() + static_cast< size_t >(i), // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
ValidIdx(i + n).begin() + static_cast< size_t >(i + n)); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor.
|
||||
*/
|
||||
void Each(Function & fn) const
|
||||
{
|
||||
for (const auto & e : mList)
|
||||
{
|
||||
fn.Execute(static_cast< SQInteger >(e.mOffset), static_cast< SQInteger >(e.mLength));
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate values in range through a functor.
|
||||
*/
|
||||
void EachRange(SQInteger p, SQInteger n, Function & fn) const
|
||||
{
|
||||
std::for_each(ValidIdx(p).begin() + static_cast< size_t >(p), // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
ValidIdx(p + n).begin() + static_cast< size_t >(p + n), // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
[&](List::const_reference & e) {
|
||||
fn.Execute(static_cast< SQInteger >(e.mOffset), static_cast< SQInteger >(e.mLength));
|
||||
});
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor until stopped (i.e. false is returned).
|
||||
*/
|
||||
void While(Function & fn) const
|
||||
{
|
||||
for (const auto & e : mList)
|
||||
{
|
||||
auto ret = fn.Eval(static_cast< SQInteger >(e.mOffset), static_cast< SQInteger >(e.mLength));
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate values in range through a functor until stopped (i.e. false is returned).
|
||||
*/
|
||||
void WhileRange(SQInteger p, SQInteger n, Function & fn) const
|
||||
{
|
||||
auto itr = ValidIdx(p).begin() + static_cast< size_t >(p); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
auto end = ValidIdx(p + n).begin() + static_cast< size_t >(p + n); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
auto ret = fn.Eval(static_cast< SQInteger >(itr->mOffset), static_cast< SQInteger >(itr->mLength));
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Extract a sub-string.
|
||||
*/
|
||||
[[nodiscard]] LightObj SubStr(SQInteger i, StackStrF & str) const
|
||||
{
|
||||
const RxMatch & m = ValidIdx(i)[i];
|
||||
// Check if match is within range
|
||||
if ((m.mOffset + m.mLength) > str.mLen)
|
||||
{
|
||||
STHROWF("Rx: Match is outside the range of the specified string.");
|
||||
}
|
||||
// Return the sub-string
|
||||
return LightObj{str.mPtr + m.mOffset, m.mLength};
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
struct RxInstance
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Whether to analyze and optimize the pattern by default for evey new instance (true).
|
||||
*/
|
||||
static bool STUDY;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default options for every new instance (0).
|
||||
*/
|
||||
static int OPTIONS;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default study options for every new instance (0).
|
||||
*/
|
||||
static int STUDY_OPTIONS;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default offset vector size (must be multiple of 3).
|
||||
*/
|
||||
static constexpr int OVEC_SIZE = 63;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal vector type used for offsets buffer.
|
||||
*/
|
||||
using OVEC_t = std::vector< int >;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal RegularExpression instance.
|
||||
*/
|
||||
pcre * mPCRE{nullptr};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal RegularExpression instance.
|
||||
*/
|
||||
pcre_extra * mExtra{nullptr};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal buffer used for offsets.
|
||||
*/
|
||||
OVEC_t mOVEC{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
RxInstance() noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor (disabled).
|
||||
*/
|
||||
RxInstance(const RxInstance &) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
RxInstance(RxInstance && o) noexcept
|
||||
: mPCRE(o.mPCRE), mExtra(o.mExtra), mOVEC(std::move(o.mOVEC)) // Replicate it
|
||||
{
|
||||
o.mPCRE = nullptr; // Take ownership
|
||||
o.mExtra = nullptr; // Take ownership
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Basic constructor.
|
||||
*/
|
||||
explicit RxInstance(StackStrF & pattern)
|
||||
: RxInstance(OPTIONS, STUDY, pattern)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Basic constructor. With specific options.
|
||||
*/
|
||||
explicit RxInstance(int options, StackStrF & pattern)
|
||||
: RxInstance(options, STUDY, pattern)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Basic constructor. With specific options.
|
||||
*/
|
||||
explicit RxInstance(int options, bool study, StackStrF & pattern)
|
||||
: mPCRE(Compile_(pattern.mPtr, options)), mExtra(nullptr)
|
||||
{
|
||||
if (study)
|
||||
{
|
||||
Study0();
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal constructor.
|
||||
*/
|
||||
RxInstance(const char * pattern, int options, bool study)
|
||||
: mPCRE(Compile_(pattern, options)), mExtra(nullptr)
|
||||
{
|
||||
if (study)
|
||||
{
|
||||
Study0();
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~RxInstance()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator (disabled).
|
||||
*/
|
||||
RxInstance & operator = (const RxInstance &) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
RxInstance & operator = (RxInstance && o) noexcept
|
||||
{
|
||||
// Prevent self assignment
|
||||
if (this != &o)
|
||||
{
|
||||
// Release current instance, if any
|
||||
Destroy();
|
||||
// Replicate it
|
||||
mPCRE = o.mPCRE;
|
||||
mExtra = o.mExtra;
|
||||
mOVEC = std::move(o.mOVEC);
|
||||
// Take ownership
|
||||
o.mPCRE = nullptr;
|
||||
o.mExtra = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Estimate the size necessary for the offsets vector buffer.
|
||||
*/
|
||||
void EstimateOVEC(bool force = false)
|
||||
{
|
||||
if (mOVEC.empty() || force)
|
||||
{
|
||||
int size = 0;
|
||||
// Attempt to estimate the size of the offsets vector buffer
|
||||
const int r = pcre_fullinfo(ValidPCRE(), mExtra, PCRE_INFO_CAPTURECOUNT, &size);
|
||||
// Check for errors
|
||||
if (r != 0)
|
||||
{
|
||||
STHROWF("Rx: Offsets vector buffer estimation failed ({})", r);
|
||||
}
|
||||
// Attempt to scale the vector (must be multiple of 3)
|
||||
mOVEC.resize((size + 1) * 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Return a valid `pcre` instance pointer or throw an exception.
|
||||
*/
|
||||
SQMOD_NODISCARD pcre * ValidPCRE() const
|
||||
{
|
||||
// Do we manage a valid instance?
|
||||
if (mPCRE == nullptr)
|
||||
{
|
||||
STHROWF("Uninitialized Regular Expression instance.");
|
||||
}
|
||||
// Return it
|
||||
return mPCRE;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Return a valid `pcre_extra` instance pointer or throw an exception.
|
||||
*/
|
||||
SQMOD_NODISCARD pcre_extra * ValidExtra() const
|
||||
{
|
||||
// Do we manage a valid instance?
|
||||
if (mExtra == nullptr)
|
||||
{
|
||||
STHROWF("Regular Expression was not studied and optimized.");
|
||||
}
|
||||
// Return it
|
||||
return mExtra;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Compile the specified pattern.
|
||||
*/
|
||||
SQMOD_NODISCARD static pcre * Compile_(const char * pattern, int options = OPTIONS)
|
||||
{
|
||||
const char * error_msg = nullptr;
|
||||
int error_code, error_offset = 0;
|
||||
// Attempt to compile the specified pattern
|
||||
pcre * ptr = pcre_compile2(pattern, options, &error_code, &error_msg, &error_offset, nullptr);
|
||||
// Did the compilation failed?
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
STHROWF("Rx: {s} (code {}) (at offset {})", error_msg, error_code, error_offset);
|
||||
}
|
||||
// Return the `pcre` instance
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to compile the specified pattern. Error information is returned instead of thrown.
|
||||
*/
|
||||
SQMOD_NODISCARD static std::pair< pcre *, Table > TryCompile_(const char * pattern, int options = OPTIONS)
|
||||
{
|
||||
const char * error_msg = nullptr;
|
||||
int error_code, error_offset = 0;
|
||||
// Attempt to compile the specified pattern
|
||||
pcre * ptr = pcre_compile2(pattern, options, &error_code, &error_msg, &error_offset, nullptr);
|
||||
// Did the compilation failed?
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
Table t;
|
||||
t.SetValue("message", error_msg);
|
||||
t.SetValue("code", error_code);
|
||||
t.SetValue("offset", error_offset);
|
||||
// Return the table with error information
|
||||
return std::make_pair(ptr, std::move(t));
|
||||
}
|
||||
// Return the `pcre` instance with no error information
|
||||
return std::make_pair(ptr, Table{});
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Compile the specified pattern.
|
||||
*/
|
||||
RxInstance & Compile1(StackStrF & pattern)
|
||||
{
|
||||
return Compile2(OPTIONS, pattern);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Compile the specified pattern. With specific options.
|
||||
*/
|
||||
RxInstance & Compile2(int options, StackStrF & pattern)
|
||||
{
|
||||
// Release current instance, if any
|
||||
Destroy();
|
||||
// Attempt to compile
|
||||
mPCRE = Compile_(pattern.mPtr, options);
|
||||
// Allocate offsets vector buffer
|
||||
EstimateOVEC();
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Compile the specified pattern.
|
||||
*/
|
||||
Table TryCompile1(StackStrF & pattern)
|
||||
{
|
||||
return TryCompile2(OPTIONS, pattern);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Compile the specified pattern. With specific options.
|
||||
*/
|
||||
Table TryCompile2(int options, StackStrF & pattern)
|
||||
{
|
||||
// Release current instance, if any
|
||||
Destroy();
|
||||
// Attempt to compile
|
||||
auto p = TryCompile_(pattern.mPtr, options);
|
||||
// Were there any compilation errors?
|
||||
if (p.first != nullptr)
|
||||
{
|
||||
mPCRE = p.first;
|
||||
}
|
||||
// Return compilation info
|
||||
return p.second;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Analyze the managed pattern and optimized it.
|
||||
*/
|
||||
RxInstance & Study0()
|
||||
{
|
||||
return Study1(STUDY_OPTIONS);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Analyze the managed pattern and optimized it. With specific options.
|
||||
*/
|
||||
RxInstance & Study1(int options)
|
||||
{
|
||||
if (mExtra != nullptr)
|
||||
{
|
||||
STHROWF("Regular Expression was already analyzed and optimized");
|
||||
}
|
||||
const char * error = nullptr;
|
||||
// Study and optimize the expression
|
||||
mExtra = pcre_study(ValidPCRE(), options, &error);
|
||||
// If there was an error studying the expression then throw it
|
||||
if (mExtra == nullptr && error != nullptr)
|
||||
{
|
||||
STHROWF("Rx: {s}", error);
|
||||
}
|
||||
// Allow chaining
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release managed resources and revert to uninitialized instance.
|
||||
*/
|
||||
SQMOD_NODISCARD bool IsValid() const
|
||||
{
|
||||
return (mPCRE != nullptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release managed resources and revert to uninitialized instance.
|
||||
*/
|
||||
SQMOD_NODISCARD bool IsStudied() const
|
||||
{
|
||||
return (mExtra != nullptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release managed resources and revert to uninitialized instance.
|
||||
*/
|
||||
void Destroy()
|
||||
{
|
||||
// Do we manage any instance?
|
||||
if (mPCRE != nullptr)
|
||||
{
|
||||
pcre_free(mPCRE);
|
||||
mPCRE = nullptr;
|
||||
}
|
||||
// Is the expression optimized?
|
||||
if (mExtra != nullptr)
|
||||
{
|
||||
pcre_free(mExtra);
|
||||
mExtra = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* Returns the position of the first captured sub-string in m.
|
||||
* If no part of the subject matches the pattern, m.mOffset is -1 and m.mLength is 0.
|
||||
* Returns the number of matches. Throws a exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int MatchFirstFrom(SQInteger o, RxMatch & m, StackStrF & s)
|
||||
{
|
||||
return MatchFirstFrom_(OPTIONS, o, m, s);
|
||||
}
|
||||
SQMOD_NODISCARD int MatchFirstFrom_(int f, SQInteger o, RxMatch & m, StackStrF & s)
|
||||
{
|
||||
if (o > s.mLen)
|
||||
{
|
||||
STHROWF("Rx: Offset is out of range");
|
||||
}
|
||||
EstimateOVEC();
|
||||
// Attempt to execute the expression on the specified subject
|
||||
const int rc = pcre_exec(ValidPCRE(), mExtra, s.mPtr, static_cast< int >(s.mLen), static_cast< int >(o), f & 0xFFFF, mOVEC.data(), static_cast< int >(mOVEC.size()));
|
||||
// Was there a match?
|
||||
if (rc == PCRE_ERROR_NOMATCH)
|
||||
{
|
||||
m.mOffset = -1;
|
||||
m.mLength = 0;
|
||||
// No match found
|
||||
return 0;
|
||||
}
|
||||
// Bad options/flags?
|
||||
else if (rc == PCRE_ERROR_BADOPTION)
|
||||
{
|
||||
STHROWF("Rx: Bad option");
|
||||
}
|
||||
// Overflow?
|
||||
else if (rc == 0)
|
||||
{
|
||||
STHROWF("Rx: too many captured sub-strings");
|
||||
}
|
||||
// Some other error?
|
||||
else if (rc < 0)
|
||||
{
|
||||
STHROWF("Rx: error {}", rc);
|
||||
}
|
||||
// Store match
|
||||
m.mOffset = mOVEC[0];
|
||||
m.mLength = mOVEC[1] - mOVEC[0];
|
||||
// Yield result back to script
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* Returns the position of the first captured sub-string in m.
|
||||
* If no part of the subject matches the pattern, m.mOffset is -1 and m.mLength is 0.
|
||||
* Returns the number of matches. Throws a exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int MatchFirst(RxMatch & m, StackStrF & s)
|
||||
{
|
||||
return MatchFirstFrom_(OPTIONS, 0, m, s);
|
||||
}
|
||||
SQMOD_NODISCARD int MatchFirst_(int f, RxMatch & m, StackStrF & s)
|
||||
{
|
||||
return MatchFirstFrom_(f, 0, m, s);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* The first entry in m contains the position of the captured sub-string.
|
||||
* The following entries identify matching sub-patterns. See the PCRE documentation for a more detailed explanation.
|
||||
* If no part of the subject matches the pattern, m is empty.
|
||||
* Returns the number of matches. Throws an exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int MatchFrom(SQInteger o, RxMatches & m, StackStrF & s)
|
||||
{
|
||||
return MatchFrom_(OPTIONS, o, m, s);
|
||||
}
|
||||
SQMOD_NODISCARD int MatchFrom_(int f, SQInteger o, RxMatches & m, StackStrF & s)
|
||||
{
|
||||
if (o > s.mLen)
|
||||
{
|
||||
STHROWF("Rx: Offset is out of range");
|
||||
}
|
||||
EstimateOVEC();
|
||||
// Clear previous matches, if any
|
||||
m.mList.clear();
|
||||
// Attempt to execute the expression on the specified subject
|
||||
const int rc = pcre_exec(ValidPCRE(), mExtra, s.mPtr, static_cast< int >(s.mLen), static_cast< int >(o), f & 0xFFFF, mOVEC.data(), static_cast< int >(mOVEC.size()));
|
||||
// Was there a match?
|
||||
if (rc == PCRE_ERROR_NOMATCH)
|
||||
{
|
||||
return 0; // No match found
|
||||
}
|
||||
// Bad options/flags?
|
||||
else if (rc == PCRE_ERROR_BADOPTION)
|
||||
{
|
||||
STHROWF("Rx: Bad option");
|
||||
}
|
||||
// Overflow?
|
||||
else if (rc == 0)
|
||||
{
|
||||
STHROWF("Rx: too many captured sub-strings");
|
||||
}
|
||||
// Some other error?
|
||||
else if (rc < 0)
|
||||
{
|
||||
STHROWF("Rx: error {}", rc);
|
||||
}
|
||||
// Reserve space in advance
|
||||
m.mList.reserve(static_cast< size_t >(rc));
|
||||
// Transfer matches to match-list
|
||||
for (int i = 0; i < rc; ++i)
|
||||
{
|
||||
m.mList.emplace_back(mOVEC[i*2], mOVEC[i*2+1] - mOVEC[i*2]);
|
||||
}
|
||||
// Yield result back to script
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* The first entry in m contains the position of the captured sub-string.
|
||||
* The following entries identify matching sub-patterns. See the PCRE documentation for a more detailed explanation.
|
||||
* If no part of the subject matches the pattern, m is empty.
|
||||
* Returns the number of matches. Throws an exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int Match(RxMatches & m, StackStrF & s)
|
||||
{
|
||||
return MatchFrom_(OPTIONS, 0, m, s);
|
||||
}
|
||||
SQMOD_NODISCARD int Match_(int f, RxMatches & m, StackStrF & s)
|
||||
{
|
||||
return MatchFrom_(f, 0, m, s);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Returns true if and only if the subject matches the regular expression.
|
||||
* Internally, this method sets the RE_ANCHORED and RE_NOTEMPTY options for matching,
|
||||
* which means that the empty string will never match and the pattern is treated as if it starts with a ^.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Matches(StackStrF & s)
|
||||
{
|
||||
return Matches_(PCRE_ANCHORED | PCRE_NOTEMPTY, s);
|
||||
}
|
||||
SQMOD_NODISCARD bool Matches_(SQInteger o, StackStrF & s)
|
||||
{
|
||||
return MatchesEx(PCRE_ANCHORED | PCRE_NOTEMPTY, 0, s);
|
||||
}
|
||||
SQMOD_NODISCARD bool MatchesEx(int f, SQInteger o, StackStrF & s)
|
||||
{
|
||||
RxMatch m;
|
||||
const int rc = MatchFirstFrom_(f, o, m, s);
|
||||
return (rc > 0) && (m.mOffset == o) && (m.mLength == (s.mLen - o));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // Namespace:: SqMod
|
||||
+152
-117
@@ -362,6 +362,15 @@ static const EnumElement g_MainEnum[] = {
|
||||
{_SC("WARNING_AUTOINDEX"), SQLITE_WARNING_AUTOINDEX}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj GetSQLiteFromSession(Poco::Data::SessionImpl * session)
|
||||
{
|
||||
// Create a reference counted connection handle instance
|
||||
SQLiteConnRef ref(new SQLiteConnHnd(session));
|
||||
// Transform it into a connection instance and yield it as a script object
|
||||
return LightObj(SqTypeIdentity< SQLiteConnection >{}, SqVM(), ref);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static inline bool IsDigitsOnly(const SQChar * str)
|
||||
{
|
||||
@@ -374,13 +383,13 @@ static inline bool IsDigitsOnly(const SQChar * str)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object GetConnectionObj(const ConnRef & conn)
|
||||
Object GetConnectionObj(const SQLiteConnRef & conn)
|
||||
{
|
||||
return Object(new SQLiteConnection(conn));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object GetStatementObj(const StmtRef & stmt)
|
||||
Object GetStatementObj(const SQLiteStmtRef & stmt)
|
||||
{
|
||||
return Object(new SQLiteStatement(stmt));
|
||||
}
|
||||
@@ -602,6 +611,7 @@ SQLiteConnHnd::SQLiteConnHnd()
|
||||
, mFlags(0)
|
||||
, mName()
|
||||
, mVFS()
|
||||
, mSession()
|
||||
, mMemory(false)
|
||||
, mTrace(false)
|
||||
, mProfile(false)
|
||||
@@ -609,6 +619,24 @@ SQLiteConnHnd::SQLiteConnHnd()
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQLiteConnHnd::SQLiteConnHnd(Poco::Data::SessionImpl * session)
|
||||
: SQLiteConnHnd()
|
||||
{
|
||||
mSession.assign(session, true);
|
||||
// Retrieve the internal handle property
|
||||
mPtr = Poco::AnyCast< sqlite3 * >(mSession->getProperty("handle"));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQLiteConnHnd::SQLiteConnHnd(Poco::AutoPtr< Poco::Data::SessionImpl > && session)
|
||||
: SQLiteConnHnd()
|
||||
{
|
||||
mSession = std::move(session);
|
||||
// Retrieve the internal handle property
|
||||
mPtr = Poco::AnyCast< sqlite3 * >(mSession->getProperty("handle"));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQLiteConnHnd::~SQLiteConnHnd()
|
||||
{
|
||||
@@ -619,10 +647,17 @@ SQLiteConnHnd::~SQLiteConnHnd()
|
||||
Flush(static_cast<uint32_t>(mQueue.size()), NullObject(), NullFunction());
|
||||
// NOTE: Should we call sqlite3_interrupt(...) before closing?
|
||||
// Attempt to close the database
|
||||
if ((sqlite3_close(mPtr)) != SQLITE_OK)
|
||||
// If this connection is a pooled session then let it clean itself up
|
||||
if (mSession.isNull() && (sqlite3_close(mPtr)) != SQLITE_OK)
|
||||
{
|
||||
LogErr("Unable to close SQLite connection [%s]", sqlite3_errmsg(mPtr));
|
||||
}
|
||||
else
|
||||
{
|
||||
mSession.reset();
|
||||
}
|
||||
// Prevent further use of this connection
|
||||
mPtr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,7 +665,7 @@ SQLiteConnHnd::~SQLiteConnHnd()
|
||||
void SQLiteConnHnd::Create(const SQChar * name, int32_t flags, const SQChar * vfs)
|
||||
{
|
||||
// Make sure a previous connection doesn't exist
|
||||
if (mPtr)
|
||||
if (Access())
|
||||
{
|
||||
STHROWF("Unable to connect to database. Database already connected");
|
||||
}
|
||||
@@ -663,7 +698,7 @@ void SQLiteConnHnd::Create(const SQChar * name, int32_t flags, const SQChar * vf
|
||||
int32_t SQLiteConnHnd::Flush(uint32_t num, Object & env, Function & func)
|
||||
{
|
||||
// Do we even have a valid connection?
|
||||
if (!mPtr)
|
||||
if (!Access())
|
||||
{
|
||||
return -1; // No connection!
|
||||
}
|
||||
@@ -751,10 +786,10 @@ int32_t SQLiteConnHnd::Flush(uint32_t num, Object & env, Function & func)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQLiteStmtHnd::SQLiteStmtHnd(ConnRef conn)
|
||||
SQLiteStmtHnd::SQLiteStmtHnd(SQLiteConnRef conn)
|
||||
: mPtr(nullptr)
|
||||
, mStatus(SQLITE_OK)
|
||||
, mConn(std::move(conn))
|
||||
, mConnection(std::move(conn))
|
||||
, mQuery()
|
||||
, mColumns(0)
|
||||
, mParameters(0)
|
||||
@@ -774,7 +809,7 @@ SQLiteStmtHnd::~SQLiteStmtHnd()
|
||||
// Attempt to finalize the statement
|
||||
if ((sqlite3_finalize(mPtr)) != SQLITE_OK)
|
||||
{
|
||||
LogErr("Unable to finalize SQLite statement [%s]", mConn->ErrMsg());
|
||||
LogErr("Unable to finalize SQLite statement [%s]", mConnection->ErrMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -783,12 +818,12 @@ SQLiteStmtHnd::~SQLiteStmtHnd()
|
||||
void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
|
||||
{
|
||||
// Make sure a previous statement doesn't exist
|
||||
if (mPtr)
|
||||
if (Access())
|
||||
{
|
||||
STHROWF("Unable to prepare statement. Statement already prepared");
|
||||
}
|
||||
// Is the specified database connection is valid?
|
||||
else if (!mConn)
|
||||
else if (!mConnection)
|
||||
{
|
||||
STHROWF("Unable to prepare statement. Invalid connection handle");
|
||||
}
|
||||
@@ -800,7 +835,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
|
||||
// Save the query string
|
||||
mQuery.assign(query, static_cast< size_t >(length));
|
||||
// Attempt to prepare a statement with the specified query string
|
||||
if ((mStatus = sqlite3_prepare_v2(mConn->mPtr, mQuery.c_str(), ConvTo< int32_t >::From(mQuery.size()),
|
||||
if ((mStatus = sqlite3_prepare_v2(mConnection->mPtr, mQuery.c_str(), ConvTo< int32_t >::From(mQuery.size()),
|
||||
&mPtr, nullptr)) != SQLITE_OK)
|
||||
{
|
||||
// Clear the query string since it failed
|
||||
@@ -808,7 +843,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
|
||||
// Explicitly make sure the handle is null
|
||||
mPtr = nullptr;
|
||||
// Now it's safe to throw the error
|
||||
STHROWF("Unable to prepare statement [{}]", mConn->ErrMsg());
|
||||
STHROWF("Unable to prepare statement [{}]", mConnection->ErrMsg());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -823,7 +858,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
|
||||
int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
|
||||
{
|
||||
// Validate the handle
|
||||
if (!mPtr)
|
||||
if (!Access())
|
||||
{
|
||||
STHROWF("Invalid SQLite statement");
|
||||
}
|
||||
@@ -861,25 +896,25 @@ int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char * SQLiteStmtHnd::ErrStr() const
|
||||
{
|
||||
return mConn ? sqlite3_errstr(sqlite3_errcode(mConn->mPtr)) : _SC("");
|
||||
return mConnection ? sqlite3_errstr(sqlite3_errcode(mConnection->Access())) : _SC("");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char * SQLiteStmtHnd::ErrMsg() const
|
||||
{
|
||||
return mConn ? sqlite3_errmsg(mConn->mPtr) : _SC("");
|
||||
return mConnection ? sqlite3_errmsg(mConnection->Access()) : _SC("");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int32_t SQLiteStmtHnd::ErrNo() const
|
||||
{
|
||||
return mConn ? sqlite3_errcode(mConn->mPtr) : SQLITE_NOMEM;
|
||||
return mConnection ? sqlite3_errcode(mConnection->Access()) : SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int32_t SQLiteStmtHnd::ExErrNo() const
|
||||
{
|
||||
return mConn ? sqlite3_extended_errcode(mConn->mPtr) : SQLITE_NOMEM;
|
||||
return mConnection ? sqlite3_extended_errcode(mConnection->Access()) : SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -921,7 +956,7 @@ void SQLiteConnection::ValidateCreated(const char * file, int32_t line) const
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite connection reference =>[{}:{}]"), file, line);
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite connection =>[{}:{}]"), file, line);
|
||||
}
|
||||
@@ -933,7 +968,7 @@ void SQLiteConnection::ValidateCreated() const
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite connection reference"));
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite connection"));
|
||||
}
|
||||
@@ -942,13 +977,13 @@ void SQLiteConnection::ValidateCreated() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const ConnRef & SQLiteConnection::GetValid(const char * file, int32_t line) const
|
||||
const SQLiteConnRef & SQLiteConnection::GetValid(const char * file, int32_t line) const
|
||||
{
|
||||
Validate(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const ConnRef & SQLiteConnection::GetValid() const
|
||||
const SQLiteConnRef & SQLiteConnection::GetValid() const
|
||||
{
|
||||
Validate();
|
||||
return m_Handle;
|
||||
@@ -957,13 +992,13 @@ const ConnRef & SQLiteConnection::GetValid() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const ConnRef & SQLiteConnection::GetCreated(const char * file, int32_t line) const
|
||||
const SQLiteConnRef & SQLiteConnection::GetCreated(const char * file, int32_t line) const
|
||||
{
|
||||
ValidateCreated(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const ConnRef & SQLiteConnection::GetCreated() const
|
||||
const SQLiteConnRef & SQLiteConnection::GetCreated() const
|
||||
{
|
||||
ValidateCreated();
|
||||
return m_Handle;
|
||||
@@ -976,7 +1011,7 @@ void SQLiteConnection::Open(StackStrF & name)
|
||||
// Should we create a connection handle?
|
||||
if (!m_Handle)
|
||||
{
|
||||
m_Handle = ConnRef(new SQLiteConnHnd());
|
||||
m_Handle = SQLiteConnRef(new SQLiteConnHnd());
|
||||
}
|
||||
// Make sure another database isn't opened
|
||||
if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
|
||||
@@ -996,7 +1031,7 @@ void SQLiteConnection::Open(StackStrF & name, int32_t flags)
|
||||
// Should we create a connection handle?
|
||||
if (!m_Handle)
|
||||
{
|
||||
m_Handle = ConnRef(new SQLiteConnHnd());
|
||||
m_Handle = SQLiteConnRef(new SQLiteConnHnd());
|
||||
}
|
||||
// Make sure another database isn't opened
|
||||
if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
|
||||
@@ -1013,7 +1048,7 @@ void SQLiteConnection::Open(StackStrF & name, int32_t flags, StackStrF & vfs)
|
||||
// Should we create a connection handle?
|
||||
if (!m_Handle)
|
||||
{
|
||||
m_Handle = ConnRef(new SQLiteConnHnd());
|
||||
m_Handle = SQLiteConnRef(new SQLiteConnHnd());
|
||||
}
|
||||
// Make sure another database isn't opened
|
||||
if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
|
||||
@@ -1029,14 +1064,14 @@ int32_t SQLiteConnection::Exec(StackStrF & str)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to execute the specified query
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, str.mPtr, nullptr, nullptr, nullptr);
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), str.mPtr, nullptr, nullptr, nullptr);
|
||||
// Validate the execution result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
STHROWF("Unable to execute query [{}]", m_Handle->ErrMsg());
|
||||
}
|
||||
// Return rows affected by this query
|
||||
return sqlite3_changes(m_Handle->mPtr);
|
||||
return sqlite3_changes(m_Handle->Access());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -1109,12 +1144,12 @@ void SQLiteConnection::SetTracing(bool SQ_UNUSED_ARG(toggle)) // NOLINT(readabil
|
||||
// Do we have to disable it?
|
||||
else if (m_Handle->mTrace)
|
||||
{
|
||||
sqlite3_trace(m_Handle->mPtr, nullptr, nullptr);
|
||||
sqlite3_trace(m_Handle->Access(), nullptr, nullptr);
|
||||
}
|
||||
// Go ahead and enable tracing
|
||||
else
|
||||
{
|
||||
sqlite3_trace(m_Handle->mPtr, &SQLiteConnection::TraceOutput, nullptr);
|
||||
sqlite3_trace(m_Handle->Access(), &SQLiteConnection::TraceOutput, nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1133,12 +1168,12 @@ void SQLiteConnection::SetProfiling(bool SQ_UNUSED_ARG(toggle)) // NOLINT(readab
|
||||
// Do we have to disable it?
|
||||
else if (m_Handle->mProfile)
|
||||
{
|
||||
sqlite3_profile(m_Handle->mPtr, nullptr, nullptr);
|
||||
sqlite3_profile(m_Handle->Access(), nullptr, nullptr);
|
||||
}
|
||||
// Go ahead and enable profiling
|
||||
else
|
||||
{
|
||||
sqlite3_profile(m_Handle->mPtr, &SQLiteConnection::ProfileOutput, nullptr);
|
||||
sqlite3_profile(m_Handle->Access(), &SQLiteConnection::ProfileOutput, nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1148,7 +1183,7 @@ void SQLiteConnection::SetBusyTimeout(int32_t millis)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Apply the requested timeout
|
||||
if ((m_Handle->mStatus = sqlite3_busy_timeout(m_Handle->mPtr, millis)) != SQLITE_OK)
|
||||
if ((m_Handle->mStatus = sqlite3_busy_timeout(m_Handle->Access(), millis)) != SQLITE_OK)
|
||||
{
|
||||
STHROWF("Unable to set busy timeout [{}]", m_Handle->ErrMsg());
|
||||
}
|
||||
@@ -1269,7 +1304,7 @@ void SQLiteParameter::ValidateCreated(const char * file, int32_t line) const
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
|
||||
}
|
||||
@@ -1286,7 +1321,7 @@ void SQLiteParameter::ValidateCreated() const
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite statement"));
|
||||
}
|
||||
@@ -1295,13 +1330,13 @@ void SQLiteParameter::ValidateCreated() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const StmtRef & SQLiteParameter::GetValid(const char * file, int32_t line) const
|
||||
const SQLiteStmtRef & SQLiteParameter::GetValid(const char * file, int32_t line) const
|
||||
{
|
||||
Validate(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const StmtRef & SQLiteParameter::GetValid() const
|
||||
const SQLiteStmtRef & SQLiteParameter::GetValid() const
|
||||
{
|
||||
Validate();
|
||||
return m_Handle;
|
||||
@@ -1310,13 +1345,13 @@ const StmtRef & SQLiteParameter::GetValid() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const StmtRef & SQLiteParameter::GetCreated(const char * file, int32_t line) const
|
||||
const SQLiteStmtRef & SQLiteParameter::GetCreated(const char * file, int32_t line) const
|
||||
{
|
||||
ValidateCreated(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const StmtRef & SQLiteParameter::GetCreated() const
|
||||
const SQLiteStmtRef & SQLiteParameter::GetCreated() const
|
||||
{
|
||||
ValidateCreated();
|
||||
return m_Handle;
|
||||
@@ -1377,7 +1412,7 @@ void SQLiteParameter::SetIndex(const Object & param)
|
||||
STHROWF("Cannot use an empty parameter name");
|
||||
}
|
||||
// Attempt to find a parameter with the specified name
|
||||
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, val.mPtr);
|
||||
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->Access(), val.mPtr);
|
||||
} break;
|
||||
// Is this an integer value? (or at least can be easily converted to one)
|
||||
case OT_INTEGER:
|
||||
@@ -1409,7 +1444,7 @@ void SQLiteParameter::SetIndex(const Object & param)
|
||||
// Attempt to find a parameter with the specified name
|
||||
else
|
||||
{
|
||||
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, val.mPtr);
|
||||
idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->Access(), val.mPtr);
|
||||
}
|
||||
} break;
|
||||
// We don't recognize this kind of value!
|
||||
@@ -1432,7 +1467,7 @@ Object SQLiteParameter::GetStatement() const
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object SQLiteParameter::GetConnection() const
|
||||
{
|
||||
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn);
|
||||
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConnection);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -1477,7 +1512,7 @@ void SQLiteParameter::SetBool(bool value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, value);
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, value);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1490,7 +1525,7 @@ void SQLiteParameter::SetChar(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< SQChar >::From(value));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< SQChar >::From(value));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1503,7 +1538,7 @@ void SQLiteParameter::SetInteger(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_integer(m_Handle->mPtr, m_Index, value);
|
||||
m_Handle->mStatus = sqlite3_bind_integer(m_Handle->Access(), m_Index, value);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1516,7 +1551,7 @@ void SQLiteParameter::SetInt8(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int8_t >::From(value));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< int8_t >::From(value));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1529,7 +1564,7 @@ void SQLiteParameter::SetUint8(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< uint8_t >::From(value));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< uint8_t >::From(value));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1542,7 +1577,7 @@ void SQLiteParameter::SetInt16(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int16_t >::From(value));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< int16_t >::From(value));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1555,7 +1590,7 @@ void SQLiteParameter::SetUint16(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< uint16_t >::From(value));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< uint16_t >::From(value));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1568,7 +1603,7 @@ void SQLiteParameter::SetInt32(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int32_t >::From(value));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, ConvTo< int32_t >::From(value));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1581,7 +1616,7 @@ void SQLiteParameter::SetUint32(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, static_cast< int32_t >(ConvTo< uint32_t >::From(value)));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, static_cast< int32_t >(ConvTo< uint32_t >::From(value)));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1594,7 +1629,7 @@ void SQLiteParameter::SetInt64(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value);
|
||||
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->Access(), m_Index, value);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1607,7 +1642,7 @@ void SQLiteParameter::SetUint64(SQInteger value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value);
|
||||
m_Handle->mStatus = sqlite3_bind_int64(m_Handle->Access(), m_Index, value);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1620,7 +1655,7 @@ void SQLiteParameter::SetFloat(SQFloat value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, value);
|
||||
m_Handle->mStatus = sqlite3_bind_double(m_Handle->Access(), m_Index, value);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1633,7 +1668,7 @@ void SQLiteParameter::SetFloat32(SQFloat value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, ConvTo< float >::From(value));
|
||||
m_Handle->mStatus = sqlite3_bind_double(m_Handle->Access(), m_Index, ConvTo< float >::From(value));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1646,7 +1681,7 @@ void SQLiteParameter::SetFloat64(SQFloat value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, value);
|
||||
m_Handle->mStatus = sqlite3_bind_double(m_Handle->Access(), m_Index, value);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1659,7 +1694,7 @@ void SQLiteParameter::SetString(StackStrF & value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, value.mPtr, static_cast<int>(value.mLen), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, value.mPtr, static_cast<int>(value.mLen), SQLITE_TRANSIENT);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1672,7 +1707,7 @@ void SQLiteParameter::SetStringRaw(const SQChar * value, SQInteger length)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, value, static_cast<int>(length), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, value, static_cast<int>(length), SQLITE_TRANSIENT);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1685,7 +1720,7 @@ void SQLiteParameter::SetZeroBlob(SQInteger size)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_zeroblob(m_Handle->mPtr, m_Index, ConvTo< int32_t >::From(size));
|
||||
m_Handle->mStatus = sqlite3_bind_zeroblob(m_Handle->Access(), m_Index, ConvTo< int32_t >::From(size));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1717,7 +1752,7 @@ void SQLiteParameter::SetBlob(const Object & value)
|
||||
len = sqstd_getblobsize(vm, -1);
|
||||
}
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, ptr, static_cast<int>(len), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->Access(), m_Index, ptr, static_cast<int>(len), SQLITE_TRANSIENT);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1731,9 +1766,9 @@ void SQLiteParameter::SetData(const SqBuffer & value)
|
||||
Buffer & buff = *value.GetRef();
|
||||
// Attempt to bind the specified value
|
||||
#ifdef _SQ64
|
||||
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->mPtr, m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->Access(), m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
|
||||
#else
|
||||
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->Access(), m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
|
||||
#endif
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
@@ -1762,9 +1797,9 @@ void SQLiteParameter::SetDataEx(const SqBuffer & value, SQInteger offset, SQInte
|
||||
}
|
||||
// Attempt to bind the specified value
|
||||
#ifdef _SQ64
|
||||
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->mPtr, m_Index, (buff.Data() + offset), static_cast< sqlite3_uint64 >(offset + length), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->Access(), m_Index, (buff.Data() + offset), static_cast< sqlite3_uint64 >(offset + length), SQLITE_TRANSIENT);
|
||||
#else
|
||||
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, (buff.Data() + offset), static_cast< int >(offset + length), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_blob(m_Handle->Access(), m_Index, (buff.Data() + offset), static_cast< int >(offset + length), SQLITE_TRANSIENT);
|
||||
#endif
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
@@ -1780,7 +1815,7 @@ void SQLiteParameter::SetDate(const Date & value)
|
||||
// Attempt to generate the specified date string
|
||||
auto str = fmt::format("{} 00:00:00", value.ToString());
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1803,7 +1838,7 @@ void SQLiteParameter::SetDateEx(SQInteger year, SQInteger month, SQInteger day)
|
||||
// Attempt to generate the specified date string
|
||||
auto str = fmt::format("{}-{}-{} 00:00:00", y, m, d);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1816,7 +1851,7 @@ void SQLiteParameter::SetTime(const Time & value)
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, static_cast<int>(value.GetTimestamp().GetSecondsI()));
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, static_cast<int>(value.GetTimestamp().GetSecondsI()));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1848,7 +1883,7 @@ void SQLiteParameter::SetTimeEx(SQInteger hour, SQInteger minute, SQInteger seco
|
||||
STHROWF("Second value is out of range: {} >= 60", s);
|
||||
}
|
||||
// Calculate the number of seconds in the specified time and bind the resulted value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, (h * (60 * 60)) + (m * 60) + s);
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index, (h * (60 * 60)) + (m * 60) + s);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1896,7 +1931,7 @@ void SQLiteParameter::SetDatetimeEx(SQInteger year, SQInteger month, SQInteger d
|
||||
// Attempt to generate the specified date string
|
||||
auto str = fmt::format(_SC("{:04}-{:02}-{:02} {:02}:{:02}:{:02}"), y, mo, d, h, mi, s);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
|
||||
m_Handle->mStatus = sqlite3_bind_text(m_Handle->Access(), m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1909,7 +1944,7 @@ void SQLiteParameter::SetNow()
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index,
|
||||
m_Handle->mStatus = sqlite3_bind_int(m_Handle->Access(), m_Index,
|
||||
static_cast< int32_t >(std::time(nullptr)));
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
@@ -1923,7 +1958,7 @@ void SQLiteParameter::SetNull()
|
||||
{
|
||||
SQMOD_VALIDATE_CREATED(*this);
|
||||
// Attempt to bind the specified value
|
||||
m_Handle->mStatus = sqlite3_bind_null(m_Handle->mPtr, m_Index);
|
||||
m_Handle->mStatus = sqlite3_bind_null(m_Handle->Access(), m_Index);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -1975,7 +2010,7 @@ void SQLiteColumn::ValidateCreated(const char * file, int32_t line) const
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
|
||||
}
|
||||
@@ -1992,7 +2027,7 @@ void SQLiteColumn::ValidateCreated() const
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite statement"));
|
||||
}
|
||||
@@ -2001,13 +2036,13 @@ void SQLiteColumn::ValidateCreated() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const StmtRef & SQLiteColumn::GetValid(const char * file, int32_t line) const
|
||||
const SQLiteStmtRef & SQLiteColumn::GetValid(const char * file, int32_t line) const
|
||||
{
|
||||
Validate(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const StmtRef & SQLiteColumn::GetValid() const
|
||||
const SQLiteStmtRef & SQLiteColumn::GetValid() const
|
||||
{
|
||||
Validate();
|
||||
return m_Handle;
|
||||
@@ -2016,13 +2051,13 @@ const StmtRef & SQLiteColumn::GetValid() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const StmtRef & SQLiteColumn::GetCreated(const char * file, int32_t line) const
|
||||
const SQLiteStmtRef & SQLiteColumn::GetCreated(const char * file, int32_t line) const
|
||||
{
|
||||
ValidateCreated(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const StmtRef & SQLiteColumn::GetCreated() const
|
||||
const SQLiteStmtRef & SQLiteColumn::GetCreated() const
|
||||
{
|
||||
ValidateCreated();
|
||||
return m_Handle;
|
||||
@@ -2161,7 +2196,7 @@ Object SQLiteColumn::GetStatement() const
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object SQLiteColumn::GetConnection() const
|
||||
{
|
||||
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn);
|
||||
return GetConnectionObj(SQMOD_GET_VALID(*this)->mConnection);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -2207,7 +2242,7 @@ Object SQLiteColumn::GetValue() const
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg;
|
||||
// Identify which type of value must be pushed on the stack
|
||||
switch (sqlite3_column_type(m_Handle->mPtr, m_Index))
|
||||
switch (sqlite3_column_type(m_Handle->Access(), m_Index))
|
||||
{
|
||||
// Is this a null value?
|
||||
case SQLITE_NULL:
|
||||
@@ -2217,28 +2252,28 @@ Object SQLiteColumn::GetValue() const
|
||||
// Is this an integer?
|
||||
case SQLITE_INTEGER:
|
||||
{
|
||||
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->mPtr, m_Index));
|
||||
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->Access(), m_Index));
|
||||
} break;
|
||||
// Is this a floating point?
|
||||
case SQLITE_FLOAT:
|
||||
{
|
||||
sq_pushfloat(SqVM(),
|
||||
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)));
|
||||
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->Access(), m_Index)));
|
||||
} break;
|
||||
// Is this a string?
|
||||
case SQLITE_TEXT:
|
||||
{
|
||||
sq_pushstring(SqVM(),
|
||||
reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index)),
|
||||
sqlite3_column_bytes(m_Handle->mPtr, m_Index));
|
||||
reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->Access(), m_Index)),
|
||||
sqlite3_column_bytes(m_Handle->Access(), m_Index));
|
||||
} break;
|
||||
// Is this raw data?
|
||||
case SQLITE_BLOB:
|
||||
{
|
||||
// Retrieve the size of the blob that must be allocated
|
||||
const int32_t size = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
|
||||
const int32_t size = sqlite3_column_bytes(m_Handle->Access(), m_Index);
|
||||
// Retrieve the the actual blob data that must be returned
|
||||
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->mPtr, m_Index));
|
||||
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->Access(), m_Index));
|
||||
// Attempt to create a buffer with the blob data on the stack
|
||||
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
|
||||
} break;
|
||||
@@ -2256,7 +2291,7 @@ Object SQLiteColumn::GetNumber() const
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg;
|
||||
// Identify which type of value must be pushed on the stack
|
||||
switch (sqlite3_column_type(m_Handle->mPtr, m_Index))
|
||||
switch (sqlite3_column_type(m_Handle->Access(), m_Index))
|
||||
{
|
||||
// Is this a null value?
|
||||
case SQLITE_NULL:
|
||||
@@ -2266,18 +2301,18 @@ Object SQLiteColumn::GetNumber() const
|
||||
// Is this an integer?
|
||||
case SQLITE_INTEGER:
|
||||
{
|
||||
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->mPtr, m_Index));
|
||||
sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->Access(), m_Index));
|
||||
} break;
|
||||
// Is this a floating point?
|
||||
case SQLITE_FLOAT:
|
||||
{
|
||||
sq_pushfloat(SqVM(),
|
||||
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)));
|
||||
ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->Access(), m_Index)));
|
||||
} break;
|
||||
// Is this a string?
|
||||
case SQLITE_TEXT:
|
||||
{
|
||||
auto str = reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index));
|
||||
auto str = reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->Access(), m_Index));
|
||||
// Is there even a string to parse?
|
||||
if (!str || *str == '\0')
|
||||
{
|
||||
@@ -2308,7 +2343,7 @@ SQInteger SQLiteColumn::GetInteger() const
|
||||
{
|
||||
SQMOD_VALIDATE_ROW(*this);
|
||||
// Return the requested information
|
||||
return sqlite3_column_integer(m_Handle->mPtr, m_Index);
|
||||
return sqlite3_column_integer(m_Handle->Access(), m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -2316,7 +2351,7 @@ SQFloat SQLiteColumn::GetFloat() const
|
||||
{
|
||||
SQMOD_VALIDATE_ROW(*this);
|
||||
// Return the requested information
|
||||
return ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index));
|
||||
return ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->Access(), m_Index));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -2324,7 +2359,7 @@ SQInteger SQLiteColumn::GetLong() const
|
||||
{
|
||||
SQMOD_VALIDATE_ROW(*this);
|
||||
// Return the requested information
|
||||
return sqlite3_column_int64(m_Handle->mPtr, m_Index);
|
||||
return sqlite3_column_int64(m_Handle->Access(), m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -2334,8 +2369,8 @@ Object SQLiteColumn::GetString() const
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg;
|
||||
// Push the column text on the stack
|
||||
sq_pushstring(SqVM(), reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index)),
|
||||
sqlite3_column_bytes(m_Handle->mPtr, m_Index));
|
||||
sq_pushstring(SqVM(), reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->Access(), m_Index)),
|
||||
sqlite3_column_bytes(m_Handle->Access(), m_Index));
|
||||
// Get the object from the stack and return it
|
||||
return Var< Object >(SqVM(), -1).value;
|
||||
}
|
||||
@@ -2345,7 +2380,7 @@ bool SQLiteColumn::GetBoolean() const
|
||||
{
|
||||
SQMOD_VALIDATE_ROW(*this);
|
||||
// Return the requested information
|
||||
return sqlite3_column_int(m_Handle->mPtr, m_Index) > 0;
|
||||
return sqlite3_column_int(m_Handle->Access(), m_Index) > 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -2353,7 +2388,7 @@ SQChar SQLiteColumn::GetChar() const
|
||||
{
|
||||
SQMOD_VALIDATE_ROW(*this);
|
||||
// Return the requested information
|
||||
return (SQChar)sqlite3_column_int(m_Handle->mPtr, m_Index);
|
||||
return (SQChar)sqlite3_column_int(m_Handle->Access(), m_Index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -2363,9 +2398,9 @@ Object SQLiteColumn::GetBuffer() const
|
||||
// Remember the current stack size
|
||||
const StackGuard sg;
|
||||
// Retrieve the size of the blob that must be allocated
|
||||
const int32_t size = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
|
||||
const int32_t size = sqlite3_column_bytes(m_Handle->Access(), m_Index);
|
||||
// Retrieve the the actual blob data that must be returned
|
||||
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->mPtr, m_Index));
|
||||
auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->Access(), m_Index));
|
||||
// Attempt to create a buffer with the blob data on the stack
|
||||
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
|
||||
// Get the object from the stack and return it
|
||||
@@ -2379,11 +2414,11 @@ Object SQLiteColumn::GetBlob() const
|
||||
// Obtain the initial stack size
|
||||
const StackGuard sg;
|
||||
// Obtain the size of the data
|
||||
const int32_t sz = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
|
||||
const int32_t sz = sqlite3_column_bytes(m_Handle->Access(), m_Index);
|
||||
// Allocate a blob of the same size
|
||||
SQUserPointer p = sqstd_createblob(SqVM(), sz);
|
||||
// Obtain a pointer to the data
|
||||
const void * b = sqlite3_column_blob(m_Handle->mPtr, m_Index);
|
||||
const void * b = sqlite3_column_blob(m_Handle->Access(), m_Index);
|
||||
// Could the memory blob be allocated?
|
||||
if (!p)
|
||||
{
|
||||
@@ -2433,7 +2468,7 @@ void SQLiteStatement::ValidateCreated(const char * file, int32_t line) const
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
|
||||
}
|
||||
@@ -2445,7 +2480,7 @@ void SQLiteStatement::ValidateCreated() const
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
|
||||
}
|
||||
else if (m_Handle->mPtr == nullptr)
|
||||
else if (m_Handle->Access() == nullptr)
|
||||
{
|
||||
SqThrowF(fmt::runtime("Invalid SQLite statement"));
|
||||
}
|
||||
@@ -2454,13 +2489,13 @@ void SQLiteStatement::ValidateCreated() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const StmtRef & SQLiteStatement::GetValid(const char * file, int32_t line) const
|
||||
const SQLiteStmtRef & SQLiteStatement::GetValid(const char * file, int32_t line) const
|
||||
{
|
||||
Validate(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const StmtRef & SQLiteStatement::GetValid() const
|
||||
const SQLiteStmtRef & SQLiteStatement::GetValid() const
|
||||
{
|
||||
Validate();
|
||||
return m_Handle;
|
||||
@@ -2469,13 +2504,13 @@ const StmtRef & SQLiteStatement::GetValid() const
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
const StmtRef & SQLiteStatement::GetCreated(const char * file, int32_t line) const
|
||||
const SQLiteStmtRef & SQLiteStatement::GetCreated(const char * file, int32_t line) const
|
||||
{
|
||||
ValidateCreated(file, line);
|
||||
return m_Handle;
|
||||
}
|
||||
#else
|
||||
const StmtRef & SQLiteStatement::GetCreated() const
|
||||
const SQLiteStmtRef & SQLiteStatement::GetCreated() const
|
||||
{
|
||||
ValidateCreated();
|
||||
return m_Handle;
|
||||
@@ -2561,7 +2596,7 @@ SQLiteStatement::SQLiteStatement(const SQLiteConnection & connection, StackStrF
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Object SQLiteStatement::GetConnection() const
|
||||
{
|
||||
return Object(new SQLiteConnection(SQMOD_GET_VALID(*this)->mConn));
|
||||
return Object(new SQLiteConnection(SQMOD_GET_VALID(*this)->mConnection));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -2572,7 +2607,7 @@ SQLiteStatement & SQLiteStatement::Reset()
|
||||
m_Handle->mGood = false;
|
||||
m_Handle->mDone = false;
|
||||
// Attempt to reset the statement to it's initial state
|
||||
m_Handle->mStatus = sqlite3_reset(m_Handle->mPtr);
|
||||
m_Handle->mStatus = sqlite3_reset(m_Handle->Access());
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -2590,7 +2625,7 @@ SQLiteStatement & SQLiteStatement::Clear()
|
||||
m_Handle->mGood = false;
|
||||
m_Handle->mDone = false;
|
||||
// Attempt to clear the statement
|
||||
m_Handle->mStatus = sqlite3_clear_bindings(m_Handle->mPtr);
|
||||
m_Handle->mStatus = sqlite3_clear_bindings(m_Handle->Access());
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -2610,7 +2645,7 @@ int32_t SQLiteStatement::Exec()
|
||||
STHROWF("Executed without resetting first");
|
||||
}
|
||||
// Attempt to step the statement
|
||||
m_Handle->mStatus = sqlite3_step(m_Handle->mPtr);
|
||||
m_Handle->mStatus = sqlite3_step(m_Handle->Access());
|
||||
// Have we finished stepping?
|
||||
if (m_Handle->mStatus == SQLITE_DONE)
|
||||
{
|
||||
@@ -2618,7 +2653,7 @@ int32_t SQLiteStatement::Exec()
|
||||
m_Handle->mGood = false;
|
||||
m_Handle->mDone = true;
|
||||
// Return the changes made by this statement
|
||||
return sqlite3_changes(m_Handle->mConn->mPtr);
|
||||
return sqlite3_changes(m_Handle->mConnection->mPtr);
|
||||
}
|
||||
// Specify that we don't have any row and we haven't finished stepping
|
||||
m_Handle->mGood = false;
|
||||
@@ -2651,7 +2686,7 @@ bool SQLiteStatement::Step()
|
||||
STHROWF("Stepped without resetting first");
|
||||
}
|
||||
// Attempt to step the statement
|
||||
m_Handle->mStatus = sqlite3_step(m_Handle->mPtr);
|
||||
m_Handle->mStatus = sqlite3_step(m_Handle->Access());
|
||||
// Do we have a row available?
|
||||
if (m_Handle->mStatus == SQLITE_ROW)
|
||||
{
|
||||
@@ -2801,7 +2836,7 @@ Table SQLiteStatement::GetTable(int32_t min, int32_t max) const
|
||||
while (min <= max)
|
||||
{
|
||||
// Attempt to obtain the column name
|
||||
const SQChar * name = sqlite3_column_name(m_Handle->mPtr, min);
|
||||
const SQChar * name = sqlite3_column_name(m_Handle->Access(), min);
|
||||
// Validate the obtained name
|
||||
if (!name)
|
||||
{
|
||||
@@ -2824,7 +2859,7 @@ SQLiteTransaction::SQLiteTransaction(const SQLiteConnection & db)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQLiteTransaction::SQLiteTransaction(ConnRef db)
|
||||
SQLiteTransaction::SQLiteTransaction(SQLiteConnRef db)
|
||||
: m_Handle(std::move(db)), m_Committed(false)
|
||||
{
|
||||
// Was the specified database connection valid?
|
||||
@@ -2833,7 +2868,7 @@ SQLiteTransaction::SQLiteTransaction(ConnRef db)
|
||||
STHROWF("Invalid connection handle");
|
||||
}
|
||||
// Attempt to begin transaction
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "BEGIN", nullptr, nullptr, nullptr);
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), "BEGIN", nullptr, nullptr, nullptr);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -2850,7 +2885,7 @@ SQLiteTransaction::~SQLiteTransaction()
|
||||
return; // We're done here!
|
||||
}
|
||||
// Attempt to roll back changes because this failed to commit
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "ROLLBACK", nullptr, nullptr, nullptr);
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), "ROLLBACK", nullptr, nullptr, nullptr);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
@@ -2873,7 +2908,7 @@ bool SQLiteTransaction::Commit()
|
||||
STHROWF("Transaction was already committed");
|
||||
}
|
||||
// Attempt to commit the change during this transaction
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "COMMIT", nullptr, nullptr, nullptr);
|
||||
m_Handle->mStatus = sqlite3_exec(m_Handle->Access(), "COMMIT", nullptr, nullptr, nullptr);
|
||||
// Validate the result
|
||||
if (m_Handle->mStatus != SQLITE_OK)
|
||||
{
|
||||
|
||||
+114
-49
@@ -2,6 +2,7 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
#include "Core/ThreadPool.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Library/IO/Buffer.hpp"
|
||||
@@ -10,6 +11,10 @@
|
||||
#include "Library/Chrono/Time.hpp"
|
||||
#include "Library/Chrono/Timestamp.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Data/SessionImpl.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -78,18 +83,18 @@ struct SQLiteStmtHnd;
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Common typedefs.
|
||||
*/
|
||||
typedef SharedPtr< SQLiteConnHnd > ConnRef;
|
||||
typedef SharedPtr< SQLiteStmtHnd > StmtRef;
|
||||
typedef SharedPtr< SQLiteConnHnd > SQLiteConnRef;
|
||||
typedef SharedPtr< SQLiteStmtHnd > SQLiteStmtRef;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Obtain a script object from a connection handle. (meant to avoid having to include the header)
|
||||
*/
|
||||
Object GetConnectionObj(const ConnRef & conn);
|
||||
Object GetConnectionObj(const SQLiteConnRef & conn);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Obtain a script object from a statement handle. (meant to avoid having to include the header)
|
||||
*/
|
||||
Object GetStatementObj(const StmtRef & stmt);
|
||||
Object GetStatementObj(const SQLiteStmtRef & stmt);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Tests if a certain query string is empty.
|
||||
@@ -178,6 +183,9 @@ public:
|
||||
String mName; // The specified name to be used as the database file.
|
||||
String mVFS; // The specified virtual file system.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Poco::AutoPtr< Poco::Data::SessionImpl > mSession; // POCO session when this connection comes from a pool.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
bool mMemory; // Whether the database exists in memory and not disk.
|
||||
bool mTrace; // Whether tracing was activated on the database.
|
||||
@@ -188,6 +196,16 @@ public:
|
||||
*/
|
||||
SQLiteConnHnd();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
explicit SQLiteConnHnd(Poco::Data::SessionImpl * session);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
explicit SQLiteConnHnd(Poco::AutoPtr< Poco::Data::SessionImpl > && session);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
@@ -254,6 +272,20 @@ public:
|
||||
{
|
||||
return sqlite3_extended_errcode(mPtr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Access the connection pointer.
|
||||
*/
|
||||
SQMOD_NODISCARD Pointer Access() const
|
||||
{
|
||||
if (!mSession.isNull()) {
|
||||
// Only reason this is necessary is to dirty the connection handle access time-stamp
|
||||
// So it won't be closed/collected when it comes from a connection/session-pool
|
||||
[[maybe_unused]] auto _ = mSession->isConnected();
|
||||
}
|
||||
// We yield access to the pointer anyway
|
||||
return mPtr;
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -286,7 +318,7 @@ public:
|
||||
int32_t mStatus; // The last status code of this connection handle.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ConnRef mConn; // The handle to the associated database connection.
|
||||
SQLiteConnRef mConnection; // The handle to the associated database connection.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
String mQuery; // The query string used to create this statement.
|
||||
@@ -303,7 +335,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
explicit SQLiteStmtHnd(ConnRef conn);
|
||||
explicit SQLiteStmtHnd(SQLiteConnRef conn);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
@@ -375,6 +407,20 @@ public:
|
||||
* Return the extended numeric result code for the most recent failed API call (if any).
|
||||
*/
|
||||
SQMOD_NODISCARD int32_t ExErrNo() const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Access the statement pointer.
|
||||
*/
|
||||
SQMOD_NODISCARD Pointer Access() const
|
||||
{
|
||||
if (bool(mConnection) && !(mConnection->mSession.isNull())) {
|
||||
// Only reason this is necessary is to dirty the connection handle access time-stamp
|
||||
// So it won't be closed/collected when it comes from a connection/session-pool
|
||||
[[maybe_unused]] auto _ = mConnection->mSession->isConnected();
|
||||
}
|
||||
// We yield access to the pointer anyway
|
||||
return mPtr;
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -385,7 +431,7 @@ class SQLiteConnection
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ConnRef m_Handle; // Reference to the managed connection.
|
||||
SQLiteConnRef m_Handle; // Reference to the managed connection.
|
||||
|
||||
protected:
|
||||
|
||||
@@ -421,18 +467,18 @@ protected:
|
||||
* Validate the managed connection handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const ConnRef & GetValid(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteConnRef & GetValid(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const ConnRef & GetValid() const;
|
||||
SQMOD_NODISCARD const SQLiteConnRef & GetValid() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the managed connection handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const ConnRef & GetCreated(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteConnRef & GetCreated(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const ConnRef & GetCreated() const;
|
||||
SQMOD_NODISCARD const SQLiteConnRef & GetCreated() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
public:
|
||||
@@ -479,7 +525,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Direct handle constructor.
|
||||
*/
|
||||
explicit SQLiteConnection(ConnRef c)
|
||||
explicit SQLiteConnection(SQLiteConnRef c)
|
||||
: m_Handle(std::move(c))
|
||||
{
|
||||
/* ... */
|
||||
@@ -526,7 +572,7 @@ public:
|
||||
*/
|
||||
operator sqlite3 * () //NOLINT (intentionally implicit)
|
||||
{
|
||||
return m_Handle ? m_Handle->mPtr : nullptr;
|
||||
return m_Handle ? m_Handle->Access() : nullptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -534,7 +580,7 @@ public:
|
||||
*/
|
||||
operator sqlite3 * () const //NOLINT (intentionally implicit)
|
||||
{
|
||||
return m_Handle ? m_Handle->mPtr : nullptr;
|
||||
return m_Handle ? m_Handle->Access() : nullptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -548,7 +594,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the associated connection handle.
|
||||
*/
|
||||
SQMOD_NODISCARD const ConnRef & GetHandle() const
|
||||
SQMOD_NODISCARD const SQLiteConnRef & GetHandle() const
|
||||
{
|
||||
return m_Handle;
|
||||
}
|
||||
@@ -566,7 +612,7 @@ public:
|
||||
*/
|
||||
SQMOD_NODISCARD bool IsConnected() const
|
||||
{
|
||||
return m_Handle && (m_Handle->mPtr != nullptr);
|
||||
return m_Handle && (m_Handle->Access() != nullptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -679,6 +725,16 @@ public:
|
||||
*/
|
||||
Object Query(StackStrF & str) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to execute the specified query asynchronously.
|
||||
*/
|
||||
LightObj AsyncExec(StackStrF & str);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Attempt to create a statement from the specified query asynchronously.
|
||||
*/
|
||||
LightObj AsyncQuery(StackStrF & str) const;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* See if the database connection was opened in read-only mode.
|
||||
*/
|
||||
@@ -858,7 +914,7 @@ private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
int32_t m_Index{0}; // The index of the managed parameter.
|
||||
StmtRef m_Handle{}; // Reference to the managed statement.
|
||||
SQLiteStmtRef m_Handle{}; // Reference to the managed statement.
|
||||
|
||||
protected:
|
||||
|
||||
@@ -884,18 +940,18 @@ protected:
|
||||
* Validate the managed statement handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const StmtRef & GetValid(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetValid(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const StmtRef & GetValid() const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetValid() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the managed statement handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const StmtRef & GetCreated(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const StmtRef & GetCreated() const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -943,7 +999,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* No parameter constructor.
|
||||
*/
|
||||
explicit SQLiteParameter(StmtRef stmt)
|
||||
explicit SQLiteParameter(SQLiteStmtRef stmt)
|
||||
: m_Index(0), m_Handle(std::move(stmt))
|
||||
{
|
||||
/* ... */
|
||||
@@ -952,7 +1008,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Index constructor.
|
||||
*/
|
||||
SQLiteParameter(StmtRef stmt, int32_t idx)
|
||||
SQLiteParameter(SQLiteStmtRef stmt, int32_t idx)
|
||||
: m_Index(idx), m_Handle(std::move(stmt))
|
||||
{
|
||||
SQMOD_VALIDATE_PARAM(*this, m_Index);
|
||||
@@ -961,7 +1017,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Name constructor.
|
||||
*/
|
||||
SQLiteParameter(const StmtRef & stmt, const SQChar * name)
|
||||
SQLiteParameter(const SQLiteStmtRef & stmt, const SQChar * name)
|
||||
: m_Index(stmt ? sqlite3_bind_parameter_index(stmt->mPtr, name) : 0), m_Handle(stmt)
|
||||
{
|
||||
SQMOD_VALIDATE_PARAM(*this, m_Index);
|
||||
@@ -970,7 +1026,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Dynamic constructor.
|
||||
*/
|
||||
SQLiteParameter(StmtRef stmt, const Object & param)
|
||||
SQLiteParameter(SQLiteStmtRef stmt, const Object & param)
|
||||
: m_Index(0), m_Handle(std::move(stmt))
|
||||
{
|
||||
if (!m_Handle)
|
||||
@@ -1033,7 +1089,7 @@ public:
|
||||
// Can we attempt to return the parameter name?
|
||||
if (m_Handle && m_Index)
|
||||
{
|
||||
const SQChar * val = sqlite3_bind_parameter_name(m_Handle->mPtr, m_Index);
|
||||
const SQChar * val = sqlite3_bind_parameter_name(m_Handle->Access(), m_Index);
|
||||
// Return the value if valid
|
||||
return val ? val : String{};
|
||||
}
|
||||
@@ -1252,7 +1308,7 @@ private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
int32_t m_Index{-1}; // The index of the managed column.
|
||||
StmtRef m_Handle{}; // The statement where the column exist.
|
||||
SQLiteStmtRef m_Handle{}; // The statement where the column exist.
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1278,18 +1334,18 @@ protected:
|
||||
* Validate the managed statement handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const StmtRef & GetValid(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetValid(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const StmtRef & GetValid() const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetValid() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the managed statement handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const StmtRef & GetCreated(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const StmtRef & GetCreated() const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -1346,7 +1402,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* No column constructor.
|
||||
*/
|
||||
explicit SQLiteColumn(StmtRef stmt)
|
||||
explicit SQLiteColumn(SQLiteStmtRef stmt)
|
||||
: m_Index(-1), m_Handle(std::move(stmt))
|
||||
{
|
||||
/* ... */
|
||||
@@ -1355,7 +1411,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Index constructor.
|
||||
*/
|
||||
SQLiteColumn(StmtRef stmt, int32_t idx)
|
||||
SQLiteColumn(SQLiteStmtRef stmt, int32_t idx)
|
||||
: m_Index(idx), m_Handle(std::move(stmt))
|
||||
{
|
||||
SQMOD_VALIDATE_COLUMN(*this, m_Index);
|
||||
@@ -1364,7 +1420,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Name constructor.
|
||||
*/
|
||||
SQLiteColumn(const StmtRef & stmt, const SQChar * name)
|
||||
SQLiteColumn(const SQLiteStmtRef & stmt, const SQChar * name)
|
||||
: m_Index(stmt ? stmt->GetColumnIndex(name) : -1), m_Handle(stmt)
|
||||
{
|
||||
SQMOD_VALIDATE_COLUMN(*this, m_Index);
|
||||
@@ -1373,7 +1429,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Dynamic constructor.
|
||||
*/
|
||||
SQLiteColumn(StmtRef stmt, const Object & column)
|
||||
SQLiteColumn(SQLiteStmtRef stmt, const Object & column)
|
||||
: m_Index(-1), m_Handle(std::move(stmt))
|
||||
{
|
||||
if (!m_Handle)
|
||||
@@ -1436,7 +1492,7 @@ public:
|
||||
// Can we attempt to return the parameter name?
|
||||
if (m_Handle && m_Index)
|
||||
{
|
||||
const SQChar * val = sqlite3_column_name(m_Handle->mPtr, m_Index);
|
||||
const SQChar * val = sqlite3_column_name(m_Handle->Access(), m_Index);
|
||||
// Return the value if valid
|
||||
return val ? val : String{};
|
||||
}
|
||||
@@ -1573,7 +1629,7 @@ class SQLiteStatement
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
StmtRef m_Handle; // Reference to the managed statement.
|
||||
SQLiteStmtRef m_Handle; // Reference to the managed statement.
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1599,18 +1655,18 @@ protected:
|
||||
* Validate the managed statement handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const StmtRef & GetValid(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetValid(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const StmtRef & GetValid() const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetValid() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Validate the managed statement handle and throw an error if invalid.
|
||||
*/
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
SQMOD_NODISCARD const StmtRef & GetCreated(const char * file, int32_t line) const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated(const char * file, int32_t line) const;
|
||||
#else
|
||||
SQMOD_NODISCARD const StmtRef & GetCreated() const;
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated() const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -1654,12 +1710,21 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct a statement under the specified connection using the specified string.
|
||||
*/
|
||||
SQLiteStatement(const ConnRef & connection, StackStrF & query)
|
||||
SQLiteStatement(const SQLiteConnRef & connection, StackStrF & query)
|
||||
: m_Handle(new SQLiteStmtHnd(connection))
|
||||
{
|
||||
SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct a statement under the specified connection using the specified string.
|
||||
*/
|
||||
SQLiteStatement(const SQLiteConnRef & connection, const SQChar * query, SQInteger length)
|
||||
: m_Handle(new SQLiteStmtHnd(connection))
|
||||
{
|
||||
SQMOD_GET_VALID(*this)->Create(query, length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct a statement under the specified connection using the specified string.
|
||||
*/
|
||||
@@ -1668,7 +1733,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Direct handle constructor.
|
||||
*/
|
||||
explicit SQLiteStatement(StmtRef s)
|
||||
explicit SQLiteStatement(SQLiteStmtRef s)
|
||||
: m_Handle(std::move(s))
|
||||
{
|
||||
/* ... */
|
||||
@@ -1715,7 +1780,7 @@ public:
|
||||
*/
|
||||
operator sqlite3_stmt * () // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
{
|
||||
return m_Handle ? m_Handle->mPtr : nullptr;
|
||||
return m_Handle ? m_Handle->Access() : nullptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -1723,7 +1788,7 @@ public:
|
||||
*/
|
||||
operator sqlite3_stmt * () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
{
|
||||
return m_Handle ? m_Handle->mPtr : nullptr;
|
||||
return m_Handle ? m_Handle->Access() : nullptr;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -1737,7 +1802,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the associated statement handle.
|
||||
*/
|
||||
SQMOD_NODISCARD const StmtRef & GetHandle() const
|
||||
SQMOD_NODISCARD const SQLiteStmtRef & GetHandle() const
|
||||
{
|
||||
return m_Handle;
|
||||
}
|
||||
@@ -1755,7 +1820,7 @@ public:
|
||||
*/
|
||||
SQMOD_NODISCARD bool IsPrepared() const
|
||||
{
|
||||
return m_Handle && (m_Handle->mPtr != nullptr);
|
||||
return m_Handle && (m_Handle->Access() != nullptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -2436,7 +2501,7 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct using the direct connection handle.
|
||||
*/
|
||||
explicit SQLiteTransaction(ConnRef db);
|
||||
explicit SQLiteTransaction(SQLiteConnRef db);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
@@ -2495,7 +2560,7 @@ public:
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ConnRef m_Handle{}; // The database connection handle where the transaction began.
|
||||
SQLiteConnRef m_Handle{}; // The database connection handle where the transaction began.
|
||||
bool m_Committed{false}; // Whether changes were successfully committed to the database.
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(SqIdPoolTypename, _SC("SqIdPool"))
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Probably not the best implementation but should cover all sorts of weird cases.
|
||||
*/
|
||||
@@ -83,15 +86,18 @@ static SQInteger SqExtractIPv4(HSQUIRRELVM vm)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern void Register_IdPool(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_Vector(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_Native_String(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_ServerAnnouncer(HSQUIRRELVM vm, Table & ns);
|
||||
|
||||
|
||||
// ================================================================================================
|
||||
void Register_Utils(HSQUIRRELVM vm)
|
||||
{
|
||||
Table ns(vm);
|
||||
|
||||
Register_IdPool(vm, ns);
|
||||
Register_Vector(vm, ns);
|
||||
Register_Native_String(vm, ns);
|
||||
Register_ServerAnnouncer(vm, ns);
|
||||
@@ -101,4 +107,35 @@ void Register_Utils(HSQUIRRELVM vm)
|
||||
RootTable(vm).Bind(_SC("SqUtils"), ns);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Register_IdPool(HSQUIRRELVM vm, Table & ns)
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(_SC("IdPool"),
|
||||
Class< SqIdPool, NoCopy< SqIdPool > >(vm, SqIdPoolTypename::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.template Ctor< SqIdPool::Type >()
|
||||
.template Ctor< SqIdPool::Type, SqIdPool::Type >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqIdPoolTypename::Fn)
|
||||
// Member Variables
|
||||
.ConstVar(_SC("Next"), &SqIdPool::mNext)
|
||||
.ConstVar(_SC("Step"), &SqIdPool::mStep)
|
||||
.ConstVar(_SC("Start"), &SqIdPool::mStart)
|
||||
// Properties
|
||||
.Prop(_SC("FreeCount"), &SqIdPool::FreeCount)
|
||||
.Prop(_SC("UsedCount"), &SqIdPool::UsedCount)
|
||||
// Member Methods
|
||||
.Func(_SC("Reset"), &SqIdPool::Reset)
|
||||
.Func(_SC("Acquire"), &SqIdPool::Acquire)
|
||||
.Func(_SC("Release"), &SqIdPool::Release)
|
||||
.Func(_SC("Using"), &SqIdPool::Using)
|
||||
.Func(_SC("EachUsed"), &SqIdPool::EachUsed)
|
||||
.Func(_SC("WhileUsed"), &SqIdPool::WhileUsed)
|
||||
.Func(_SC("EachFree"), &SqIdPool::EachFree)
|
||||
.Func(_SC("WhileFree"), &SqIdPool::WhileFree)
|
||||
);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -6,4 +6,187 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Helper utility used to provide reusable unique IDs of signed integer type.
|
||||
* It is not thread-safe since the script runs in single-threaded mode.
|
||||
*/
|
||||
struct SqIdPool
|
||||
{
|
||||
using Type = SQInteger; // Type that is used to represent an ID.
|
||||
using Pool = std::vector< Type >; // Container for both used and unused IDs.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Pool of available IDs.
|
||||
Pool mPool{};
|
||||
// Pool of currently used IDs.
|
||||
Pool mUsed{};
|
||||
// The ID that will be generated next time the pool is empty.
|
||||
Type mNext{0};
|
||||
// How much to increment with each ID.
|
||||
Type mStep{1};
|
||||
// Where to start generating IDs.
|
||||
Type mStart{0};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructors.
|
||||
*/
|
||||
SqIdPool() noexcept = default;
|
||||
SqIdPool(Type start) noexcept
|
||||
: SqIdPool(start, 1)
|
||||
{
|
||||
}
|
||||
SqIdPool(Type start, Type step) noexcept
|
||||
: mPool(), mUsed(), mNext(start), mStep(step), mStart(start)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy/Move constructors (disabled).
|
||||
*/
|
||||
SqIdPool(const SqIdPool &) noexcept = delete;
|
||||
SqIdPool(SqIdPool &&) noexcept = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy/Move assignment operators (disabled).
|
||||
*/
|
||||
SqIdPool & operator = (const SqIdPool &) noexcept = delete;
|
||||
SqIdPool & operator = (SqIdPool &&) noexcept = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Discard all current IDs (free and used) and reset the start to the specified start.
|
||||
* This invalidates all IDs that are currently left in use.
|
||||
*/
|
||||
void Reset()
|
||||
{
|
||||
mNext = mStart;
|
||||
mPool.clear();
|
||||
mUsed.clear();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Acquire a unique ID from the pool.
|
||||
*/
|
||||
SQMOD_NODISCARD Type Acquire()
|
||||
{
|
||||
Type id = mNext;
|
||||
// Do we have some reusable IDs?
|
||||
if (mPool.empty())
|
||||
{
|
||||
mNext += mStep; // Create a new one and update the next one
|
||||
}
|
||||
else
|
||||
{
|
||||
id = mPool.back(); // Get one from the back of the pool
|
||||
mPool.pop_back(); // Remove it from the free pool
|
||||
}
|
||||
// Store it in the list of active IDs
|
||||
mUsed.push_back(id);
|
||||
// Return this ID
|
||||
return id;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Release a unique ID back to the pool.
|
||||
*/
|
||||
bool Release(Type id)
|
||||
{
|
||||
// Find the specified ID into
|
||||
for (Pool::size_type i = 0; i < mUsed.size(); ++i)
|
||||
{
|
||||
// Is this the ID we're looking for?
|
||||
if (mUsed[i] == id)
|
||||
{
|
||||
// Swap the element with the last one
|
||||
std::swap(mUsed[i], mUsed.back());
|
||||
// Remove the last element
|
||||
mUsed.pop_back();
|
||||
// Make this ID available, again
|
||||
mPool.push_back(id);
|
||||
// We actually found this ID
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// This ID does not belong to this pool
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if the pool has the specified ID currently in use.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Using(Type id)
|
||||
{
|
||||
return std::find(mUsed.begin(), mUsed.end(), id) != mUsed.end();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of IDs that are currently available in the free pool.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger FreeCount() const
|
||||
{
|
||||
return mPool.size();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of IDs that are currently in use.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger UsedCount() const
|
||||
{
|
||||
return mUsed.size();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all used IDs through a functor.
|
||||
*/
|
||||
void EachUsed(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mUsed)
|
||||
{
|
||||
fn.Execute(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all used IDs through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void WhileUsed(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mUsed)
|
||||
{
|
||||
auto ret = fn.Eval(id);
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all free IDs through a functor.
|
||||
*/
|
||||
void EachFree(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mPool)
|
||||
{
|
||||
fn.Execute(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all free IDs through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void WhileFree(Function & fn) const
|
||||
{
|
||||
for (const auto & id : mPool)
|
||||
{
|
||||
auto ret = fn.Eval(id);
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -556,6 +556,21 @@ void Logger::ProcessMessage()
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Logger::Send(uint8_t level, bool sub, const char * msg)
|
||||
{
|
||||
// Is this level even allowed?
|
||||
if ((m_ConsoleLevels & level) || (m_LogFileLevels & level))
|
||||
{
|
||||
// Create a new message builder
|
||||
MsgPtr message(new Message(level, sub));
|
||||
// Generate the log message
|
||||
message->Append(msg);
|
||||
// Process the message in the buffer
|
||||
PushMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Logger::Send(uint8_t level, bool sub, const char * msg, size_t len)
|
||||
{
|
||||
|
||||
@@ -409,6 +409,11 @@ public:
|
||||
*/
|
||||
void BindCb(uint8_t level, Function & func);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Send a log message.
|
||||
*/
|
||||
void Send(uint8_t level, bool sub, const char * msg);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Send a log message.
|
||||
*/
|
||||
|
||||
+10
-3
@@ -17,7 +17,7 @@ namespace SqMod {
|
||||
static bool g_Reload = false;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
//extern void InitExports();
|
||||
extern void InitExports();
|
||||
extern void InitializeNet();
|
||||
extern void InitializePocoDataConnectors();
|
||||
extern void ProcessRoutines();
|
||||
@@ -97,7 +97,7 @@ static uint8_t OnServerInitialise()
|
||||
{
|
||||
SQMOD_SV_EV_TRACEBACK("[TRACE<] OnServerInitialise")
|
||||
// Signal outside plug-ins to do fetch our proxies
|
||||
//_Func->SendPluginCommand(0xDABBAD00, "%d", 1);
|
||||
_Func->SendPluginCommand(SQMOD_INITIALIZE_CMD, "%d", 1);
|
||||
// Attempt to load the module core
|
||||
if (Core::Get().Execute())
|
||||
{
|
||||
@@ -965,6 +965,11 @@ static void OnServerPerformanceReport(size_t /*entry_count*/, const char * * /*d
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Automatically terminate the third-party allocator.
|
||||
*/
|
||||
static std::unique_ptr< SqMod::RPMallocInit > gsRPMallocInit;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Plug-in initialization procedure.
|
||||
*/
|
||||
@@ -989,6 +994,8 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback
|
||||
_Info->apiMinorVersion = PLUGIN_API_MINOR;
|
||||
// Assign the plug-in name
|
||||
std::snprintf(_Info->name, sizeof(_Info->name), "%s", SQMOD_HOST_NAME);
|
||||
// Initialize third-party allocator
|
||||
gsRPMallocInit = std::make_unique< RPMallocInit >();
|
||||
// Attempt to initialize the logger before anything else
|
||||
Logger::Get().Initialize(nullptr);
|
||||
// Attempt to initialize the plug-in core
|
||||
@@ -1076,7 +1083,7 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback
|
||||
_Clbk->OnEntityStreamingChange = OnEntityStreamingChange;
|
||||
#endif
|
||||
// Attempt to initialize the plug-in exports
|
||||
//InitExports();
|
||||
InitExports();
|
||||
// Dummy spacing
|
||||
puts("");
|
||||
// Initialization was successful
|
||||
|
||||
+123
-62
@@ -52,6 +52,66 @@ SQMOD_DECL_TYPENAME(CPickupTn, _SC("CPickup"))
|
||||
SQMOD_DECL_TYPENAME(CPlayerTn, _SC("CPlayer"))
|
||||
SQMOD_DECL_TYPENAME(CVehicleTn, _SC("CVehicle"))
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Used to fetch the legacy entity instance even if a native one was specified.
|
||||
*/
|
||||
template < class LEGACY, class NATIVE > inline LEGACY & GetLgEnt(LightObj & o)
|
||||
{
|
||||
const auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
|
||||
// Legacy entity type?
|
||||
if (type == StaticClassTypeTag< LEGACY >::Get())
|
||||
{
|
||||
return *o.CastI< LEGACY >();
|
||||
}
|
||||
// Native entity type?
|
||||
if (type == StaticClassTypeTag< NATIVE >::Get())
|
||||
{
|
||||
return *EntityInstSelect< NATIVE >::Get(o.CastI< NATIVE >()->GetID()).mLgInst;
|
||||
}
|
||||
STHROWF("Invalid entity type: {}", SqTypeName(SqVM(), o));
|
||||
SQ_UNREACHABLE
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Used to fetch the native entity instance even if a legacy one was specified.
|
||||
*/
|
||||
template < class LEGACY, class NATIVE > inline NATIVE & GetNativeEnt(LightObj & o)
|
||||
{
|
||||
const auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
|
||||
// Legacy entity type?
|
||||
if (type == StaticClassTypeTag< LEGACY >::Get())
|
||||
{
|
||||
return o.CastI< LEGACY >()->Get();
|
||||
}
|
||||
// Native entity type?
|
||||
if (type == StaticClassTypeTag< NATIVE >::Get())
|
||||
{
|
||||
return *EntityInstSelect< NATIVE >::Get(o.CastI< NATIVE >()->GetID()).mInst;
|
||||
}
|
||||
STHROWF("Invalid entity type: {}", SqTypeName(SqVM(), o));
|
||||
SQ_UNREACHABLE
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Used to fetch the legacy entity identifier even if a native one was specified.
|
||||
*/
|
||||
template < class LEGACY, class NATIVE > SQMOD_NODISCARD inline int32_t GetLgEntID(LightObj & o)
|
||||
{
|
||||
const auto type = static_cast< AbstractStaticClassData * >(o.GetTypeTag());
|
||||
// Legacy entity type?
|
||||
if (type == StaticClassTypeTag< LEGACY >::Get())
|
||||
{
|
||||
return o.CastI< LEGACY >()->mID;
|
||||
}
|
||||
// Native entity type?
|
||||
if (type == StaticClassTypeTag< NATIVE >::Get())
|
||||
{
|
||||
return o.CastI< NATIVE >()->GetID();
|
||||
}
|
||||
STHROWF("Invalid entity type: {}", SqTypeName(SqVM(), o));
|
||||
SQ_UNREACHABLE
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Entity type enumeration.
|
||||
*/
|
||||
@@ -250,10 +310,10 @@ void LgEntityQuaternion::Set()
|
||||
case LgEntityType::Vehicle:
|
||||
switch (mFlag)
|
||||
{
|
||||
case LgVehicleVectorFlag::Angle:
|
||||
case LgVehicleQuaternionFlag::Angle:
|
||||
_Func->SetVehicleRotation(mID, x, y, z, w);
|
||||
break;
|
||||
case LgVehicleVectorFlag::SpawnAngle:
|
||||
case LgVehicleQuaternionFlag::SpawnAngle:
|
||||
_Func->SetVehicleSpawnRotation(mID, x, y, z, w);
|
||||
break;
|
||||
default: break;
|
||||
@@ -438,14 +498,14 @@ struct LgCheckpoint
|
||||
SQMOD_NODISCARD int GetWorld() const { return Get().GetWorld(); }
|
||||
SQMOD_NODISCARD LgARGB GetColor() const { const Color4 c = Get().GetColor(); return LgARGB{c.a, c.r, c.g, c.b}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetPos() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Checkpoint, 0, Get().GetPosition()); }
|
||||
{ return {mID, LgEntityType::Checkpoint, 0, Get().GetPosition()}; }
|
||||
SQMOD_NODISCARD float GetRadius() const { return Get().GetRadius(); }
|
||||
SQMOD_NODISCARD int GetID() const { return mID; }
|
||||
SQMOD_NODISCARD LgPlayer * GetOwner() const
|
||||
{ const int id = Get().GetOwnerID(); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Delete() const { _Func->DeleteCheckPoint(GetIdentifier()); }
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(LgPlayer & player) const;
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -506,11 +566,11 @@ struct LgObject
|
||||
SQMOD_NODISCARD int GetAlpha() const { return Get().GetAlpha(); }
|
||||
SQMOD_NODISCARD int GetWorld() const { return Get().GetWorld(); }
|
||||
SQMOD_NODISCARD LgEntityVector GetPos() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Object, LgObjectVectorFlag::Pos, Get().GetPosition()); }
|
||||
{ return {mID, LgEntityType::Object, LgObjectVectorFlag::Pos, Get().GetPosition()}; }
|
||||
SQMOD_NODISCARD LgEntityQuaternion GetRotation() const
|
||||
{ return LgEntityQuaternion(mID, LgEntityType::Object, 0, Get().GetRotation()); }
|
||||
{ return {mID, LgEntityType::Object, 0, Get().GetRotation()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetRotationEuler() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Object, LgObjectVectorFlag::Rotation, Get().GetRotationEuler()); }
|
||||
{ return {mID, LgEntityType::Object, LgObjectVectorFlag::Rotation, Get().GetRotationEuler()}; }
|
||||
SQMOD_NODISCARD int GetID() const { return mID; }
|
||||
SQMOD_NODISCARD bool GetReportingShots() const { return Get().GetShotReport(); }
|
||||
SQMOD_NODISCARD bool GetReportingBumps() const { return Get().GetTouchedReport(); }
|
||||
@@ -523,7 +583,7 @@ struct LgObject
|
||||
void RotateToEuler(const Vector3 & rotation, int time) const { Get().RotateToEuler(rotation, static_cast< uint32_t >(time)); }
|
||||
void RotateByEuler(const Vector3 & rotOffset, int time) const { Get().RotateByEuler(rotOffset, static_cast< uint32_t >(time)); }
|
||||
void SetAlpha(int alpha, int fadeTime) const { Get().SetAlphaEx(alpha, static_cast< uint32_t >(fadeTime)); }
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(LgPlayer & player) const;
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -587,7 +647,7 @@ struct LgPickup
|
||||
SQMOD_NODISCARD bool GetAuto() const { return Get().GetAutomatic(); }
|
||||
SQMOD_NODISCARD int GetAutoTimer() const { return Get().GetAutoTimer(); }
|
||||
SQMOD_NODISCARD LgEntityVector GetPos() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Pickup, 0, Get().GetPosition()); }
|
||||
{ return {mID, LgEntityType::Pickup, 0, Get().GetPosition()}; }
|
||||
SQMOD_NODISCARD int GetModel() const { return Get().GetModel(); }
|
||||
SQMOD_NODISCARD int GetQuantity() const { return Get().GetQuantity(); }
|
||||
SQMOD_NODISCARD int GetID() const { return mID; }
|
||||
@@ -595,7 +655,7 @@ struct LgPickup
|
||||
// --------------------------------------------------------------------------------------------
|
||||
void Delete() const { _Func->DeletePickup(GetIdentifier()); }
|
||||
void Respawn() const { Get().Refresh(); }
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(LgPlayer & player) const;
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
@@ -663,7 +723,7 @@ struct LgPlayer
|
||||
void SetScore(int score) const { Get().SetScore(score); }
|
||||
void SetImmunity(uint32_t immunity) const { Get().SetImmunity(immunity); }
|
||||
void SetHeading(float heading) const { Get().SetHeading(heading); }
|
||||
void SetVehicle(LgVehicle & vehicle) const;
|
||||
void SetVehicle(LightObj & vehicle) const;
|
||||
void SetFrozen(bool toggle) const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionControllable, static_cast< uint8_t >(!toggle)); }
|
||||
void SetDriveByEnabled(bool toggle) const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionDriveBy, static_cast< uint8_t >(toggle)); }
|
||||
void SetWhiteScanLines(bool toggle) const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionWhiteScanlines, static_cast< uint8_t >(toggle)); }
|
||||
@@ -680,7 +740,7 @@ struct LgPlayer
|
||||
void SetWantedLevel(int level) const { Get().SetWantedLevel(level); }
|
||||
// --------------------------------------------------------------------------------------------
|
||||
SQMOD_NODISCARD LgEntityVector GetPosition() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Player, LgPlayerVectorFlag::Pos, Get().GetPosition()); }
|
||||
{ return {mID, LgEntityType::Player, LgPlayerVectorFlag::Pos, Get().GetPosition()}; }
|
||||
SQMOD_NODISCARD int GetClass() const { return Get().GetClass(); }
|
||||
SQMOD_NODISCARD bool GetAdmin() const { return Get().GetAdmin(); }
|
||||
SQMOD_NODISCARD const SQChar * GetIP() const { return Get().GetIP(); }
|
||||
@@ -692,7 +752,7 @@ struct LgPlayer
|
||||
SQMOD_NODISCARD const SQChar * GetName() const { return Get().GetName(); }
|
||||
SQMOD_NODISCARD int GetTeam() const { return Get().GetTeam(); }
|
||||
SQMOD_NODISCARD int GetSkin() const { return Get().GetSkin(); }
|
||||
SQMOD_NODISCARD LgEntityRGB GetColour() const { return LgEntityRGB(mID, LgEntityType::Player, 0, Get().GetColor()); }
|
||||
SQMOD_NODISCARD LgEntityRGB GetColour() const { return {mID, LgEntityType::Player, 0, Get().GetColor()}; }
|
||||
SQMOD_NODISCARD int GetMoney() const { return Get().GetMoney(); }
|
||||
SQMOD_NODISCARD int GetScore() const { return Get().GetScore(); }
|
||||
SQMOD_NODISCARD int GetPing() const { return Get().GetPing(); }
|
||||
@@ -724,7 +784,7 @@ struct LgPlayer
|
||||
SQMOD_NODISCARD LgPlayer * GetSpectateTarget() const
|
||||
{ const int id = _Func->GetPlayerSpectateTarget(GetIdentifier()); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
|
||||
SQMOD_NODISCARD LgEntityVector GetSpeed() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Player, LgPlayerVectorFlag::Speed, Get().GetSpeed()); }
|
||||
{ return {mID, LgEntityType::Player, LgPlayerVectorFlag::Speed, Get().GetSpeed()}; }
|
||||
SQMOD_NODISCARD bool GetCanUseColors() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionChatTagsEnabled) >= 1; }
|
||||
SQMOD_NODISCARD bool GetMarkerVisible() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker) >= 1; }
|
||||
SQMOD_NODISCARD bool GetDrunkStatus() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionDrunkEffects) >= 1; }
|
||||
@@ -761,8 +821,8 @@ struct LgPlayer
|
||||
SQMOD_NODISCARD int GetWeaponAtSlot(int slot) const { return Get().GetWeaponAtSlot(slot); }
|
||||
SQMOD_NODISCARD int GetAmmoAtSlot(int slot) const { return Get().GetAmmoAtSlot(slot); }
|
||||
void SetAlpha(int alpha, int fadeTime) const { Get().SetAlphaEx(alpha, fadeTime); }
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(const LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
||||
void SetVehicleSlot(const LgVehicle & vehicle, int slot) const;
|
||||
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||
void SetVehicleSlot(LightObj & vehicle, int slot) const;
|
||||
void Select() const { Get().ForceSelect(); }
|
||||
void RestoreCamera() const { Get().RestoreCamera(); }
|
||||
void RemoveMarker() const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker, 0); }
|
||||
@@ -875,13 +935,13 @@ struct LgVehicle
|
||||
SQMOD_NODISCARD int GetModel() const { return Get().GetModel(); }
|
||||
SQMOD_NODISCARD uint32_t GetImmunity() const { return Get().GetImmunity(); }
|
||||
SQMOD_NODISCARD LgEntityVector GetPosition() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Pos, Get().GetPosition()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Pos, Get().GetPosition()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetSpawnPos() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnPos, Get().GetSpawnPosition()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnPos, Get().GetSpawnPosition()}; }
|
||||
SQMOD_NODISCARD LgEntityQuaternion GetSpawnAngle() const
|
||||
{ return LgEntityQuaternion(mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::SpawnAngle, Get().GetSpawnRotation()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::SpawnAngle, Get().GetSpawnRotation()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetSpawnAngleEuler() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnAngle, Get().GetSpawnRotationEuler()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::SpawnAngle, Get().GetSpawnRotationEuler()}; }
|
||||
SQMOD_NODISCARD uint32_t GetIdleRespawnTimer() const { return Get().GetIdleRespawnTimer(); }
|
||||
SQMOD_NODISCARD float GetHealth() const { return Get().GetHealth(); }
|
||||
SQMOD_NODISCARD int GetColour1() const { return Get().GetPrimaryColor(); }
|
||||
@@ -899,21 +959,21 @@ struct LgVehicle
|
||||
SQMOD_NODISCARD int GetSyncType() const { return Get().GetSyncType(); }
|
||||
SQMOD_NODISCARD bool GetWrecked() const { return Get().IsWrecked(); }
|
||||
SQMOD_NODISCARD LgEntityQuaternion GetRotation() const
|
||||
{ return LgEntityQuaternion(mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::Angle, Get().GetRotation()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleQuaternionFlag::Angle, Get().GetRotation()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetEulerRotation() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Angle, Get().GetRotationEuler()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Angle, Get().GetRotationEuler()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetSpeed() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Speed, Get().GetSpeed()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::Speed, Get().GetSpeed()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetRelativeSpeed() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelSpeed, Get().GetRelativeSpeed()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelSpeed, Get().GetRelativeSpeed()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetTurnSpeed() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::TurnSpeed, Get().GetTurnSpeed()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::TurnSpeed, Get().GetTurnSpeed()}; }
|
||||
SQMOD_NODISCARD LgEntityVector GetRelativeTurnSpeed() const
|
||||
{ return LgEntityVector(mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelTurnSpeed, Get().GetRelativeTurnSpeed()); }
|
||||
{ return {mID, LgEntityType::Vehicle, LgVehicleVectorFlag::RelTurnSpeed, Get().GetRelativeTurnSpeed()}; }
|
||||
SQMOD_NODISCARD int GetRadio() const { return Get().GetRadio(); }
|
||||
SQMOD_NODISCARD bool GetRadioLockStatus() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionRadioLocked) >= 1; }
|
||||
SQMOD_NODISCARD bool GetGhost() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionGhost) >= 1; }
|
||||
SQMOD_NODISCARD LgVector GetTurretRotation() const { const Vector2 v = Get().GetTurretRotation(); return LgVector(v.x, v.y, 0); }
|
||||
SQMOD_NODISCARD LgVector GetTurretRotation() const { const Vector2 v = Get().GetTurretRotation(); return {v.x, v.y, 0}; }
|
||||
SQMOD_NODISCARD bool GetSingleUse() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionSingleUse) >= 1; }
|
||||
SQMOD_NODISCARD bool GetTaxiLight() const { return (_Func->GetVehicleLightsData(GetIdentifier()) & (1 << 8)) != 0; }
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@@ -926,7 +986,7 @@ struct LgVehicle
|
||||
void SetPartStatus(int part, int status) const { Get().SetPartStatus(part, status); }
|
||||
SQMOD_NODISCARD int GetTyreStatus(int tyre) const { return Get().GetTyreStatus(tyre); }
|
||||
void SetTyreStatus(int part, int status) const { Get().SetTyreStatus(part, status); }
|
||||
SQMOD_NODISCARD bool GetStreamedForPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
||||
SQMOD_NODISCARD bool GetStreamedForPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||
SQMOD_NODISCARD LgPlayer * GetOccupant(int slot) const
|
||||
{ const int id = _Func->GetVehicleOccupant(GetIdentifier(), slot); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
|
||||
void SetHandlingData(int rule, float value) const { Get().SetHandlingRule(rule, value); }
|
||||
@@ -942,11 +1002,11 @@ struct LgVehicle
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline bool LgCheckpoint::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
||||
inline bool LgObject::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
||||
inline bool LgPickup::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
||||
inline void LgPlayer::SetVehicle(LgVehicle & vehicle) const { Get().Embark(vehicle.Get()); }
|
||||
inline void LgPlayer::SetVehicleSlot(const LgVehicle & vehicle, int slot) const { Get().EmbarkEx(vehicle.Get(), slot, true, false); }
|
||||
inline bool LgCheckpoint::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||
inline bool LgObject::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||
inline bool LgPickup::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||
inline void LgPlayer::SetVehicle(LightObj & vehicle) const { Get().Embark(GetNativeEnt< LgVehicle, CVehicle >(vehicle)); }
|
||||
inline void LgPlayer::SetVehicleSlot(LightObj & vehicle, int slot) const { Get().EmbarkEx(GetNativeEnt< LgVehicle, CVehicle >(vehicle), slot, true, false); }
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LgCheckpointSetID(LgCheckpoint * inst, int32_t id) { assert(inst); if (inst) inst->mID = id; }
|
||||
@@ -1233,11 +1293,11 @@ void Register_Official_Entity(HSQUIRRELVM vm)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void LgClientMessage(StackStrF & msg, LgPlayer & player, int r, int g, int b)
|
||||
{ _Func->SendClientMessage(player.GetIdentifier(), Color4(static_cast< uint8_t >(r), static_cast< uint8_t >(g),
|
||||
static void LgClientMessage(StackStrF & msg, LightObj & player, int r, int g, int b)
|
||||
{ _Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(player), Color4(static_cast< uint8_t >(r), static_cast< uint8_t >(g),
|
||||
static_cast< uint8_t >(b), 255).GetRGBA(), "%s", msg.mPtr); }
|
||||
static void LgClientMessageWithAlpha(StackStrF & msg, LgPlayer & player, int r, int g, int b, int a)
|
||||
{ _Func->SendClientMessage(player.GetIdentifier(), Color4(static_cast< uint8_t >(r), static_cast< uint8_t >(g),
|
||||
static void LgClientMessageWithAlpha(StackStrF & msg, LightObj & player, int r, int g, int b, int a)
|
||||
{ _Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(player), Color4(static_cast< uint8_t >(r), static_cast< uint8_t >(g),
|
||||
static_cast< uint8_t >(b), static_cast< uint8_t >(a)).GetRGBA(), "%s", msg.mPtr); }
|
||||
static void LgClientMessageToAll(StackStrF & msg, int r, int g, int b) {
|
||||
const uint32_t c = Color4(static_cast< uint8_t >(r), static_cast< uint8_t >(g),
|
||||
@@ -1249,10 +1309,10 @@ static void LgClientMessageToAllWithAlpha(StackStrF & msg, int r, int g, int b,
|
||||
static_cast< uint8_t >(b), static_cast< uint8_t >(a)).GetRGBA();
|
||||
ForeachActivePlayer([&](auto & p) { _Func->SendClientMessage(p.mID, c, "%s", msg.mPtr); });
|
||||
}
|
||||
static void LgGameMessage(StackStrF & msg, LgPlayer & player, int type)
|
||||
{ _Func->SendGameMessage(player.GetIdentifier(), type, msg.mPtr); }
|
||||
static void LgGameMessageAlternate(StackStrF & msg, LgPlayer & player)
|
||||
{ { _Func->SendGameMessage(player.GetIdentifier(), 1, msg.mPtr); } }
|
||||
static void LgGameMessage(StackStrF & msg, LightObj & player, int type)
|
||||
{ _Func->SendGameMessage(GetLgEntID< LgPlayer, CPlayer >(player), type, msg.mPtr); }
|
||||
static void LgGameMessageAlternate(StackStrF & msg, LightObj & player)
|
||||
{ { _Func->SendGameMessage(GetLgEntID< LgPlayer, CPlayer >(player), 1, msg.mPtr); } }
|
||||
static void LgGameMessageToAll(StackStrF & msg, int type)
|
||||
{ _Func->SendGameMessage(-1, type, msg.mPtr); }
|
||||
static void LgGameMessageToAllAlternate(StackStrF & msg)
|
||||
@@ -1394,8 +1454,8 @@ static void LgUnbanIP(StackStrF & ip) { _Func->UnbanIP(const_cast< SQChar * >(ip
|
||||
SQMOD_NODISCARD static bool LgIsIPBanned(StackStrF & ip) { return _Func->IsIPBanned(const_cast< SQChar * >(ip.mPtr)) >= 1; }
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_NODISCARD static int LgGetPlayerIDFromName(StackStrF & name) { return _Func->GetPlayerIdFromName(name.mPtr); }
|
||||
SQMOD_NODISCARD static bool LgIsWorldCompatibleWithPlayer (LgPlayer & player, int world)
|
||||
{ return _Func->IsPlayerWorldCompatible(player.GetIdentifier(), world) >= 1; }
|
||||
SQMOD_NODISCARD static bool LgIsWorldCompatibleWithPlayer(LightObj & player, int world)
|
||||
{ return _Func->IsPlayerWorldCompatible(GetLgEntID< LgPlayer, CPlayer >(player), world) >= 1; }
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static LightObj & LgCreatePickupCompat(int model, const Vector3 & pos)
|
||||
{ return Core::Get().NewPickup(model, 1, 0, pos.x, pos.y, pos.z, 255, false, SQMOD_CREATE_DEFAULT, NullLightObj()).mLgObj; }
|
||||
@@ -1409,7 +1469,7 @@ static LightObj & LgCreatePickup(int model, int world, int quantity, const Vecto
|
||||
static LightObj & LgCreateObject(int model, int world, const Vector3 & pos, int alpha)
|
||||
{ return Core::Get().NewObject(model, world, pos.x, pos.y, pos.z, alpha, SQMOD_CREATE_DEFAULT, NullLightObj()).mLgObj; }
|
||||
static LightObj & LgCreateCheckpoint(LightObj & player, int world, bool sphere, const Vector3 & pos, const Color4 & col, float radius) {
|
||||
const int32_t id = player.IsNull() ? -1 : player.CastI< LgPlayer >()->GetIdentifier();
|
||||
const int32_t id = player.IsNull() ? -1 : GetLgEntID< LgPlayer, CPlayer >(player);
|
||||
return Core::Get().NewCheckpoint(id, world, sphere, pos.x, pos.y, pos.z, col.r, col.g, col.b, col.a, radius, SQMOD_CREATE_DEFAULT, NullLightObj()).mLgObj;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -1467,30 +1527,30 @@ SQMOD_NODISCARD static int LgBindKey(bool down, int key1, int key2, int key3)
|
||||
SQMOD_NODISCARD static bool LgRemoveKeybind(int id) { return _Func->RemoveKeyBind(id) == vcmpErrorNone; }
|
||||
static void LgRemoveAllKeybinds() { _Func->RemoveAllKeyBinds(); }
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_NODISCARD static bool LgGetCinematicBorder(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWidescreen) >= 1; }
|
||||
SQMOD_NODISCARD static bool LgGetGreenScanLines(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionGreenScanlines) >= 1; }
|
||||
SQMOD_NODISCARD static bool LgGetWhiteScanLines(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWhiteScanlines) >= 1; }
|
||||
static void LgSetCinematicBorder(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWidescreen, static_cast< uint8_t >(toggle)); }
|
||||
static void LgSetGreenScanLines(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionGreenScanlines, static_cast< uint8_t >(toggle)); }
|
||||
static void LgSetWhiteScanLines(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWhiteScanlines, static_cast< uint8_t >(toggle)); }
|
||||
SQMOD_NODISCARD static bool LgGetCinematicBorder(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWidescreen) >= 1; }
|
||||
SQMOD_NODISCARD static bool LgGetGreenScanLines(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionGreenScanlines) >= 1; }
|
||||
SQMOD_NODISCARD static bool LgGetWhiteScanLines(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWhiteScanlines) >= 1; }
|
||||
static void LgSetCinematicBorder(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWidescreen, static_cast< uint8_t >(toggle)); }
|
||||
static void LgSetGreenScanLines(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionGreenScanlines, static_cast< uint8_t >(toggle)); }
|
||||
static void LgSetWhiteScanLines(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWhiteScanlines, static_cast< uint8_t >(toggle)); }
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void LgKickPlayer(LgPlayer & player) { _Func->KickPlayer(player.GetIdentifier()); }
|
||||
static void LgBanPlayer(LgPlayer & player) { _Func->BanPlayer(player.GetIdentifier()); }
|
||||
static void LgKickPlayer(LightObj & player) { _Func->KickPlayer(GetLgEntID< LgPlayer, CPlayer >(player)); }
|
||||
static void LgBanPlayer(LightObj & player) { _Func->BanPlayer(GetLgEntID< LgPlayer, CPlayer >(player)); }
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void LgMessage(StackStrF & msg) { _Func->SendClientMessage(-1, 0x0b5fa5ff, "%s", msg.mPtr); }
|
||||
static void LgMessagePlayer(StackStrF & msg, LgPlayer & player) { _Func->SendClientMessage(player.GetIdentifier(), 0x0b5fa5ff, "%s", msg.mPtr); }
|
||||
static void LgMessageAllExcept(StackStrF & msg, LgPlayer & player) {
|
||||
const int32_t p = player.GetIdentifier();
|
||||
static void LgMessagePlayer(StackStrF & msg, LightObj & player) { _Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(player), 0x0b5fa5ff, "%s", msg.mPtr); }
|
||||
static void LgMessageAllExcept(StackStrF & msg, LightObj & player) {
|
||||
const auto p = GetLgEntID< LgPlayer, CPlayer >(player);
|
||||
const SQChar * m = msg.mPtr;
|
||||
ForeachConnectedPlayer([=](int32_t id) { if (id != p) _Func->SendClientMessage(id, 0x0b5fa5ff, "%s", m); });
|
||||
}
|
||||
static void LgPrivMessage(LgPlayer & player, StackStrF & msg) { _Func->SendClientMessage(player.GetIdentifier(), 0x007f16ff, "** pm >> %s", msg.mPtr); }
|
||||
static void LgPrivMessage(LightObj & player, StackStrF & msg) { _Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(player), 0x007f16ff, "** pm >> %s", msg.mPtr); }
|
||||
static void LgPrivMessageAll(StackStrF & msg) {
|
||||
const SQChar * m = msg.mPtr;
|
||||
ForeachConnectedPlayer([=](int32_t id) { _Func->SendClientMessage(id, 0x007f16ff, "** pm >> %s", m); });
|
||||
}
|
||||
static void LgSendPlayerMessage(LgPlayer & source, LgPlayer & target, StackStrF & msg) {
|
||||
_Func->SendClientMessage(target.GetIdentifier(), 0x007f16ff, "** pm from %s >> %s", source.Get().GetName(), msg.mPtr);
|
||||
static void LgSendPlayerMessage(LightObj & source, LightObj & target, StackStrF & msg) {
|
||||
_Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(target), 0x007f16ff, "** pm from %s >> %s",GetNativeEnt< LgPlayer, CPlayer >(source).GetName(), msg.mPtr);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_NODISCARD static const SQChar * LgGetWeaponName(int id) { return GetWeaponName(static_cast< uint32_t >(id)); }
|
||||
@@ -1545,7 +1605,7 @@ SQMOD_NODISCARD SQInteger LgGetObjectCount() {
|
||||
}
|
||||
return count;
|
||||
}
|
||||
SQMOD_NODISCARD SQInteger LgGetPlayers() { return ForeachConnectedPlayerCount([](int32_t) { return true; }); }
|
||||
SQMOD_NODISCARD SQInteger LgGetPlayers() { return ForeachPlayerSlotCount([](int32_t idx) -> bool { return _Func->IsPlayerConnected(idx) != 0; }); }
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void LgSetVehiclesForcedRespawnHeight(SQFloat height) { _Func->SetVehiclesForcedRespawnHeight(static_cast< float >(height)); }
|
||||
SQMOD_NODISCARD static SQFloat LgGetVehiclesForcedRespawnHeight() { return _Func->GetVehiclesForcedRespawnHeight(); }
|
||||
@@ -1569,7 +1629,7 @@ SQMOD_NODISCARD static SQInteger LgFindPlayer(HSQUIRRELVM vm) {
|
||||
char name_buf[SQMOD_NAMELENGTH];
|
||||
const int32_t id = ForeachConnectedPlayerUntil([&](int32_t id) -> bool {
|
||||
_Func->GetPlayerName(id, name_buf, 64);
|
||||
std::transform(name_buf, name_buf + strlen(name_buf), name_buf, [](unsigned char c){ return std::tolower(c); });
|
||||
std::transform(name_buf, name_buf + strlen(name_buf), name_buf, [](unsigned char c) { return std::tolower(c); });
|
||||
return name.compare(name_buf) == 0; // NOLINT(readability-string-compare)
|
||||
});
|
||||
if (VALID_ENTITYEX(id, SQMOD_PLAYER_POOL)) Var< LightObj >::push(vm, Core::Get().GetPlayer(id).mLgObj);
|
||||
@@ -1946,6 +2006,7 @@ void Register_Official_Functions(HSQUIRRELVM vm)
|
||||
.Func(_SC("SetVehiclesForcedRespawnHeight"), LgSetVehiclesForcedRespawnHeight)
|
||||
|
||||
.SquirrelFunc(_SC("FindPlayer"), LgFindPlayer)
|
||||
.SquirrelFunc(_SC("FindPlayerCompat"), LgFindPlayer)
|
||||
.SquirrelFunc(_SC("InPoly"), LgInPoly)
|
||||
|
||||
.SquirrelFunc(_SC("SetAmmuWeapon"), LgSetAmmuWeapon)
|
||||
@@ -2261,8 +2322,8 @@ struct LgStream {
|
||||
int32_t id;
|
||||
if (target.IsNull()) id = -1;
|
||||
else if (target.GetType() == OT_INTEGER || target.GetType() == OT_FLOAT) id = target.Cast< int32_t >();
|
||||
else if (static_cast< AbstractStaticClassData * >(target.GetTypeTag()) == StaticClassTypeTag< LgPlayer >::Get()) {
|
||||
id = target.CastI< LgPlayer >()->GetIdentifier();
|
||||
else if (target.GetType() == OT_INSTANCE) {
|
||||
id = GetLgEntID< LgPlayer, CPlayer >(target);
|
||||
} else STHROWF("Invalid target type");
|
||||
if (id >= SQMOD_PLAYER_POOL) STHROWF("Invalid player ID");
|
||||
_Func->SendClientScriptData(id, m_OutputStreamData, m_OutputStreamEnd);
|
||||
|
||||
@@ -113,8 +113,8 @@ int32_t GetSkinID(StackStrF & name)
|
||||
{
|
||||
// Clone the string into an editable version
|
||||
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
||||
// Strip non alphanumeric characters from the name
|
||||
str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
|
||||
// Strip non-alphanumeric characters from the name
|
||||
str.erase(std::remove_if(str.begin(), str.end(), [](char c) -> bool { return std::isalnum(c) == 0; }), str.end());
|
||||
// Convert the string to lowercase
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
// See if we still have a valid name after the cleanup
|
||||
|
||||
@@ -122,8 +122,8 @@ int32_t GetAutomobileID(StackStrF & name)
|
||||
{
|
||||
// Clone the string into an editable version
|
||||
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
||||
// Strip non alphanumeric characters from the name
|
||||
str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
|
||||
// Strip non-alphanumeric characters from the name
|
||||
str.erase(std::remove_if(str.begin(), str.end(), [](char c) -> bool { return std::isalnum(c) == 0; }), str.end());
|
||||
// Convert the string to lowercase
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
// See if we still have a valid name after the cleanup
|
||||
|
||||
@@ -162,8 +162,8 @@ int32_t GetWeaponID(StackStrF & name)
|
||||
{
|
||||
// Clone the string into an editable version
|
||||
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
||||
// Strip non alphanumeric characters from the name
|
||||
str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
|
||||
// Strip non-alphanumeric characters from the name
|
||||
str.erase(std::remove_if(str.begin(), str.end(), [](char c) -> bool { return std::isalnum(c) == 0; }), str.end());
|
||||
// Convert the string to lowercase
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
// See if we still have a valid name after the cleanup
|
||||
@@ -324,6 +324,7 @@ int32_t GetWeaponID(StackStrF & name)
|
||||
// [S]PAS-12 Shotgun
|
||||
// [S]tubby Shotgun
|
||||
// [S]uicide
|
||||
// Pump action [S]hotgun
|
||||
case 's':
|
||||
// [Sc]rewdriver
|
||||
if (b == 'c') return SQMOD_WEAPON_SCREWDRIVER;
|
||||
|
||||
+586
-3
@@ -1,5 +1,9 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "PocoLib/Data.hpp"
|
||||
#include "Core/ThreadPool.hpp"
|
||||
#include "Library/SQLite.hpp"
|
||||
#include "Library/MySQL.hpp"
|
||||
#include "Poco/Data/SessionImpl.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sqratConst.h>
|
||||
@@ -33,6 +37,7 @@ SQMOD_DECL_TYPENAME(SqPcDataStatement, _SC("SqDataStatement"))
|
||||
SQMOD_DECL_TYPENAME(SqPcDataRecordSet, _SC("SqDataRecordSet"))
|
||||
SQMOD_DECL_TYPENAME(SqPcDataTransaction, _SC("SqDataTransaction"))
|
||||
SQMOD_DECL_TYPENAME(SqPcDataSessionPool, _SC("SqDataSessionPool"))
|
||||
SQMOD_DECL_TYPENAME(SqPcSqDataAsyncBuilder, _SC("SqSqDataAsyncBuilder"))
|
||||
SQMOD_DECL_TYPENAME(SqPcDataStatementResult, _SC("SqDataStatementResult"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -66,7 +71,7 @@ static LightObj SQLiteEscapeString(StackStrF & str)
|
||||
// Allocate a memory buffer
|
||||
Buffer b(static_cast< Buffer::SzType >(str.mLen * 2 + 1));
|
||||
// Attempt to escape the specified string
|
||||
sqlite3_snprintf(b.Capacity(), b.Get< char >(), "%q", str.mPtr);
|
||||
sqlite3_snprintf(static_cast< int >(b.Capacity()), b.Get< char >(), "%q", str.mPtr);
|
||||
// Return the resulted string
|
||||
return LightObj(b.Get< SQChar >(), -1);
|
||||
}
|
||||
@@ -90,7 +95,7 @@ static LightObj SQLiteEscapeStringEx(SQChar spec, StackStrF & str)
|
||||
// Allocate a memory buffer
|
||||
Buffer b(static_cast< Buffer::SzType >(str.mLen * 2 + 1));
|
||||
// Attempt to escape the specified string
|
||||
sqlite3_snprintf(b.Capacity(), b.Get< char >(), fs, str.mPtr);
|
||||
sqlite3_snprintf(static_cast< int >(b.Capacity()), b.Get< char >(), fs, str.mPtr);
|
||||
// Return the resulted string
|
||||
return LightObj(b.Get< SQChar >(), -1);
|
||||
}
|
||||
@@ -196,7 +201,7 @@ SqDataStatement SqDataSession::GetStatement(StackStrF & data)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SqDataRecordSet SqDataSession::GetRecordSet(StackStrF & data)
|
||||
{
|
||||
return SqDataRecordSet(*this, data);
|
||||
return {*this, data};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -470,6 +475,566 @@ SqDataStatement & SqDataStatement::Into_(LightObj & obj, LightObj & def)
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
extern LightObj GetSQLiteFromSession(Poco::Data::SessionImpl * session);
|
||||
extern LightObj GetMySQLFromSession(Poco::Data::SessionImpl * session);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqDataSessionPool::GetSq()
|
||||
{
|
||||
auto session = get();
|
||||
auto * session_impl = session.impl();
|
||||
auto & connector = session_impl->connectorName();
|
||||
// Is this a SQLite session?
|
||||
if (connector == "sqlite")
|
||||
{
|
||||
return GetSQLiteFromSession(session_impl);
|
||||
}
|
||||
// Is this a MySQL session?
|
||||
else if (connector == "mysql")
|
||||
{
|
||||
return GetMySQLFromSession(session_impl);
|
||||
}
|
||||
STHROWF("Unknown connector type {}", connector);
|
||||
SQ_UNREACHABLE
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqDataSessionPool::AsyncExec(StackStrF & sql)
|
||||
{
|
||||
return LightObj{SqTypeIdentity< SqDataAsyncBuilder >{}, SqVM(), get().impl(), sql, true, false, false};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqDataSessionPool::AsyncQuery(StackStrF & sql)
|
||||
{
|
||||
return LightObj{SqTypeIdentity< SqDataAsyncBuilder >{}, SqVM(), get().impl(), sql, false, true, false};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqDataSessionPool::IncAsyncQuery(StackStrF & sql)
|
||||
{
|
||||
return LightObj{SqTypeIdentity< SqDataAsyncBuilder >{}, SqVM(), get().impl(), sql, false, true, true};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqDataSessionPool::ExecAsyncQuery(StackStrF & sql)
|
||||
{
|
||||
return LightObj{SqTypeIdentity< SqDataAsyncBuilder >{}, SqVM(), get().impl(), sql, true, true, false};
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Asynchronous SQLite query execution implementation.
|
||||
*/
|
||||
struct SQLiteAsyncExec : public ThreadPoolItem
|
||||
{
|
||||
using SessionRef = Poco::AutoPtr< Poco::Data::SessionImpl >;
|
||||
// --------------------------------------------------------------------------------------------
|
||||
SQLiteConnRef mConnection{}; // Internal connection handle.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Function mResolved{}; // Callback to invoke when the task was completed.
|
||||
Function mRejected{}; // Callback to invoke when the task was aborted.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
int32_t mResult{SQLITE_OK}; // Execution result code.
|
||||
int32_t mChanges{0}; // Rows affected by this query.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
const SQChar * mQueryStr{nullptr}; // The query string that will be executed.
|
||||
LightObj mQueryObj{}; // Strong reference to the query string object.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj mCtx{}; // User specified context object, if any.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
String mError{}; // Error message, if any.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor. Members are supposed to be validated and filled by the builder/proxy.
|
||||
*/
|
||||
SQLiteAsyncExec() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~SQLiteAsyncExec() override = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide a name to what type of task this is. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD const char * TypeName() noexcept override { return "sqlite async execute"; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide unique information that may help identify the task. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD const char * IdentifiableInfo() noexcept override { return mQueryStr; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in worker thread by the thread pool after obtaining the task from the queue.
|
||||
* Must return true to indicate that the task can be performed. False indicates failure.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnPrepare() override
|
||||
{
|
||||
// Coincidentally, this also dirties the handle time-stamp so, it doesn't get collected
|
||||
return mConnection->mSession->isConnected();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Called in worker by the thread pool to performed by the associated tasks.
|
||||
* Will be called continuously while the returned value is true. While false means it finished.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnProcess() override
|
||||
{
|
||||
char * err_msg = nullptr;
|
||||
// Attempt to execute the specified query
|
||||
mResult = sqlite3_exec(mConnection->Access(), mQueryStr, nullptr, nullptr, &err_msg);
|
||||
// Store changes count
|
||||
if (mResult == SQLITE_OK)
|
||||
{
|
||||
mChanges = sqlite3_changes(mConnection->Access());
|
||||
}
|
||||
// Check for error message
|
||||
if (err_msg != nullptr)
|
||||
{
|
||||
mError.assign(err_msg);
|
||||
sqlite3_free(err_msg);
|
||||
}
|
||||
// Don't retry
|
||||
return false;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in main thread by the thread pool after the task was completed.
|
||||
* If it returns true then it will be put back into the queue to be processed again.
|
||||
* If the boolean parameter is try then the thread-pool is in the process of shutting down.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnCompleted(bool SQ_UNUSED_ARG(stop)) override
|
||||
{
|
||||
if (mResult == SQLITE_OK)
|
||||
{
|
||||
if (!mResolved.IsNull())
|
||||
{
|
||||
LightObj c{SqTypeIdentity< SQLiteConnection >{}, SqVM(), mConnection};
|
||||
mResolved.Execute(c, mCtx, mChanges, mQueryObj);
|
||||
}
|
||||
}
|
||||
else if (!mRejected.IsNull())
|
||||
{
|
||||
LightObj c{SqTypeIdentity< SQLiteConnection >{}, SqVM(), mConnection};
|
||||
mRejected.Execute(c, mCtx, mResult, mError, mQueryObj);
|
||||
}
|
||||
// Finished
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Called in worker by the thread pool to let the task know that it will be aborted.
|
||||
* Most likely due to a shutdown of the thread pool.
|
||||
*/
|
||||
void OnAborted(bool SQ_UNUSED_ARG(retry)) override
|
||||
{
|
||||
// We don't really have to do anything for now
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Asynchronous SQLite statement implementation.
|
||||
*/
|
||||
struct SQLiteAsyncStmtBase : public ThreadPoolItem
|
||||
{
|
||||
using SessionRef = Poco::AutoPtr< Poco::Data::SessionImpl >;
|
||||
// --------------------------------------------------------------------------------------------
|
||||
SQLiteConnRef mConnection{}; // Internal connection handle.
|
||||
SQLiteStmtRef mStatement{}; // Internal statement handle.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Function mResolved{}; // Callback to invoke when the task was completed.
|
||||
Function mRejected{}; // Callback to invoke when the task was aborted.
|
||||
Function mPrepared{}; // Callback to invoke when the task must be prepared.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
SQLiteStatement * mStatementPtr{nullptr}; // Pointer to the script statement instance.
|
||||
LightObj mStatementObj{}; // Strong reference to the statement instance object.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
const SQChar * mQueryStr{nullptr}; // The query string that will be executed.
|
||||
LightObj mQueryObj{}; // Strong reference to the query string object.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
LightObj mCtx{}; // User specified context object, if any.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
int32_t mChanges{0}; // Rows affected by this query.
|
||||
bool mPrepped{false}; // Whether the statement was prepared.
|
||||
bool mRow{false}; // Whether we still have rows to process.
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor. Members are supposed to be validated and filled by the builder/proxy.
|
||||
*/
|
||||
SQLiteAsyncStmtBase() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~SQLiteAsyncStmtBase() override = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide unique information that may help identify the task. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD const char * IdentifiableInfo() noexcept override { return mQueryStr; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in worker thread by the thread pool after obtaining the task from the queue.
|
||||
* Must return true to indicate that the task can be performed. False indicates failure.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnPrepare() override
|
||||
{
|
||||
// Coincidentally, this also dirties the handle time-stamp so, it doesn't get collected
|
||||
if (mConnection->mSession->isConnected())
|
||||
{
|
||||
if (mStatement->mPtr == nullptr)
|
||||
{
|
||||
mStatement->Create(mQueryStr, static_cast< SQInteger >(strlen(mQueryStr)));
|
||||
// Statement was not prepared/filled with information (yet)
|
||||
mPrepped = mPrepared.IsNull();
|
||||
}
|
||||
// Prepared
|
||||
return true;
|
||||
}
|
||||
// Can't prepare
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Called in worker by the thread pool to let the task know that it will be aborted.
|
||||
* Most likely due to a shutdown of the thread pool.
|
||||
*/
|
||||
void OnAborted(bool SQ_UNUSED_ARG(retry)) override
|
||||
{
|
||||
// We don't really have to do anything for now
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Asynchronous SQLite statement execution implementation.
|
||||
*/
|
||||
struct SQLiteAsyncStmtExec : public SQLiteAsyncStmtBase
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide a name to what type of task this is. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD const char * TypeName() noexcept override { return "sqlite async query exec"; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Called in worker by the thread pool to performed by the associated tasks.
|
||||
* Will be called continuously while the returned value is true. While false means it finished.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnProcess() override
|
||||
{
|
||||
// Was the statement prepared?
|
||||
if (mPrepped)
|
||||
{
|
||||
mChanges = mStatementPtr->Exec();
|
||||
}
|
||||
// Don't retry
|
||||
return false;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in main thread by the thread pool after the task was completed.
|
||||
* If it returns true then it will be put back into the queue to be processed again.
|
||||
* If the boolean parameter is try then the thread-pool is in the process of shutting down.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnCompleted(bool SQ_UNUSED_ARG(stop)) override
|
||||
{
|
||||
if (mPrepped && mStatement->mDone)
|
||||
{
|
||||
if (!mResolved.IsNull())
|
||||
{
|
||||
LightObj o = mResolved.Eval(mStatementObj, mCtx, mChanges);
|
||||
// Should we abort the whole thing?
|
||||
if (!o.IsNull() && o.Cast< bool >() == false)
|
||||
{
|
||||
return false; // Allow to abort itself
|
||||
}
|
||||
}
|
||||
// No longer prepared
|
||||
mPrepped = false;
|
||||
}
|
||||
// Allow to prepare itself, either on initial call or again after execution
|
||||
if (!mPrepped && (mStatement->mStatus == SQLITE_OK || mStatement->mStatus == SQLITE_DONE))
|
||||
{
|
||||
mPrepped = true;
|
||||
// Is there a prepping callback?
|
||||
if (!mPrepared.IsNull())
|
||||
{
|
||||
// Should we reset?
|
||||
if (mStatement->mStatus == SQLITE_DONE)
|
||||
{
|
||||
mStatementPtr->Reset();
|
||||
}
|
||||
LightObj o = mPrepared.Eval(mStatementObj, mCtx);
|
||||
// Should we abort the whole thing?
|
||||
if (!o.IsNull())
|
||||
{
|
||||
return o.Cast< bool >(); // Allow to abort itself
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // Re-queue the task by default
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!mRejected.IsNull() && (mStatement->mStatus != SQLITE_OK && mStatement->mStatus != SQLITE_DONE))
|
||||
{
|
||||
mRejected.Execute(mStatementObj, mCtx, mQueryObj);
|
||||
}
|
||||
// Finished
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Asynchronous SQLite statement stepping implementation.
|
||||
*/
|
||||
struct SQLiteAsyncStmtStep : public SQLiteAsyncStmtBase
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide a name to what type of task this is. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD const char * TypeName() noexcept override { return "sqlite async query step"; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Called in worker by the thread pool to performed by the associated tasks.
|
||||
* Will be called continuously while the returned value is true. While false means it finished.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnProcess() override
|
||||
{
|
||||
// Was the statement prepared?
|
||||
if (mPrepped)
|
||||
{
|
||||
mRow = mStatementPtr->Step();
|
||||
}
|
||||
// Don't retry
|
||||
return false;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in main thread by the thread pool after the task was completed.
|
||||
* If it returns true then it will be put back into the queue to be processed again.
|
||||
* If the boolean parameter is try then the thread-pool is in the process of shutting down.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnCompleted(bool SQ_UNUSED_ARG(stop)) override
|
||||
{
|
||||
// This is only done once, before performing any step
|
||||
if (!mPrepped)
|
||||
{
|
||||
mPrepped = true;
|
||||
// Is there a prepping callback?
|
||||
if (!mPrepared.IsNull())
|
||||
{
|
||||
LightObj o = mPrepared.Eval(mStatementObj, mCtx);
|
||||
// Should we abort the whole thing?
|
||||
if (!o.IsNull())
|
||||
{
|
||||
return o.Cast< bool >(); // Allow to abort itself
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // Re-queue the task by default
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mStatement->mGood || mStatement->mDone)
|
||||
{
|
||||
if (!mResolved.IsNull())
|
||||
{
|
||||
// You are expected to step the statement manually until the end
|
||||
mResolved.Execute(mStatementObj, mCtx);
|
||||
}
|
||||
}
|
||||
else if (!mRejected.IsNull())
|
||||
{
|
||||
mRejected.Execute(mStatementObj, mCtx, mQueryObj);
|
||||
}
|
||||
// Finished
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Asynchronous SQLite incremental statement stepping implementation.
|
||||
*/
|
||||
struct SQLiteAsyncStmtIncStep : public SQLiteAsyncStmtBase
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Provide a name to what type of task this is. Mainly for debugging purposes.
|
||||
*/
|
||||
SQMOD_NODISCARD const char * TypeName() noexcept override { return "sqlite incremental async query step"; }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Called in worker by the thread pool to performed by the associated tasks.
|
||||
* Will be called continuously while the returned value is true. While false means it finished.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnProcess() override
|
||||
{
|
||||
// Was the statement prepared?
|
||||
if (mPrepped)
|
||||
{
|
||||
mRow = mStatementPtr->Step();
|
||||
}
|
||||
// Don't retry
|
||||
return false;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Invoked in main thread by the thread pool after the task was completed.
|
||||
* If it returns true then it will be put back into the queue to be processed again.
|
||||
* If the boolean parameter is try then the thread-pool is in the process of shutting down.
|
||||
*/
|
||||
SQMOD_NODISCARD bool OnCompleted(bool SQ_UNUSED_ARG(stop)) override
|
||||
{
|
||||
// This is only done once, before performing any step
|
||||
if (!mPrepped)
|
||||
{
|
||||
mPrepped = true;
|
||||
// Is there a prepping callback?
|
||||
if (!mPrepared.IsNull())
|
||||
{
|
||||
LightObj o = mPrepared.Eval(mStatementObj, mCtx);
|
||||
// Should we abort the whole thing?
|
||||
if (!o.IsNull())
|
||||
{
|
||||
return o.Cast< bool >(); // Allow to abort itself
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // Re-queue the task by default
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mStatement->mGood && !mStatement->mDone)
|
||||
{
|
||||
if (!mResolved.IsNull())
|
||||
{
|
||||
// Should all steps be completed here?
|
||||
if (stop)
|
||||
{
|
||||
do {
|
||||
LightObj o = mResolved.Eval(mStatementObj, mCtx);
|
||||
// Should we abort the whole thing?
|
||||
if (!o.IsNull() && !o.Cast< bool >())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Don't let exceptions be stupid
|
||||
mRow = false;
|
||||
// Force process whole statement
|
||||
if (mStatement->mGood) OnProcess();
|
||||
} while (mRow);
|
||||
}
|
||||
else
|
||||
{
|
||||
LightObj o = mResolved.Eval(mStatementObj, mCtx);
|
||||
// Should we abort the whole thing?
|
||||
if (!o.IsNull() && !o.Cast< bool >())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!mRejected.IsNull() && (mStatement->mStatus != SQLITE_OK && mStatement->mStatus != SQLITE_DONE))
|
||||
{
|
||||
mRejected.Execute(mStatementObj, mCtx, mQueryObj);
|
||||
}
|
||||
// Re-queue if we still have rows to process
|
||||
return mRow;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SqDataAsyncBuilder::SqDataAsyncBuilder(Poco::Data::SessionImpl * session, StackStrF & sql, bool exec, bool stmt, bool inc) noexcept
|
||||
: mSession(session, true)
|
||||
, mResolved(), mRejected()
|
||||
, mQueryStr(sql.mPtr), mQueryObj(sql.mObj)
|
||||
, mExec(exec), mStmt(stmt), mInc(inc)
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SqDataAsyncBuilder::Submit_(LightObj & ctx)
|
||||
{
|
||||
if (mSession.isNull())
|
||||
{
|
||||
STHROWF("Asynchronous query builder instance is invalid.");
|
||||
}
|
||||
auto & connector = mSession->connectorName();
|
||||
// Is this a SQLite session?
|
||||
if (connector == "sqlite")
|
||||
{
|
||||
// Retrieve the internal handle property
|
||||
auto * connection = Poco::AnyCast< sqlite3 * >(mSession->getProperty("handle"));
|
||||
// Is this a statement?
|
||||
if (mStmt)
|
||||
{
|
||||
SQLiteAsyncStmtBase * item = nullptr;
|
||||
// Is this just for executing?
|
||||
if (mExec)
|
||||
{
|
||||
item = static_cast< SQLiteAsyncStmtBase * >(new SQLiteAsyncStmtExec());
|
||||
}
|
||||
// Is this incremental?
|
||||
else if (mInc)
|
||||
{
|
||||
item = static_cast< SQLiteAsyncStmtBase * >(new SQLiteAsyncStmtIncStep());
|
||||
}
|
||||
else
|
||||
{
|
||||
item = static_cast< SQLiteAsyncStmtBase * >(new SQLiteAsyncStmtStep());
|
||||
}
|
||||
// Take ownership before any exception can be thrown
|
||||
std::unique_ptr< ThreadPoolItem > task{static_cast< ThreadPoolItem * >(item)};
|
||||
// Populate task information
|
||||
item->mConnection = SQLiteConnRef{new SQLiteConnHnd(std::move(mSession))};
|
||||
item->mStatement = SQLiteStmtRef{new SQLiteStmtHnd(item->mConnection)};
|
||||
item->mResolved = std::move(mResolved);
|
||||
item->mRejected = std::move(mRejected);
|
||||
item->mPrepared = std::move(mPrepared);
|
||||
item->mStatementObj = LightObj{SqTypeIdentity< SQLiteStatement >{}, SqVM(), item->mStatement};
|
||||
item->mStatementPtr = item->mStatementObj.CastI< SQLiteStatement >();
|
||||
item->mQueryStr = mQueryStr;
|
||||
item->mQueryObj = std::move(mQueryObj);
|
||||
item->mCtx = std::move(ctx);
|
||||
// Submit the task
|
||||
ThreadPool::Get().Enqueue(std::move(task));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto * item = new SQLiteAsyncExec();
|
||||
// Take ownership before any exception can be thrown
|
||||
std::unique_ptr< ThreadPoolItem > task{static_cast< ThreadPoolItem * >(item)};
|
||||
// Populate task information
|
||||
item->mConnection = SQLiteConnRef{new SQLiteConnHnd(std::move(mSession))};
|
||||
item->mResolved = std::move(mResolved);
|
||||
item->mRejected = std::move(mRejected);
|
||||
item->mQueryStr = mQueryStr;
|
||||
item->mQueryObj = std::move(mQueryObj);
|
||||
item->mCtx = std::move(ctx);
|
||||
// Submit the task
|
||||
ThreadPool::Get().Enqueue(std::move(task));
|
||||
}
|
||||
}
|
||||
// Is this a MySQL session?
|
||||
else if (connector == "mysql")
|
||||
{
|
||||
if (mStmt)
|
||||
{
|
||||
//...
|
||||
}
|
||||
else
|
||||
{
|
||||
//...
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
STHROWF("Unknown connector type {}", connector);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LightObj SqDataSessionPool::GetProperty(StackStrF & name)
|
||||
{
|
||||
@@ -746,6 +1311,19 @@ void Register_POCO_Data(HSQUIRRELVM vm, Table &)
|
||||
.Overload(_SC("Value"), &SqDataRecordSet::GetValueOr)
|
||||
);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(_SC("AsyncBuilder"),
|
||||
Class< SqDataAsyncBuilder, NoConstructor< SqDataAsyncBuilder > >(vm, SqPcSqDataAsyncBuilder::Str)
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqPcSqDataAsyncBuilder::Fn)
|
||||
// Member Methods
|
||||
.CbFunc(_SC("Resolved"), &SqDataAsyncBuilder::OnResolved)
|
||||
.CbFunc(_SC("Rejected"), &SqDataAsyncBuilder::OnRejected)
|
||||
.CbFunc(_SC("Prepared"), &SqDataAsyncBuilder::OnPrepared)
|
||||
// Overloaded methods
|
||||
.Overload(_SC("Submit"), &SqDataAsyncBuilder::Submit)
|
||||
.Overload(_SC("Submit"), &SqDataAsyncBuilder::Submit_)
|
||||
);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(_SC("SessionPool"),
|
||||
Class< SqDataSessionPool, NoCopy< SqDataSessionPool > >(vm, SqPcDataSessionPool::Str)
|
||||
// Constructors
|
||||
@@ -764,6 +1342,11 @@ void Register_POCO_Data(HSQUIRRELVM vm, Table &)
|
||||
.Prop(_SC("IsActive"), &SqDataSessionPool::IsActive)
|
||||
// Member Methods
|
||||
.Func(_SC("Get"), &SqDataSessionPool::Get)
|
||||
.Func(_SC("GetSq"), &SqDataSessionPool::GetSq)
|
||||
.FmtFunc(_SC("AsyncExec"), &SqDataSessionPool::AsyncExec)
|
||||
.FmtFunc(_SC("AsyncQuery"), &SqDataSessionPool::AsyncQuery)
|
||||
.FmtFunc(_SC("IncAsyncQuery"), &SqDataSessionPool::IncAsyncQuery)
|
||||
.FmtFunc(_SC("ExecAsyncQuery"), &SqDataSessionPool::ExecAsyncQuery)
|
||||
.FmtFunc(_SC("GetWithProperty"), &SqDataSessionPool::GetWithProperty)
|
||||
.FmtFunc(_SC("GetWithFeature"), &SqDataSessionPool::GetWithFeature)
|
||||
.FmtFunc(_SC("SetFeature"), &SqDataSessionPool::SetFeature)
|
||||
|
||||
+115
-2
@@ -1707,7 +1707,7 @@ protected:
|
||||
}
|
||||
SQ_UNREACHABLE
|
||||
// Unreachable
|
||||
return LightObj();
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1746,7 +1746,7 @@ struct SqDataSessionPool : public SessionPool
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destroys the SessionPool.
|
||||
*/
|
||||
~SqDataSessionPool() = default;
|
||||
~SqDataSessionPool() override = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Assignment operator (disabled).
|
||||
@@ -1766,6 +1766,31 @@ struct SqDataSessionPool : public SessionPool
|
||||
return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a Session wrapped in a native/legacy implementation.
|
||||
*/
|
||||
LightObj GetSq();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create an asynchronous query execution builder.
|
||||
*/
|
||||
LightObj AsyncExec(StackStrF & sql);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create an asynchronous query execution builder.
|
||||
*/
|
||||
LightObj AsyncQuery(StackStrF & sql);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create an asynchronous query execution builder.
|
||||
*/
|
||||
LightObj IncAsyncQuery(StackStrF & sql);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create an asynchronous query execution builder.
|
||||
*/
|
||||
LightObj ExecAsyncQuery(StackStrF & sql);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a Session with requested property set.
|
||||
*/
|
||||
@@ -2070,4 +2095,92 @@ struct SqDataTransaction : public Transaction
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Common session action implementation.
|
||||
*/
|
||||
struct SqDataAsyncBuilder
|
||||
{
|
||||
using SessionRef = Poco::AutoPtr< Poco::Data::SessionImpl >;
|
||||
// --------------------------------------------------------------------------------------------
|
||||
SessionRef mSession{}; // The connection that will be used by the task.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Function mResolved{}; // Callback to invoke when the task was completed.
|
||||
Function mRejected{}; // Callback to invoke when the task was aborted.
|
||||
Function mPrepared{}; // Callback to invoke when the task was must be prepared.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
const SQChar * mQueryStr{nullptr}; // The query string that will be executed.
|
||||
LightObj mQueryObj{}; // Strong reference to the query string object.
|
||||
// --------------------------------------------------------------------------------------------
|
||||
bool mExec{false}; // Whether this is a query execution.
|
||||
bool mStmt{false}; // Whether this is a query statement.
|
||||
bool mInc{false}; // Whether this is an incremental query statement.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
SqDataAsyncBuilder(Poco::Data::SessionImpl * session, StackStrF & sql, bool exec, bool stmt, bool inc) noexcept;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
SqDataAsyncBuilder(const SqDataAsyncBuilder & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
SqDataAsyncBuilder(SqDataAsyncBuilder && o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~SqDataAsyncBuilder() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
SqDataAsyncBuilder & operator = (const SqDataAsyncBuilder & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
SqDataAsyncBuilder & operator = (SqDataAsyncBuilder && o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create the task with the supplied information and submit it to the worker pool.
|
||||
*/
|
||||
void Submit() { Submit_(NullLightObj()); }
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create the task with the supplied information and submit it to the worker pool.
|
||||
*/
|
||||
void Submit_(LightObj & ctx);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set the callback to be executed if the query was resolved.
|
||||
*/
|
||||
SqDataAsyncBuilder & OnResolved(Function & cb)
|
||||
{
|
||||
mResolved = std::move(cb);
|
||||
return *this; // Allow chaining
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set the callback to be executed if the query was rejected/failed.
|
||||
*/
|
||||
SqDataAsyncBuilder & OnRejected(Function & cb)
|
||||
{
|
||||
mRejected = std::move(cb);
|
||||
return *this; // Allow chaining
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Set the callback to be executed in order to compose the query/statement.
|
||||
*/
|
||||
SqDataAsyncBuilder & OnPrepared(Function & cb)
|
||||
{
|
||||
mPrepared = std::move(cb);
|
||||
return *this; // Allow chaining
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "PocoLib/RegEx.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <sqratConst.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SQMOD_DECL_TYPENAME(SqRegEx, _SC("SqRegEx"))
|
||||
SQMOD_DECL_TYPENAME(SqRegExMatch, _SC("SqRegExMatch"))
|
||||
SQMOD_DECL_TYPENAME(SqRegExMatches, _SC("SqRegExMatches"))
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ================================================================================================
|
||||
void Register_POCO_RegEx(HSQUIRRELVM vm, Table & ns)
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(_SC("RegExMatch"),
|
||||
Class< PcRegExMatch >(vm, SqRegExMatch::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
.Ctor< SQInteger >()
|
||||
.Ctor< SQInteger, SQInteger >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqRegExMatch::Fn)
|
||||
// Properties
|
||||
.Prop(_SC("Offset"), &PcRegExMatch::GetOffset, &PcRegExMatch::SetOffset)
|
||||
.Prop(_SC("Length"), &PcRegExMatch::GetLength, &PcRegExMatch::SetLength)
|
||||
);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(_SC("RegExMatches"),
|
||||
Class< PcRegExMatches >(vm, SqRegExMatches::Str)
|
||||
// Constructors
|
||||
.Ctor()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqRegExMatches::Fn)
|
||||
// Properties
|
||||
.Prop(_SC("Front"), &PcRegExMatches::Front)
|
||||
.Prop(_SC("Back"), &PcRegExMatches::Back)
|
||||
.Prop(_SC("Empty"), &PcRegExMatches::Empty)
|
||||
.Prop(_SC("Size"), &PcRegExMatches::Size)
|
||||
.Prop(_SC("Capacity"), &PcRegExMatches::Capacity, &PcRegExMatches::Reserve)
|
||||
// Member Methods
|
||||
.Func(_SC("Get"), &PcRegExMatches::Get)
|
||||
.Func(_SC("Reserve"), &PcRegExMatches::Reserve)
|
||||
.Func(_SC("Compact"), &PcRegExMatches::Compact)
|
||||
.Func(_SC("Clear"), &PcRegExMatches::Clear)
|
||||
.Func(_SC("Pop"), &PcRegExMatches::Pop)
|
||||
.Func(_SC("EraseAt"), &PcRegExMatches::EraseAt)
|
||||
.Func(_SC("EraseFrom"), &PcRegExMatches::EraseFrom)
|
||||
.Func(_SC("Each"), &PcRegExMatches::Each)
|
||||
.Func(_SC("EachRange"), &PcRegExMatches::EachRange)
|
||||
.Func(_SC("While"), &PcRegExMatches::While)
|
||||
.Func(_SC("WhileRange"), &PcRegExMatches::WhileRange)
|
||||
);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ns.Bind(_SC("RegEx"),
|
||||
Class< PcRegEx, NoCopy< PcRegEx > >(vm, SqRegEx::Str)
|
||||
// Constructors
|
||||
.Ctor< StackStrF & >()
|
||||
.Ctor< int, StackStrF & >()
|
||||
.Ctor< int, bool, StackStrF & >()
|
||||
// Meta-methods
|
||||
.SquirrelFunc(_SC("_typename"), &SqRegEx::Fn)
|
||||
// Member Methods
|
||||
//.Func(_SC("Assign"), &PcRegEx::assign)
|
||||
// Overloaded Member Methods
|
||||
.Overload(_SC("MatchFirst"), &PcRegEx::MatchFirst)
|
||||
.Overload(_SC("MatchFirst"), &PcRegEx::MatchFirst_)
|
||||
.Overload(_SC("MatchFirstFrom"), &PcRegEx::MatchFirstFrom)
|
||||
.Overload(_SC("MatchFirstFrom"), &PcRegEx::MatchFirstFrom_)
|
||||
.Overload(_SC("Match"), &PcRegEx::Match)
|
||||
.Overload(_SC("Match"), &PcRegEx::Match_)
|
||||
.Overload(_SC("MatchFrom"), &PcRegEx::MatchFrom)
|
||||
.Overload(_SC("MatchFrom"), &PcRegEx::MatchFrom_)
|
||||
.Overload(_SC("Matches"), &PcRegEx::Matches)
|
||||
.Overload(_SC("Matches"), &PcRegEx::Matches_)
|
||||
.Overload(_SC("Matches"), &PcRegEx::MatchesEx)
|
||||
);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
ConstTable(vm).Enum(_SC("SqRegExOption"), Enumeration(vm)
|
||||
.Const(_SC("Caseless"), static_cast< SQInteger >(Poco::RegularExpression::RE_CASELESS))
|
||||
.Const(_SC("MultiLine"), static_cast< SQInteger >(Poco::RegularExpression::RE_MULTILINE))
|
||||
.Const(_SC("DotAll"), static_cast< SQInteger >(Poco::RegularExpression::RE_DOTALL))
|
||||
.Const(_SC("Extended"), static_cast< SQInteger >(Poco::RegularExpression::RE_EXTENDED))
|
||||
.Const(_SC("Anchored"), static_cast< SQInteger >(Poco::RegularExpression::RE_ANCHORED))
|
||||
.Const(_SC("DollarEndOnly"), static_cast< SQInteger >(Poco::RegularExpression::RE_DOLLAR_ENDONLY))
|
||||
.Const(_SC("Extra"), static_cast< SQInteger >(Poco::RegularExpression::RE_EXTRA))
|
||||
.Const(_SC("NotBOL"), static_cast< SQInteger >(Poco::RegularExpression::RE_NOTBOL))
|
||||
.Const(_SC("NotEOL"), static_cast< SQInteger >(Poco::RegularExpression::RE_NOTEOL))
|
||||
.Const(_SC("Ungreedy"), static_cast< SQInteger >(Poco::RegularExpression::RE_UNGREEDY))
|
||||
.Const(_SC("NotEmpty"), static_cast< SQInteger >(Poco::RegularExpression::RE_NOTEMPTY))
|
||||
.Const(_SC("UTF8"), static_cast< SQInteger >(Poco::RegularExpression::RE_UTF8))
|
||||
.Const(_SC("NoAutoCapture"), static_cast< SQInteger >(Poco::RegularExpression::RE_NO_AUTO_CAPTURE))
|
||||
.Const(_SC("NoUTF8Check"), static_cast< SQInteger >(Poco::RegularExpression::RE_NO_UTF8_CHECK))
|
||||
.Const(_SC("FirstLine"), static_cast< SQInteger >(Poco::RegularExpression::RE_FIRSTLINE))
|
||||
.Const(_SC("DupNames"), static_cast< SQInteger >(Poco::RegularExpression::RE_DUPNAMES))
|
||||
.Const(_SC("NewLineCR"), static_cast< SQInteger >(Poco::RegularExpression::RE_NEWLINE_CR))
|
||||
.Const(_SC("NewLineLF"), static_cast< SQInteger >(Poco::RegularExpression::RE_NEWLINE_LF))
|
||||
.Const(_SC("NewLineCRLF"), static_cast< SQInteger >(Poco::RegularExpression::RE_NEWLINE_CRLF))
|
||||
.Const(_SC("NewLineAny"), static_cast< SQInteger >(Poco::RegularExpression::RE_NEWLINE_ANY))
|
||||
.Const(_SC("NewLineAnyCRLF"), static_cast< SQInteger >(Poco::RegularExpression::RE_NEWLINE_ANYCRLF))
|
||||
.Const(_SC("Global"), static_cast< SQInteger >(Poco::RegularExpression::RE_GLOBAL))
|
||||
.Const(_SC("NoVars"), static_cast< SQInteger >(Poco::RegularExpression::RE_NO_VARS))
|
||||
);
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -1,481 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Core/Utility.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <algorithm>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <Poco/RegularExpression.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace SqMod {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
struct PcRegExMatch : public Poco::RegularExpression::Match
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
PcRegExMatch() noexcept
|
||||
: Poco::RegularExpression::Match{}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Offset constructor.
|
||||
*/
|
||||
explicit PcRegExMatch(SQInteger offset) noexcept
|
||||
: Poco::RegularExpression::Match{static_cast< std::string::size_type >(offset), 0}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
PcRegExMatch(SQInteger offset, SQInteger length) noexcept
|
||||
: Poco::RegularExpression::Match{
|
||||
static_cast< std::string::size_type >(offset),
|
||||
static_cast< std::string::size_type >(length)
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
PcRegExMatch(const PcRegExMatch & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
PcRegExMatch(PcRegExMatch && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
PcRegExMatch & operator = (const PcRegExMatch & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
PcRegExMatch & operator = (PcRegExMatch && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve offset.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetOffset() const noexcept
|
||||
{
|
||||
return static_cast< SQInteger >(Poco::RegularExpression::Match::offset);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify offset.
|
||||
*/
|
||||
void SetOffset(SQInteger value) noexcept
|
||||
{
|
||||
Poco::RegularExpression::Match::offset = static_cast< std::string::size_type >(value);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve length.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger GetLength() const noexcept
|
||||
{
|
||||
return static_cast< SQInteger >(Poco::RegularExpression::Match::length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Modify length.
|
||||
*/
|
||||
void SetLength(SQInteger value) noexcept
|
||||
{
|
||||
Poco::RegularExpression::Match::length = static_cast< std::string::size_type >(value);
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
struct PcRegExMatches
|
||||
{
|
||||
using List = Poco::RegularExpression::MatchVec;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal RegularExpression instance.
|
||||
*/
|
||||
List m_List;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor.
|
||||
*/
|
||||
PcRegExMatches() = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy list constructor.
|
||||
*/
|
||||
explicit PcRegExMatches(const List & l) // NOLINT(modernize-pass-by-value)
|
||||
: m_List{l}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move list constructor.
|
||||
*/
|
||||
explicit PcRegExMatches(List && m) noexcept
|
||||
: m_List{std::move(m)}
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor.
|
||||
*/
|
||||
PcRegExMatches(const PcRegExMatches & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
PcRegExMatches(PcRegExMatches && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
*/
|
||||
PcRegExMatches & operator = (const PcRegExMatches & o) = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
*/
|
||||
PcRegExMatches & operator = (PcRegExMatches && o) noexcept = default;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure an index is within range and return the container. Container must exist.
|
||||
*/
|
||||
List & ValidIdx(SQInteger i)
|
||||
{
|
||||
if (static_cast< size_t >(i) >= m_List.size())
|
||||
{
|
||||
STHROWF("Invalid RegEx match list index({})", i);
|
||||
}
|
||||
return m_List;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure an index is within range and return the container. Container must exist.
|
||||
*/
|
||||
SQMOD_NODISCARD const List & ValidIdx(SQInteger i) const
|
||||
{
|
||||
if (static_cast< size_t >(i) >= m_List.size())
|
||||
{
|
||||
STHROWF("Invalid RegEx match list index({})", i);
|
||||
}
|
||||
return m_List;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Make sure a container instance is populated, then return it.
|
||||
*/
|
||||
SQMOD_NODISCARD List & ValidPop()
|
||||
{
|
||||
if (m_List.empty())
|
||||
{
|
||||
STHROWF("RegEx match list container is empty");
|
||||
}
|
||||
return m_List;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve a value from the container.
|
||||
*/
|
||||
SQMOD_NODISCARD List::reference Get(SQInteger i)
|
||||
{
|
||||
return ValidIdx(i).at(ClampL< SQInteger, size_t >(i));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the first element in the container.
|
||||
*/
|
||||
SQMOD_NODISCARD List::reference Front()
|
||||
{
|
||||
return ValidPop().front();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the last element in the container.
|
||||
*/
|
||||
SQMOD_NODISCARD List::reference Back()
|
||||
{
|
||||
return m_List.back();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Check if the container has no elements.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Empty() const
|
||||
{
|
||||
return m_List.empty();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of elements in the container.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Size() const
|
||||
{
|
||||
return static_cast< SQInteger >(m_List.size());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the number of elements that the container has currently allocated space for.
|
||||
*/
|
||||
SQMOD_NODISCARD SQInteger Capacity() const
|
||||
{
|
||||
return static_cast< SQInteger >(m_List.capacity());
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Increase the capacity of the container to a value that's greater or equal to the one specified.
|
||||
*/
|
||||
PcRegExMatches & Reserve(SQInteger n)
|
||||
{
|
||||
m_List.reserve(ClampL< SQInteger, size_t >(n));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Request the removal of unused capacity.
|
||||
*/
|
||||
void Compact()
|
||||
{
|
||||
m_List.shrink_to_fit();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase all elements from the container.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
m_List.clear();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Pop the last element in the container.
|
||||
*/
|
||||
void Pop()
|
||||
{
|
||||
ValidPop().pop_back();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase the element at a certain position.
|
||||
*/
|
||||
void EraseAt(SQInteger i)
|
||||
{
|
||||
m_List.erase(ValidIdx(i).begin() + static_cast< size_t >(i));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Erase a certain amount of elements starting from a specific position.
|
||||
*/
|
||||
void EraseFrom(SQInteger i, SQInteger n)
|
||||
{
|
||||
m_List.erase(ValidIdx(i).begin() + static_cast< size_t >(i),
|
||||
ValidIdx(i + n).begin() + static_cast< size_t >(i + n));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor.
|
||||
*/
|
||||
void Each(Function & fn) const
|
||||
{
|
||||
for (const auto & e : m_List)
|
||||
{
|
||||
fn.Execute(static_cast< SQInteger >(e.offset), static_cast< SQInteger >(e.length));
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate values in range through a functor.
|
||||
*/
|
||||
void EachRange(SQInteger p, SQInteger n, Function & fn) const
|
||||
{
|
||||
std::for_each(ValidIdx(p).begin() + static_cast< size_t >(p),
|
||||
ValidIdx(p + n).begin() + static_cast< size_t >(p + n),
|
||||
[&](List::const_reference & e) {
|
||||
fn.Execute(static_cast< SQInteger >(e.offset), static_cast< SQInteger >(e.length));
|
||||
});
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate all values through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void While(Function & fn) const
|
||||
{
|
||||
for (const auto & e : m_List)
|
||||
{
|
||||
auto ret = fn.Eval(static_cast< SQInteger >(e.offset), static_cast< SQInteger >(e.length));
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Iterate values in range through a functor until stopped (i.e false is returned).
|
||||
*/
|
||||
void WhileRange(SQInteger p, SQInteger n, Function & fn) const
|
||||
{
|
||||
auto itr = ValidIdx(p).begin() + static_cast< size_t >(p);
|
||||
auto end = ValidIdx(p + n).begin() + static_cast< size_t >(p + n);
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
auto ret = fn.Eval(static_cast< SQInteger >(itr->offset), static_cast< SQInteger >(itr->length));
|
||||
// (null || true) == continue & false == break
|
||||
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* A class for working with regular expressions.
|
||||
* Implemented using PCRE, the Perl Compatible Regular Expressions library. (see http://www.pcre.org)
|
||||
*/
|
||||
struct PcRegEx
|
||||
{
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Internal RegularExpression instance.
|
||||
*/
|
||||
Poco::RegularExpression m_Rx;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Base constructor.
|
||||
*/
|
||||
explicit PcRegEx(StackStrF & str)
|
||||
: m_Rx(str.ToStr())
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
PcRegEx(int options, StackStrF & str)
|
||||
: m_Rx(str.ToStr(), options)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Explicit constructor.
|
||||
*/
|
||||
PcRegEx(int options, bool study, StackStrF & str)
|
||||
: m_Rx(str.ToStr(), options, study)
|
||||
{
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy constructor. (disabled)
|
||||
*/
|
||||
PcRegEx(const PcRegEx & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor. (disabled)
|
||||
*/
|
||||
PcRegEx(PcRegEx && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator. (disabled)
|
||||
*/
|
||||
PcRegEx & operator = (const PcRegEx & o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator. (disabled)
|
||||
*/
|
||||
PcRegEx & operator = (PcRegEx && o) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* Returns the position of the first captured sub-string in m.
|
||||
* If no part of the subject matches the pattern, m.offset is std::string::npos and m.length is 0.
|
||||
* Returns the number of matches. Throws a exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int MatchFirst(PcRegExMatch & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), m);
|
||||
}
|
||||
SQMOD_NODISCARD int MatchFirst_(int f, PcRegExMatch & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), m, f);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* Returns the position of the first captured sub-string in m.
|
||||
* If no part of the subject matches the pattern, m.offset is std::string::npos and m.length is 0.
|
||||
* Returns the number of matches. Throws a exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int MatchFirstFrom(SQInteger o, PcRegExMatch & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), static_cast< std::string::size_type >(o), m);
|
||||
}
|
||||
SQMOD_NODISCARD int MatchFirstFrom_(int f, SQInteger o, PcRegExMatch & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), static_cast< std::string::size_type >(o), m, f);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* The first entry in m contains the position of the captured sub-string.
|
||||
* The following entries identify matching subpatterns. See the PCRE documentation for a more detailed explanation.
|
||||
* If no part of the subject matches the pattern, m is empty.
|
||||
* Returns the number of matches. Throws a exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int Match(PcRegExMatches & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), 0, m.m_List);
|
||||
}
|
||||
SQMOD_NODISCARD int Match_(int f, PcRegExMatches & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), 0, m.m_List, f);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Matches the given subject string against the pattern.
|
||||
* The first entry in m contains the position of the captured sub-string.
|
||||
* The following entries identify matching subpatterns. See the PCRE documentation for a more detailed explanation.
|
||||
* If no part of the subject matches the pattern, m is empty.
|
||||
* Returns the number of matches. Throws a exception in case of an error.
|
||||
*/
|
||||
SQMOD_NODISCARD int MatchFrom(SQInteger o, PcRegExMatches & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), static_cast< std::string::size_type >(o), m.m_List);
|
||||
}
|
||||
SQMOD_NODISCARD int MatchFrom_(int f, SQInteger o, PcRegExMatches & m, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), static_cast< std::string::size_type >(o), m.m_List, f);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Returns true if and only if the subject matches the regular expression.
|
||||
* Internally, this method sets the RE_ANCHORED and RE_NOTEMPTY options for matching,
|
||||
* which means that the empty string will never match and the pattern is treated as if it starts with a ^.
|
||||
*/
|
||||
SQMOD_NODISCARD bool Matches(StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr());
|
||||
}
|
||||
SQMOD_NODISCARD bool Matches_(SQInteger o, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), static_cast< std::string::size_type >(o));
|
||||
}
|
||||
SQMOD_NODISCARD bool MatchesEx(int f, SQInteger o, StackStrF & s) const
|
||||
{
|
||||
return m_Rx.match(s.ToStr(), static_cast< std::string::size_type >(o), f);
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
@@ -8,7 +8,6 @@ namespace SqMod {
|
||||
extern void Register_POCO_Crypto(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_POCO_Data(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_POCO_Net(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_POCO_RegEx(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_POCO_Time(HSQUIRRELVM vm, Table & ns);
|
||||
extern void Register_POCO_Util(HSQUIRRELVM vm, Table & ns);
|
||||
|
||||
@@ -20,7 +19,6 @@ void Register_POCO(HSQUIRRELVM vm)
|
||||
Register_POCO_Crypto(vm, ns);
|
||||
Register_POCO_Data(vm, ns);
|
||||
Register_POCO_Net(vm, ns);
|
||||
Register_POCO_RegEx(vm, ns);
|
||||
Register_POCO_Time(vm, ns);
|
||||
Register_POCO_Util(vm, ns);
|
||||
|
||||
|
||||
+2
-5
@@ -1,6 +1,3 @@
|
||||
#ifndef _REGISTER_HPP_
|
||||
#define _REGISTER_HPP_
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <squirrelex.h>
|
||||
|
||||
@@ -39,6 +36,7 @@ extern void Register_JSON(HSQUIRRELVM vm);
|
||||
extern void Register_MMDB(HSQUIRRELVM vm);
|
||||
extern void Register_Net(HSQUIRRELVM vm);
|
||||
extern void Register_Numeric(HSQUIRRELVM vm);
|
||||
extern void Register_RegEx(HSQUIRRELVM vm);
|
||||
extern void Register_String(HSQUIRRELVM vm);
|
||||
extern void Register_System(HSQUIRRELVM vm);
|
||||
extern void Register_UTF8(HSQUIRRELVM vm);
|
||||
@@ -106,6 +104,7 @@ bool RegisterAPI(HSQUIRRELVM vm)
|
||||
Register_MMDB(vm);
|
||||
Register_Net(vm);
|
||||
Register_Numeric(vm);
|
||||
Register_RegEx(vm);
|
||||
Register_String(vm);
|
||||
Register_System(vm);
|
||||
Register_UTF8(vm);
|
||||
@@ -142,5 +141,3 @@ bool RegisterAPI(HSQUIRRELVM vm)
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
#endif // _REGISTER_HPP_
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#if !defined(_SQ_MOD_API_H_)
|
||||
#define _SQ_MOD_API_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifndef SQMOD_API_EXPORT
|
||||
#if defined(_MSC_VER)
|
||||
#define SQMOD_API_EXPORT extern "C" __declspec(dllexport)
|
||||
#elif defined(__GNUC__)
|
||||
#define SQMOD_API_EXPORT extern "C"
|
||||
#else
|
||||
#define SQMOD_API_EXPORT extern "C"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SQMOD_HOST_NAME "SqModHost"
|
||||
#define SQMOD_INITIALIZE_CMD 0xDABBAD00 // host plug-in was initialized
|
||||
#define SQMOD_LOAD_CMD 0xDEADBABE // API is being registered
|
||||
#define SQMOD_TERMINATE_CMD 0xDEADC0DE // release your resources
|
||||
#define SQMOD_CLOSING_CMD 0xBAAAAAAD // virtual machine is closing
|
||||
#define SQMOD_RELEASED_CMD 0xDEADBEAF // virtual machine was closed
|
||||
#define SQMOD_API_VER 1
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
typedef int32_t(*ExtPluginCommand_t)(int32_t, int32_t, int32_t, const uint8_t *, size_t);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* The structure exported by the host plug-in to import the module and squirrel API.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t StructSize;
|
||||
/* Register a pointer to a function used to processes commands from script.
|
||||
This is like the functionality offered by SendPluginCommand but offers interaction from
|
||||
script side without interfering with other native plugins. And also offers a few extra
|
||||
methods of identification to provide back and forth communication.
|
||||
It offers a bare minimum, primitive way of interacting with the script from native plug-ins.
|
||||
return : -1 it failed (no free slot), 0 if it was already registered and 1 if it succeeded.
|
||||
*/
|
||||
int32_t (*RegisterCommand) (ExtPluginCommand_t fn);
|
||||
/* Remove a pointer to a function used to processes commands from script.
|
||||
return : -1 it failed (no free slot) and 1 if it succeeded.
|
||||
*/
|
||||
int32_t (*UnregisterCommand) (ExtPluginCommand_t fn);
|
||||
/* Send a command to all functions currently registered to receive them. This is mostly used by the script.
|
||||
target - ideally a unique value that can be used to identify the intended audience for the command.
|
||||
req : ideally a unique value that can be used to identify the requested information from the command.
|
||||
tag : ideally a unique value that can be used to identify a later response if one is generated.
|
||||
data : binary data that represents the command payload. the command is free to interpret it however it wants.
|
||||
size : size of the binary data. most likely in bytes but the command is free to interpret it however it wants.
|
||||
*/
|
||||
int32_t (*SendCommand) (int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size);
|
||||
/* Send a response to the script that may have resulted from a previous command. This is mostly by the native plug-ins.
|
||||
sender : ideally a unique value that can be used to identify the intended who generated the response.
|
||||
tag : ideally a unique value that can be used to identify what the generated response might contain/provide.
|
||||
data : binary data that represents the command payload. the command is free to interpret it however it wants.
|
||||
size : size of the binary data. most likely in bytes but the command is free to interpret it however it wants.
|
||||
*/
|
||||
int32_t (*SendCommandReply) (int32_t sender, int32_t tag, const uint8_t * data, size_t size);
|
||||
/* Forward an event to the script from an external plug-in. This is mostly by the native plug-ins.
|
||||
Similar to SendCommandReply but may not have been the result of a previous command.
|
||||
*/
|
||||
int32_t (*SendCommandEvent) (int32_t sender, int32_t tag, const uint8_t * data, size_t size);
|
||||
} sq_mod_exports, SQ_MOD_EXPORTS, *HSQ_MOD_EXPORTS;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /*_SQ_MOD_API_H_*/
|
||||
+1
-1
@@ -75,7 +75,7 @@
|
||||
|
||||
#define SQMOD_NAME "Squirrel Module"
|
||||
#define SQMOD_AUTHOR "Sandu Liviu Catalin (S.L.C)"
|
||||
#define SQMOD_COPYRIGHT "Copyright (C) 2021 Sandu Liviu Catalin"
|
||||
#define SQMOD_COPYRIGHT "Copyright (C) 2022 Sandu Liviu Catalin"
|
||||
#define SQMOD_HOST_NAME "SqModHost"
|
||||
#define SQMOD_VERSION 001
|
||||
#define SQMOD_VERSION_STR "0.0.1"
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <squirrelex.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "sqratObject.h"
|
||||
@@ -661,6 +662,80 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Used internally to proxy calls to wrapped squirrel methods.
|
||||
template < class T = C, SQInteger(T::*Mptr)(HSQUIRRELVM) > static SQInteger SquirrelMethodProxy(HSQUIRRELVM vm) noexcept
|
||||
{
|
||||
try {
|
||||
return ((::Sqrat::Var<T*>(vm, 1).value)->*Mptr)(vm);
|
||||
} catch (const Poco::Exception& e) {
|
||||
return sq_throwerror(vm, e.displayText().c_str());
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
}
|
||||
}
|
||||
|
||||
// Used internally to proxy calls to wrapped squirrel methods.
|
||||
template < class T = C, SQInteger(T::*Mptr)(HSQUIRRELVM) const > static SQInteger SquirrelMethodProxy(HSQUIRRELVM vm) noexcept
|
||||
{
|
||||
try {
|
||||
return ((::Sqrat::Var<T*>(vm, 1).value)->*Mptr)(vm);
|
||||
} catch (const Poco::Exception& e) {
|
||||
return sq_throwerror(vm, e.displayText().c_str());
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Binds a class method that is treated as a squirrel function but invoked on the instance itself
|
||||
///
|
||||
/// \param name Name of the function as it will appear in Squirrel
|
||||
/// \param func Function to bind
|
||||
///
|
||||
/// \return The Class itself so the call can be chained
|
||||
///
|
||||
/// \remarks
|
||||
/// Inside of the function, the class instance the function was called with will be at index 1 on the
|
||||
/// stack and all arguments will be after that index in the order they were given to the function.
|
||||
///
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template < class T = C, SQInteger(T::*Mptr)(HSQUIRRELVM) > Class& SquirrelMethod(const SQChar* name) {
|
||||
return SquirrelFunc(name, &SquirrelMethodProxy< T, Mptr >);
|
||||
}
|
||||
template < class T = C, SQInteger(T::*Mptr)(HSQUIRRELVM) const > Class& SquirrelMethod(const SQChar* name) {
|
||||
return SquirrelFunc(name, &SquirrelMethodProxy< T, Mptr >);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Binds a class method that is treated as a squirrel function but invoked on the instance itself
|
||||
///
|
||||
/// \param name Name of the function as it will appear in Squirrel
|
||||
/// \param func Function to bind
|
||||
/// \param pnum Number of parameters the function expects.
|
||||
/// \param mask Types of parameters the function expects.
|
||||
///
|
||||
/// \return The Class itself so the call can be chained
|
||||
///
|
||||
/// \remarks
|
||||
/// Inside of the function, the class instance the function was called with will be at index 1 on the
|
||||
/// stack and all arguments will be after that index in the order they were given to the function.
|
||||
///
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template < class T = C, SQInteger(T::*Mptr)(HSQUIRRELVM) > Class& SquirrelMethod(const SQChar* name, SQInteger pnum, const SQChar * mask) {
|
||||
return SquirrelFunc(name, &SquirrelMethodProxy< T, Mptr >, pnum, mask);
|
||||
}
|
||||
template < class T = C, SQInteger(T::*Mptr)(HSQUIRRELVM) const > Class& SquirrelMethod(const SQChar* name, SQInteger pnum, const SQChar * mask) {
|
||||
return SquirrelFunc(name, &SquirrelMethodProxy< T, Mptr >, pnum, mask);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Gets a Function from a name in the Class
|
||||
///
|
||||
|
||||
@@ -88,6 +88,15 @@ struct LightObj {
|
||||
sq_addref(SqVM(), &mObj);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Constructs a LightObj from a string object
|
||||
///
|
||||
/// \param o Squirrel object
|
||||
///
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
explicit LightObj(const string & s) : LightObj(s.c_str(), static_cast< SQInteger >(s.size())) {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Constructs a LightObj from a Squirrel object at a certain index on the stack
|
||||
///
|
||||
@@ -186,21 +195,7 @@ struct LightObj {
|
||||
///
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<class T, class... A>
|
||||
LightObj(SqTypeIdentity< T > SQ_UNUSED_ARG(t), HSQUIRRELVM vm, A&&... a) {
|
||||
// Create the instance and guard it to make sure it gets deleted in case of exceptions
|
||||
DeleteGuard< T > instance(new T(std::forward< A >(a)...));
|
||||
// Preserve the stack state
|
||||
const StackGuard sg(vm);
|
||||
// Push the instance on the stack
|
||||
ClassType<T>::PushInstance(vm, instance);
|
||||
// Attempt to retrieve it
|
||||
if (SQ_FAILED(sq_getstackobj(vm, -1, &mObj))) {
|
||||
sq_resetobject(&mObj);
|
||||
} else {
|
||||
sq_addref(vm, &mObj);
|
||||
}
|
||||
// Stop guarding the instance
|
||||
instance.Release();
|
||||
LightObj(SqTypeIdentity< T > SQ_UNUSED_ARG(t), HSQUIRRELVM vm, A&&... a) : LightObj(DeleteGuard< T >(new T(std::forward< A >(a)...))) {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -237,7 +232,21 @@ struct LightObj {
|
||||
///
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<class T>
|
||||
LightObj(DeleteGuard<T> guard, HSQUIRRELVM v = SqVM()) : LightObj(guard.Get(), v) {
|
||||
LightObj(DeleteGuard<T> && guard, HSQUIRRELVM v = SqVM()) : LightObj(guard.Get(), v) {
|
||||
guard.Release();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Constructs an LightObj from a C++ instance wrapped inside a DeleteGuard
|
||||
///
|
||||
/// \param instance Pointer to a C++ class instance that has been bound already
|
||||
/// \param v VM that the object will exist in
|
||||
///
|
||||
/// \tparam T Type of instance
|
||||
///
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<class T>
|
||||
LightObj(DeleteGuard<T> & guard, HSQUIRRELVM v = SqVM()) : LightObj(guard.Get(), v) {
|
||||
guard.Release();
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ template <class C,class R> struct SqMember {
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||
}
|
||||
SQ_UNREACHABLE
|
||||
};
|
||||
@@ -178,7 +178,7 @@ template <class C,class R> struct SqMember {
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||
}
|
||||
SQ_UNREACHABLE
|
||||
};
|
||||
@@ -206,7 +206,7 @@ template <class C, class R> struct SqMember<C,R&> {
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||
}
|
||||
SQ_UNREACHABLE
|
||||
};
|
||||
@@ -227,7 +227,7 @@ template <class C, class R> struct SqMember<C,R&> {
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||
}
|
||||
SQ_UNREACHABLE
|
||||
};
|
||||
@@ -256,7 +256,7 @@ template <class C> struct SqMember<C, void> {
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||
}
|
||||
SQ_UNREACHABLE
|
||||
};
|
||||
@@ -277,7 +277,7 @@ template <class C> struct SqMember<C, void> {
|
||||
} catch (const std::exception& e) {
|
||||
return sq_throwerror(vm, e.what());
|
||||
} catch (...) {
|
||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
||||
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||
}
|
||||
SQ_UNREACHABLE
|
||||
};
|
||||
|
||||
+166
-42
@@ -35,6 +35,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <Poco/Exception.h>
|
||||
@@ -1580,12 +1581,31 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Helper structure for one element from the top of stack. Uses default global VM instead.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct SqPopTopGuardLite
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Base constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
SqPopTopGuardLite() noexcept = default;
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Destructor. Pops the specified elements from the stack.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
~SqPopTopGuardLite()
|
||||
{
|
||||
sq_poptop(SqVM());
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Helper structure for one element from the top of stack.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct SqPopTopGuard
|
||||
{
|
||||
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Base constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1603,13 +1623,70 @@ struct SqPopTopGuard
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Helper structure for popping elements from the stack. Uses default global VM instead.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct SqPopGuardLite
|
||||
{
|
||||
SQInteger mNum{0}; // The number of elements to be popped.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Base constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
explicit SqPopGuardLite(SQInteger num) noexcept
|
||||
: mNum(num)
|
||||
{
|
||||
//...
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Destructor. Pops the specified elements from the stack.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
~SqPopGuardLite()
|
||||
{
|
||||
sq_pop(SqVM(), mNum);
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Increment the number of elements to be popped.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
SqPopGuardLite & operator ++ ()
|
||||
{
|
||||
++mNum;
|
||||
return *this;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Decrement the number of elements to be popped.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
SqPopGuardLite & operator -- ()
|
||||
{
|
||||
--mNum;
|
||||
return *this;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Increase the number of elements to be popped.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
SqPopGuardLite & operator += (SQInteger n)
|
||||
{
|
||||
mNum += n;
|
||||
return *this;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Decrease the number of elements to be popped.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
SqPopGuardLite & operator -= (SQInteger n)
|
||||
{
|
||||
mNum -= n;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Helper structure for popping elements from the stack.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct SqPopGuard
|
||||
{
|
||||
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
|
||||
SQInteger mNum; // The number of elements to be popped.
|
||||
HSQUIRRELVM mVM{nullptr}; // The VM from which the elements must be popped.
|
||||
SQInteger mNum{0}; // The number of elements to be popped.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Base constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1659,17 +1736,79 @@ struct SqPopGuard
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Implements RAII to restore the VM stack to it's initial size on function exit. Uses default global VM instead.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct StackGuardLite
|
||||
{
|
||||
SQInteger mTop{0}; ///< The top of the stack when this instance was created.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Default constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
StackGuardLite() noexcept
|
||||
: mTop(sq_gettop(SqVM()))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Copy constructor. (disabled)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
StackGuardLite(const StackGuardLite &) = delete;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Move constructor. (disabled)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
StackGuardLite(StackGuardLite &&) = delete;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Destructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
~StackGuardLite()
|
||||
{
|
||||
Restore();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Copy assignment operator. (disabled)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
StackGuardLite & operator = (const StackGuardLite &) = delete;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Move assignment operator. (disabled)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
StackGuardLite & operator = (StackGuardLite &&) = delete;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Restore the stack to what was known to be.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Restore() const
|
||||
{
|
||||
auto vm = SqVM();
|
||||
// Retrieve the new stack top
|
||||
const SQInteger top = sq_gettop(vm);
|
||||
// Did the stack size change?
|
||||
if (top > mTop)
|
||||
{
|
||||
sq_pop(vm, top - mTop); // Trim the stack
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Implements RAII to restore the VM stack to it's initial size on function exit.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct StackGuard
|
||||
{
|
||||
HSQUIRRELVM mVM{nullptr}; ///< The VM where the stack should be restored.
|
||||
SQInteger mTop{0}; ///< The top of the stack when this instance was created.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Default constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
StackGuard()
|
||||
: m_VM(SqVM()), m_Top(sq_gettop(m_VM))
|
||||
: mVM(SqVM()), mTop(sq_gettop(mVM))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@@ -1677,8 +1816,8 @@ struct StackGuard
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Base constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
StackGuard(HSQUIRRELVM vm)
|
||||
: m_VM(vm), m_Top(sq_gettop(vm))
|
||||
explicit StackGuard(HSQUIRRELVM vm)
|
||||
: mVM(vm), mTop(sq_gettop(vm))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@@ -1717,18 +1856,13 @@ struct StackGuard
|
||||
void Restore() const
|
||||
{
|
||||
// Retrieve the new stack top
|
||||
const SQInteger top = sq_gettop(m_VM);
|
||||
const SQInteger top = sq_gettop(mVM);
|
||||
// Did the stack size change?
|
||||
if (top > m_Top)
|
||||
if (top > mTop)
|
||||
{
|
||||
sq_pop(m_VM, top - m_Top); // Trim the stack
|
||||
sq_pop(mVM, top - mTop); // Trim the stack
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
HSQUIRRELVM m_VM; ///< The VM where the stack should be restored.
|
||||
SQInteger m_Top; ///< The top of the stack when this instance was created.
|
||||
};
|
||||
|
||||
|
||||
@@ -2131,18 +2265,13 @@ inline void ErrorToException(HSQUIRRELVM vm, bool keep = false) {
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template < typename T > struct DeleteGuard
|
||||
{
|
||||
private:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
T * m_Ptr; // Pointer to the instance to manage.
|
||||
|
||||
public:
|
||||
T * mPtr; // Pointer to the instance to manage.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Default constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
explicit DeleteGuard(T * ptr)
|
||||
: m_Ptr(ptr)
|
||||
: mPtr(ptr)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@@ -2152,7 +2281,7 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<class... A>
|
||||
explicit DeleteGuard(SqInPlace SQ_UNUSED_ARG(t), A&&... a)
|
||||
: m_Ptr(new T(std::forward< A >(a)...))
|
||||
: mPtr(new T(std::forward< A >(a)...))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
@@ -2166,9 +2295,9 @@ public:
|
||||
/// Move constructor.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DeleteGuard(DeleteGuard && o) noexcept
|
||||
: m_Ptr(o.m_Ptr)
|
||||
: mPtr(o.mPtr)
|
||||
{
|
||||
o.m_Ptr = nullptr;
|
||||
o.mPtr = nullptr;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2176,9 +2305,9 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
~DeleteGuard()
|
||||
{
|
||||
if (m_Ptr)
|
||||
if (mPtr)
|
||||
{
|
||||
delete m_Ptr;
|
||||
delete mPtr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2197,7 +2326,7 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
operator T * () const
|
||||
{
|
||||
return m_Ptr;
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2205,7 +2334,7 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
T * Get() const
|
||||
{
|
||||
return m_Ptr;
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2213,7 +2342,7 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Release()
|
||||
{
|
||||
m_Ptr = nullptr;
|
||||
mPtr = nullptr;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2221,8 +2350,8 @@ public:
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
T * Grab()
|
||||
{
|
||||
T * ptr = m_Ptr;
|
||||
m_Ptr = nullptr;
|
||||
T * ptr = mPtr;
|
||||
mPtr = nullptr;
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
@@ -2320,18 +2449,13 @@ template < typename T > T * SqChainedInstances< T >::sHead = nullptr;
|
||||
/// @cond DEV
|
||||
/// Used internally to get and manipulate the underlying type of variables - retrieved from cppreference.com
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<class T> struct remove_const {typedef T type;};
|
||||
template<class T> struct remove_const<const T> {typedef T type;};
|
||||
template<class T> struct remove_volatile {typedef T type;};
|
||||
template<class T> struct remove_volatile<volatile T> {typedef T type;};
|
||||
template<class T> struct remove_cv {typedef typename remove_volatile<typename remove_const<T>::type>::type type;};
|
||||
template<class T> struct is_pointer_helper {static constexpr bool value = false;};
|
||||
template<class T> struct is_pointer_helper<T*> {static constexpr bool value = true;};
|
||||
template<class T,class D> struct is_pointer_helper<SharedPtr<T,D> > {static constexpr bool value = true;};
|
||||
template<class T,class D> struct is_pointer_helper<WeakPtr<T,D> > {static constexpr bool value = true;};
|
||||
template<class T> struct is_pointer : is_pointer_helper<typename remove_cv<T>::type> {};
|
||||
template<class T> struct is_reference {static constexpr bool value = false;};
|
||||
template<class T> struct is_reference<T&> {static constexpr bool value = true;};
|
||||
template<class T> using remove_const = std::remove_const< T >;
|
||||
template<class T> using remove_volatile = std::remove_volatile< T >;
|
||||
template<class T> using remove_cv = std::remove_cv< T >;
|
||||
template<class T> struct is_pointer : public std::is_pointer< T > { };
|
||||
template<class T,class D> struct is_pointer<SharedPtr<T,D> > : public std::true_type { };
|
||||
template<class T,class D> struct is_pointer<WeakPtr<T,D> > : public std::true_type { };
|
||||
template<class T> using is_reference = std::is_lvalue_reference< T >;
|
||||
/// @endcond
|
||||
|
||||
|
||||
|
||||
Vendored
+1
@@ -1,6 +1,7 @@
|
||||
add_subdirectory(ConcurrentQueue)
|
||||
add_subdirectory(Fmt)
|
||||
add_subdirectory(xxHash)
|
||||
add_subdirectory(RPMalloc)
|
||||
add_subdirectory(Squirrel)
|
||||
add_subdirectory(SimpleIni)
|
||||
add_subdirectory(TinyDir)
|
||||
|
||||
Vendored
+11
-27
@@ -81,6 +81,7 @@ option(FMT_FUZZ "Generate the fuzz target." OFF)
|
||||
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
|
||||
option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
|
||||
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
|
||||
option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF)
|
||||
|
||||
set(FMT_CAN_MODULE OFF)
|
||||
if (CMAKE_CXX_STANDARD GREATER 17 AND
|
||||
@@ -96,6 +97,10 @@ if (FMT_TEST AND FMT_MODULE)
|
||||
# The tests require {fmt} to be compiled as traditional library
|
||||
message(STATUS "Testing is incompatible with build mode 'module'.")
|
||||
endif ()
|
||||
set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
|
||||
if (FMT_SYSTEM_HEADERS)
|
||||
set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
|
||||
endif ()
|
||||
|
||||
# Get version from core.h
|
||||
file(READ include/fmt/core.h core_h)
|
||||
@@ -151,7 +156,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
-Wcast-align
|
||||
-Wctor-dtor-privacy -Wdisabled-optimization
|
||||
-Winvalid-pch -Woverloaded-virtual
|
||||
-Wconversion -Wswitch-enum -Wundef
|
||||
-Wconversion -Wundef
|
||||
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
|
||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
||||
@@ -204,18 +209,6 @@ if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||
endif ()
|
||||
|
||||
set(strtod_l_headers stdlib.h)
|
||||
if (APPLE)
|
||||
set(strtod_l_headers ${strtod_l_headers} xlocale.h)
|
||||
endif ()
|
||||
|
||||
include(CheckSymbolExists)
|
||||
if (WIN32)
|
||||
check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
||||
else ()
|
||||
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
||||
endif ()
|
||||
|
||||
function(add_headers VAR)
|
||||
set(headers ${${VAR}})
|
||||
foreach (header ${ARGN})
|
||||
@@ -239,17 +232,6 @@ endif ()
|
||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
||||
add_library(fmt::fmt ALIAS fmt)
|
||||
|
||||
if (HAVE_STRTOD_L)
|
||||
target_compile_definitions(fmt PUBLIC FMT_LOCALE)
|
||||
endif ()
|
||||
|
||||
if (MINGW)
|
||||
check_cxx_compiler_flag("Wa,-mbig-obj" FMT_HAS_MBIG_OBJ)
|
||||
if (${FMT_HAS_MBIG_OBJ})
|
||||
target_compile_options(fmt PUBLIC "-Wa,-mbig-obj")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (FMT_WERROR)
|
||||
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
||||
endif ()
|
||||
@@ -262,7 +244,7 @@ endif ()
|
||||
|
||||
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
|
||||
|
||||
target_include_directories(fmt PUBLIC
|
||||
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||
|
||||
@@ -270,6 +252,7 @@ set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
|
||||
|
||||
set_target_properties(fmt PROPERTIES
|
||||
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
PUBLIC_HEADER "${FMT_HEADERS}"
|
||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||
|
||||
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
||||
@@ -298,7 +281,7 @@ add_library(fmt::fmt-header-only ALIAS fmt-header-only)
|
||||
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
|
||||
target_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES})
|
||||
|
||||
target_include_directories(fmt-header-only INTERFACE
|
||||
target_include_directories(fmt-header-only ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||
|
||||
@@ -347,6 +330,8 @@ if (FMT_INSTALL)
|
||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
||||
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
||||
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
||||
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
|
||||
FRAMEWORK DESTINATION "."
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# Use a namespace because CMake provides better diagnostics for namespaced
|
||||
@@ -363,7 +348,6 @@ if (FMT_INSTALL)
|
||||
|
||||
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
|
||||
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
||||
install(FILES ${FMT_HEADERS} DESTINATION "${FMT_INC_DIR}/fmt")
|
||||
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
||||
endif ()
|
||||
|
||||
|
||||
Vendored
+382
-8
@@ -1,3 +1,374 @@
|
||||
8.1.1 - 2022-01-06
|
||||
------------------
|
||||
|
||||
* Restored ABI compatibility with version 8.0.x
|
||||
(`#2695 <https://github.com/fmtlib/fmt/issues/2695>`_,
|
||||
`#2696 <https://github.com/fmtlib/fmt/pull/2696>`_).
|
||||
Thanks `@saraedum (Julian Rüth) <https://github.com/saraedum>`_.
|
||||
|
||||
* Fixed chrono formatting on big endian systems
|
||||
(`#2698 <https://github.com/fmtlib/fmt/issues/2698>`_,
|
||||
`#2699 <https://github.com/fmtlib/fmt/pull/2699>`_).
|
||||
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_ and
|
||||
`@xvitaly (Vitaly Zaitsev) <https://github.com/xvitaly>`_.
|
||||
|
||||
* Fixed a linkage error with mingw
|
||||
(`#2691 <https://github.com/fmtlib/fmt/issues/2691>`_,
|
||||
`#2692 <https://github.com/fmtlib/fmt/pull/2692>`_).
|
||||
Thanks `@rbberger (Richard Berger) <https://github.com/rbberger>`_.
|
||||
|
||||
8.1.0 - 2022-01-02
|
||||
------------------
|
||||
|
||||
* Optimized chrono formatting
|
||||
(`#2500 <https://github.com/fmtlib/fmt/pull/2500>`_,
|
||||
`#2537 <https://github.com/fmtlib/fmt/pull/2537>`_,
|
||||
`#2541 <https://github.com/fmtlib/fmt/issues/2541>`_,
|
||||
`#2544 <https://github.com/fmtlib/fmt/pull/2544>`_,
|
||||
`#2550 <https://github.com/fmtlib/fmt/pull/2550>`_,
|
||||
`#2551 <https://github.com/fmtlib/fmt/pull/2551>`_,
|
||||
`#2576 <https://github.com/fmtlib/fmt/pull/2576>`_,
|
||||
`#2577 <https://github.com/fmtlib/fmt/issues/2577>`_,
|
||||
`#2586 <https://github.com/fmtlib/fmt/pull/2586>`_,
|
||||
`#2591 <https://github.com/fmtlib/fmt/pull/2591>`_,
|
||||
`#2594 <https://github.com/fmtlib/fmt/pull/2594>`_,
|
||||
`#2602 <https://github.com/fmtlib/fmt/pull/2602>`_,
|
||||
`#2617 <https://github.com/fmtlib/fmt/pull/2617>`_,
|
||||
`#2628 <https://github.com/fmtlib/fmt/issues/2628>`_,
|
||||
`#2633 <https://github.com/fmtlib/fmt/pull/2633>`_,
|
||||
`#2670 <https://github.com/fmtlib/fmt/issues/2670>`_,
|
||||
`#2671 <https://github.com/fmtlib/fmt/pull/2671>`_).
|
||||
|
||||
Processing of some specifiers such as ``%z`` and ``%Y`` is now up to 10-20
|
||||
times faster, for example on GCC 11 with libstdc++::
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Benchmark Before After
|
||||
----------------------------------------------------------------------------
|
||||
FMTFormatter_z 261 ns 26.3 ns
|
||||
FMTFormatterCompile_z 246 ns 11.6 ns
|
||||
FMTFormatter_Y 263 ns 26.1 ns
|
||||
FMTFormatterCompile_Y 244 ns 10.5 ns
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_ and
|
||||
`@toughengineer (Pavel Novikov) <https://github.com/toughengineer>`_.
|
||||
|
||||
* Implemented subsecond formatting for chrono durations
|
||||
(`#2623 <https://github.com/fmtlib/fmt/pull/2623>`_).
|
||||
For example (`godbolt <https://godbolt.org/z/es7vWTETe>`__):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
int main() {
|
||||
fmt::print("{:%S}", std::chrono::milliseconds(1234));
|
||||
}
|
||||
|
||||
prints "01.234".
|
||||
|
||||
Thanks `@matrackif <https://github.com/matrackif>`_.
|
||||
|
||||
* Fixed handling of precision 0 when formatting chrono durations
|
||||
(`#2587 <https://github.com/fmtlib/fmt/issues/2587>`_,
|
||||
`#2588 <https://github.com/fmtlib/fmt/pull/2588>`_).
|
||||
Thanks `@lukester1975 <https://github.com/lukester1975>`_.
|
||||
|
||||
* Fixed an overflow on invalid inputs in the ``tm`` formatter
|
||||
(`#2564 <https://github.com/fmtlib/fmt/pull/2564>`_).
|
||||
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||
|
||||
* Added ``fmt::group_digits`` that formats integers with a non-localized digit
|
||||
separator (comma) for groups of three digits.
|
||||
For example (`godbolt <https://godbolt.org/z/TxGxG9Poq>`__):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
int main() {
|
||||
fmt::print("{} dollars", fmt::group_digits(1000000));
|
||||
}
|
||||
|
||||
prints "1,000,000 dollars".
|
||||
|
||||
* Added support for faint, conceal, reverse and blink text styles
|
||||
(`#2394 <https://github.com/fmtlib/fmt/pull/2394>`_):
|
||||
|
||||
https://user-images.githubusercontent.com/576385/147710227-c68f5317-f8fa-42c3-9123-7c4ba3c398cb.mp4
|
||||
|
||||
Thanks `@benit8 (Benoît Lormeau) <https://github.com/benit8>`_ and
|
||||
`@data-man (Dmitry Atamanov) <https://github.com/data-man>`_.
|
||||
|
||||
* Added experimental support for compile-time floating point formatting
|
||||
(`#2426 <https://github.com/fmtlib/fmt/pull/2426>`_,
|
||||
`#2470 <https://github.com/fmtlib/fmt/pull/2470>`_).
|
||||
It is currently limited to the header-only mode.
|
||||
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||
|
||||
* Added UDL-based named argument support to compile-time format string checks
|
||||
(`#2640 <https://github.com/fmtlib/fmt/issues/2640>`_,
|
||||
`#2649 <https://github.com/fmtlib/fmt/pull/2649>`_).
|
||||
For example (`godbolt <https://godbolt.org/z/ohGbbvonv>`__):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
int main() {
|
||||
using namespace fmt::literals;
|
||||
fmt::print("{answer:s}", "answer"_a=42);
|
||||
}
|
||||
|
||||
gives a compile-time error on compilers with C++20 ``consteval`` and non-type
|
||||
template parameter support (gcc 10+) because ``s`` is not a valid format
|
||||
specifier for an integer.
|
||||
|
||||
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||
|
||||
* Implemented escaping of string range elements.
|
||||
For example (`godbolt <https://godbolt.org/z/rKvM1vKf3>`__):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
#include <vector>
|
||||
|
||||
int main() {
|
||||
fmt::print("{}", std::vector<std::string>{"\naan"});
|
||||
}
|
||||
|
||||
is now printed as::
|
||||
|
||||
["\naan"]
|
||||
|
||||
instead of::
|
||||
|
||||
["
|
||||
aan"]
|
||||
|
||||
* Switched to JSON-like representation of maps and sets for consistency with
|
||||
Python's ``str.format``.
|
||||
For example (`godbolt <https://godbolt.org/z/seKjoY9W5>`__):
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include <fmt/ranges.h>
|
||||
#include <map>
|
||||
|
||||
int main() {
|
||||
fmt::print("{}", std::map<std::string, int>{{"answer", 42}});
|
||||
}
|
||||
|
||||
is now printed as::
|
||||
|
||||
{"answer": 42}
|
||||
|
||||
* Extended ``fmt::join`` to support C++20-only ranges
|
||||
(`#2549 <https://github.com/fmtlib/fmt/pull/2549>`_).
|
||||
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
|
||||
|
||||
* Optimized handling of non-const-iterable ranges and implemented initial
|
||||
support for non-const-formattable types.
|
||||
|
||||
* Disabled implicit conversions of scoped enums to integers that was
|
||||
accidentally introduced in earlier versions
|
||||
(`#1841 <https://github.com/fmtlib/fmt/pull/1841>`_).
|
||||
|
||||
* Deprecated implicit conversion of ``[const] signed char*`` and
|
||||
``[const] unsigned char*`` to C strings.
|
||||
|
||||
* Deprecated ``_format``, a legacy UDL-based format API
|
||||
(`#2646 <https://github.com/fmtlib/fmt/pull/2646>`_).
|
||||
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||
|
||||
* Marked ``format``, ``formatted_size`` and ``to_string`` as ``[[nodiscard]]``
|
||||
(`#2612 <https://github.com/fmtlib/fmt/pull/2612>`_).
|
||||
`@0x8000-0000 (Florin Iucha) <https://github.com/0x8000-0000>`_.
|
||||
|
||||
* Added missing diagnostic when trying to format function and member pointers
|
||||
as well as objects convertible to pointers which is explicitly disallowed
|
||||
(`#2598 <https://github.com/fmtlib/fmt/issues/2598>`_,
|
||||
`#2609 <https://github.com/fmtlib/fmt/pull/2609>`_,
|
||||
`#2610 <https://github.com/fmtlib/fmt/pull/2610>`_).
|
||||
Thanks `@AlexGuteniev (Alex Guteniev) <https://github.com/AlexGuteniev>`_.
|
||||
|
||||
* Optimized writing to a contiguous buffer with ``format_to_n``
|
||||
(`#2489 <https://github.com/fmtlib/fmt/pull/2489>`_).
|
||||
Thanks `@Roman-Koshelev <https://github.com/Roman-Koshelev>`_.
|
||||
|
||||
* Optimized writing to non-``char`` buffers
|
||||
(`#2477 <https://github.com/fmtlib/fmt/pull/2477>`_).
|
||||
Thanks `@Roman-Koshelev <https://github.com/Roman-Koshelev>`_.
|
||||
|
||||
* Decimal point is now localized when using the ``L`` specifier.
|
||||
|
||||
* Improved floating point formatter implementation
|
||||
(`#2498 <https://github.com/fmtlib/fmt/pull/2498>`_,
|
||||
`#2499 <https://github.com/fmtlib/fmt/pull/2499>`_).
|
||||
Thanks `@Roman-Koshelev <https://github.com/Roman-Koshelev>`_.
|
||||
|
||||
* Fixed handling of very large precision in fixed format
|
||||
(`#2616 <https://github.com/fmtlib/fmt/pull/2616>`_).
|
||||
|
||||
* Made a table of cached powers used in FP formatting static
|
||||
(`#2509 <https://github.com/fmtlib/fmt/pull/2509>`_).
|
||||
Thanks `@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_.
|
||||
|
||||
* Resolved a lookup ambiguity with C++20 format-related functions due to ADL
|
||||
(`#2639 <https://github.com/fmtlib/fmt/issues/2639>`_,
|
||||
`#2641 <https://github.com/fmtlib/fmt/pull/2641>`_).
|
||||
Thanks `@mkurdej (Marek Kurdej) <https://github.com/mkurdej>`_.
|
||||
|
||||
* Removed unnecessary inline namespace qualification
|
||||
(`#2642 <https://github.com/fmtlib/fmt/issues/2642>`_,
|
||||
`#2643 <https://github.com/fmtlib/fmt/pull/2643>`_).
|
||||
Thanks `@mkurdej (Marek Kurdej) <https://github.com/mkurdej>`_.
|
||||
|
||||
* Implemented argument forwarding in ``format_to_n``
|
||||
(`#2462 <https://github.com/fmtlib/fmt/issues/2462>`_,
|
||||
`#2463 <https://github.com/fmtlib/fmt/pull/2463>`_).
|
||||
Thanks `@owent (WenTao Ou) <https://github.com/owent>`_.
|
||||
|
||||
* Fixed handling of implicit conversions in ``fmt::to_string`` and format string
|
||||
compilation (`#2565 <https://github.com/fmtlib/fmt/issues/2565>`_).
|
||||
|
||||
* Changed the default access mode of files created by ``fmt::output_file`` to
|
||||
``-rw-r--r--`` for consistency with ``fopen``
|
||||
(`#2530 <https://github.com/fmtlib/fmt/issues/2530>`_).
|
||||
|
||||
* Make ``fmt::ostream::flush`` public
|
||||
(`#2435 <https://github.com/fmtlib/fmt/issues/2435>`_).
|
||||
|
||||
* Improved C++14/17 attribute detection
|
||||
(`#2615 <https://github.com/fmtlib/fmt/pull/2615>`_).
|
||||
Thanks `@AlexGuteniev (Alex Guteniev) <https://github.com/AlexGuteniev>`_.
|
||||
|
||||
* Improved ``consteval`` detection for MSVC
|
||||
(`#2559 <https://github.com/fmtlib/fmt/pull/2559>`_).
|
||||
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||
|
||||
* Improved documentation
|
||||
(`#2406 <https://github.com/fmtlib/fmt/issues/2406>`_,
|
||||
`#2446 <https://github.com/fmtlib/fmt/pull/2446>`_,
|
||||
`#2493 <https://github.com/fmtlib/fmt/issues/2493>`_,
|
||||
`#2513 <https://github.com/fmtlib/fmt/issues/2513>`_,
|
||||
`#2515 <https://github.com/fmtlib/fmt/pull/2515>`_,
|
||||
`#2522 <https://github.com/fmtlib/fmt/issues/2522>`_,
|
||||
`#2562 <https://github.com/fmtlib/fmt/pull/2562>`_,
|
||||
`#2575 <https://github.com/fmtlib/fmt/pull/2575>`_,
|
||||
`#2606 <https://github.com/fmtlib/fmt/pull/2606>`_,
|
||||
`#2620 <https://github.com/fmtlib/fmt/pull/2620>`_,
|
||||
`#2676 <https://github.com/fmtlib/fmt/issues/2676>`_).
|
||||
Thanks `@sobolevn (Nikita Sobolev) <https://github.com/sobolevn>`_,
|
||||
`@UnePierre (Max FERGER) <https://github.com/UnePierre>`_,
|
||||
`@zhsj <https://github.com/zhsj>`_,
|
||||
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
|
||||
`@ericcurtin (Eric Curtin) <https://github.com/ericcurtin>`_,
|
||||
`@Lounarok <https://github.com/Lounarok>`_.
|
||||
|
||||
* Improved fuzzers and added a fuzzer for chrono timepoint formatting
|
||||
(`#2461 <https://github.com/fmtlib/fmt/pull/2461>`_,
|
||||
`#2469 <https://github.com/fmtlib/fmt/pull/2469>`_).
|
||||
`@pauldreik (Paul Dreik) <https://github.com/pauldreik>`_,
|
||||
|
||||
* Added the ``FMT_SYSTEM_HEADERS`` CMake option setting which marks {fmt}'s
|
||||
headers as system. It can be used to suppress warnings
|
||||
(`#2644 <https://github.com/fmtlib/fmt/issues/2644>`_,
|
||||
`#2651 <https://github.com/fmtlib/fmt/pull/2651>`_).
|
||||
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||
|
||||
* Added the Bazel build system support
|
||||
(`#2505 <https://github.com/fmtlib/fmt/pull/2505>`_,
|
||||
`#2516 <https://github.com/fmtlib/fmt/pull/2516>`_).
|
||||
Thanks `@Vertexwahn <https://github.com/Vertexwahn>`_.
|
||||
|
||||
* Improved build configuration and tests
|
||||
(`#2437 <https://github.com/fmtlib/fmt/issues/2437>`_,
|
||||
`#2558 <https://github.com/fmtlib/fmt/pull/2558>`_,
|
||||
`#2648 <https://github.com/fmtlib/fmt/pull/2648>`_,
|
||||
`#2650 <https://github.com/fmtlib/fmt/pull/2650>`_,
|
||||
`#2663 <https://github.com/fmtlib/fmt/pull/2663>`_,
|
||||
`#2677 <https://github.com/fmtlib/fmt/pull/2677>`_).
|
||||
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
|
||||
`@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_,
|
||||
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||
|
||||
* Fixed various warnings and compilation issues
|
||||
(`#2353 <https://github.com/fmtlib/fmt/pull/2353>`_,
|
||||
`#2356 <https://github.com/fmtlib/fmt/pull/2356>`_,
|
||||
`#2399 <https://github.com/fmtlib/fmt/pull/2399>`_,
|
||||
`#2408 <https://github.com/fmtlib/fmt/issues/2408>`_,
|
||||
`#2414 <https://github.com/fmtlib/fmt/pull/2414>`_,
|
||||
`#2427 <https://github.com/fmtlib/fmt/pull/2427>`_,
|
||||
`#2432 <https://github.com/fmtlib/fmt/pull/2432>`_,
|
||||
`#2442 <https://github.com/fmtlib/fmt/pull/2442>`_,
|
||||
`#2434 <https://github.com/fmtlib/fmt/pull/2434>`_,
|
||||
`#2439 <https://github.com/fmtlib/fmt/issues/2439>`_,
|
||||
`#2447 <https://github.com/fmtlib/fmt/pull/2447>`_,
|
||||
`#2450 <https://github.com/fmtlib/fmt/pull/2450>`_,
|
||||
`#2455 <https://github.com/fmtlib/fmt/issues/2455>`_,
|
||||
`#2465 <https://github.com/fmtlib/fmt/issues/2465>`_,
|
||||
`#2472 <https://github.com/fmtlib/fmt/issues/2472>`_,
|
||||
`#2474 <https://github.com/fmtlib/fmt/issues/2474>`_,
|
||||
`#2476 <https://github.com/fmtlib/fmt/pull/2476>`_,
|
||||
`#2478 <https://github.com/fmtlib/fmt/issues/2478>`_,
|
||||
`#2479 <https://github.com/fmtlib/fmt/issues/2479>`_,
|
||||
`#2481 <https://github.com/fmtlib/fmt/issues/2481>`_,
|
||||
`#2482 <https://github.com/fmtlib/fmt/pull/2482>`_,
|
||||
`#2483 <https://github.com/fmtlib/fmt/pull/2483>`_,
|
||||
`#2490 <https://github.com/fmtlib/fmt/issues/2490>`_,
|
||||
`#2491 <https://github.com/fmtlib/fmt/pull/2491>`_,
|
||||
`#2510 <https://github.com/fmtlib/fmt/pull/2510>`_,
|
||||
`#2518 <https://github.com/fmtlib/fmt/pull/2518>`_,
|
||||
`#2528 <https://github.com/fmtlib/fmt/issues/2528>`_,
|
||||
`#2529 <https://github.com/fmtlib/fmt/pull/2529>`_,
|
||||
`#2539 <https://github.com/fmtlib/fmt/pull/2539>`_,
|
||||
`#2540 <https://github.com/fmtlib/fmt/issues/2540>`_,
|
||||
`#2545 <https://github.com/fmtlib/fmt/pull/2545>`_,
|
||||
`#2555 <https://github.com/fmtlib/fmt/pull/2555>`_,
|
||||
`#2557 <https://github.com/fmtlib/fmt/issues/2557>`_,
|
||||
`#2570 <https://github.com/fmtlib/fmt/issues/2570>`_,
|
||||
`#2573 <https://github.com/fmtlib/fmt/pull/2573>`_,
|
||||
`#2582 <https://github.com/fmtlib/fmt/pull/2582>`_,
|
||||
`#2605 <https://github.com/fmtlib/fmt/issues/2605>`_,
|
||||
`#2611 <https://github.com/fmtlib/fmt/pull/2611>`_,
|
||||
`#2647 <https://github.com/fmtlib/fmt/pull/2647>`_,
|
||||
`#2627 <https://github.com/fmtlib/fmt/issues/2627>`_,
|
||||
`#2630 <https://github.com/fmtlib/fmt/pull/2630>`_,
|
||||
`#2635 <https://github.com/fmtlib/fmt/issues/2635>`_,
|
||||
`#2638 <https://github.com/fmtlib/fmt/issues/2638>`_,
|
||||
`#2653 <https://github.com/fmtlib/fmt/issues/2653>`_,
|
||||
`#2654 <https://github.com/fmtlib/fmt/issues/2654>`_,
|
||||
`#2661 <https://github.com/fmtlib/fmt/issues/2661>`_,
|
||||
`#2664 <https://github.com/fmtlib/fmt/pull/2664>`_,
|
||||
`#2684 <https://github.com/fmtlib/fmt/pull/2684>`_).
|
||||
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
|
||||
`@mwinterb <https://github.com/mwinterb>`_,
|
||||
`@cdacamar (Cameron DaCamara) <https://github.com/cdacamar>`_,
|
||||
`@TrebledJ (Johnathan) <https://github.com/TrebledJ>`_,
|
||||
`@bodomartin (brm) <https://github.com/bodomartin>`_,
|
||||
`@cquammen (Cory Quammen) <https://github.com/cquammen>`_,
|
||||
`@white238 (Chris White) <https://github.com/white238>`_,
|
||||
`@mmarkeloff (Max) <https://github.com/mmarkeloff>`_,
|
||||
`@palacaze (Pierre-Antoine Lacaze) <https://github.com/palacaze>`_,
|
||||
`@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_,
|
||||
`@mborn-adi (Mathias Born) <https://github.com/mborn-adi>`_,
|
||||
`@BrukerJWD (Jonathan W) <https://github.com/BrukerJWD>`_,
|
||||
`@spyridon97 (Spiros Tsalikis) <https://github.com/spyridon97>`_,
|
||||
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
|
||||
`@oliverlee (Oliver Lee) <https://github.com/oliverlee>`_,
|
||||
`@joshessman-llnl (Josh Essman) <https://github.com/joshessman-llnl>`_,
|
||||
`@akohlmey (Axel Kohlmeyer) <https://github.com/akohlmey>`_,
|
||||
`@timkalu <https://github.com/timkalu>`_,
|
||||
`@olupton (Olli Lupton) <https://github.com/olupton>`_,
|
||||
`@Acretock <https://github.com/Acretock>`_,
|
||||
`@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_,
|
||||
`@andrewcorrigan (Andrew Corrigan) <https://github.com/andrewcorrigan>`_,
|
||||
`@lucpelletier <https://github.com/lucpelletier>`_,
|
||||
`@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_.
|
||||
|
||||
8.0.1 - 2021-07-02
|
||||
------------------
|
||||
|
||||
@@ -34,7 +405,7 @@
|
||||
`#2389 <https://github.com/fmtlib/fmt/pull/2389>`_,
|
||||
`#2395 <https://github.com/fmtlib/fmt/pull/2395>`_,
|
||||
`#2397 <https://github.com/fmtlib/fmt/pull/2397>`_,
|
||||
`#2400 <https://github.com/fmtlib/fmt/issues/2400>`_
|
||||
`#2400 <https://github.com/fmtlib/fmt/issues/2400>`_,
|
||||
`#2401 <https://github.com/fmtlib/fmt/issues/2401>`_,
|
||||
`#2407 <https://github.com/fmtlib/fmt/pull/2407>`_).
|
||||
Thanks `@zx2c4 (Jason A. Donenfeld) <https://github.com/zx2c4>`_,
|
||||
@@ -50,7 +421,7 @@
|
||||
8.0.0 - 2021-06-21
|
||||
------------------
|
||||
|
||||
* Enabled compile-time format string check by default.
|
||||
* Enabled compile-time format string checks by default.
|
||||
For example (`godbolt <https://godbolt.org/z/sMxcohGjz>`__):
|
||||
|
||||
.. code:: c++
|
||||
@@ -281,6 +652,9 @@
|
||||
This doesn't introduce a dependency on ``<locale>`` so there is virtually no
|
||||
compile time effect.
|
||||
|
||||
* Deprecated an undocumented ``format_to`` overload that takes
|
||||
``basic_memory_buffer``.
|
||||
|
||||
* Made parameter order in ``vformat_to`` consistent with ``format_to``
|
||||
(`#2327 <https://github.com/fmtlib/fmt/issues/2327>`_).
|
||||
|
||||
@@ -562,13 +936,13 @@
|
||||
`#2067 <https://github.com/fmtlib/fmt/pull/2067>`_,
|
||||
`#2068 <https://github.com/fmtlib/fmt/pull/2068>`_,
|
||||
`#2073 <https://github.com/fmtlib/fmt/pull/2073>`_,
|
||||
`#2103 <https://github.com/fmtlib/fmt/issues/2103>`_
|
||||
`#2105 <https://github.com/fmtlib/fmt/issues/2105>`_
|
||||
`#2103 <https://github.com/fmtlib/fmt/issues/2103>`_,
|
||||
`#2105 <https://github.com/fmtlib/fmt/issues/2105>`_,
|
||||
`#2106 <https://github.com/fmtlib/fmt/pull/2106>`_,
|
||||
`#2107 <https://github.com/fmtlib/fmt/pull/2107>`_,
|
||||
`#2116 <https://github.com/fmtlib/fmt/issues/2116>`_
|
||||
`#2116 <https://github.com/fmtlib/fmt/issues/2116>`_,
|
||||
`#2117 <https://github.com/fmtlib/fmt/pull/2117>`_,
|
||||
`#2118 <https://github.com/fmtlib/fmt/issues/2118>`_
|
||||
`#2118 <https://github.com/fmtlib/fmt/issues/2118>`_,
|
||||
`#2119 <https://github.com/fmtlib/fmt/pull/2119>`_,
|
||||
`#2127 <https://github.com/fmtlib/fmt/issues/2127>`_,
|
||||
`#2128 <https://github.com/fmtlib/fmt/pull/2128>`_,
|
||||
@@ -641,7 +1015,7 @@
|
||||
`@yeswalrus (Walter Gray) <https://github.com/yeswalrus>`_,
|
||||
`@Finkman <https://github.com/Finkman>`_,
|
||||
`@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_,
|
||||
`@dkavolis (Daumantas Kavolis) <https://github.com/dkavolis>`_
|
||||
`@dkavolis (Daumantas Kavolis) <https://github.com/dkavolis>`_,
|
||||
`@concatime (Issam Maghni) <https://github.com/concatime>`_,
|
||||
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
|
||||
`@summivox (Yin Zhong) <https://github.com/summivox>`_,
|
||||
@@ -1098,7 +1472,7 @@
|
||||
`#1912 <https://github.com/fmtlib/fmt/issues/1912>`_,
|
||||
`#1928 <https://github.com/fmtlib/fmt/issues/1928>`_,
|
||||
`#1929 <https://github.com/fmtlib/fmt/pull/1929>`_,
|
||||
`#1935 <https://github.com/fmtlib/fmt/issues/1935>`_
|
||||
`#1935 <https://github.com/fmtlib/fmt/issues/1935>`_,
|
||||
`#1937 <https://github.com/fmtlib/fmt/pull/1937>`_,
|
||||
`#1942 <https://github.com/fmtlib/fmt/pull/1942>`_,
|
||||
`#1949 <https://github.com/fmtlib/fmt/issues/1949>`_).
|
||||
|
||||
Vendored
+9
-8
@@ -1,5 +1,7 @@
|
||||
{fmt}
|
||||
=====
|
||||
.. image:: https://user-images.githubusercontent.com/
|
||||
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
|
||||
:width: 25%
|
||||
:alt: {fmt}
|
||||
|
||||
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
||||
@@ -26,9 +28,8 @@
|
||||
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||
alternative to C stdio and C++ iostreams.
|
||||
|
||||
If you like this project, please consider donating to the BYSOL
|
||||
Foundation that helps victims of political repressions in Belarus:
|
||||
https://bysol.org/en/bs/general/.
|
||||
If you like this project, please consider donating to one of the funds that
|
||||
help victims of the war in Ukraine: https://www.stopputin.net/.
|
||||
|
||||
`Documentation <https://fmt.dev>`__
|
||||
|
||||
@@ -123,7 +124,7 @@ Output::
|
||||
Default format: 42s 100ms
|
||||
strftime-like format: 03:15:30
|
||||
|
||||
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
|
||||
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
|
||||
|
||||
.. code:: c++
|
||||
|
||||
@@ -205,7 +206,7 @@ The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
||||
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
|
||||
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
||||
further details refer to the `source
|
||||
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
|
||||
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
|
||||
|
||||
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
||||
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
||||
@@ -469,7 +470,7 @@ Boost Format
|
||||
|
||||
This is a very powerful library which supports both ``printf``-like format
|
||||
strings and positional arguments. Its main drawback is performance. According to
|
||||
various, benchmarks it is much slower than other methods considered here. Boost
|
||||
various benchmarks, it is much slower than other methods considered here. Boost
|
||||
Format also has excessive build times and severe code bloat issues (see
|
||||
`Benchmarks`_).
|
||||
|
||||
|
||||
Vendored
+55
-33
@@ -37,10 +37,12 @@ similar to that of Python's `str.format
|
||||
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
||||
They take *fmt* and *args* as arguments.
|
||||
|
||||
*fmt* is a format string that contains literal text and replacement
|
||||
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
||||
arguments in the resulting string. A function taking *fmt* doesn't
|
||||
participate in an overload resolution if the latter is not a string.
|
||||
*fmt* is a format string that contains literal text and replacement fields
|
||||
surrounded by braces ``{}``. The fields are replaced with formatted arguments
|
||||
in the resulting string. `~fmt::format_string` is a format string which can be
|
||||
implicitly constructed from a string literal or a ``constexpr`` string and is
|
||||
checked at compile time in C++20. To pass a runtime format string wrap it in
|
||||
`fmt::runtime`.
|
||||
|
||||
*args* is an argument list representing objects to be formatted.
|
||||
|
||||
@@ -50,7 +52,7 @@ participate in an overload resolution if the latter is not a string.
|
||||
.. doxygenfunction:: vformat(string_view fmt, format_args args) -> std::string
|
||||
|
||||
.. doxygenfunction:: format_to(OutputIt out, format_string<T...> fmt, T&&... args) -> OutputIt
|
||||
.. doxygenfunction:: format_to_n(OutputIt out, size_t n, format_string<T...> fmt, const T&... args) -> format_to_n_result<OutputIt>
|
||||
.. doxygenfunction:: format_to_n(OutputIt out, size_t n, format_string<T...> fmt, T&&... args) -> format_to_n_result<OutputIt>
|
||||
.. doxygenfunction:: formatted_size(format_string<T...> fmt, T&&... args) -> size_t
|
||||
|
||||
.. doxygenstruct:: fmt::format_to_n_result
|
||||
@@ -59,7 +61,7 @@ participate in an overload resolution if the latter is not a string.
|
||||
.. _print:
|
||||
|
||||
.. doxygenfunction:: fmt::print(format_string<T...> fmt, T&&... args)
|
||||
.. doxygenfunction:: vprint(string_view fmt, format_args args)
|
||||
.. doxygenfunction:: fmt::vprint(string_view fmt, format_args args)
|
||||
|
||||
.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
|
||||
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
|
||||
@@ -70,6 +72,7 @@ Compile-time Format String Checks
|
||||
Compile-time checks are enabled when using ``FMT_STRING``. They support built-in
|
||||
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||
functions in their ``formatter`` specializations.
|
||||
Requires C++14 and is a no-op in C++11.
|
||||
|
||||
.. doxygendefine:: FMT_STRING
|
||||
|
||||
@@ -78,6 +81,13 @@ To force the use of compile-time checks, define the preprocessor variable
|
||||
will fail to compile with regular strings. Runtime-checked
|
||||
formatting is still possible using ``fmt::vformat``, ``fmt::vprint``, etc.
|
||||
|
||||
.. doxygenclass:: fmt::basic_format_string
|
||||
:members:
|
||||
|
||||
.. doxygentypedef:: fmt::format_string
|
||||
|
||||
.. doxygenfunction:: fmt::runtime(const S&)
|
||||
|
||||
Named Arguments
|
||||
---------------
|
||||
|
||||
@@ -103,8 +113,7 @@ binary footprint, for example (https://godbolt.org/z/oba4Mc):
|
||||
|
||||
template <typename S, typename... Args>
|
||||
void log(const char* file, int line, const S& format, Args&&... args) {
|
||||
vlog(file, line, format,
|
||||
fmt::make_args_checked<Args...>(format, args...));
|
||||
vlog(file, line, format, fmt::make_format_args(args...));
|
||||
}
|
||||
|
||||
#define MY_LOG(format, ...) \
|
||||
@@ -115,8 +124,6 @@ binary footprint, for example (https://godbolt.org/z/oba4Mc):
|
||||
Note that ``vlog`` is not parameterized on argument types which improves compile
|
||||
times and reduces binary code size compared to a fully parameterized version.
|
||||
|
||||
.. doxygenfunction:: fmt::make_args_checked(const S&, const remove_reference_t<Args>&...)
|
||||
|
||||
.. doxygenfunction:: fmt::make_format_args(const Args&...)
|
||||
|
||||
.. doxygenclass:: fmt::format_arg_store
|
||||
@@ -172,12 +179,19 @@ functions and locale support.
|
||||
Formatting User-defined Types
|
||||
-----------------------------
|
||||
|
||||
The {fmt} library provides formatters for many standard C++ types.
|
||||
See :ref:`fmt/ranges.h <ranges-api>` for ranges and tuples including standard
|
||||
containers such as ``std::vector`` and :ref:`fmt/chrono.h <chrono-api>` for date
|
||||
and time formatting.
|
||||
|
||||
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
||||
template and implement ``parse`` and ``format`` methods::
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
struct point { double x, y; };
|
||||
struct point {
|
||||
double x, y;
|
||||
};
|
||||
|
||||
template <> struct fmt::formatter<point> {
|
||||
// Presentation format: 'f' - fixed, 'e' - exponential.
|
||||
@@ -201,8 +215,7 @@ template and implement ``parse`` and ``format`` methods::
|
||||
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
|
||||
|
||||
// Check if reached the end of the range:
|
||||
if (it != end && *it != '}')
|
||||
throw format_error("invalid format");
|
||||
if (it != end && *it != '}') throw format_error("invalid format");
|
||||
|
||||
// Return an iterator past the end of the parsed range:
|
||||
return it;
|
||||
@@ -211,12 +224,11 @@ template and implement ``parse`` and ``format`` methods::
|
||||
// Formats the point p using the parsed format specification (presentation)
|
||||
// stored in this formatter.
|
||||
template <typename FormatContext>
|
||||
auto format(const point& p, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
auto format(const point& p, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
// ctx.out() is an output iterator to write to.
|
||||
return format_to(
|
||||
ctx.out(),
|
||||
presentation == 'f' ? "({:.1f}, {:.1f})" : "({:.1e}, {:.1e})",
|
||||
p.x, p.y);
|
||||
return presentation == 'f'
|
||||
? format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
|
||||
: format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -234,7 +246,7 @@ example::
|
||||
template <> struct fmt::formatter<color>: formatter<string_view> {
|
||||
// parse is inherited from formatter<string_view>.
|
||||
template <typename FormatContext>
|
||||
auto format(color c, FormatContext& ctx) {
|
||||
auto format(color c, FormatContext& ctx) const {
|
||||
string_view name = "unknown";
|
||||
switch (c) {
|
||||
case color::red: name = "red"; break;
|
||||
@@ -272,7 +284,7 @@ You can also write a formatter for a hierarchy of classes::
|
||||
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
|
||||
fmt::formatter<std::string> {
|
||||
template <typename FormatCtx>
|
||||
auto format(const A& a, FormatCtx& ctx) {
|
||||
auto format(const A& a, FormatCtx& ctx) const {
|
||||
return fmt::formatter<std::string>::format(a.name(), ctx);
|
||||
}
|
||||
};
|
||||
@@ -306,6 +318,8 @@ Utilities
|
||||
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T> &p) -> const void*
|
||||
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
|
||||
|
||||
.. doxygenfunction:: fmt::underlying(Enum e) -> typename std::underlying_type<Enum>::type
|
||||
|
||||
.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
|
||||
|
||||
.. doxygenfunction:: fmt::to_string_view(const Char *s) -> basic_string_view<Char>
|
||||
@@ -314,6 +328,8 @@ Utilities
|
||||
|
||||
.. doxygenfunction:: fmt::join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel>
|
||||
|
||||
.. doxygenfunction:: fmt::group_digits(T value) -> group_digits_view<T>
|
||||
|
||||
.. doxygenclass:: fmt::detail::buffer
|
||||
:members:
|
||||
|
||||
@@ -434,16 +450,19 @@ The format syntax is described in :ref:`chrono-specs`.
|
||||
Format string compilation
|
||||
=========================
|
||||
|
||||
``fmt/compile.h`` provides format string compilation support when using
|
||||
``FMT_COMPILE``. Format strings are parsed, checked and converted into efficient
|
||||
formatting code at compile-time. This supports arguments of built-in and string
|
||||
types as well as user-defined types with ``constexpr`` ``parse`` functions in
|
||||
their ``formatter`` specializations. Format string compilation can generate more
|
||||
binary code compared to the default API and is only recommended in places where
|
||||
formatting is a performance bottleneck.
|
||||
``fmt/compile.h`` provides format string compilation enabled via the
|
||||
``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
|
||||
marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
|
||||
efficient formatting code at compile-time. This supports arguments of built-in
|
||||
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||
functions in their ``formatter`` specializations. Format string compilation can
|
||||
generate more binary code compared to the default API and is only recommended in
|
||||
places where formatting is a performance bottleneck.
|
||||
|
||||
.. doxygendefine:: FMT_COMPILE
|
||||
|
||||
.. doxygenfunction:: operator""_cf()
|
||||
|
||||
.. _color-api:
|
||||
|
||||
Terminal color and text style
|
||||
@@ -457,6 +476,8 @@ Terminal color and text style
|
||||
|
||||
.. doxygenfunction:: bg(detail::color_type)
|
||||
|
||||
.. doxygenfunction:: styled(const T& value, text_style ts)
|
||||
|
||||
.. _os-api:
|
||||
|
||||
System APIs
|
||||
@@ -474,7 +495,9 @@ System APIs
|
||||
========================
|
||||
|
||||
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
|
||||
user-defined types that have an overloaded insertion operator (``operator<<``)::
|
||||
user-defined types that have an overloaded insertion operator (``operator<<``).
|
||||
In order to make a type formattable via ``std::ostream`` you should provide a
|
||||
``formatter`` specialization inherited from ``ostream_formatter``::
|
||||
|
||||
#include <fmt/ostream.h>
|
||||
|
||||
@@ -488,12 +511,11 @@ user-defined types that have an overloaded insertion operator (``operator<<``)::
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct fmt::formatter<date> : ostream_formatter {};
|
||||
|
||||
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
||||
// s == "The date is 2012-12-9"
|
||||
|
||||
{fmt} only supports insertion operators that are defined in the same namespaces
|
||||
as the types they format and can be found with the argument-dependent lookup.
|
||||
|
||||
.. doxygenfunction:: print(std::basic_ostream<Char> &os, const S &format_str, Args&&... args)
|
||||
|
||||
.. _printf-api:
|
||||
@@ -519,8 +541,8 @@ argument type doesn't match its format specification.
|
||||
``wchar_t`` Support
|
||||
===================
|
||||
|
||||
The optional header ``fmt/wchar_t.h`` provides support for ``wchar_t`` and
|
||||
exotic character types.
|
||||
The optional header ``fmt/xchar.h`` provides support for ``wchar_t`` and exotic
|
||||
character types.
|
||||
|
||||
.. doxygenstruct:: fmt::is_char
|
||||
|
||||
|
||||
+3
-1
@@ -90,12 +90,14 @@
|
||||
VERSION: '{{ release|e }}',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
||||
LINK_SUFFIX: '{{ link_suffix }}',
|
||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}',
|
||||
HAS_SOURCE: {{ has_source|lower }},
|
||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
||||
};
|
||||
</script>
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{{ js_tag(scriptfile) }}
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
Vendored
+5
-1
@@ -4,7 +4,7 @@
|
||||
import errno, os, re, sys
|
||||
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
|
||||
|
||||
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1']
|
||||
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1', '8.1.0', '8.1.1']
|
||||
|
||||
class Pip:
|
||||
def __init__(self, venv_dir):
|
||||
@@ -26,6 +26,8 @@ def create_build_env(venv_dir='virtualenv'):
|
||||
pip = Pip(venv_dir)
|
||||
pip.install('wheel')
|
||||
pip.install('six')
|
||||
# See: https://github.com/sphinx-doc/sphinx/issues/9777
|
||||
pip.install('docutils==0.17.1')
|
||||
pip.install('sphinx-doc/sphinx', 'v3.3.0')
|
||||
pip.install('michaeljones/breathe', 'v4.25.0')
|
||||
|
||||
@@ -58,10 +60,12 @@ def build_docs(version='dev', **kwargs):
|
||||
MACRO_EXPANSION = YES
|
||||
PREDEFINED = _WIN32=1 \
|
||||
__linux__=1 \
|
||||
FMT_ENABLE_IF(...)= \
|
||||
FMT_USE_VARIADIC_TEMPLATES=1 \
|
||||
FMT_USE_RVALUE_REFERENCES=1 \
|
||||
FMT_USE_USER_DEFINED_LITERALS=1 \
|
||||
FMT_USE_ALIAS_TEMPLATES=1 \
|
||||
FMT_USE_NONTYPE_TEMPLATE_PARAMETERS=1 \
|
||||
FMT_API= \
|
||||
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
||||
"FMT_END_NAMESPACE=}}" \
|
||||
|
||||
Vendored
+1
-1
@@ -101,7 +101,7 @@ The code
|
||||
format(FMT_STRING("The answer is {:d}"), "forty-two");
|
||||
|
||||
reports a compile-time error on compilers that support relaxed ``constexpr``.
|
||||
See `here <api.html#c.fmt>`_ for details.
|
||||
See `here <api.html#compile-time-format-string-checks>`_ for details.
|
||||
|
||||
The following code
|
||||
|
||||
|
||||
Vendored
+41
-13
@@ -112,18 +112,18 @@ meaning in this case.
|
||||
The *sign* option is only valid for number types, and can be one of the
|
||||
following:
|
||||
|
||||
+---------+----------------------------------------------------------+
|
||||
+---------+------------------------------------------------------------+
|
||||
| Option | Meaning |
|
||||
+=========+==========================================================+
|
||||
+=========+============================================================+
|
||||
| ``'+'`` | indicates that a sign should be used for both |
|
||||
| | positive as well as negative numbers. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| | nonnegative as well as negative numbers. |
|
||||
+---------+------------------------------------------------------------+
|
||||
| ``'-'`` | indicates that a sign should be used only for negative |
|
||||
| | numbers (this is the default behavior). |
|
||||
+---------+----------------------------------------------------------+
|
||||
+---------+------------------------------------------------------------+
|
||||
| space | indicates that a leading space should be used on |
|
||||
| | positive numbers, and a minus sign on negative numbers. |
|
||||
+---------+----------------------------------------------------------+
|
||||
| | nonnegative numbers, and a minus sign on negative numbers. |
|
||||
+---------+------------------------------------------------------------+
|
||||
|
||||
The ``'#'`` option causes the "alternate form" to be used for the
|
||||
conversion. The alternate form is defined differently for different
|
||||
@@ -161,7 +161,8 @@ displayed after the decimal point for a floating-point value formatted with
|
||||
value formatted with ``'g'`` or ``'G'``. For non-number types the field
|
||||
indicates the maximum field size - in other words, how many characters will be
|
||||
used from the field content. The *precision* is not allowed for integer,
|
||||
character, Boolean, and pointer values.
|
||||
character, Boolean, and pointer values. Note that a C string must be
|
||||
null-terminated even if precision is specified.
|
||||
|
||||
The ``'L'`` option uses the current locale setting to insert the appropriate
|
||||
number separator characters. This option is only valid for numeric types.
|
||||
@@ -303,7 +304,8 @@ The available presentation types for pointers are:
|
||||
Chrono Format Specifications
|
||||
============================
|
||||
|
||||
Format specifications for chrono types have the following syntax:
|
||||
Format specifications for chrono types and ``std::tm`` have the following
|
||||
syntax:
|
||||
|
||||
.. productionlist:: sf
|
||||
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
|
||||
@@ -347,9 +349,35 @@ points are:
|
||||
Specifiers that have a calendaric component such as `'d'` (the day of month)
|
||||
are valid only for ``std::tm`` and not durations or time points.
|
||||
|
||||
``std::tm`` uses the system's `strftime
|
||||
<https://en.cppreference.com/w/cpp/chrono/c/strftime>`_ so refer to its
|
||||
documentation for details on supported conversion specifiers.
|
||||
.. range-specs:
|
||||
|
||||
Range Format Specifications
|
||||
===========================
|
||||
|
||||
Format specifications for range types have the following syntax:
|
||||
|
||||
..productionlist:: sf
|
||||
range_format_spec: [":" [`underlying_spec`]]
|
||||
|
||||
The `underlying_spec` is parsed based on the formatter of the range's
|
||||
reference type.
|
||||
|
||||
By default, a range of characters or strings is printed escaped and quoted. But
|
||||
if any `underlying_spec` is provided (even if it is empty), then the characters
|
||||
or strings are printed according to the provided specification.
|
||||
|
||||
Examples:
|
||||
|
||||
fmt::format("{}", std::vector{10, 20, 30});
|
||||
// Result: [10, 20, 30]
|
||||
fmt::format("{::#x}", std::vector{10, 20, 30});
|
||||
// Result: [0xa, 0x14, 0x13]
|
||||
fmt::format("{}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Result: ['h', 'e', 'l', 'l', 'o']
|
||||
fmt::format("{::}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Result: [h, e, l, l, o]
|
||||
fmt::format("{::d}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||
// Result: [104, 101, 108, 108, 111]
|
||||
|
||||
.. _formatexamples:
|
||||
|
||||
@@ -449,7 +477,7 @@ Using type-specific formatting::
|
||||
|
||||
Using the comma as a thousands separator::
|
||||
|
||||
#include <fmt/locale.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
|
||||
// s == "1,234,567,890"
|
||||
|
||||
Vendored
+2
-12
@@ -95,8 +95,8 @@ class dynamic_format_arg_store
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using stored_type = conditional_t<detail::is_string<T>::value &&
|
||||
!has_formatter<T, Context>::value &&
|
||||
using stored_type = conditional_t<
|
||||
std::is_convertible<T, std::basic_string<char_type>>::value &&
|
||||
!detail::is_reference_wrapper<T>::value,
|
||||
std::basic_string<char_type>, T>;
|
||||
|
||||
@@ -145,16 +145,6 @@ class dynamic_format_arg_store
|
||||
public:
|
||||
constexpr dynamic_format_arg_store() = default;
|
||||
|
||||
constexpr dynamic_format_arg_store(
|
||||
const dynamic_format_arg_store<Context>& store)
|
||||
:
|
||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||
basic_format_args<Context>(),
|
||||
#endif
|
||||
data_(store.data_),
|
||||
named_info_(store.named_info_) {
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Adds an argument into the dynamic store for later passing to a formatting
|
||||
|
||||
Vendored
+974
-211
File diff suppressed because it is too large
Load Diff
Vendored
+108
-52
@@ -214,17 +214,16 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
||||
|
||||
// color is a struct of either a rgb color or a terminal color.
|
||||
struct color_type {
|
||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
||||
value{} {
|
||||
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
|
||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||
}
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
|
||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||
}
|
||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
||||
value{} {
|
||||
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
|
||||
: is_rgb(), value{} {
|
||||
value.term_color = static_cast<uint8_t>(term_color);
|
||||
}
|
||||
bool is_rgb;
|
||||
@@ -239,10 +238,8 @@ FMT_END_DETAIL_NAMESPACE
|
||||
/** A text style consisting of foreground and background colors and emphasis. */
|
||||
class text_style {
|
||||
public:
|
||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||
: set_foreground_color(),
|
||||
set_background_color(),
|
||||
ems(em) {}
|
||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
|
||||
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||
|
||||
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
||||
if (!set_foreground_color) {
|
||||
@@ -283,34 +280,32 @@ class text_style {
|
||||
return lhs.and_assign(rhs);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR bool has_foreground() const noexcept {
|
||||
return set_foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR bool has_background() const noexcept {
|
||||
return set_background_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR bool has_emphasis() const noexcept {
|
||||
return static_cast<uint8_t>(ems) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
|
||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||
return foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR detail::color_type get_background() const noexcept {
|
||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||
return background_color;
|
||||
}
|
||||
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR emphasis get_emphasis() const noexcept {
|
||||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||
return ems;
|
||||
}
|
||||
|
||||
private:
|
||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||
detail::color_type text_color) FMT_NOEXCEPT
|
||||
: set_foreground_color(),
|
||||
set_background_color(),
|
||||
ems() {
|
||||
detail::color_type text_color) noexcept
|
||||
: set_foreground_color(), set_background_color(), ems() {
|
||||
if (is_foreground) {
|
||||
foreground_color = text_color;
|
||||
set_foreground_color = true;
|
||||
@@ -345,11 +340,11 @@ class text_style {
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
||||
FMT_NOEXCEPT;
|
||||
friend FMT_CONSTEXPR_DECL text_style
|
||||
fg(detail::color_type foreground) noexcept;
|
||||
|
||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
||||
FMT_NOEXCEPT;
|
||||
friend FMT_CONSTEXPR_DECL text_style
|
||||
bg(detail::color_type background) noexcept;
|
||||
|
||||
detail::color_type foreground_color;
|
||||
detail::color_type background_color;
|
||||
@@ -359,17 +354,16 @@ class text_style {
|
||||
};
|
||||
|
||||
/** Creates a text style from the foreground (text) color. */
|
||||
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept {
|
||||
return text_style(true, foreground);
|
||||
}
|
||||
|
||||
/** Creates a text style from the background color. */
|
||||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
|
||||
return text_style(false, background);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
|
||||
emphasis rhs) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
|
||||
return text_style(lhs) | rhs;
|
||||
}
|
||||
|
||||
@@ -377,7 +371,7 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
||||
|
||||
template <typename Char> struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
||||
const char* esc) FMT_NOEXCEPT {
|
||||
const char* esc) noexcept {
|
||||
// If we have a terminal color, we need to output another escape code
|
||||
// sequence.
|
||||
if (!text_color.is_rgb) {
|
||||
@@ -412,7 +406,7 @@ template <typename Char> struct ansi_color_escape {
|
||||
to_esc(color.b, buffer + 15, 'm');
|
||||
buffer[19] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
|
||||
uint8_t em_codes[num_emphases] = {};
|
||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
||||
@@ -433,10 +427,10 @@ template <typename Char> struct ansi_color_escape {
|
||||
}
|
||||
buffer[index++] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
|
||||
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
|
||||
|
||||
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
|
||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
|
||||
return buffer + std::char_traits<Char>::length(buffer);
|
||||
}
|
||||
|
||||
@@ -445,59 +439,64 @@ template <typename Char> struct ansi_color_escape {
|
||||
Char buffer[7u + 3u * num_emphases + 1u];
|
||||
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||
char delimiter) FMT_NOEXCEPT {
|
||||
char delimiter) noexcept {
|
||||
out[0] = static_cast<Char>('0' + c / 100);
|
||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||
out[2] = static_cast<Char>('0' + c % 10);
|
||||
out[3] = static_cast<Char>(delimiter);
|
||||
}
|
||||
static FMT_CONSTEXPR bool has_emphasis(emphasis em,
|
||||
emphasis mask) FMT_NOEXCEPT {
|
||||
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
|
||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||
detail::color_type foreground) FMT_NOEXCEPT {
|
||||
detail::color_type foreground) noexcept {
|
||||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||
detail::color_type background) FMT_NOEXCEPT {
|
||||
detail::color_type background) noexcept {
|
||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
|
||||
return ansi_color_escape<Char>(em);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
|
||||
std::fputs(chars, stream);
|
||||
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
|
||||
int result = std::fputs(chars, stream);
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
|
||||
std::fputws(chars, stream);
|
||||
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
|
||||
int result = std::fputws(chars, stream);
|
||||
if (result < 0)
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
||||
template <typename Char> inline void reset_color(FILE* stream) {
|
||||
fputs("\x1b[0m", stream);
|
||||
}
|
||||
|
||||
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
||||
template <> inline void reset_color<wchar_t>(FILE* stream) {
|
||||
fputs(L"\x1b[0m", stream);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
|
||||
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
buffer.append(reset_color.begin(), reset_color.end());
|
||||
}
|
||||
|
||||
template <typename T> struct styled_arg {
|
||||
const T& value;
|
||||
text_style style;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||
basic_string_view<Char> format_str,
|
||||
@@ -529,8 +528,12 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
basic_memory_buffer<Char> buf;
|
||||
detail::vformat_to(buf, ts, to_string_view(format), args);
|
||||
if (detail::is_utf8()) {
|
||||
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
|
||||
} else {
|
||||
buf.push_back(Char(0));
|
||||
detail::fputs(buf.data(), f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -549,7 +552,7 @@ template <typename S, typename... Args,
|
||||
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||
const Args&... args) {
|
||||
vprint(f, ts, format_str,
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,7 +597,7 @@ template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||
const Args&... args) {
|
||||
return fmt::vformat(ts, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -629,7 +632,60 @@ inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
||||
Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
return vformat_to(out, ts, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
const auto& ts = arg.style;
|
||||
const auto& value = arg.value;
|
||||
auto out = ctx.out();
|
||||
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||
out = std::copy(emphasis.begin(), emphasis.end(), out);
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
auto foreground =
|
||||
detail::make_foreground_color<Char>(ts.get_foreground());
|
||||
out = std::copy(foreground.begin(), foreground.end(), out);
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
has_style = true;
|
||||
auto background =
|
||||
detail::make_background_color<Char>(ts.get_background());
|
||||
out = std::copy(background.begin(), background.end(), out);
|
||||
}
|
||||
out = formatter<T, Char>::format(value, ctx);
|
||||
if (has_style) {
|
||||
auto reset_color = string_view("\x1b[0m");
|
||||
out = std::copy(reset_color.begin(), reset_color.end(), out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns an argument that will be formatted using ANSI escape sequences,
|
||||
to be used in a formatting function.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print("Elapsed time: {s:.2f} seconds",
|
||||
fmt::styled(1.23, fmt::fg(fmt::colors::green) | fmt::bg(fmt::color::blue)));
|
||||
\endrst
|
||||
*/
|
||||
template <typename T>
|
||||
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
|
||||
-> detail::styled_arg<remove_cvref_t<T>> {
|
||||
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
|
||||
}
|
||||
|
||||
FMT_MODULE_EXPORT_END
|
||||
|
||||
Vendored
+27
-63
@@ -13,45 +13,6 @@
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
// An output iterator that counts the number of objects written to it and
|
||||
// discards them.
|
||||
class counting_iterator {
|
||||
private:
|
||||
size_t count_;
|
||||
|
||||
public:
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
using _Unchecked_type = counting_iterator; // Mark iterator as checked.
|
||||
|
||||
struct value_type {
|
||||
template <typename T> void operator=(const T&) {}
|
||||
};
|
||||
|
||||
counting_iterator() : count_(0) {}
|
||||
|
||||
size_t count() const { return count_; }
|
||||
|
||||
counting_iterator& operator++() {
|
||||
++count_;
|
||||
return *this;
|
||||
}
|
||||
counting_iterator operator++(int) {
|
||||
auto it = *this;
|
||||
++*this;
|
||||
return it;
|
||||
}
|
||||
|
||||
friend counting_iterator operator+(counting_iterator it, difference_type n) {
|
||||
it.count_ += static_cast<size_t>(n);
|
||||
return it;
|
||||
}
|
||||
|
||||
value_type operator*() const { return {}; }
|
||||
};
|
||||
|
||||
template <typename Char, typename InputIt>
|
||||
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
||||
counting_iterator it) {
|
||||
@@ -156,7 +117,7 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||
\endrst
|
||||
*/
|
||||
#ifdef __cpp_if_constexpr
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
# define FMT_COMPILE(s) \
|
||||
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
|
||||
#else
|
||||
@@ -168,7 +129,7 @@ template <typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct udl_compiled_string : compiled_string {
|
||||
using char_type = Char;
|
||||
constexpr operator basic_string_view<char_type>() const {
|
||||
explicit constexpr operator basic_string_view<char_type>() const {
|
||||
return {Str.data, N - 1};
|
||||
}
|
||||
};
|
||||
@@ -179,7 +140,7 @@ const T& first(const T& value, const Tail&...) {
|
||||
return value;
|
||||
}
|
||||
|
||||
#ifdef __cpp_if_constexpr
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
template <typename... Args> struct type_list {};
|
||||
|
||||
// Returns a reference to the argument at index N from [first, rest...].
|
||||
@@ -190,7 +151,7 @@ constexpr const auto& get([[maybe_unused]] const T& first,
|
||||
if constexpr (N == 0)
|
||||
return first;
|
||||
else
|
||||
return get<N - 1>(rest...);
|
||||
return detail::get<N - 1>(rest...);
|
||||
}
|
||||
|
||||
template <typename Char, typename... Args>
|
||||
@@ -202,7 +163,8 @@ constexpr int get_arg_index_by_name(basic_string_view<Char> name,
|
||||
template <int N, typename> struct get_type_impl;
|
||||
|
||||
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||
using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
|
||||
using type =
|
||||
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
|
||||
};
|
||||
|
||||
template <int N, typename T>
|
||||
@@ -242,7 +204,7 @@ template <typename Char> struct code_unit {
|
||||
// This ensures that the argument type is convertible to `const T&`.
|
||||
template <typename T, int N, typename... Args>
|
||||
constexpr const T& get_arg_checked(const Args&... args) {
|
||||
const auto& arg = get<N>(args...);
|
||||
const auto& arg = detail::get<N>(args...);
|
||||
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
||||
return arg.value;
|
||||
} else {
|
||||
@@ -399,7 +361,9 @@ template <typename Char> struct arg_id_handler {
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr void on_error(const char* message) { FMT_THROW(format_error(message)); }
|
||||
constexpr void on_error(const char* message) {
|
||||
FMT_THROW(format_error(message));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char> struct parse_arg_id_result {
|
||||
@@ -527,12 +491,12 @@ constexpr auto compile(S format_str) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif // __cpp_if_constexpr
|
||||
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
} // namespace detail
|
||||
|
||||
FMT_MODULE_EXPORT_BEGIN
|
||||
|
||||
#ifdef __cpp_if_constexpr
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
|
||||
template <typename CompiledFormat, typename... Args,
|
||||
typename Char = typename CompiledFormat::char_type,
|
||||
@@ -570,10 +534,11 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
return fmt::format(
|
||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return format(compiled, std::forward<Args>(args)...);
|
||||
return fmt::format(compiled, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,11 +548,11 @@ FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return format_to(out,
|
||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
return fmt::format_to(
|
||||
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
return format_to(out, compiled, std::forward<Args>(args)...);
|
||||
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -596,22 +561,23 @@ template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||
const S& format_str, Args&&... args) {
|
||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
|
||||
std::forward<Args>(args)...);
|
||||
auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
|
||||
format_str, std::forward<Args>(args)...);
|
||||
return {it.base(), it.count()};
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
size_t formatted_size(const S& format_str, const Args&... args) {
|
||||
return format_to(detail::counting_iterator(), format_str, args...).count();
|
||||
return fmt::format_to(detail::counting_iterator(), format_str, args...)
|
||||
.count();
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
||||
memory_buffer buffer;
|
||||
format_to(std::back_inserter(buffer), format_str, args...);
|
||||
fmt::format_to(std::back_inserter(buffer), format_str, args...);
|
||||
detail::print(f, {buffer.data(), buffer.size()});
|
||||
}
|
||||
|
||||
@@ -623,12 +589,10 @@ void print(const S& format_str, const Args&... args) {
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
inline namespace literals {
|
||||
template <detail_exported::fixed_string Str>
|
||||
constexpr detail::udl_compiled_string<
|
||||
remove_cvref_t<decltype(Str.data[0])>,
|
||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
|
||||
operator""_cf() {
|
||||
return {};
|
||||
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
|
||||
using char_t = remove_cvref_t<decltype(Str.data[0])>;
|
||||
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
|
||||
Str>();
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
Vendored
+522
-306
File diff suppressed because it is too large
Load Diff
Vendored
+1083
-1031
File diff suppressed because it is too large
Load Diff
Vendored
+784
-407
File diff suppressed because it is too large
Load Diff
Vendored
+41
-77
@@ -9,10 +9,8 @@
|
||||
#define FMT_OS_H_
|
||||
|
||||
#include <cerrno>
|
||||
#include <clocale> // locale_t
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib> // strtod_l
|
||||
#include <system_error> // std::system_error
|
||||
|
||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||
@@ -21,17 +19,20 @@
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifndef FMT_USE_FCNTL
|
||||
// UWP doesn't provide _pipe.
|
||||
#if FMT_HAS_INCLUDE("winapifamily.h")
|
||||
# if FMT_HAS_INCLUDE("winapifamily.h")
|
||||
# include <winapifamily.h>
|
||||
#endif
|
||||
#if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||
# endif
|
||||
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||
(!defined(WINAPI_FAMILY) || \
|
||||
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||
# include <fcntl.h> // for O_RDONLY
|
||||
# define FMT_USE_FCNTL 1
|
||||
#else
|
||||
# else
|
||||
# define FMT_USE_FCNTL 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FMT_POSIX
|
||||
@@ -138,7 +139,7 @@ template <typename Char> struct formatter<std::error_code, Char> {
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
|
||||
FMT_API const std::error_category& system_category() noexcept;
|
||||
|
||||
FMT_BEGIN_DETAIL_NAMESPACE
|
||||
// A converter from UTF-16 to UTF-8.
|
||||
@@ -162,7 +163,7 @@ class utf16_to_utf8 {
|
||||
};
|
||||
|
||||
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||
const char* message) FMT_NOEXCEPT;
|
||||
const char* message) noexcept;
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
|
||||
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
||||
@@ -204,10 +205,9 @@ std::system_error windows_error(int error_code, string_view message,
|
||||
|
||||
// Reports a Windows error without throwing an exception.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_windows_error(int error_code,
|
||||
const char* message) FMT_NOEXCEPT;
|
||||
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
||||
#else
|
||||
inline const std::error_category& system_category() FMT_NOEXCEPT {
|
||||
inline const std::error_category& system_category() noexcept {
|
||||
return std::system_category();
|
||||
}
|
||||
#endif // _WIN32
|
||||
@@ -234,13 +234,13 @@ class buffered_file {
|
||||
void operator=(const buffered_file&) = delete;
|
||||
|
||||
// Constructs a buffered_file object which doesn't represent any file.
|
||||
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
||||
buffered_file() noexcept : file_(nullptr) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||
FMT_API ~buffered_file() noexcept;
|
||||
|
||||
public:
|
||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
||||
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
||||
other.file_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -258,10 +258,11 @@ class buffered_file {
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the pointer to a FILE object representing this file.
|
||||
FILE* get() const FMT_NOEXCEPT { return file_; }
|
||||
FILE* get() const noexcept { return file_; }
|
||||
|
||||
// We place parentheses around fileno to workaround a bug in some versions
|
||||
// of MinGW that define fileno as a macro.
|
||||
// DEPRECATED! Rename to descriptor to avoid issues with macros.
|
||||
FMT_API int(fileno)() const;
|
||||
|
||||
void vprint(string_view format_str, format_args args) {
|
||||
@@ -276,12 +277,12 @@ class buffered_file {
|
||||
|
||||
#if FMT_USE_FCNTL
|
||||
// A file. Closed file is represented by a file object with descriptor -1.
|
||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
||||
// Methods that are not declared with noexcept may throw
|
||||
// fmt::system_error in case of failure. Note that some errors such as
|
||||
// closing the file multiple times will cause a crash on Windows rather
|
||||
// than an exception. You can get standard behavior by overriding the
|
||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||
class file {
|
||||
class FMT_API file {
|
||||
private:
|
||||
int fd_; // File descriptor.
|
||||
|
||||
@@ -300,16 +301,16 @@ class file {
|
||||
};
|
||||
|
||||
// Constructs a file object which doesn't represent any file.
|
||||
file() FMT_NOEXCEPT : fd_(-1) {}
|
||||
file() noexcept : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a file object representing this file.
|
||||
FMT_API file(cstring_view path, int oflag);
|
||||
file(cstring_view path, int oflag);
|
||||
|
||||
public:
|
||||
file(const file&) = delete;
|
||||
void operator=(const file&) = delete;
|
||||
|
||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
||||
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
|
||||
|
||||
// Move assignment is not noexcept because close may throw.
|
||||
file& operator=(file&& other) {
|
||||
@@ -320,43 +321,43 @@ class file {
|
||||
}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~file() FMT_NOEXCEPT;
|
||||
~file() noexcept;
|
||||
|
||||
// Returns the file descriptor.
|
||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||
int descriptor() const noexcept { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
FMT_API void close();
|
||||
void close();
|
||||
|
||||
// Returns the file size. The size has signed type for consistency with
|
||||
// stat::st_size.
|
||||
FMT_API long long size() const;
|
||||
long long size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
FMT_API size_t read(void* buffer, size_t count);
|
||||
size_t read(void* buffer, size_t count);
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
FMT_API size_t write(const void* buffer, size_t count);
|
||||
size_t write(const void* buffer, size_t count);
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
FMT_API static file dup(int fd);
|
||||
static file dup(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
FMT_API void dup2(int fd);
|
||||
void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT;
|
||||
void dup2(int fd, std::error_code& ec) noexcept;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
FMT_API static void pipe(file& read_end, file& write_end);
|
||||
static void pipe(file& read_end, file& write_end);
|
||||
|
||||
// Creates a buffered_file object associated with this file and detaches
|
||||
// this file object from the file.
|
||||
FMT_API buffered_file fdopen(const char* mode);
|
||||
buffered_file fdopen(const char* mode);
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
@@ -390,6 +391,13 @@ struct ostream_params {
|
||||
: ostream_params(params...) {
|
||||
this->buffer_size = bs.value;
|
||||
}
|
||||
|
||||
// Intel has a bug that results in failure to deduce a constructor
|
||||
// for empty parameter packs.
|
||||
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
|
||||
ostream_params(int new_oflag) : oflag(new_oflag) {}
|
||||
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
|
||||
# endif
|
||||
};
|
||||
|
||||
FMT_END_DETAIL_NAMESPACE
|
||||
@@ -452,7 +460,7 @@ class FMT_API ostream final : private detail::buffer<char> {
|
||||
|
||||
* ``<integer>``: Flags passed to `open
|
||||
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
||||
(``file::WRONLY | file::CREATE`` by default)
|
||||
(``file::WRONLY | file::CREATE | file::TRUNC`` by default)
|
||||
* ``buffer_size=<integer>``: Output buffer size
|
||||
|
||||
**Example**::
|
||||
@@ -467,50 +475,6 @@ inline ostream output_file(cstring_view path, T... params) {
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
#ifdef FMT_LOCALE
|
||||
// A "C" numeric locale.
|
||||
class locale {
|
||||
private:
|
||||
# ifdef _WIN32
|
||||
using locale_t = _locale_t;
|
||||
|
||||
static void freelocale(locale_t loc) { _free_locale(loc); }
|
||||
|
||||
static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
|
||||
return _strtod_l(nptr, endptr, loc);
|
||||
}
|
||||
# endif
|
||||
|
||||
locale_t locale_;
|
||||
|
||||
public:
|
||||
using type = locale_t;
|
||||
locale(const locale&) = delete;
|
||||
void operator=(const locale&) = delete;
|
||||
|
||||
locale() {
|
||||
# ifndef _WIN32
|
||||
locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
|
||||
# else
|
||||
locale_ = _create_locale(LC_NUMERIC, "C");
|
||||
# endif
|
||||
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
|
||||
}
|
||||
~locale() { freelocale(locale_); }
|
||||
|
||||
type get() const { return locale_; }
|
||||
|
||||
// Converts string to floating-point number and advances str past the end
|
||||
// of the parsed input.
|
||||
double strtod(const char*& str) const {
|
||||
char* end = nullptr;
|
||||
double result = strtod_l(str, &end, locale_);
|
||||
str = end;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
using Locale FMT_DEPRECATED_ALIAS = locale;
|
||||
#endif // FMT_LOCALE
|
||||
FMT_MODULE_EXPORT_END
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
|
||||
Vendored
+48
-86
@@ -14,73 +14,20 @@
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
template <typename Char> class basic_printf_parse_context;
|
||||
template <typename OutputIt, typename Char> class basic_printf_context;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
||||
private:
|
||||
using int_type = typename std::basic_streambuf<Char>::int_type;
|
||||
using traits_type = typename std::basic_streambuf<Char>::traits_type;
|
||||
|
||||
buffer<Char>& buffer_;
|
||||
|
||||
public:
|
||||
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
|
||||
|
||||
protected:
|
||||
// The put-area is actually always empty. This makes the implementation
|
||||
// simpler and has the advantage that the streambuf and the buffer are always
|
||||
// in sync and sputc never writes into uninitialized memory. The obvious
|
||||
// disadvantage is that each call to sputc always results in a (virtual) call
|
||||
// to overflow. There is no disadvantage here for sputn since this always
|
||||
// results in a call to xsputn.
|
||||
|
||||
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
|
||||
if (!traits_type::eq_int_type(ch, traits_type::eof()))
|
||||
buffer_.push_back(static_cast<Char>(ch));
|
||||
return ch;
|
||||
}
|
||||
|
||||
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
|
||||
buffer_.append(s, s + count);
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
struct converter {
|
||||
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
|
||||
};
|
||||
|
||||
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
||||
private:
|
||||
void_t<> operator<<(converter);
|
||||
};
|
||||
|
||||
// Hide insertion operators for built-in types.
|
||||
template <typename Char, typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<Char, Traits>&, Char);
|
||||
template <typename Char, typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<Char, Traits>&, char);
|
||||
template <typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<char, Traits>&, char);
|
||||
template <typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<char, Traits>&, signed char);
|
||||
template <typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<char, Traits>&, unsigned char);
|
||||
|
||||
// Checks if T has a user-defined operator<< (e.g. not a member of
|
||||
// std::ostream).
|
||||
template <typename T, typename Char> class is_streamable {
|
||||
// Checks if T has a user-defined operator<<.
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
class is_streamable {
|
||||
private:
|
||||
template <typename U>
|
||||
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
|
||||
<< std::declval<U>()),
|
||||
void_t<>>::value>
|
||||
test(int);
|
||||
static auto test(int)
|
||||
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
|
||||
<< std::declval<U>()) != 0>;
|
||||
|
||||
template <typename> static std::false_type test(...);
|
||||
template <typename> static auto test(...) -> std::false_type;
|
||||
|
||||
using result = decltype(test<T>(0));
|
||||
|
||||
@@ -90,7 +37,21 @@ template <typename T, typename Char> class is_streamable {
|
||||
static const bool value = result::value;
|
||||
};
|
||||
|
||||
// Formatting of built-in types and arrays is intentionally disabled because
|
||||
// it's handled by standard (non-ostream) formatters.
|
||||
template <typename T, typename Char>
|
||||
struct is_streamable<
|
||||
T, Char,
|
||||
enable_if_t<
|
||||
std::is_arithmetic<T>::value || std::is_array<T>::value ||
|
||||
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
|
||||
std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
|
||||
std::is_same<T, std_string_view<Char>>::value ||
|
||||
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
|
||||
: std::false_type {};
|
||||
|
||||
// Write the content of buf to os.
|
||||
// It is a separate function rather than a part of vprint to simplify testing.
|
||||
template <typename Char>
|
||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||
const Char* buf_data = buf.data();
|
||||
@@ -108,8 +69,8 @@ void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||
template <typename Char, typename T>
|
||||
void format_value(buffer<Char>& buf, const T& value,
|
||||
locale_ref loc = locale_ref()) {
|
||||
formatbuf<Char> format_buf(buf);
|
||||
std::basic_ostream<Char> output(&format_buf);
|
||||
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
|
||||
auto&& output = std::basic_ostream<Char>(&format_buf);
|
||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
if (loc) output.imbue(loc.get<std::locale>());
|
||||
#endif
|
||||
@@ -117,34 +78,35 @@ void format_value(buffer<Char>& buf, const T& value,
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
buf.try_resize(buf.size());
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename Char>
|
||||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||
template <typename T, typename OutputIt>
|
||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
|
||||
-> OutputIt {
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
format_value(buffer, value, ctx.locale());
|
||||
return formatter<basic_string_view<Char>, Char>::format(
|
||||
{buffer.data(), buffer.size()}, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
using ostream_formatter = basic_ostream_formatter<char>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename T, typename Char>
|
||||
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
||||
: private formatter<basic_string_view<Char>, Char> {
|
||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||
-> decltype(ctx.begin()) {
|
||||
return formatter<basic_string_view<Char>, Char>::parse(ctx);
|
||||
}
|
||||
template <typename ParseCtx,
|
||||
FMT_ENABLE_IF(std::is_same<
|
||||
ParseCtx, basic_printf_parse_context<Char>>::value)>
|
||||
auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
: basic_ostream_formatter<Char> {
|
||||
using basic_ostream_formatter<Char>::format;
|
||||
// DEPRECATED!
|
||||
template <typename OutputIt>
|
||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
|
||||
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx) const
|
||||
-> OutputIt {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
format_value(buffer, value, ctx.locale());
|
||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
||||
}
|
||||
template <typename OutputIt>
|
||||
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
|
||||
-> OutputIt {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
format_value(buffer, value, ctx.locale());
|
||||
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
||||
}
|
||||
@@ -155,7 +117,7 @@ FMT_MODULE_EXPORT
|
||||
template <typename Char>
|
||||
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
auto buffer = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buffer, format_str, args);
|
||||
detail::write_buffer(os, buffer);
|
||||
}
|
||||
@@ -174,7 +136,7 @@ template <typename S, typename... Args,
|
||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||
vprint(os, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||
}
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
|
||||
Vendored
+12
-7
@@ -233,7 +233,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
|
||||
OutputIt write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs;
|
||||
s.type = 0;
|
||||
s.type = presentation_type::none;
|
||||
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
||||
}
|
||||
|
||||
@@ -249,8 +249,10 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
// std::is_same instead.
|
||||
if (std::is_same<T, Char>::value) {
|
||||
format_specs fmt_specs = this->specs;
|
||||
if (fmt_specs.type && fmt_specs.type != 'c')
|
||||
if (fmt_specs.type != presentation_type::none &&
|
||||
fmt_specs.type != presentation_type::chr) {
|
||||
return (*this)(static_cast<int>(value));
|
||||
}
|
||||
fmt_specs.sign = sign::none;
|
||||
fmt_specs.alt = false;
|
||||
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
||||
@@ -271,13 +273,13 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
/** Formats a null-terminated C string. */
|
||||
OutputIt operator()(const char* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs.type != 'p');
|
||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated wide C string. */
|
||||
OutputIt operator()(const wchar_t* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs.type != 'p');
|
||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
}
|
||||
|
||||
OutputIt operator()(basic_string_view<Char> value) {
|
||||
@@ -490,13 +492,13 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
|
||||
// Parse type.
|
||||
if (it == end) FMT_THROW(format_error("invalid format string"));
|
||||
specs.type = static_cast<char>(*it++);
|
||||
char type = static_cast<char>(*it++);
|
||||
if (arg.is_integral()) {
|
||||
// Normalize type.
|
||||
switch (specs.type) {
|
||||
switch (type) {
|
||||
case 'i':
|
||||
case 'u':
|
||||
specs.type = 'd';
|
||||
type = 'd';
|
||||
break;
|
||||
case 'c':
|
||||
visit_format_arg(
|
||||
@@ -505,6 +507,9 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
break;
|
||||
}
|
||||
}
|
||||
specs.type = parse_presentation_type(type);
|
||||
if (specs.type == presentation_type::none)
|
||||
parse_ctx.on_error("invalid type specifier");
|
||||
|
||||
start = it;
|
||||
|
||||
|
||||
Vendored
+233
-354
@@ -13,37 +13,13 @@
|
||||
#define FMT_RANGES_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
template <typename Char, typename Enable = void> struct formatting_range {
|
||||
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
||||
Char prefix = '{';
|
||||
Char postfix = '}';
|
||||
#else
|
||||
Char prefix = '[';
|
||||
Char postfix = ']';
|
||||
#endif
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Enable = void> struct formatting_tuple {
|
||||
Char prefix = '(';
|
||||
Char postfix = ')';
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename RangeT, typename OutputIterator>
|
||||
@@ -71,7 +47,7 @@ OutputIterator copy(wchar_t ch, OutputIterator out) {
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Return true value if T has std::string interface, like std::string_view.
|
||||
// Returns true if T has a std::string-like interface, like std::string_view.
|
||||
template <typename T> class is_std_string_like {
|
||||
template <typename U>
|
||||
static auto check(U* p)
|
||||
@@ -80,12 +56,40 @@ template <typename T> class is_std_string_like {
|
||||
|
||||
public:
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
is_string<T>::value ||
|
||||
std::is_convertible<T, std_string_view<char>>::value ||
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
||||
|
||||
template <typename T> class is_map {
|
||||
template <typename U> static auto check(U*) -> typename U::mapped_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
#ifdef FMT_FORMAT_MAP_AS_LIST
|
||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
||||
#else
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T> class is_set {
|
||||
template <typename U> static auto check(U*) -> typename U::key_type;
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
#ifdef FMT_FORMAT_SET_AS_LIST
|
||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
||||
#else
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename... Ts> struct conditional_helper {};
|
||||
|
||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||
@@ -163,7 +167,7 @@ struct is_range_<T, void>
|
||||
# undef FMT_DECLTYPE_RETURN
|
||||
#endif
|
||||
|
||||
/// tuple_size and tuple_element check.
|
||||
// tuple_size and tuple_element check.
|
||||
template <typename T> class is_tuple_like_ {
|
||||
template <typename U>
|
||||
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
|
||||
@@ -199,7 +203,7 @@ using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||
#endif
|
||||
|
||||
template <class Tuple, class F, size_t... Is>
|
||||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
|
||||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
|
||||
using std::get;
|
||||
// using free function get<I>(T) now.
|
||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
||||
@@ -217,9 +221,28 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||
}
|
||||
|
||||
#if FMT_MSC_VER
|
||||
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||
template <typename R> struct range_reference_type_impl {
|
||||
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
|
||||
using type = T&;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using range_reference_type = typename range_reference_type_impl<T>::type;
|
||||
#else
|
||||
template <typename Range>
|
||||
using value_type =
|
||||
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
|
||||
using range_reference_type =
|
||||
decltype(*detail::range_begin(std::declval<Range&>()));
|
||||
#endif
|
||||
|
||||
// We don't use the Range's value_type for anything, but we do need the Range's
|
||||
// reference type, with cv-ref stripped.
|
||||
template <typename Range>
|
||||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||
|
||||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||
*out++ = ',';
|
||||
@@ -227,283 +250,22 @@ template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||
return out;
|
||||
}
|
||||
|
||||
struct singleton {
|
||||
unsigned char upper;
|
||||
unsigned char lowercount;
|
||||
};
|
||||
|
||||
inline auto check(uint16_t x, const singleton* singletonuppers,
|
||||
size_t singletonuppers_size,
|
||||
const unsigned char* singletonlowers,
|
||||
const unsigned char* normal, size_t normal_size) -> bool {
|
||||
auto xupper = x >> 8;
|
||||
auto lowerstart = 0;
|
||||
for (size_t i = 0; i < singletonuppers_size; ++i) {
|
||||
auto su = singletonuppers[i];
|
||||
auto lowerend = lowerstart + su.lowercount;
|
||||
if (xupper < su.upper) break;
|
||||
if (xupper == su.upper) {
|
||||
for (auto j = lowerstart; j < lowerend; ++j) {
|
||||
if (singletonlowers[j] == x) return false;
|
||||
}
|
||||
}
|
||||
lowerstart = lowerend;
|
||||
}
|
||||
|
||||
auto xsigned = static_cast<int>(x);
|
||||
auto current = true;
|
||||
for (size_t i = 0; i < normal_size; ++i) {
|
||||
auto v = static_cast<int>(normal[i]);
|
||||
auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[i++] : v;
|
||||
xsigned -= len;
|
||||
if (xsigned < 0) break;
|
||||
current = !current;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
// Returns true iff the code point cp is printable.
|
||||
// This code is generated by support/printable.py.
|
||||
inline auto is_printable(uint32_t cp) -> bool {
|
||||
static constexpr singleton singletons0u[] = {
|
||||
{0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
|
||||
{0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
|
||||
{0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
|
||||
{0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
|
||||
{0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
|
||||
{0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
|
||||
{0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
|
||||
};
|
||||
static constexpr unsigned char singletons0l[] = {
|
||||
0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
|
||||
0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
|
||||
0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
|
||||
0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
|
||||
0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
|
||||
0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
|
||||
0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
||||
0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
|
||||
0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
|
||||
0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
|
||||
0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
|
||||
0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
|
||||
0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
|
||||
0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
|
||||
0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
|
||||
0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
|
||||
0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
|
||||
0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
|
||||
0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
|
||||
0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
|
||||
0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
|
||||
0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
|
||||
0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
|
||||
0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
|
||||
0xfe, 0xff,
|
||||
};
|
||||
static constexpr singleton singletons1u[] = {
|
||||
{0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
|
||||
{0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
|
||||
{0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
|
||||
{0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
|
||||
{0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
|
||||
{0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
|
||||
{0xfa, 2}, {0xfb, 1},
|
||||
};
|
||||
static constexpr unsigned char singletons1l[] = {
|
||||
0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
|
||||
0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
|
||||
0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
|
||||
0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
||||
0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
|
||||
0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
|
||||
0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
|
||||
0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
|
||||
0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
|
||||
0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
|
||||
0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
|
||||
0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
|
||||
0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
|
||||
0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
|
||||
0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
|
||||
};
|
||||
static constexpr unsigned char normal0[] = {
|
||||
0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
|
||||
0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
|
||||
0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
|
||||
0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
|
||||
0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
|
||||
0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
|
||||
0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
|
||||
0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
|
||||
0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
|
||||
0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
|
||||
0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
|
||||
0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
|
||||
0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
|
||||
0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
|
||||
0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
|
||||
0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
|
||||
0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
|
||||
0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
|
||||
0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
|
||||
0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
|
||||
0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
|
||||
0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
|
||||
0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
|
||||
0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
|
||||
0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
|
||||
0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
|
||||
};
|
||||
static constexpr unsigned char normal1[] = {
|
||||
0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
|
||||
0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
|
||||
0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
|
||||
0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
|
||||
0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
|
||||
0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
|
||||
0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
|
||||
0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
|
||||
0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
|
||||
0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
|
||||
0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
|
||||
0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
|
||||
0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
|
||||
0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
|
||||
0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
|
||||
0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
|
||||
0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
|
||||
0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
|
||||
0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
|
||||
0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
|
||||
0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
|
||||
0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
|
||||
0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
|
||||
0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
|
||||
0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
|
||||
0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
|
||||
0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
|
||||
0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
|
||||
0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
|
||||
0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
|
||||
0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
|
||||
0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
|
||||
0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
|
||||
0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
|
||||
0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
|
||||
};
|
||||
auto lower = static_cast<uint16_t>(cp);
|
||||
if (cp < 0x10000) {
|
||||
return check(lower, singletons0u,
|
||||
sizeof(singletons0u) / sizeof(*singletons0u), singletons0l,
|
||||
normal0, sizeof(normal0));
|
||||
}
|
||||
if (cp < 0x20000) {
|
||||
return check(lower, singletons1u,
|
||||
sizeof(singletons1u) / sizeof(*singletons1u), singletons1l,
|
||||
normal1, sizeof(normal1));
|
||||
}
|
||||
if (0x2a6de <= cp && cp < 0x2a700) return false;
|
||||
if (0x2b735 <= cp && cp < 0x2b740) return false;
|
||||
if (0x2b81e <= cp && cp < 0x2b820) return false;
|
||||
if (0x2cea2 <= cp && cp < 0x2ceb0) return false;
|
||||
if (0x2ebe1 <= cp && cp < 0x2f800) return false;
|
||||
if (0x2fa1e <= cp && cp < 0x30000) return false;
|
||||
if (0x3134b <= cp && cp < 0xe0100) return false;
|
||||
if (0xe01f0 <= cp && cp < 0x110000) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline auto needs_escape(uint32_t cp) -> bool {
|
||||
return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
|
||||
!is_printable(cp);
|
||||
}
|
||||
|
||||
template <typename Char> struct find_escape_result {
|
||||
const Char* begin;
|
||||
const Char* end;
|
||||
uint32_t cp;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
auto find_escape(const Char* begin, const Char* end)
|
||||
-> find_escape_result<Char> {
|
||||
for (; begin != end; ++begin) {
|
||||
auto cp = static_cast<typename std::make_unsigned<Char>::type>(*begin);
|
||||
if (needs_escape(cp)) return {begin, begin + 1, cp};
|
||||
}
|
||||
return {begin, nullptr, 0};
|
||||
}
|
||||
|
||||
auto find_escape(const char* begin, const char* end)
|
||||
-> find_escape_result<char> {
|
||||
if (!is_utf8()) return find_escape<char>(begin, end);
|
||||
auto result = find_escape_result<char>{end, nullptr, 0};
|
||||
for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
|
||||
[&](uint32_t cp, string_view sv) {
|
||||
if (needs_escape(cp)) {
|
||||
result = {sv.begin(), sv.end(), cp};
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
||||
*out++ = '"';
|
||||
auto begin = str.begin(), end = str.end();
|
||||
do {
|
||||
auto escape = find_escape(begin, end);
|
||||
out = copy_str<Char>(begin, escape.begin, out);
|
||||
begin = escape.end;
|
||||
if (!begin) break;
|
||||
auto c = static_cast<Char>(escape.cp);
|
||||
switch (escape.cp) {
|
||||
case '\n':
|
||||
*out++ = '\\';
|
||||
c = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*out++ = '\\';
|
||||
c = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*out++ = '\\';
|
||||
c = 't';
|
||||
break;
|
||||
case '"':
|
||||
FMT_FALLTHROUGH;
|
||||
case '\\':
|
||||
*out++ = '\\';
|
||||
break;
|
||||
default:
|
||||
if (is_utf8() && escape.cp > 0xffff) {
|
||||
out = format_to(out, "\\U{:08x}", escape.cp);
|
||||
continue;
|
||||
}
|
||||
for (Char escape_char : basic_string_view<Char>(
|
||||
escape.begin, to_unsigned(escape.end - escape.begin))) {
|
||||
out = format_to(
|
||||
out, "\\x{:02x}",
|
||||
static_cast<typename std::make_unsigned<Char>::type>(escape_char));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*out++ = c;
|
||||
} while (begin != end);
|
||||
*out++ = '"';
|
||||
return out;
|
||||
return write_escaped_string(out, str);
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
|
||||
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
|
||||
auto sv = std_string_view<Char>(str);
|
||||
return write_range_entry<Char>(out, basic_string_view<Char>(sv));
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt, typename Arg,
|
||||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||
*out++ = '\'';
|
||||
*out++ = v;
|
||||
*out++ = '\'';
|
||||
return out;
|
||||
return write_escaped_char(out, v);
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -524,63 +286,153 @@ template <typename T> struct is_tuple_like {
|
||||
template <typename TupleT, typename Char>
|
||||
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
||||
private:
|
||||
// C++11 generic lambda for format()
|
||||
// C++11 generic lambda for format().
|
||||
template <typename FormatContext> struct format_each {
|
||||
template <typename T> void operator()(const T& v) {
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
out = detail::write_range_entry<Char>(out, v);
|
||||
++i;
|
||||
}
|
||||
formatting_tuple<Char>& formatting;
|
||||
size_t& i;
|
||||
typename std::add_lvalue_reference<
|
||||
decltype(std::declval<FormatContext>().out())>::type out;
|
||||
int i;
|
||||
typename FormatContext::iterator& out;
|
||||
};
|
||||
|
||||
public:
|
||||
formatting_tuple<Char> formatting;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return formatting.parse(ctx);
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext = format_context>
|
||||
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
auto format(const TupleT& values, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
size_t i = 0;
|
||||
|
||||
detail::copy(formatting.prefix, out);
|
||||
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
||||
detail::copy(formatting.postfix, out);
|
||||
|
||||
return ctx.out();
|
||||
*out++ = '(';
|
||||
detail::for_each(values, format_each<FormatContext>{0, out});
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||
!detail::is_map<T>::value &&
|
||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename Context> struct range_mapper {
|
||||
using mapper = arg_mapper<Context>;
|
||||
|
||||
template <typename T,
|
||||
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||
static auto map(T&& value) -> T&& {
|
||||
return static_cast<T&&>(value);
|
||||
}
|
||||
template <typename T,
|
||||
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||
static auto map(T&& value)
|
||||
-> decltype(mapper().map(static_cast<T&&>(value))) {
|
||||
return mapper().map(static_cast<T&&>(value));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Element>
|
||||
using range_formatter_type = conditional_t<
|
||||
is_formattable<Element, Char>::value,
|
||||
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
|
||||
std::declval<Element>()))>,
|
||||
Char>,
|
||||
fallback_formatter<Element, Char>>;
|
||||
|
||||
template <typename R>
|
||||
using maybe_const_range =
|
||||
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||
} // namespace detail
|
||||
|
||||
template <typename R, typename Char>
|
||||
struct formatter<
|
||||
R, Char,
|
||||
enable_if_t<
|
||||
fmt::is_range<R, Char>::value
|
||||
// Workaround a bug in MSVC 2019 and earlier.
|
||||
#if !FMT_MSC_VER
|
||||
&&
|
||||
(is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
|
||||
Char>::value ||
|
||||
detail::has_fallback_formatter<
|
||||
detail::uncvref_type<detail::maybe_const_range<R>>, Char>::value)
|
||||
#endif
|
||||
>> {
|
||||
|
||||
using range_type = detail::maybe_const_range<R>;
|
||||
using formatter_type =
|
||||
detail::range_formatter_type<Char, detail::uncvref_type<range_type>>;
|
||||
formatter_type underlying_;
|
||||
bool custom_specs_ = false;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it == end || *it == '}') return it;
|
||||
|
||||
if (*it != ':')
|
||||
FMT_THROW(format_error("no top-level range formatters supported"));
|
||||
|
||||
custom_specs_ = true;
|
||||
++it;
|
||||
ctx.advance_to(it);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(range_type& range, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
||||
Char prefix = '{';
|
||||
Char postfix = '}';
|
||||
#else
|
||||
Char prefix = detail::is_set<R>::value ? '{' : '[';
|
||||
Char postfix = detail::is_set<R>::value ? '}' : ']';
|
||||
#endif
|
||||
detail::range_mapper<buffer_context<Char>> mapper;
|
||||
auto out = ctx.out();
|
||||
*out++ = prefix;
|
||||
int i = 0;
|
||||
auto it = detail::range_begin(range);
|
||||
auto end = detail::range_end(range);
|
||||
for (; it != end; ++it) {
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
if (custom_specs_) {
|
||||
ctx.advance_to(out);
|
||||
out = underlying_.format(mapper.map(*it), ctx);
|
||||
} else {
|
||||
out = detail::write_range_entry<Char>(out, *it);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
*out++ = postfix;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char,
|
||||
enable_if_t<
|
||||
fmt::is_range<T, Char>::value
|
||||
// Workaround a bug in MSVC 2017 and earlier.
|
||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
|
||||
&& (has_formatter<detail::value_type<T>, format_context>::value ||
|
||||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
||||
enable_if_t<detail::is_map<T>::value
|
||||
// Workaround a bug in MSVC 2019 and earlier.
|
||||
#if !FMT_MSC_VER
|
||||
&& (is_formattable<detail::uncvref_type<T>, Char>::value ||
|
||||
detail::has_fallback_formatter<detail::uncvref_type<T>,
|
||||
Char>::value)
|
||||
#endif
|
||||
>> {
|
||||
formatting_range<Char> formatting;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return formatting.parse(ctx);
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -588,17 +440,20 @@ struct formatter<
|
||||
FMT_ENABLE_IF(
|
||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
||||
const T, T>>::value)>
|
||||
auto format(U& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
auto out = detail::copy(formatting.prefix, ctx.out());
|
||||
size_t i = 0;
|
||||
auto it = std::begin(values);
|
||||
auto end = std::end(values);
|
||||
for (; it != end; ++it) {
|
||||
auto format(U& map, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
*out++ = '{';
|
||||
int i = 0;
|
||||
for (const auto& item : map) {
|
||||
if (i > 0) out = detail::write_delimiter(out);
|
||||
out = detail::write_range_entry<Char>(out, *it);
|
||||
out = detail::write_range_entry<Char>(out, item.first);
|
||||
*out++ = ':';
|
||||
*out++ = ' ';
|
||||
out = detail::write_range_entry<Char>(out, item.second);
|
||||
++i;
|
||||
}
|
||||
return detail::copy(formatting.postfix, out);
|
||||
*out++ = '}';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -613,46 +468,70 @@ template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
||||
template <typename Char, typename... T>
|
||||
using tuple_arg_join = tuple_join_view<Char, T...>;
|
||||
|
||||
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
||||
// support in tuple_join. It is disabled by default because of issues with
|
||||
// the dynamic width and precision.
|
||||
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
|
||||
# define FMT_TUPLE_JOIN_SPECIFIERS 0
|
||||
#endif
|
||||
|
||||
template <typename Char, typename... T>
|
||||
struct formatter<tuple_join_view<Char, T...>, Char> {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx) ->
|
||||
typename FormatContext::iterator {
|
||||
return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
|
||||
auto format(const tuple_join_view<Char, T...>& value,
|
||||
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||
return do_format(value, ctx,
|
||||
std::integral_constant<size_t, sizeof...(T)>());
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename FormatContext, size_t... N>
|
||||
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||
detail::index_sequence<N...>) ->
|
||||
typename FormatContext::iterator {
|
||||
using std::get;
|
||||
return format_args(value, ctx, get<N>(value.tuple)...);
|
||||
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||
std::integral_constant<size_t, 0>)
|
||||
-> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename ParseContext, size_t N>
|
||||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||
std::integral_constant<size_t, N>)
|
||||
-> decltype(ctx.begin()) {
|
||||
auto end = ctx.begin();
|
||||
#if FMT_TUPLE_JOIN_SPECIFIERS
|
||||
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
|
||||
if (N > 1) {
|
||||
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
||||
if (end != end1)
|
||||
FMT_THROW(format_error("incompatible format specs for tuple elements"));
|
||||
}
|
||||
#endif
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format_args(const tuple_join_view<Char, T...>&, FormatContext& ctx) ->
|
||||
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
|
||||
std::integral_constant<size_t, 0>) const ->
|
||||
typename FormatContext::iterator {
|
||||
// NOTE: for compilers that support C++17, this empty function instantiation
|
||||
// can be replaced with a constexpr branch in the variadic overload.
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
template <typename FormatContext, typename Arg, typename... Args>
|
||||
auto format_args(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||
const Arg& arg, const Args&... args) ->
|
||||
template <typename FormatContext, size_t N>
|
||||
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
typename FormatContext::iterator {
|
||||
using base = formatter<typename std::decay<Arg>::type, Char>;
|
||||
auto out = base().format(arg, ctx);
|
||||
if (sizeof...(Args) > 0) {
|
||||
auto out = std::get<sizeof...(T) - N>(formatters_)
|
||||
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
|
||||
if (N > 1) {
|
||||
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
||||
ctx.advance_to(out);
|
||||
return format_args(value, ctx, args...);
|
||||
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user