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
|
# This plug-in only works on 64-bit
|
||||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
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()
|
endif()
|
||||||
|
|
||||||
# Tell CMake where to find our scripts
|
# 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)
|
#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
|
# This option should only be available in certain conditions
|
||||||
if(WIN32 AND MINGW)
|
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()
|
endif()
|
||||||
|
|
||||||
# C++14 is mandatory
|
# C++14 is mandatory
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
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);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &AABB::ToString)
|
.Func(_SC("_tostring"), &AABB::ToString)
|
||||||
|
.Func(_SC("_tojson"), &AABB::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< AABB >, SQFloat, SQInteger, bool, std::nullptr_t, AABB >)
|
||||||
|
|||||||
@@ -304,6 +304,11 @@ struct AABB
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set the values extracted from the specified string using the specified delimiter.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -360,6 +361,19 @@ String Circle::ToString() const
|
|||||||
return fmt::format("{},{},{}", pos.x, pos.y, rad);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Circle::ToString)
|
.Func(_SC("_tostring"), &Circle::ToString)
|
||||||
|
.Func(_SC("_toJSON"), &Circle::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Circle >, SQFloat, SQInteger, bool, std::nullptr_t, Circle >)
|
||||||
|
|||||||
@@ -341,6 +341,11 @@ struct Circle
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set the specified radius.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -481,6 +482,19 @@ String Color3::ToString() const
|
|||||||
return fmt::format("{},{},{}", r, g, b);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Color3::ToString)
|
.Func(_SC("_tostring"), &Color3::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Color3::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Color3 >, SQFloat, SQInteger, bool, std::nullptr_t, Color3 >)
|
||||||
|
|||||||
@@ -405,6 +405,11 @@ struct Color3
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set all components to the specified scalar value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -506,6 +507,19 @@ String Color4::ToString() const
|
|||||||
return fmt::format("{},{},{},{}", r, g, b, a);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Color4::ToString)
|
.Func(_SC("_tostring"), &Color4::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Color4::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Color4 >, SQFloat, SQInteger, bool, std::nullptr_t, Color4 >)
|
||||||
|
|||||||
@@ -405,6 +405,11 @@ struct Color4
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set all components to the specified scalar value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -349,6 +350,19 @@ String Quaternion::ToString() const
|
|||||||
return fmt::format("{},{},{},{}", x, y, z, w);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Quaternion::ToString)
|
.Func(_SC("_tostring"), &Quaternion::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Quaternion::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Quaternion >, SQFloat, SQInteger, bool, std::nullptr_t, Quaternion >)
|
||||||
|
|||||||
@@ -296,6 +296,11 @@ struct Quaternion
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set all components to the specified scalar value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
struct CtxJSON;
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Helper constants used by the bas types.
|
* Helper constants used by the bas types.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -360,6 +361,19 @@ String Sphere::ToString() const
|
|||||||
return fmt::format("{},{},{},{}", pos.x, pos.y, pos.z, rad);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Sphere::ToString)
|
.Func(_SC("_tostring"), &Sphere::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Sphere::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Sphere >, SQFloat, SQInteger, bool, std::nullptr_t, Sphere >)
|
||||||
|
|||||||
@@ -341,6 +341,11 @@ struct Sphere
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set the specified radius.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -295,6 +296,19 @@ String Vector2::ToString() const
|
|||||||
return fmt::format("{},{}", x, y);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Vector2::ToString)
|
.Func(_SC("_tostring"), &Vector2::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Vector2::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector2 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2 >)
|
||||||
|
|||||||
@@ -285,6 +285,11 @@ struct Vector2
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set all components to the specified scalar value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -441,6 +442,19 @@ String Vector2i::ToString() const
|
|||||||
return fmt::format("{},{}", x, y);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Vector2i::ToString)
|
.Func(_SC("_tostring"), &Vector2i::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Vector2i::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector2i >, SQFloat, SQInteger, bool, std::nullptr_t, Vector2i >)
|
||||||
|
|||||||
@@ -390,6 +390,11 @@ struct Vector2i
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set all components to the specified scalar value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -331,6 +332,19 @@ String Vector3::ToString() const
|
|||||||
return fmt::format("{},{},{}", x, y, z);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Vector3::ToString)
|
.Func(_SC("_tostring"), &Vector3::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Vector3::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector3 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector3 >)
|
||||||
|
|||||||
@@ -297,6 +297,11 @@ struct Vector3
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set all components to the specified scalar value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Base/DynArg.hpp"
|
#include "Base/DynArg.hpp"
|
||||||
#include "Core/Buffer.hpp"
|
#include "Core/Buffer.hpp"
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Library/JSON.hpp"
|
||||||
#include "Library/Numeric/Random.hpp"
|
#include "Library/Numeric/Random.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -344,6 +345,19 @@ String Vector4::ToString() const
|
|||||||
return fmt::format("{},{},{},{}", x, y, z, w);
|
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)
|
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("cmp"), &SqDynArgFwd< SqDynArgCmpFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
|
||||||
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
.SquirrelFunc(_SC("_typename"), &Typename::Fn)
|
||||||
.Func(_SC("_tostring"), &Vector4::ToString)
|
.Func(_SC("_tostring"), &Vector4::ToString)
|
||||||
|
.Func(_SC("_tojson"), &Vector4::ToJSON)
|
||||||
// Meta-methods
|
// Meta-methods
|
||||||
.SquirrelFunc(_SC("_add"), &SqDynArgFwd< SqDynArgAddFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
|
.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 >)
|
.SquirrelFunc(_SC("_sub"), &SqDynArgFwd< SqDynArgSubFn< Vector4 >, SQFloat, SQInteger, bool, std::nullptr_t, Vector4 >)
|
||||||
|
|||||||
@@ -295,6 +295,11 @@ struct Vector4
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String ToString() const;
|
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.
|
* Set all components to the specified scalar value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+22
-9
@@ -1,5 +1,7 @@
|
|||||||
# Create the Squirrel module
|
# Create the Squirrel module
|
||||||
add_library(SqModule MODULE SqBase.hpp Main.cpp
|
add_library(SqModule MODULE SqBase.hpp Main.cpp
|
||||||
|
# SDK
|
||||||
|
SDK/sqmod.h
|
||||||
# VCMP
|
# VCMP
|
||||||
VCMP/vcmp.h
|
VCMP/vcmp.h
|
||||||
VCMP/vcmp20.h
|
VCMP/vcmp20.h
|
||||||
@@ -80,6 +82,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
|
|||||||
Library/Numeric.cpp Library/Numeric.hpp
|
Library/Numeric.cpp Library/Numeric.hpp
|
||||||
Library/Numeric/Math.cpp Library/Numeric/Math.hpp
|
Library/Numeric/Math.cpp Library/Numeric/Math.hpp
|
||||||
Library/Numeric/Random.cpp Library/Numeric/Random.hpp
|
Library/Numeric/Random.cpp Library/Numeric/Random.hpp
|
||||||
|
Library/RegEx.cpp Library/RegEx.hpp
|
||||||
Library/String.cpp Library/String.hpp
|
Library/String.cpp Library/String.hpp
|
||||||
Library/System.cpp Library/System.hpp
|
Library/System.cpp Library/System.hpp
|
||||||
Library/System/Dir.cpp Library/System/Dir.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/Crypto.cpp PocoLib/Crypto.hpp
|
||||||
PocoLib/Data.cpp PocoLib/Data.hpp
|
PocoLib/Data.cpp PocoLib/Data.hpp
|
||||||
PocoLib/Net.cpp PocoLib/Net.hpp
|
PocoLib/Net.cpp PocoLib/Net.hpp
|
||||||
PocoLib/RegEx.cpp PocoLib/RegEx.hpp
|
|
||||||
PocoLib/Register.cpp PocoLib/Register.hpp
|
PocoLib/Register.cpp PocoLib/Register.hpp
|
||||||
PocoLib/Time.cpp PocoLib/Time.hpp
|
PocoLib/Time.cpp PocoLib/Time.hpp
|
||||||
PocoLib/Util.cpp PocoLib/Util.hpp
|
PocoLib/Util.cpp PocoLib/Util.hpp
|
||||||
@@ -114,6 +116,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
|
|||||||
Core.cpp Core.hpp
|
Core.cpp Core.hpp
|
||||||
Logger.cpp Logger.hpp
|
Logger.cpp Logger.hpp
|
||||||
Register.cpp
|
Register.cpp
|
||||||
|
Exports.cpp
|
||||||
)
|
)
|
||||||
# Various definitions required by the plug-in
|
# Various definitions required by the plug-in
|
||||||
target_compile_definitions(SqModule PRIVATE SCRAT_USE_EXCEPTIONS=1)
|
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)
|
target_link_libraries(SqModule wsock32 ws2_32 shlwapi)
|
||||||
endif()
|
endif()
|
||||||
# Link to base libraries
|
# 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
|
# Link to POCO libraries
|
||||||
target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net)
|
target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net)
|
||||||
# Does POCO have SQLite support?
|
# Does POCO have SQLite support?
|
||||||
@@ -201,8 +204,18 @@ else(WIN32)
|
|||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
# Include current directory in the search path
|
# 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})
|
||||||
|
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}/VCMP)
|
||||||
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/Sqrat)
|
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
|
# 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")
|
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)
|
# 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()
|
endif()
|
||||||
# Make sure the deps folder exists
|
# Make sure the deps folder exists
|
||||||
file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/bin/deps")
|
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}/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}/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}/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}/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}/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}/libssh2-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||||
file(COPY "${MINGW_BIN_PATH}/libidn2-0.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}/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}/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}/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}/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}/libwinpthread-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||||
file(COPY "${MINGW_BIN_PATH}/libstdc++-6.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)
|
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}/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}/libssl-3-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}/libcrypto-3-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||||
else()
|
else()
|
||||||
file(COPY "${MINGW_BIN_PATH}/libssl-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-1_1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
file(COPY "${MINGW_BIN_PATH}/libcrypto-3.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
||||||
endif()
|
endif()
|
||||||
if(POCO_UNBUNDLED)
|
if(POCO_UNBUNDLED)
|
||||||
file(COPY "${MINGW_BIN_PATH}/libexpat-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
|
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_Scripts()
|
||||||
, m_PendingScripts()
|
, m_PendingScripts()
|
||||||
, m_Options()
|
, m_Options()
|
||||||
|
, m_ExtCommands{nullptr, nullptr, nullptr, nullptr}
|
||||||
, m_Blips()
|
, m_Blips()
|
||||||
, m_Checkpoints()
|
, m_Checkpoints()
|
||||||
, m_KeyBinds()
|
, m_KeyBinds()
|
||||||
@@ -441,9 +442,9 @@ bool Core::Execute()
|
|||||||
m_LockPostLoadSignal = false;
|
m_LockPostLoadSignal = false;
|
||||||
m_LockUnloadSignal = 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
|
// 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
|
// Load pending scripts while we're in the bounds of the allowed recursiveness
|
||||||
for (unsigned levels = 0; !m_PendingScripts.empty() && (levels < 8); ++levels)
|
for (unsigned levels = 0; !m_PendingScripts.empty() && (levels < 8); ++levels)
|
||||||
@@ -511,9 +512,9 @@ void Core::Terminate(bool shutdown)
|
|||||||
// Clear the callbacks
|
// Clear the callbacks
|
||||||
ResetSignalPair(mOnUnload);
|
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
|
// 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");
|
cLogDbg(m_Verbosity >= 1, "Clearing the entity containers");
|
||||||
@@ -596,9 +597,9 @@ void Core::Terminate(bool shutdown)
|
|||||||
HSQUIRRELVM sq_vm = m_VM;
|
HSQUIRRELVM sq_vm = m_VM;
|
||||||
m_VM = nullptr;
|
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
|
// Tell modules to do their monkey business
|
||||||
//_Func->SendPluginCommand(0xBAAAAAAD, "");
|
_Func->SendPluginCommand(SQMOD_CLOSING_CMD, SQMOD_HOST_NAME);
|
||||||
// Release any callbacks from the logger
|
// Release any callbacks from the logger
|
||||||
Logger::Get().Release();
|
Logger::Get().Release();
|
||||||
cLogDbg(m_Verbosity >= 2, "Closing Virtual Machine");
|
cLogDbg(m_Verbosity >= 2, "Closing Virtual Machine");
|
||||||
@@ -629,9 +630,9 @@ void Core::Terminate(bool shutdown)
|
|||||||
// Destroy the VM context, if any
|
// Destroy the VM context, if any
|
||||||
delete ctx;
|
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
|
// 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");
|
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);
|
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)
|
bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end)
|
||||||
{
|
{
|
||||||
@@ -2371,6 +2447,8 @@ void Core::InitEvents()
|
|||||||
InitSignalPair(mOnServerOption, m_Events, "ServerOption");
|
InitSignalPair(mOnServerOption, m_Events, "ServerOption");
|
||||||
InitSignalPair(mOnScriptReload, m_Events, "ScriptReload");
|
InitSignalPair(mOnScriptReload, m_Events, "ScriptReload");
|
||||||
InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded");
|
InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded");
|
||||||
|
InitSignalPair(mOnExtCommandReply, m_Events, "ExtCommandReply");
|
||||||
|
InitSignalPair(mOnExtCommandEvent, m_Events, "ExtCommandEvent");
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Core::DropEvents()
|
void Core::DropEvents()
|
||||||
@@ -2516,6 +2594,8 @@ void Core::DropEvents()
|
|||||||
ResetSignalPair(mOnServerOption);
|
ResetSignalPair(mOnServerOption);
|
||||||
ResetSignalPair(mOnScriptReload);
|
ResetSignalPair(mOnScriptReload);
|
||||||
ResetSignalPair(mOnScriptLoaded);
|
ResetSignalPair(mOnScriptLoaded);
|
||||||
|
ResetSignalPair(mOnExtCommandReply);
|
||||||
|
ResetSignalPair(mOnExtCommandEvent);
|
||||||
m_Events.Release();
|
m_Events.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2861,6 +2941,31 @@ static LightObj & SqGetClientDataBuffer()
|
|||||||
return Core::Get().GetClientDataBuffer();
|
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)
|
void Register_Core(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
@@ -2910,6 +3015,8 @@ void Register_Core(HSQUIRRELVM vm)
|
|||||||
.Func(_SC("DestroyPickup"), &SqDelPickup)
|
.Func(_SC("DestroyPickup"), &SqDelPickup)
|
||||||
.Func(_SC("DestroyVehicle"), &SqDelVehicle)
|
.Func(_SC("DestroyVehicle"), &SqDelVehicle)
|
||||||
.Func(_SC("ClientDataBuffer"), &SqGetClientDataBuffer)
|
.Func(_SC("ClientDataBuffer"), &SqGetClientDataBuffer)
|
||||||
|
.Func(_SC("SendExtCommand"), &SqSendExtCommand)
|
||||||
|
.FmtFunc(_SC("SendExtCommandStr"), &SqSendExtCommandStr)
|
||||||
.Func(_SC("OnPreLoad"), &SqGetPreLoadEvent)
|
.Func(_SC("OnPreLoad"), &SqGetPreLoadEvent)
|
||||||
.Func(_SC("OnPostLoad"), &SqGetPostLoadEvent)
|
.Func(_SC("OnPostLoad"), &SqGetPostLoadEvent)
|
||||||
.Func(_SC("OnUnload"), &SqGetUnloadEvent)
|
.Func(_SC("OnUnload"), &SqGetUnloadEvent)
|
||||||
|
|||||||
+105
-5
@@ -9,6 +9,9 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "SDK/sqmod.h"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
|
||||||
@@ -56,6 +59,8 @@ public:
|
|||||||
typedef std::vector< ScriptSrc > Scripts; // List of loaded scripts.
|
typedef std::vector< ScriptSrc > Scripts; // List of loaded scripts.
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
typedef std::unordered_map< String, String > Options; // List of custom options.
|
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:
|
private:
|
||||||
|
|
||||||
@@ -68,6 +73,7 @@ private:
|
|||||||
Scripts m_Scripts; // Loaded scripts objects.
|
Scripts m_Scripts; // Loaded scripts objects.
|
||||||
Scripts m_PendingScripts; // Pending scripts objects.
|
Scripts m_PendingScripts; // Pending scripts objects.
|
||||||
Options m_Options; // Custom configuration options.
|
Options m_Options; // Custom configuration options.
|
||||||
|
ExtCommands m_ExtCommands; // External command parsers pointers.
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
Blips m_Blips; // Blips pool.
|
Blips m_Blips; // Blips pool.
|
||||||
@@ -399,6 +405,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String FetchCodeLine(const SQChar * src, SQInteger line, bool trim = true);
|
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:
|
protected:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -710,6 +733,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
void EmitClientScriptData(int32_t player_id, const uint8_t * data, size_t size);
|
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:
|
public:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -864,6 +897,8 @@ public:
|
|||||||
SignalPair mOnServerOption{};
|
SignalPair mOnServerOption{};
|
||||||
SignalPair mOnScriptReload{};
|
SignalPair mOnScriptReload{};
|
||||||
SignalPair mOnScriptLoaded{};
|
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 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)); }
|
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.
|
* Process the identifier of each connected player.
|
||||||
*/
|
*/
|
||||||
template < class F > inline void ForeachConnectedPlayer(F f) {
|
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.
|
* Process the identifier of each connected player and count processed players.
|
||||||
*/
|
*/
|
||||||
template < class F > SQMOD_NODISCARD inline int32_t ForeachConnectedPlayerCount(F f) {
|
template < class F > SQMOD_NODISCARD inline int32_t ForeachConnectedPlayerCount(F f) {
|
||||||
int32_t c = 0;
|
int32_t c = 0;
|
||||||
for (int32_t i = 0, n = _Func->GetMaxPlayers(); i < n; ++i)
|
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||||
if (f(i)) ++c;
|
if (_Func->IsPlayerConnected(i) != 0 && f(i)) ++c;
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Process the identifier of each connected player until a certain criteria is met.
|
* Process the identifier of each connected player until a certain criteria is met.
|
||||||
*/
|
*/
|
||||||
template < class F > SQMOD_NODISCARD inline int32_t ForeachConnectedPlayerUntil(F f) {
|
template < class F > SQMOD_NODISCARD inline int32_t ForeachConnectedPlayerUntil(F f) {
|
||||||
for (int32_t i = 0, n = _Func->GetMaxPlayers(); i < n; ++i)
|
for (int32_t i = 0, n = static_cast< int32_t >(_Func->GetMaxPlayers()); i < n; ++i) {
|
||||||
if (f(i)) return i;
|
if (_Func->IsPlayerConnected(i) != 0 && f(i)) return i;
|
||||||
|
}
|
||||||
return -1;
|
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
|
} // Namespace:: SqMod
|
||||||
|
|||||||
+33
-5
@@ -161,7 +161,7 @@ bool Area::IsInside(float x, float y) const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AreaManager::AreaManager(size_t sz) noexcept
|
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)
|
// Negative half grid size (left)
|
||||||
int l = (-GRIDH * CELLD);
|
int l = (-GRIDH * CELLD);
|
||||||
@@ -171,21 +171,30 @@ AreaManager::AreaManager(size_t sz) noexcept
|
|||||||
int r = (l + CELLD);
|
int r = (l + CELLD);
|
||||||
// Positive half grid size (top)
|
// Positive half grid size (top)
|
||||||
int t = abs(l);
|
int t = abs(l);
|
||||||
|
// Row/Column of the grid
|
||||||
|
int row = 0, col = 0;
|
||||||
// Initialize the grid cells
|
// Initialize the grid cells
|
||||||
for (auto & a : m_Grid)
|
for (auto & a : m_Grid)
|
||||||
{
|
{
|
||||||
|
// Reset the column
|
||||||
|
col = 0;
|
||||||
|
// Process row
|
||||||
for (auto & c : a)
|
for (auto & c : a)
|
||||||
{
|
{
|
||||||
|
auto & cx = m_Cells[row][col];
|
||||||
// Grab a reference to the cell
|
// Grab a reference to the cell
|
||||||
// Configure the range of the cell
|
// Configure the range of the cell
|
||||||
c.mL = static_cast< float >(l);
|
c.mL = cx.mL = static_cast< float >(l);
|
||||||
c.mB = static_cast< float >(b);
|
c.mB = cx.mB = static_cast< float >(b);
|
||||||
c.mR = static_cast< float >(r);
|
c.mR = cx.mR = static_cast< float >(r);
|
||||||
c.mT = static_cast< float >(t);
|
c.mT = cx.mT = static_cast< float >(t);
|
||||||
// Reserve area memory if requested
|
// Reserve area memory if requested
|
||||||
c.mAreas.reserve(sz);
|
c.mAreas.reserve(sz);
|
||||||
// Reset the locks on this area
|
// Reset the locks on this area
|
||||||
c.mLocks = 0;
|
c.mLocks = 0;
|
||||||
|
// Set the row and column
|
||||||
|
c.mRow = row;
|
||||||
|
c.mCol = col++;
|
||||||
// Advance the left side
|
// Advance the left side
|
||||||
l = r;
|
l = r;
|
||||||
// Advance the right side
|
// Advance the right side
|
||||||
@@ -203,6 +212,8 @@ AreaManager::AreaManager(size_t sz) noexcept
|
|||||||
t -= CELLD;
|
t -= CELLD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Advance row
|
||||||
|
++row;
|
||||||
}
|
}
|
||||||
// Reserve some space in the queue
|
// Reserve some space in the queue
|
||||||
m_Queue.reserve(128);
|
m_Queue.reserve(128);
|
||||||
@@ -340,6 +351,21 @@ void AreaManager::RemoveArea(Area & a)
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Vector2i AreaManager::LocateCell(float x, float y)
|
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
|
// Transform the world coordinates into a cell coordinates
|
||||||
// and cast to integral after rounding the value
|
// and cast to integral after rounding the value
|
||||||
int xc = static_cast< int >(std::round(x / CELLD));
|
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 the identified cell row and column
|
||||||
return {GRIDH+xc, GRIDH-yc};
|
return {GRIDH+xc, GRIDH-yc};
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -469,6 +496,7 @@ void Register_Areas(HSQUIRRELVM vm)
|
|||||||
.Func(_SC("TestEx"), &Area::TestEx)
|
.Func(_SC("TestEx"), &Area::TestEx)
|
||||||
.Func(_SC("Manage"), &Area::Manage)
|
.Func(_SC("Manage"), &Area::Manage)
|
||||||
.Func(_SC("Unmanage"), &Area::Unmanage)
|
.Func(_SC("Unmanage"), &Area::Unmanage)
|
||||||
|
.CbFunc(_SC("EachCell"), &Area::EachCell)
|
||||||
// Static Functions
|
// Static Functions
|
||||||
.StaticFunc(_SC("GlobalTest"), &Areas_TestPoint)
|
.StaticFunc(_SC("GlobalTest"), &Areas_TestPoint)
|
||||||
.StaticFunc(_SC("GlobalTestEx"), &Areas_TestPointEx)
|
.StaticFunc(_SC("GlobalTestEx"), &Areas_TestPointEx)
|
||||||
|
|||||||
+28
-4
@@ -29,15 +29,25 @@ struct AreaCell
|
|||||||
Areas mAreas; // Areas that intersect with the cell.
|
Areas mAreas; // Areas that intersect with the cell.
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
int mLocks; // The amount of locks on 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.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
AreaCell()
|
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();
|
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:
|
protected:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -610,7 +631,10 @@ private:
|
|||||||
ProcList m_ProcList; // Actions ready to be completed.
|
ProcList m_ProcList; // Actions ready to be completed.
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
AreaCell m_Grid[GRIDN][GRIDN]; // A grid of area lists.
|
AreaCell m_Grid[GRIDN][GRIDN]; // A grid of area lists.
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
struct {
|
||||||
|
float mL, mB, mR, mT;
|
||||||
|
} m_Cells[GRIDN][GRIDN];
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -664,7 +688,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Clear all cell lists and release any script references.
|
* 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
|
* Test a point to see whether it intersects with any areas
|
||||||
@@ -679,7 +703,7 @@ public:
|
|||||||
return; // Not our problem
|
return; // Not our problem
|
||||||
}
|
}
|
||||||
// Retrieve a reference to the identified cell
|
// 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?
|
// Is this cell empty?
|
||||||
if (c.mAreas.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
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Make sure that the specified element is withing buffer range
|
// Make sure that the specified element is withing buffer range
|
||||||
else if (n > (m_Cap - sizeof(T)))
|
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);
|
sizeof(T), n, m_Cap);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -306,13 +306,13 @@ public:
|
|||||||
// Make sure that the buffer can host at least one element of this type
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Make sure that the specified element is withing buffer range
|
// Make sure that the specified element is withing buffer range
|
||||||
else if (n > (m_Cap - sizeof(T)))
|
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);
|
sizeof(T), n, m_Cap);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -359,7 +359,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least one element of this type
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -374,7 +374,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least one element of this type
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -389,7 +389,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least two elements of this type
|
// Make sure that the buffer can host at least two elements of this type
|
||||||
if (m_Cap < (sizeof(T) * 2))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -404,7 +404,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least two elements of this type
|
// Make sure that the buffer can host at least two elements of this type
|
||||||
if (m_Cap < (sizeof(T) * 2))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -419,7 +419,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least one element of this type
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -434,7 +434,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least one element of this type
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -449,7 +449,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least two elements of this type
|
// Make sure that the buffer can host at least two elements of this type
|
||||||
if (m_Cap < (sizeof(T) * 2))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -464,7 +464,7 @@ public:
|
|||||||
// Make sure that the buffer can host at least two elements of this type
|
// Make sure that the buffer can host at least two elements of this type
|
||||||
if (m_Cap < (sizeof(T) * 2))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -540,7 +540,7 @@ public:
|
|||||||
// Make sure that at least one element of this type exists after the cursor
|
// Make sure that at least one element of this type exists after the cursor
|
||||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
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);
|
sizeof(T), m_Cur, m_Cap);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -555,7 +555,7 @@ public:
|
|||||||
// Make sure that at least one element of this type exists after the cursor
|
// Make sure that at least one element of this type exists after the cursor
|
||||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
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);
|
sizeof(T), m_Cur, m_Cap);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -570,7 +570,7 @@ public:
|
|||||||
// The cursor must have at least one element of this type behind
|
// The cursor must have at least one element of this type behind
|
||||||
if (m_Cur < sizeof(T))
|
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);
|
sizeof(T), m_Cur);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -585,7 +585,7 @@ public:
|
|||||||
// The cursor must have at least one element of this type behind
|
// The cursor must have at least one element of this type behind
|
||||||
if (m_Cur < sizeof(T))
|
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);
|
sizeof(T), m_Cur);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -600,13 +600,13 @@ public:
|
|||||||
// Make sure that the buffer can host at least one element of this type
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// There must be buffer left for at least two elements of this type after the cursor
|
// 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)
|
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);
|
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -621,13 +621,13 @@ public:
|
|||||||
// Make sure that the buffer can host at least one element of this type
|
// Make sure that the buffer can host at least one element of this type
|
||||||
if (m_Cap < sizeof(T))
|
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));
|
m_Cap, sizeof(T));
|
||||||
}
|
}
|
||||||
// There must be buffer left for at least two elements of this type after the cursor
|
// 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)
|
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);
|
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||||
}
|
}
|
||||||
// Return the requested element
|
// Return the requested element
|
||||||
@@ -708,7 +708,7 @@ public:
|
|||||||
// See if the requested capacity doesn't exceed the limit
|
// See if the requested capacity doesn't exceed the limit
|
||||||
if (n > Max< T >())
|
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?
|
// Is there an existing buffer?
|
||||||
else if (n && !m_Cap)
|
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));
|
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)
|
LightObj BufferToStrObj(const Buffer & b)
|
||||||
{
|
{
|
||||||
|
|||||||
+97
-2
@@ -40,6 +40,7 @@
|
|||||||
#include <sqratTable.h>
|
#include <sqratTable.h>
|
||||||
#include <sqratUtil.h>
|
#include <sqratUtil.h>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
#include <rpmalloc.h>
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
@@ -173,7 +174,7 @@ void OutputError(const char * msg, ...);
|
|||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Generate a formatted string and throw it as a Sqrat exception.
|
* 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)...));
|
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.
|
* 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;
|
String msg;
|
||||||
try
|
try
|
||||||
@@ -241,6 +242,11 @@ SQMOD_NODISCARD const SQChar * SqTypeName(SQObjectType type);
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD String SqTypeName(HSQUIRRELVM vm, SQInteger idx);
|
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.
|
* 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);
|
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
|
} // 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
|
// Release any stored buffer information
|
||||||
m_IncomingNameBuffer = nullptr;
|
m_IncomingNameBuffer = nullptr;
|
||||||
m_IncomingNameCapacity = 0;
|
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
|
throw; // re-throw it
|
||||||
}
|
}
|
||||||
// Release any stored buffer information
|
// Release any stored buffer information
|
||||||
@@ -392,7 +392,8 @@ void Core::EmitPlayerRequestSpawn(int32_t player_id)
|
|||||||
#ifdef VCMP_ENABLE_OFFICIAL
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
if (IsOfficial())
|
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
|
#endif
|
||||||
}
|
}
|
||||||
@@ -2245,6 +2246,44 @@ void Core::EmitClientScriptData(int32_t player_id, const uint8_t * data, size_t
|
|||||||
m_ClientData.Release();
|
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
|
#undef NULL_SQOBJ_ // don't need this anymore
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
|||||||
@@ -1723,6 +1723,7 @@ void Register_Signal(HSQUIRRELVM vm)
|
|||||||
.SquirrelFunc(_SC("Eliminate"), &Signal::SqEliminate)
|
.SquirrelFunc(_SC("Eliminate"), &Signal::SqEliminate)
|
||||||
.SquirrelFunc(_SC("EliminateThis"), &Signal::SqEliminateThis)
|
.SquirrelFunc(_SC("EliminateThis"), &Signal::SqEliminateThis)
|
||||||
.SquirrelFunc(_SC("EliminateFunc"), &Signal::SqEliminateFunc)
|
.SquirrelFunc(_SC("EliminateFunc"), &Signal::SqEliminateFunc)
|
||||||
|
.SquirrelFunc(_SC("Broadcast"), &Signal::SqEmit)
|
||||||
.SquirrelFunc(_SC("Emit"), &Signal::SqEmit)
|
.SquirrelFunc(_SC("Emit"), &Signal::SqEmit)
|
||||||
.SquirrelFunc(_SC("Query"), &Signal::SqQuery)
|
.SquirrelFunc(_SC("Query"), &Signal::SqQuery)
|
||||||
.SquirrelFunc(_SC("Consume"), &Signal::SqConsume)
|
.SquirrelFunc(_SC("Consume"), &Signal::SqConsume)
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ void ThreadPool::Terminate(bool SQ_UNUSED_ARG(shutdown))
|
|||||||
// Is the item valid?
|
// Is the item valid?
|
||||||
if (item)
|
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 processed
|
||||||
item.reset();
|
item.reset();
|
||||||
@@ -125,7 +125,15 @@ void ThreadPool::Process()
|
|||||||
// Is the item valid?
|
// Is the item valid?
|
||||||
if (item)
|
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;
|
bool retry = false;
|
||||||
// Pointer to the dequeued item
|
// Pointer to the dequeued item
|
||||||
Item item;
|
Item item;
|
||||||
|
// Initialize third-party allocator for this thread
|
||||||
|
auto rpmallocinit = std::make_unique< RPMallocThreadInit >();
|
||||||
// Constantly process items from the queue
|
// Constantly process items from the queue
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -147,7 +157,11 @@ void ThreadPool::WorkerProc()
|
|||||||
// Is there an item that requested to try again?
|
// Is there an item that requested to try again?
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
item->OnAborted(true); // NOLINT(bugprone-use-after-move) There's an `if` condition above idiot!
|
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
|
// Exit the loop
|
||||||
break;
|
break;
|
||||||
@@ -173,15 +187,30 @@ void ThreadPool::WorkerProc()
|
|||||||
// Is there an item to be processed?
|
// Is there an item to be processed?
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
item->OnAborted(false); // It should mark itself as aborted somehow!
|
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
|
// Exit the loop
|
||||||
break;
|
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
|
// Perform the task
|
||||||
if (item->OnPrepare())
|
if (r)
|
||||||
{
|
{
|
||||||
retry = item->OnProcess();
|
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
|
// The task was performed
|
||||||
if (!retry)
|
if (!retry)
|
||||||
|
|||||||
+55
-12
@@ -55,6 +55,16 @@ struct ThreadPoolItem
|
|||||||
*/
|
*/
|
||||||
ThreadPoolItem & operator = (ThreadPoolItem && o) = delete;
|
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.
|
* 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.
|
* 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.
|
* 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.
|
* Called in worker by the thread pool to let the task know that it will be aborted.
|
||||||
@@ -98,13 +110,13 @@ private:
|
|||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
~ThreadPool();
|
~ThreadPool();
|
||||||
|
public:
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
using Item = std::unique_ptr< ThreadPoolItem >; // Owning pointer of an item.
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
using Pool = std::vector< std::thread >; // Worker container.
|
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.
|
using Finished = moodycamel::ConcurrentQueue< Item >; // Finished items.
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
@@ -171,9 +183,25 @@ public:
|
|||||||
void Process();
|
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)
|
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
|
// Only queue valid items
|
||||||
if (!item || !m_Running) return;
|
if (!item || !m_Running) return;
|
||||||
@@ -183,7 +211,7 @@ public:
|
|||||||
// Acquire a lock on the mutex
|
// Acquire a lock on the mutex
|
||||||
std::unique_lock< std::mutex > lock(m_Mutex);
|
std::unique_lock< std::mutex > lock(m_Mutex);
|
||||||
// Push the item in the queue
|
// Push the item in the queue
|
||||||
m_Queue.push(Item(item));
|
m_Queue.push(std::forward< Item >(item));
|
||||||
// Release the mutex before notifying
|
// Release the mutex before notifying
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
// Notify one thread that there's work
|
// Notify one thread that there's work
|
||||||
@@ -191,16 +219,32 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
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
|
// 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)
|
||||||
{
|
{
|
||||||
item->OnAborted(true); // Not accepted in single thread
|
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
|
// Task is completed in processing stage
|
||||||
item->OnCompleted();
|
m_Finished.enqueue(std::forward< Item >(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +255,6 @@ public:
|
|||||||
{
|
{
|
||||||
return m_Threads.size();
|
return m_Threads.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
|||||||
@@ -251,6 +251,20 @@ template < class Key, class T, class Pred = std::equal_to< Key > > struct VecMap
|
|||||||
return m_Storage.back().second;
|
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:
|
private:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -468,6 +468,16 @@ void CCheckpoint::SetColorA(int32_t a) const
|
|||||||
// Perform the requested operation
|
// Perform the requested operation
|
||||||
_Func->SetCheckPointColour(m_ID, r, g, b, a);
|
_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,
|
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("Tag"), &CCheckpoint::GetTag, &CCheckpoint::SetTag)
|
||||||
.Prop(_SC("Data"), &CCheckpoint::GetData, &CCheckpoint::SetData)
|
.Prop(_SC("Data"), &CCheckpoint::GetData, &CCheckpoint::SetData)
|
||||||
.Prop(_SC("Active"), &CCheckpoint::IsActive)
|
.Prop(_SC("Active"), &CCheckpoint::IsActive)
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
.Prop(_SC("Legacy"), &CCheckpoint::GetLegacyObject)
|
||||||
|
#endif
|
||||||
// Core Methods
|
// Core Methods
|
||||||
.FmtFunc(_SC("SetTag"), &CCheckpoint::ApplyTag)
|
.FmtFunc(_SC("SetTag"), &CCheckpoint::ApplyTag)
|
||||||
.Func(_SC("CustomEvent"), &CCheckpoint::CustomEvent)
|
.Func(_SC("CustomEvent"), &CCheckpoint::CustomEvent)
|
||||||
|
|||||||
@@ -320,6 +320,12 @@ public:
|
|||||||
* Modify the alpha transparency of the managed checkpoint entity.
|
* Modify the alpha transparency of the managed checkpoint entity.
|
||||||
*/
|
*/
|
||||||
void SetColorA(int32_t a) const;
|
void SetColorA(int32_t a) const;
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve legacy object instance for this entity.
|
||||||
|
*/
|
||||||
|
LightObj & GetLegacyObject() const;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
|||||||
@@ -833,6 +833,16 @@ void CObject::RotateByEulerZ(float z) const
|
|||||||
// Perform the requested operation
|
// Perform the requested operation
|
||||||
_Func->RotateObjectByEuler(m_ID, 0.0f, 0.0f, z, mRotateByEulerDuration);
|
_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,
|
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("Tag"), &CObject::GetTag, &CObject::SetTag)
|
||||||
.Prop(_SC("Data"), &CObject::GetData, &CObject::SetData)
|
.Prop(_SC("Data"), &CObject::GetData, &CObject::SetData)
|
||||||
.Prop(_SC("Active"), &CObject::IsActive)
|
.Prop(_SC("Active"), &CObject::IsActive)
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
.Prop(_SC("Legacy"), &CObject::GetLegacyObject)
|
||||||
|
#endif
|
||||||
// Core Methods
|
// Core Methods
|
||||||
.FmtFunc(_SC("SetTag"), &CObject::ApplyTag)
|
.FmtFunc(_SC("SetTag"), &CObject::ApplyTag)
|
||||||
.Func(_SC("CustomEvent"), &CObject::CustomEvent)
|
.Func(_SC("CustomEvent"), &CObject::CustomEvent)
|
||||||
|
|||||||
@@ -499,6 +499,12 @@ public:
|
|||||||
* Modify the rotation on the z axis of the managed object entity.
|
* Modify the rotation on the z axis of the managed object entity.
|
||||||
*/
|
*/
|
||||||
void RotateByEulerZ(float z) const;
|
void RotateByEulerZ(float z) const;
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve legacy object instance for this entity.
|
||||||
|
*/
|
||||||
|
LightObj & GetLegacyObject() const;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
|||||||
@@ -449,6 +449,16 @@ void CPickup::SetPositionZ(float z) const
|
|||||||
// Perform the requested operation
|
// Perform the requested operation
|
||||||
_Func->SetPickupPosition(m_ID, z, y, z);
|
_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,
|
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("Tag"), &CPickup::GetTag, &CPickup::SetTag)
|
||||||
.Prop(_SC("Data"), &CPickup::GetData, &CPickup::SetData)
|
.Prop(_SC("Data"), &CPickup::GetData, &CPickup::SetData)
|
||||||
.Prop(_SC("Active"), &CPickup::IsActive)
|
.Prop(_SC("Active"), &CPickup::IsActive)
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
.Prop(_SC("Legacy"), &CPickup::GetLegacyObject)
|
||||||
|
#endif
|
||||||
// Core Methods
|
// Core Methods
|
||||||
.FmtFunc(_SC("SetTag"), &CPickup::ApplyTag)
|
.FmtFunc(_SC("SetTag"), &CPickup::ApplyTag)
|
||||||
.Func(_SC("CustomEvent"), &CPickup::CustomEvent)
|
.Func(_SC("CustomEvent"), &CPickup::CustomEvent)
|
||||||
|
|||||||
@@ -298,6 +298,12 @@ public:
|
|||||||
* Modify the position on the z axis of the managed pickup entity.
|
* Modify the position on the z axis of the managed pickup entity.
|
||||||
*/
|
*/
|
||||||
void SetPositionZ(float z) const;
|
void SetPositionZ(float z) const;
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve legacy object instance for this entity.
|
||||||
|
*/
|
||||||
|
LightObj & GetLegacyObject() const;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
|||||||
@@ -2593,7 +2593,16 @@ SQInteger CPlayer::AnnounceEx(HSQUIRRELVM vm)
|
|||||||
// This function does not return a value
|
// This function does not return a value
|
||||||
return 0;
|
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)
|
SQInteger Player_FindAuto(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
@@ -2793,6 +2802,9 @@ void Register_CPlayer(HSQUIRRELVM vm)
|
|||||||
.Prop(_SC("Tag"), &CPlayer::GetTag, &CPlayer::SetTag)
|
.Prop(_SC("Tag"), &CPlayer::GetTag, &CPlayer::SetTag)
|
||||||
.Prop(_SC("Data"), &CPlayer::GetData, &CPlayer::SetData)
|
.Prop(_SC("Data"), &CPlayer::GetData, &CPlayer::SetData)
|
||||||
.Prop(_SC("Active"), &CPlayer::IsActive)
|
.Prop(_SC("Active"), &CPlayer::IsActive)
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
.Prop(_SC("Legacy"), &CPlayer::GetLegacyObject)
|
||||||
|
#endif
|
||||||
// Core Methods
|
// Core Methods
|
||||||
.FmtFunc(_SC("SetTag"), &CPlayer::ApplyTag)
|
.FmtFunc(_SC("SetTag"), &CPlayer::ApplyTag)
|
||||||
.Func(_SC("CustomEvent"), &CPlayer::CustomEvent)
|
.Func(_SC("CustomEvent"), &CPlayer::CustomEvent)
|
||||||
|
|||||||
@@ -1101,6 +1101,12 @@ public:
|
|||||||
* Send a formatted announcement message to the managed player entity.
|
* Send a formatted announcement message to the managed player entity.
|
||||||
*/
|
*/
|
||||||
static SQInteger AnnounceEx(HSQUIRRELVM vm);
|
static SQInteger AnnounceEx(HSQUIRRELVM vm);
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve legacy object instance for this entity.
|
||||||
|
*/
|
||||||
|
LightObj & GetLegacyObject() const;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
|||||||
@@ -2015,6 +2015,16 @@ void CVehicle::SetRelativeTurnSpeedZ(float z) const
|
|||||||
// Perform the requested operation
|
// Perform the requested operation
|
||||||
_Func->SetVehicleTurnSpeed(m_ID, z, y, z, static_cast< uint8_t >(false), static_cast< uint8_t >(true));
|
_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,
|
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("ID"), &CVehicle::GetID)
|
||||||
.Prop(_SC("Tag"), &CVehicle::GetTag, &CVehicle::SetTag)
|
.Prop(_SC("Tag"), &CVehicle::GetTag, &CVehicle::SetTag)
|
||||||
.Prop(_SC("Data"), &CVehicle::GetData, &CVehicle::SetData)
|
.Prop(_SC("Data"), &CVehicle::GetData, &CVehicle::SetData)
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
.Prop(_SC("Legacy"), &CVehicle::GetLegacyObject)
|
||||||
|
#endif
|
||||||
.Prop(_SC("Active"), &CVehicle::IsActive)
|
.Prop(_SC("Active"), &CVehicle::IsActive)
|
||||||
// Core Methods
|
// Core Methods
|
||||||
.FmtFunc(_SC("SetTag"), &CVehicle::ApplyTag)
|
.FmtFunc(_SC("SetTag"), &CVehicle::ApplyTag)
|
||||||
|
|||||||
@@ -942,6 +942,12 @@ public:
|
|||||||
* Modify the relative turn velocity on the z axis of the managed vehicle entity.
|
* Modify the relative turn velocity on the z axis of the managed vehicle entity.
|
||||||
*/
|
*/
|
||||||
void SetRelativeTurnSpeedZ(float z) const;
|
void SetRelativeTurnSpeedZ(float z) const;
|
||||||
|
#ifdef VCMP_ENABLE_OFFICIAL
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve legacy object instance for this entity.
|
||||||
|
*/
|
||||||
|
LightObj & GetLegacyObject() const;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // 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;
|
~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?
|
// Is there a callback?
|
||||||
if (!mCallback.IsNull())
|
if (!mCallback.IsNull())
|
||||||
@@ -58,6 +60,8 @@ struct CpBaseAction : public ThreadPoolItem
|
|||||||
}
|
}
|
||||||
// Unlock the session
|
// Unlock the session
|
||||||
mInstance->mPending = nullptr;
|
mInstance->mPending = nullptr;
|
||||||
|
// Don't re-queue
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -11,6 +11,13 @@
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include <Poco/Checksum.h>
|
#include <Poco/Checksum.h>
|
||||||
|
#include <Poco/Base32Encoder.h>
|
||||||
|
#include <Poco/Base32Decoder.h>
|
||||||
|
#include <Poco/Base64Encoder.h>
|
||||||
|
#include <Poco/Base64Decoder.h>
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
@@ -30,7 +37,7 @@ SQInteger SqBuffer::WriteRawString(StackStrF & val) const
|
|||||||
}
|
}
|
||||||
// Calculate the string length
|
// Calculate the string length
|
||||||
Buffer::SzType length = ConvTo< Buffer::SzType >::From(val.mLen);
|
Buffer::SzType length = ConvTo< Buffer::SzType >::From(val.mLen);
|
||||||
// Write the the string contents
|
// Write the string contents
|
||||||
m_Buffer->AppendS(val.mPtr, length);
|
m_Buffer->AppendS(val.mPtr, length);
|
||||||
// Return the length of the written string
|
// Return the length of the written string
|
||||||
return val.mLen;
|
return val.mLen;
|
||||||
@@ -224,7 +231,7 @@ AABB SqBuffer::ReadAABB() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< AABB >(1);
|
m_Buffer->Advance< AABB >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return AABB(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -237,7 +244,7 @@ Circle SqBuffer::ReadCircle() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Circle >(1);
|
m_Buffer->Advance< Circle >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Circle(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -250,7 +257,7 @@ Color3 SqBuffer::ReadColor3() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Color3 >(1);
|
m_Buffer->Advance< Color3 >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Color3(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -263,7 +270,7 @@ Color4 SqBuffer::ReadColor4() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Color4 >(1);
|
m_Buffer->Advance< Color4 >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Color4(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -276,7 +283,7 @@ Quaternion SqBuffer::ReadQuaternion() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Quaternion >(1);
|
m_Buffer->Advance< Quaternion >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Quaternion(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -289,7 +296,7 @@ Sphere SqBuffer::ReadSphere() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Sphere >(1);
|
m_Buffer->Advance< Sphere >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Sphere(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -302,7 +309,7 @@ Vector2 SqBuffer::ReadVector2() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Vector2 >(1);
|
m_Buffer->Advance< Vector2 >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Vector2(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -315,7 +322,7 @@ Vector2i SqBuffer::ReadVector2i() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Vector2i >(1);
|
m_Buffer->Advance< Vector2i >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Vector2i(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -328,7 +335,7 @@ Vector3 SqBuffer::ReadVector3() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Vector3 >(1);
|
m_Buffer->Advance< Vector3 >(1);
|
||||||
// Return the requested information
|
// Return the requested information
|
||||||
return Vector3(value);
|
return {value};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -341,7 +348,34 @@ Vector4 SqBuffer::ReadVector4() const
|
|||||||
// Advance the buffer cursor
|
// Advance the buffer cursor
|
||||||
m_Buffer->Advance< Vector4 >(1);
|
m_Buffer->Advance< Vector4 >(1);
|
||||||
// Return the requested information
|
// 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
|
// Create the checksum computer
|
||||||
Poco::Checksum c(Poco::Checksum::TYPE_CRC32);
|
Poco::Checksum c(Poco::Checksum::TYPE_CRC32);
|
||||||
// Give it the data to process
|
// 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 the result
|
||||||
return static_cast< SQInteger >(c.checksum());
|
return static_cast< SQInteger >(c.checksum());
|
||||||
}
|
}
|
||||||
@@ -365,12 +399,46 @@ SQInteger SqBuffer::GetADLER32(SQInteger n) const
|
|||||||
// Create the checksum computer
|
// Create the checksum computer
|
||||||
Poco::Checksum c(Poco::Checksum::TYPE_ADLER32);
|
Poco::Checksum c(Poco::Checksum::TYPE_ADLER32);
|
||||||
// Give it the data to process
|
// 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 the result
|
||||||
return static_cast< SQInteger >(c.checksum());
|
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)
|
void Register_Buffer(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
@@ -457,6 +525,9 @@ void Register_Buffer(HSQUIRRELVM vm)
|
|||||||
.Func(_SC("ReadVector4"), &SqBuffer::ReadVector4)
|
.Func(_SC("ReadVector4"), &SqBuffer::ReadVector4)
|
||||||
.Func(_SC("CRC32"), &SqBuffer::GetCRC32)
|
.Func(_SC("CRC32"), &SqBuffer::GetCRC32)
|
||||||
.Func(_SC("ADLER32"), &SqBuffer::GetADLER32)
|
.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;
|
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.
|
* 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.
|
* 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));
|
Valid().Advance(ConvTo< SzType >::From(n));
|
||||||
|
// Allow chaining
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Reposition the edit cursor to the specified number of elements behind.
|
* 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));
|
Valid().Retreat(ConvTo< SzType >::From(n));
|
||||||
|
// Allow chaining
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Reposition the edit cursor to a fixed position within the buffer.
|
* 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));
|
Valid().Move(ConvTo< SzType >::From(n));
|
||||||
|
// Allow chaining
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Append a value to the current cursor location and advance the cursor.
|
* 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));
|
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.
|
* 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.
|
* 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 the managed buffer reference
|
||||||
Validate();
|
Validate();
|
||||||
@@ -420,6 +448,8 @@ public:
|
|||||||
{
|
{
|
||||||
STHROWF("{}", e.what()); // Re-package
|
STHROWF("{}", e.what()); // Re-package
|
||||||
}
|
}
|
||||||
|
// Allow chaining
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -752,6 +782,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD Vector4 ReadVector4() const;
|
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.
|
* 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.
|
* Compute the Adler-32 checksums on the data in the buffer.
|
||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD SQInteger GetADLER32(SQInteger n) const;
|
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
|
} // Namespace:: SqMod
|
||||||
|
|||||||
+608
-5
@@ -2,6 +2,7 @@
|
|||||||
#include "Library/JSON.hpp"
|
#include "Library/JSON.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include <sajson.h>
|
||||||
#include <sqratConst.h>
|
#include <sqratConst.h>
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -11,13 +12,10 @@
|
|||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
static SQInteger SqToJSON(HSQUIRRELVM vm) noexcept
|
SQMOD_DECL_TYPENAME(SqCtxJSON, _SC("SqCtxJSON"))
|
||||||
{
|
|
||||||
return sq_throwerror(vm, _SC("Not implemented yet!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
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
|
// Operation result
|
||||||
SQInteger r = SQ_OK;
|
SQInteger r = SQ_OK;
|
||||||
@@ -151,11 +149,616 @@ static SQInteger SqFromJSON(HSQUIRRELVM vm) noexcept
|
|||||||
return SQ_SUCCEEDED(r) ? 1 : r;
|
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)
|
void Register_JSON(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
RootTable(vm).SquirrelFunc(_SC("SqToJSON"), SqToJSON);
|
RootTable(vm).SquirrelFunc(_SC("SqToJSON"), SqToJSON);
|
||||||
|
RootTable(vm).SquirrelFunc(_SC("SqToCompactJSON"), SqToCompactJSON);
|
||||||
RootTable(vm).SquirrelFunc(_SC("SqFromJSON"), SqFromJSON);
|
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
|
} // Namespace:: SqMod
|
||||||
|
|||||||
+271
-2
@@ -5,12 +5,281 @@
|
|||||||
#include "Library/IO/Buffer.hpp"
|
#include "Library/IO/Buffer.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include <sajson.h>
|
#include <functional>
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include <fmt/args.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fmt/xchar.h>
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
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
|
} // Namespace:: SqMod
|
||||||
|
|||||||
+423
-387
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
|
#endif
|
||||||
#ifndef NO_SSL
|
#ifndef NO_SSL
|
||||||
f |= MG_FEATURES_SSL;
|
f |= MG_FEATURES_SSL;
|
||||||
|
#else
|
||||||
|
OutputMessage("Network compiled without SSL support.");
|
||||||
#endif
|
#endif
|
||||||
#ifndef NO_CGI
|
#ifndef NO_CGI
|
||||||
f |= MG_FEATURES_CGI;
|
f |= MG_FEATURES_CGI;
|
||||||
@@ -89,6 +91,9 @@ WebSocketClient & WebSocketClient::Connect()
|
|||||||
{
|
{
|
||||||
STHROWF("Connection failed: {}", err_buf);
|
STHROWF("Connection failed: {}", err_buf);
|
||||||
}
|
}
|
||||||
|
// Reset memebrs
|
||||||
|
mClosing.store(false);
|
||||||
|
mClosed.store(false);
|
||||||
// Allow chaining
|
// Allow chaining
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -113,6 +118,9 @@ WebSocketClient & WebSocketClient::ConnectExt()
|
|||||||
{
|
{
|
||||||
STHROWF("Connection failed: {}", err_buf);
|
STHROWF("Connection failed: {}", err_buf);
|
||||||
}
|
}
|
||||||
|
// Reset memebrs
|
||||||
|
mClosing.store(false);
|
||||||
|
mClosed.store(false);
|
||||||
// Allow chaining
|
// Allow chaining
|
||||||
return *this;
|
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");
|
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 to keep the connection open
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -167,6 +180,7 @@ void Register_Net(HSQUIRRELVM vm)
|
|||||||
.Prop(_SC("OnClose"), &WebSocketClient::GetOnClose, &WebSocketClient::SetOnClose)
|
.Prop(_SC("OnClose"), &WebSocketClient::GetOnClose, &WebSocketClient::SetOnClose)
|
||||||
.Prop(_SC("Valid"), &WebSocketClient::IsValid)
|
.Prop(_SC("Valid"), &WebSocketClient::IsValid)
|
||||||
.Prop(_SC("Closing"), &WebSocketClient::IsClosing)
|
.Prop(_SC("Closing"), &WebSocketClient::IsClosing)
|
||||||
|
.Prop(_SC("AutoClose"), &WebSocketClient::GetAutoClose, &WebSocketClient::SetAutoClose)
|
||||||
// Member Methods
|
// Member Methods
|
||||||
.FmtFunc(_SC("SetTag"), &WebSocketClient::ApplyTag)
|
.FmtFunc(_SC("SetTag"), &WebSocketClient::ApplyTag)
|
||||||
.FmtFunc(_SC("SetData"), &WebSocketClient::ApplyData)
|
.FmtFunc(_SC("SetData"), &WebSocketClient::ApplyData)
|
||||||
|
|||||||
+40
-9
@@ -154,6 +154,18 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
|||||||
*/
|
*/
|
||||||
std::atomic< bool > mClosing{false};
|
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".
|
* 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()
|
WebSocketClient()
|
||||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
: 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
|
ChainInstance(); // Remember this instance
|
||||||
}
|
}
|
||||||
@@ -189,7 +202,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
|||||||
*/
|
*/
|
||||||
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path)
|
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path)
|
||||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
: 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())
|
, mHost(host.mPtr, host.GetSize())
|
||||||
, mPath(path.mPtr, path.GetSize())
|
, mPath(path.mPtr, path.GetSize())
|
||||||
, mOrigin(), mExtensions()
|
, mOrigin(), mExtensions()
|
||||||
@@ -202,7 +215,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
|||||||
*/
|
*/
|
||||||
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure)
|
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure)
|
||||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
: 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())
|
, mHost(host.mPtr, host.GetSize())
|
||||||
, mPath(path.mPtr, path.GetSize())
|
, mPath(path.mPtr, path.GetSize())
|
||||||
, mOrigin(), mExtensions()
|
, mOrigin(), mExtensions()
|
||||||
@@ -215,7 +228,7 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
|||||||
*/
|
*/
|
||||||
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure, StackStrF & origin)
|
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure, StackStrF & origin)
|
||||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
: 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())
|
, mHost(host.mPtr, host.GetSize())
|
||||||
, mPath(path.mPtr, path.GetSize())
|
, mPath(path.mPtr, path.GetSize())
|
||||||
, mOrigin(origin.mPtr, origin.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)
|
WebSocketClient(StackStrF & host, uint16_t port, StackStrF & path, bool secure, StackStrF & origin, StackStrF & ext)
|
||||||
: Base(), mHandle(nullptr), mQueue(1024), mOnData(), mOnClose(), mTag(), mData()
|
: 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())
|
, mHost(host.mPtr, host.GetSize())
|
||||||
, mPath(path.mPtr, path.GetSize())
|
, mPath(path.mPtr, path.GetSize())
|
||||||
, mOrigin(origin.mPtr, origin.GetSize())
|
, mOrigin(origin.mPtr, origin.GetSize())
|
||||||
@@ -289,6 +302,22 @@ struct WebSocketClient : public SqChainedInstances< WebSocketClient >
|
|||||||
return mClosing.load();
|
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.
|
* 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.
|
* 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);
|
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?
|
// 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
|
} // 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}
|
{_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)
|
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));
|
return Object(new SQLiteConnection(conn));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Object GetStatementObj(const StmtRef & stmt)
|
Object GetStatementObj(const SQLiteStmtRef & stmt)
|
||||||
{
|
{
|
||||||
return Object(new SQLiteStatement(stmt));
|
return Object(new SQLiteStatement(stmt));
|
||||||
}
|
}
|
||||||
@@ -602,6 +611,7 @@ SQLiteConnHnd::SQLiteConnHnd()
|
|||||||
, mFlags(0)
|
, mFlags(0)
|
||||||
, mName()
|
, mName()
|
||||||
, mVFS()
|
, mVFS()
|
||||||
|
, mSession()
|
||||||
, mMemory(false)
|
, mMemory(false)
|
||||||
, mTrace(false)
|
, mTrace(false)
|
||||||
, mProfile(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()
|
SQLiteConnHnd::~SQLiteConnHnd()
|
||||||
{
|
{
|
||||||
@@ -619,10 +647,17 @@ SQLiteConnHnd::~SQLiteConnHnd()
|
|||||||
Flush(static_cast<uint32_t>(mQueue.size()), NullObject(), NullFunction());
|
Flush(static_cast<uint32_t>(mQueue.size()), NullObject(), NullFunction());
|
||||||
// NOTE: Should we call sqlite3_interrupt(...) before closing?
|
// NOTE: Should we call sqlite3_interrupt(...) before closing?
|
||||||
// Attempt to close the database
|
// 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));
|
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)
|
void SQLiteConnHnd::Create(const SQChar * name, int32_t flags, const SQChar * vfs)
|
||||||
{
|
{
|
||||||
// Make sure a previous connection doesn't exist
|
// Make sure a previous connection doesn't exist
|
||||||
if (mPtr)
|
if (Access())
|
||||||
{
|
{
|
||||||
STHROWF("Unable to connect to database. Database already connected");
|
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)
|
int32_t SQLiteConnHnd::Flush(uint32_t num, Object & env, Function & func)
|
||||||
{
|
{
|
||||||
// Do we even have a valid connection?
|
// Do we even have a valid connection?
|
||||||
if (!mPtr)
|
if (!Access())
|
||||||
{
|
{
|
||||||
return -1; // No connection!
|
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)
|
: mPtr(nullptr)
|
||||||
, mStatus(SQLITE_OK)
|
, mStatus(SQLITE_OK)
|
||||||
, mConn(std::move(conn))
|
, mConnection(std::move(conn))
|
||||||
, mQuery()
|
, mQuery()
|
||||||
, mColumns(0)
|
, mColumns(0)
|
||||||
, mParameters(0)
|
, mParameters(0)
|
||||||
@@ -774,7 +809,7 @@ SQLiteStmtHnd::~SQLiteStmtHnd()
|
|||||||
// Attempt to finalize the statement
|
// Attempt to finalize the statement
|
||||||
if ((sqlite3_finalize(mPtr)) != SQLITE_OK)
|
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)
|
void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
|
||||||
{
|
{
|
||||||
// Make sure a previous statement doesn't exist
|
// Make sure a previous statement doesn't exist
|
||||||
if (mPtr)
|
if (Access())
|
||||||
{
|
{
|
||||||
STHROWF("Unable to prepare statement. Statement already prepared");
|
STHROWF("Unable to prepare statement. Statement already prepared");
|
||||||
}
|
}
|
||||||
// Is the specified database connection is valid?
|
// Is the specified database connection is valid?
|
||||||
else if (!mConn)
|
else if (!mConnection)
|
||||||
{
|
{
|
||||||
STHROWF("Unable to prepare statement. Invalid connection handle");
|
STHROWF("Unable to prepare statement. Invalid connection handle");
|
||||||
}
|
}
|
||||||
@@ -800,7 +835,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
|
|||||||
// Save the query string
|
// Save the query string
|
||||||
mQuery.assign(query, static_cast< size_t >(length));
|
mQuery.assign(query, static_cast< size_t >(length));
|
||||||
// Attempt to prepare a statement with the specified query string
|
// 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)
|
&mPtr, nullptr)) != SQLITE_OK)
|
||||||
{
|
{
|
||||||
// Clear the query string since it failed
|
// 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
|
// Explicitly make sure the handle is null
|
||||||
mPtr = nullptr;
|
mPtr = nullptr;
|
||||||
// Now it's safe to throw the error
|
// Now it's safe to throw the error
|
||||||
STHROWF("Unable to prepare statement [{}]", mConn->ErrMsg());
|
STHROWF("Unable to prepare statement [{}]", mConnection->ErrMsg());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -823,7 +858,7 @@ void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
|
|||||||
int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
|
int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
|
||||||
{
|
{
|
||||||
// Validate the handle
|
// Validate the handle
|
||||||
if (!mPtr)
|
if (!Access())
|
||||||
{
|
{
|
||||||
STHROWF("Invalid SQLite statement");
|
STHROWF("Invalid SQLite statement");
|
||||||
}
|
}
|
||||||
@@ -861,25 +896,25 @@ int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const char * SQLiteStmtHnd::ErrStr() const
|
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
|
const char * SQLiteStmtHnd::ErrMsg() const
|
||||||
{
|
{
|
||||||
return mConn ? sqlite3_errmsg(mConn->mPtr) : _SC("");
|
return mConnection ? sqlite3_errmsg(mConnection->Access()) : _SC("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
int32_t SQLiteStmtHnd::ErrNo() const
|
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
|
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);
|
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);
|
SqThrowF(SQMOD_RTFMT("Invalid SQLite connection =>[{}:{}]"), file, line);
|
||||||
}
|
}
|
||||||
@@ -933,7 +968,7 @@ void SQLiteConnection::ValidateCreated() const
|
|||||||
{
|
{
|
||||||
SqThrowF(fmt::runtime("Invalid SQLite connection reference"));
|
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"));
|
SqThrowF(fmt::runtime("Invalid SQLite connection"));
|
||||||
}
|
}
|
||||||
@@ -942,13 +977,13 @@ void SQLiteConnection::ValidateCreated() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
Validate(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const ConnRef & SQLiteConnection::GetValid() const
|
const SQLiteConnRef & SQLiteConnection::GetValid() const
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -957,13 +992,13 @@ const ConnRef & SQLiteConnection::GetValid() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
ValidateCreated(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const ConnRef & SQLiteConnection::GetCreated() const
|
const SQLiteConnRef & SQLiteConnection::GetCreated() const
|
||||||
{
|
{
|
||||||
ValidateCreated();
|
ValidateCreated();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -976,7 +1011,7 @@ void SQLiteConnection::Open(StackStrF & name)
|
|||||||
// Should we create a connection handle?
|
// Should we create a connection handle?
|
||||||
if (!m_Handle)
|
if (!m_Handle)
|
||||||
{
|
{
|
||||||
m_Handle = ConnRef(new SQLiteConnHnd());
|
m_Handle = SQLiteConnRef(new SQLiteConnHnd());
|
||||||
}
|
}
|
||||||
// Make sure another database isn't opened
|
// Make sure another database isn't opened
|
||||||
if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
|
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?
|
// Should we create a connection handle?
|
||||||
if (!m_Handle)
|
if (!m_Handle)
|
||||||
{
|
{
|
||||||
m_Handle = ConnRef(new SQLiteConnHnd());
|
m_Handle = SQLiteConnRef(new SQLiteConnHnd());
|
||||||
}
|
}
|
||||||
// Make sure another database isn't opened
|
// Make sure another database isn't opened
|
||||||
if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
|
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?
|
// Should we create a connection handle?
|
||||||
if (!m_Handle)
|
if (!m_Handle)
|
||||||
{
|
{
|
||||||
m_Handle = ConnRef(new SQLiteConnHnd());
|
m_Handle = SQLiteConnRef(new SQLiteConnHnd());
|
||||||
}
|
}
|
||||||
// Make sure another database isn't opened
|
// Make sure another database isn't opened
|
||||||
if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
|
if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
|
||||||
@@ -1029,14 +1064,14 @@ int32_t SQLiteConnection::Exec(StackStrF & str)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to execute the specified query
|
// 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
|
// Validate the execution result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
STHROWF("Unable to execute query [{}]", m_Handle->ErrMsg());
|
STHROWF("Unable to execute query [{}]", m_Handle->ErrMsg());
|
||||||
}
|
}
|
||||||
// Return rows affected by this query
|
// 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?
|
// Do we have to disable it?
|
||||||
else if (m_Handle->mTrace)
|
else if (m_Handle->mTrace)
|
||||||
{
|
{
|
||||||
sqlite3_trace(m_Handle->mPtr, nullptr, nullptr);
|
sqlite3_trace(m_Handle->Access(), nullptr, nullptr);
|
||||||
}
|
}
|
||||||
// Go ahead and enable tracing
|
// Go ahead and enable tracing
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sqlite3_trace(m_Handle->mPtr, &SQLiteConnection::TraceOutput, nullptr);
|
sqlite3_trace(m_Handle->Access(), &SQLiteConnection::TraceOutput, nullptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1133,12 +1168,12 @@ void SQLiteConnection::SetProfiling(bool SQ_UNUSED_ARG(toggle)) // NOLINT(readab
|
|||||||
// Do we have to disable it?
|
// Do we have to disable it?
|
||||||
else if (m_Handle->mProfile)
|
else if (m_Handle->mProfile)
|
||||||
{
|
{
|
||||||
sqlite3_profile(m_Handle->mPtr, nullptr, nullptr);
|
sqlite3_profile(m_Handle->Access(), nullptr, nullptr);
|
||||||
}
|
}
|
||||||
// Go ahead and enable profiling
|
// Go ahead and enable profiling
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sqlite3_profile(m_Handle->mPtr, &SQLiteConnection::ProfileOutput, nullptr);
|
sqlite3_profile(m_Handle->Access(), &SQLiteConnection::ProfileOutput, nullptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1148,7 +1183,7 @@ void SQLiteConnection::SetBusyTimeout(int32_t millis)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Apply the requested timeout
|
// 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());
|
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);
|
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);
|
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
|
||||||
}
|
}
|
||||||
@@ -1286,7 +1321,7 @@ void SQLiteParameter::ValidateCreated() const
|
|||||||
{
|
{
|
||||||
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
|
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"));
|
SqThrowF(fmt::runtime("Invalid SQLite statement"));
|
||||||
}
|
}
|
||||||
@@ -1295,13 +1330,13 @@ void SQLiteParameter::ValidateCreated() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
Validate(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const StmtRef & SQLiteParameter::GetValid() const
|
const SQLiteStmtRef & SQLiteParameter::GetValid() const
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -1310,13 +1345,13 @@ const StmtRef & SQLiteParameter::GetValid() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
ValidateCreated(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const StmtRef & SQLiteParameter::GetCreated() const
|
const SQLiteStmtRef & SQLiteParameter::GetCreated() const
|
||||||
{
|
{
|
||||||
ValidateCreated();
|
ValidateCreated();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -1377,7 +1412,7 @@ void SQLiteParameter::SetIndex(const Object & param)
|
|||||||
STHROWF("Cannot use an empty parameter name");
|
STHROWF("Cannot use an empty parameter name");
|
||||||
}
|
}
|
||||||
// Attempt to find a parameter with the specified 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;
|
} break;
|
||||||
// Is this an integer value? (or at least can be easily converted to one)
|
// Is this an integer value? (or at least can be easily converted to one)
|
||||||
case OT_INTEGER:
|
case OT_INTEGER:
|
||||||
@@ -1409,7 +1444,7 @@ void SQLiteParameter::SetIndex(const Object & param)
|
|||||||
// Attempt to find a parameter with the specified name
|
// Attempt to find a parameter with the specified name
|
||||||
else
|
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;
|
} break;
|
||||||
// We don't recognize this kind of value!
|
// We don't recognize this kind of value!
|
||||||
@@ -1432,7 +1467,7 @@ Object SQLiteParameter::GetStatement() const
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Object SQLiteParameter::GetConnection() 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);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1490,7 +1525,7 @@ void SQLiteParameter::SetChar(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1503,7 +1538,7 @@ void SQLiteParameter::SetInteger(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1516,7 +1551,7 @@ void SQLiteParameter::SetInt8(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1529,7 +1564,7 @@ void SQLiteParameter::SetUint8(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1542,7 +1577,7 @@ void SQLiteParameter::SetInt16(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1555,7 +1590,7 @@ void SQLiteParameter::SetUint16(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1568,7 +1603,7 @@ void SQLiteParameter::SetInt32(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1581,7 +1616,7 @@ void SQLiteParameter::SetUint32(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1594,7 +1629,7 @@ void SQLiteParameter::SetInt64(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1607,7 +1642,7 @@ void SQLiteParameter::SetUint64(SQInteger value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1620,7 +1655,7 @@ void SQLiteParameter::SetFloat(SQFloat value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1633,7 +1668,7 @@ void SQLiteParameter::SetFloat32(SQFloat value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1646,7 +1681,7 @@ void SQLiteParameter::SetFloat64(SQFloat value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1659,7 +1694,7 @@ void SQLiteParameter::SetString(StackStrF & value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1672,7 +1707,7 @@ void SQLiteParameter::SetStringRaw(const SQChar * value, SQInteger length)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1685,7 +1720,7 @@ void SQLiteParameter::SetZeroBlob(SQInteger size)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1717,7 +1752,7 @@ void SQLiteParameter::SetBlob(const Object & value)
|
|||||||
len = sqstd_getblobsize(vm, -1);
|
len = sqstd_getblobsize(vm, -1);
|
||||||
}
|
}
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1731,9 +1766,9 @@ void SQLiteParameter::SetData(const SqBuffer & value)
|
|||||||
Buffer & buff = *value.GetRef();
|
Buffer & buff = *value.GetRef();
|
||||||
// Attempt to bind the specified value
|
// Attempt to bind the specified value
|
||||||
#ifdef _SQ64
|
#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
|
#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
|
#endif
|
||||||
// Validate the result
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
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
|
// Attempt to bind the specified value
|
||||||
#ifdef _SQ64
|
#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
|
#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
|
#endif
|
||||||
// Validate the result
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
@@ -1780,7 +1815,7 @@ void SQLiteParameter::SetDate(const Date & value)
|
|||||||
// Attempt to generate the specified date string
|
// Attempt to generate the specified date string
|
||||||
auto str = fmt::format("{} 00:00:00", value.ToString());
|
auto str = fmt::format("{} 00:00:00", value.ToString());
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
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
|
// Attempt to generate the specified date string
|
||||||
auto str = fmt::format("{}-{}-{} 00:00:00", y, m, d);
|
auto str = fmt::format("{}-{}-{} 00:00:00", y, m, d);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1816,7 +1851,7 @@ void SQLiteParameter::SetTime(const Time & value)
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
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);
|
STHROWF("Second value is out of range: {} >= 60", s);
|
||||||
}
|
}
|
||||||
// Calculate the number of seconds in the specified time and bind the resulted value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
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
|
// Attempt to generate the specified date string
|
||||||
auto str = fmt::format(_SC("{:04}-{:02}-{:02} {:02}:{:02}:{:02}"), y, mo, d, h, mi, s);
|
auto str = fmt::format(_SC("{:04}-{:02}-{:02} {:02}:{:02}:{:02}"), y, mo, d, h, mi, s);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -1909,7 +1944,7 @@ void SQLiteParameter::SetNow()
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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)));
|
static_cast< int32_t >(std::time(nullptr)));
|
||||||
// Validate the result
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
@@ -1923,7 +1958,7 @@ void SQLiteParameter::SetNull()
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_CREATED(*this);
|
SQMOD_VALIDATE_CREATED(*this);
|
||||||
// Attempt to bind the specified value
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
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);
|
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);
|
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
|
||||||
}
|
}
|
||||||
@@ -1992,7 +2027,7 @@ void SQLiteColumn::ValidateCreated() const
|
|||||||
{
|
{
|
||||||
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
|
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"));
|
SqThrowF(fmt::runtime("Invalid SQLite statement"));
|
||||||
}
|
}
|
||||||
@@ -2001,13 +2036,13 @@ void SQLiteColumn::ValidateCreated() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
Validate(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const StmtRef & SQLiteColumn::GetValid() const
|
const SQLiteStmtRef & SQLiteColumn::GetValid() const
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -2016,13 +2051,13 @@ const StmtRef & SQLiteColumn::GetValid() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
ValidateCreated(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const StmtRef & SQLiteColumn::GetCreated() const
|
const SQLiteStmtRef & SQLiteColumn::GetCreated() const
|
||||||
{
|
{
|
||||||
ValidateCreated();
|
ValidateCreated();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -2161,7 +2196,7 @@ Object SQLiteColumn::GetStatement() const
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Object SQLiteColumn::GetConnection() 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
|
// Obtain the initial stack size
|
||||||
const StackGuard sg;
|
const StackGuard sg;
|
||||||
// Identify which type of value must be pushed on the stack
|
// 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?
|
// Is this a null value?
|
||||||
case SQLITE_NULL:
|
case SQLITE_NULL:
|
||||||
@@ -2217,28 +2252,28 @@ Object SQLiteColumn::GetValue() const
|
|||||||
// Is this an integer?
|
// Is this an integer?
|
||||||
case SQLITE_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;
|
} break;
|
||||||
// Is this a floating point?
|
// Is this a floating point?
|
||||||
case SQLITE_FLOAT:
|
case SQLITE_FLOAT:
|
||||||
{
|
{
|
||||||
sq_pushfloat(SqVM(),
|
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;
|
} break;
|
||||||
// Is this a string?
|
// Is this a string?
|
||||||
case SQLITE_TEXT:
|
case SQLITE_TEXT:
|
||||||
{
|
{
|
||||||
sq_pushstring(SqVM(),
|
sq_pushstring(SqVM(),
|
||||||
reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index)),
|
reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->Access(), m_Index)),
|
||||||
sqlite3_column_bytes(m_Handle->mPtr, m_Index));
|
sqlite3_column_bytes(m_Handle->Access(), m_Index));
|
||||||
} break;
|
} break;
|
||||||
// Is this raw data?
|
// Is this raw data?
|
||||||
case SQLITE_BLOB:
|
case SQLITE_BLOB:
|
||||||
{
|
{
|
||||||
// Retrieve the size of the blob that must be allocated
|
// 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
|
// 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
|
// Attempt to create a buffer with the blob data on the stack
|
||||||
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
|
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
|
||||||
} break;
|
} break;
|
||||||
@@ -2256,7 +2291,7 @@ Object SQLiteColumn::GetNumber() const
|
|||||||
// Obtain the initial stack size
|
// Obtain the initial stack size
|
||||||
const StackGuard sg;
|
const StackGuard sg;
|
||||||
// Identify which type of value must be pushed on the stack
|
// 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?
|
// Is this a null value?
|
||||||
case SQLITE_NULL:
|
case SQLITE_NULL:
|
||||||
@@ -2266,18 +2301,18 @@ Object SQLiteColumn::GetNumber() const
|
|||||||
// Is this an integer?
|
// Is this an integer?
|
||||||
case SQLITE_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;
|
} break;
|
||||||
// Is this a floating point?
|
// Is this a floating point?
|
||||||
case SQLITE_FLOAT:
|
case SQLITE_FLOAT:
|
||||||
{
|
{
|
||||||
sq_pushfloat(SqVM(),
|
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;
|
} break;
|
||||||
// Is this a string?
|
// Is this a string?
|
||||||
case SQLITE_TEXT:
|
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?
|
// Is there even a string to parse?
|
||||||
if (!str || *str == '\0')
|
if (!str || *str == '\0')
|
||||||
{
|
{
|
||||||
@@ -2308,7 +2343,7 @@ SQInteger SQLiteColumn::GetInteger() const
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_ROW(*this);
|
SQMOD_VALIDATE_ROW(*this);
|
||||||
// Return the requested information
|
// 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);
|
SQMOD_VALIDATE_ROW(*this);
|
||||||
// Return the requested information
|
// 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);
|
SQMOD_VALIDATE_ROW(*this);
|
||||||
// Return the requested information
|
// 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
|
// Obtain the initial stack size
|
||||||
const StackGuard sg;
|
const StackGuard sg;
|
||||||
// Push the column text on the stack
|
// Push the column text on the stack
|
||||||
sq_pushstring(SqVM(), reinterpret_cast< const SQChar * >(sqlite3_column_text(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->mPtr, m_Index));
|
sqlite3_column_bytes(m_Handle->Access(), m_Index));
|
||||||
// Get the object from the stack and return it
|
// Get the object from the stack and return it
|
||||||
return Var< Object >(SqVM(), -1).value;
|
return Var< Object >(SqVM(), -1).value;
|
||||||
}
|
}
|
||||||
@@ -2345,7 +2380,7 @@ bool SQLiteColumn::GetBoolean() const
|
|||||||
{
|
{
|
||||||
SQMOD_VALIDATE_ROW(*this);
|
SQMOD_VALIDATE_ROW(*this);
|
||||||
// Return the requested information
|
// 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);
|
SQMOD_VALIDATE_ROW(*this);
|
||||||
// Return the requested information
|
// 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
|
// Remember the current stack size
|
||||||
const StackGuard sg;
|
const StackGuard sg;
|
||||||
// Retrieve the size of the blob that must be allocated
|
// 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
|
// 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
|
// Attempt to create a buffer with the blob data on the stack
|
||||||
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
|
Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
|
||||||
// Get the object from the stack and return it
|
// Get the object from the stack and return it
|
||||||
@@ -2379,11 +2414,11 @@ Object SQLiteColumn::GetBlob() const
|
|||||||
// Obtain the initial stack size
|
// Obtain the initial stack size
|
||||||
const StackGuard sg;
|
const StackGuard sg;
|
||||||
// Obtain the size of the data
|
// 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
|
// Allocate a blob of the same size
|
||||||
SQUserPointer p = sqstd_createblob(SqVM(), sz);
|
SQUserPointer p = sqstd_createblob(SqVM(), sz);
|
||||||
// Obtain a pointer to the data
|
// 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?
|
// Could the memory blob be allocated?
|
||||||
if (!p)
|
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);
|
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);
|
SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
|
||||||
}
|
}
|
||||||
@@ -2445,7 +2480,7 @@ void SQLiteStatement::ValidateCreated() const
|
|||||||
{
|
{
|
||||||
SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
|
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"));
|
SqThrowF(fmt::runtime("Invalid SQLite statement"));
|
||||||
}
|
}
|
||||||
@@ -2454,13 +2489,13 @@ void SQLiteStatement::ValidateCreated() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
Validate(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const StmtRef & SQLiteStatement::GetValid() const
|
const SQLiteStmtRef & SQLiteStatement::GetValid() const
|
||||||
{
|
{
|
||||||
Validate();
|
Validate();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -2469,13 +2504,13 @@ const StmtRef & SQLiteStatement::GetValid() const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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);
|
ValidateCreated(file, line);
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const StmtRef & SQLiteStatement::GetCreated() const
|
const SQLiteStmtRef & SQLiteStatement::GetCreated() const
|
||||||
{
|
{
|
||||||
ValidateCreated();
|
ValidateCreated();
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
@@ -2561,7 +2596,7 @@ SQLiteStatement::SQLiteStatement(const SQLiteConnection & connection, StackStrF
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Object SQLiteStatement::GetConnection() const
|
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->mGood = false;
|
||||||
m_Handle->mDone = false;
|
m_Handle->mDone = false;
|
||||||
// Attempt to reset the statement to it's initial state
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -2590,7 +2625,7 @@ SQLiteStatement & SQLiteStatement::Clear()
|
|||||||
m_Handle->mGood = false;
|
m_Handle->mGood = false;
|
||||||
m_Handle->mDone = false;
|
m_Handle->mDone = false;
|
||||||
// Attempt to clear the statement
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -2610,7 +2645,7 @@ int32_t SQLiteStatement::Exec()
|
|||||||
STHROWF("Executed without resetting first");
|
STHROWF("Executed without resetting first");
|
||||||
}
|
}
|
||||||
// Attempt to step the statement
|
// 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?
|
// Have we finished stepping?
|
||||||
if (m_Handle->mStatus == SQLITE_DONE)
|
if (m_Handle->mStatus == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
@@ -2618,7 +2653,7 @@ int32_t SQLiteStatement::Exec()
|
|||||||
m_Handle->mGood = false;
|
m_Handle->mGood = false;
|
||||||
m_Handle->mDone = true;
|
m_Handle->mDone = true;
|
||||||
// Return the changes made by this statement
|
// 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
|
// Specify that we don't have any row and we haven't finished stepping
|
||||||
m_Handle->mGood = false;
|
m_Handle->mGood = false;
|
||||||
@@ -2651,7 +2686,7 @@ bool SQLiteStatement::Step()
|
|||||||
STHROWF("Stepped without resetting first");
|
STHROWF("Stepped without resetting first");
|
||||||
}
|
}
|
||||||
// Attempt to step the statement
|
// 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?
|
// Do we have a row available?
|
||||||
if (m_Handle->mStatus == SQLITE_ROW)
|
if (m_Handle->mStatus == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
@@ -2801,7 +2836,7 @@ Table SQLiteStatement::GetTable(int32_t min, int32_t max) const
|
|||||||
while (min <= max)
|
while (min <= max)
|
||||||
{
|
{
|
||||||
// Attempt to obtain the column name
|
// 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
|
// Validate the obtained name
|
||||||
if (!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)
|
: m_Handle(std::move(db)), m_Committed(false)
|
||||||
{
|
{
|
||||||
// Was the specified database connection valid?
|
// Was the specified database connection valid?
|
||||||
@@ -2833,7 +2868,7 @@ SQLiteTransaction::SQLiteTransaction(ConnRef db)
|
|||||||
STHROWF("Invalid connection handle");
|
STHROWF("Invalid connection handle");
|
||||||
}
|
}
|
||||||
// Attempt to begin transaction
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -2850,7 +2885,7 @@ SQLiteTransaction::~SQLiteTransaction()
|
|||||||
return; // We're done here!
|
return; // We're done here!
|
||||||
}
|
}
|
||||||
// Attempt to roll back changes because this failed to commit
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
@@ -2873,7 +2908,7 @@ bool SQLiteTransaction::Commit()
|
|||||||
STHROWF("Transaction was already committed");
|
STHROWF("Transaction was already committed");
|
||||||
}
|
}
|
||||||
// Attempt to commit the change during this transaction
|
// 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
|
// Validate the result
|
||||||
if (m_Handle->mStatus != SQLITE_OK)
|
if (m_Handle->mStatus != SQLITE_OK)
|
||||||
{
|
{
|
||||||
|
|||||||
+115
-50
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include "Core/Utility.hpp"
|
#include "Core/Utility.hpp"
|
||||||
|
#include "Core/ThreadPool.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include "Library/IO/Buffer.hpp"
|
#include "Library/IO/Buffer.hpp"
|
||||||
@@ -10,6 +11,10 @@
|
|||||||
#include "Library/Chrono/Time.hpp"
|
#include "Library/Chrono/Time.hpp"
|
||||||
#include "Library/Chrono/Timestamp.hpp"
|
#include "Library/Chrono/Timestamp.hpp"
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "Poco/AutoPtr.h"
|
||||||
|
#include "Poco/Data/SessionImpl.h"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -78,18 +83,18 @@ struct SQLiteStmtHnd;
|
|||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Common typedefs.
|
* Common typedefs.
|
||||||
*/
|
*/
|
||||||
typedef SharedPtr< SQLiteConnHnd > ConnRef;
|
typedef SharedPtr< SQLiteConnHnd > SQLiteConnRef;
|
||||||
typedef SharedPtr< SQLiteStmtHnd > StmtRef;
|
typedef SharedPtr< SQLiteStmtHnd > SQLiteStmtRef;
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Obtain a script object from a connection handle. (meant to avoid having to include the header)
|
* 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)
|
* 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.
|
* 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 mName; // The specified name to be used as the database file.
|
||||||
String mVFS; // The specified virtual file system.
|
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 mMemory; // Whether the database exists in memory and not disk.
|
||||||
bool mTrace; // Whether tracing was activated on the database.
|
bool mTrace; // Whether tracing was activated on the database.
|
||||||
@@ -188,6 +196,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
SQLiteConnHnd();
|
SQLiteConnHnd();
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Explicit constructor.
|
||||||
|
*/
|
||||||
|
explicit SQLiteConnHnd(Poco::Data::SessionImpl * session);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Explicit constructor.
|
||||||
|
*/
|
||||||
|
explicit SQLiteConnHnd(Poco::AutoPtr< Poco::Data::SessionImpl > && session);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Copy constructor. (disabled)
|
* Copy constructor. (disabled)
|
||||||
*/
|
*/
|
||||||
@@ -254,6 +272,20 @@ public:
|
|||||||
{
|
{
|
||||||
return sqlite3_extended_errcode(mPtr);
|
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.
|
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.
|
String mQuery; // The query string used to create this statement.
|
||||||
@@ -303,7 +335,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
explicit SQLiteStmtHnd(ConnRef conn);
|
explicit SQLiteStmtHnd(SQLiteConnRef conn);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Copy constructor. (disabled)
|
* Copy constructor. (disabled)
|
||||||
@@ -375,6 +407,20 @@ public:
|
|||||||
* Return the extended numeric result code for the most recent failed API call (if any).
|
* Return the extended numeric result code for the most recent failed API call (if any).
|
||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD int32_t ExErrNo() const;
|
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:
|
private:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
ConnRef m_Handle; // Reference to the managed connection.
|
SQLiteConnRef m_Handle; // Reference to the managed connection.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -421,18 +467,18 @@ protected:
|
|||||||
* Validate the managed connection handle and throw an error if invalid.
|
* Validate the managed connection handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const ConnRef & GetValid() const;
|
SQMOD_NODISCARD const SQLiteConnRef & GetValid() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Validate the managed connection handle and throw an error if invalid.
|
* Validate the managed connection handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const ConnRef & GetCreated() const;
|
SQMOD_NODISCARD const SQLiteConnRef & GetCreated() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -479,7 +525,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Direct handle constructor.
|
* Direct handle constructor.
|
||||||
*/
|
*/
|
||||||
explicit SQLiteConnection(ConnRef c)
|
explicit SQLiteConnection(SQLiteConnRef c)
|
||||||
: m_Handle(std::move(c))
|
: m_Handle(std::move(c))
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
@@ -526,7 +572,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
operator sqlite3 * () //NOLINT (intentionally implicit)
|
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)
|
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.
|
* Retrieve the associated connection handle.
|
||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD const ConnRef & GetHandle() const
|
SQMOD_NODISCARD const SQLiteConnRef & GetHandle() const
|
||||||
{
|
{
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
@@ -566,7 +612,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD bool IsConnected() const
|
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;
|
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.
|
* See if the database connection was opened in read-only mode.
|
||||||
*/
|
*/
|
||||||
@@ -857,8 +913,8 @@ class SQLiteParameter
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
int32_t m_Index{0}; // The index of the managed parameter.
|
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:
|
protected:
|
||||||
|
|
||||||
@@ -884,18 +940,18 @@ protected:
|
|||||||
* Validate the managed statement handle and throw an error if invalid.
|
* Validate the managed statement handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const StmtRef & GetValid() const;
|
SQMOD_NODISCARD const SQLiteStmtRef & GetValid() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Validate the managed statement handle and throw an error if invalid.
|
* Validate the managed statement handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const StmtRef & GetCreated() const;
|
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -943,7 +999,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* No parameter constructor.
|
* No parameter constructor.
|
||||||
*/
|
*/
|
||||||
explicit SQLiteParameter(StmtRef stmt)
|
explicit SQLiteParameter(SQLiteStmtRef stmt)
|
||||||
: m_Index(0), m_Handle(std::move(stmt))
|
: m_Index(0), m_Handle(std::move(stmt))
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
@@ -952,7 +1008,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Index constructor.
|
* Index constructor.
|
||||||
*/
|
*/
|
||||||
SQLiteParameter(StmtRef stmt, int32_t idx)
|
SQLiteParameter(SQLiteStmtRef stmt, int32_t idx)
|
||||||
: m_Index(idx), m_Handle(std::move(stmt))
|
: m_Index(idx), m_Handle(std::move(stmt))
|
||||||
{
|
{
|
||||||
SQMOD_VALIDATE_PARAM(*this, m_Index);
|
SQMOD_VALIDATE_PARAM(*this, m_Index);
|
||||||
@@ -961,7 +1017,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Name constructor.
|
* 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)
|
: m_Index(stmt ? sqlite3_bind_parameter_index(stmt->mPtr, name) : 0), m_Handle(stmt)
|
||||||
{
|
{
|
||||||
SQMOD_VALIDATE_PARAM(*this, m_Index);
|
SQMOD_VALIDATE_PARAM(*this, m_Index);
|
||||||
@@ -970,7 +1026,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Dynamic constructor.
|
* Dynamic constructor.
|
||||||
*/
|
*/
|
||||||
SQLiteParameter(StmtRef stmt, const Object & param)
|
SQLiteParameter(SQLiteStmtRef stmt, const Object & param)
|
||||||
: m_Index(0), m_Handle(std::move(stmt))
|
: m_Index(0), m_Handle(std::move(stmt))
|
||||||
{
|
{
|
||||||
if (!m_Handle)
|
if (!m_Handle)
|
||||||
@@ -1033,7 +1089,7 @@ public:
|
|||||||
// Can we attempt to return the parameter name?
|
// Can we attempt to return the parameter name?
|
||||||
if (m_Handle && m_Index)
|
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 the value if valid
|
||||||
return val ? val : String{};
|
return val ? val : String{};
|
||||||
}
|
}
|
||||||
@@ -1252,7 +1308,7 @@ private:
|
|||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
int32_t m_Index{-1}; // The index of the managed column.
|
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:
|
protected:
|
||||||
|
|
||||||
@@ -1278,18 +1334,18 @@ protected:
|
|||||||
* Validate the managed statement handle and throw an error if invalid.
|
* Validate the managed statement handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const StmtRef & GetValid() const;
|
SQMOD_NODISCARD const SQLiteStmtRef & GetValid() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Validate the managed statement handle and throw an error if invalid.
|
* Validate the managed statement handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const StmtRef & GetCreated() const;
|
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -1346,7 +1402,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* No column constructor.
|
* No column constructor.
|
||||||
*/
|
*/
|
||||||
explicit SQLiteColumn(StmtRef stmt)
|
explicit SQLiteColumn(SQLiteStmtRef stmt)
|
||||||
: m_Index(-1), m_Handle(std::move(stmt))
|
: m_Index(-1), m_Handle(std::move(stmt))
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
@@ -1355,7 +1411,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Index constructor.
|
* Index constructor.
|
||||||
*/
|
*/
|
||||||
SQLiteColumn(StmtRef stmt, int32_t idx)
|
SQLiteColumn(SQLiteStmtRef stmt, int32_t idx)
|
||||||
: m_Index(idx), m_Handle(std::move(stmt))
|
: m_Index(idx), m_Handle(std::move(stmt))
|
||||||
{
|
{
|
||||||
SQMOD_VALIDATE_COLUMN(*this, m_Index);
|
SQMOD_VALIDATE_COLUMN(*this, m_Index);
|
||||||
@@ -1364,7 +1420,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Name constructor.
|
* 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)
|
: m_Index(stmt ? stmt->GetColumnIndex(name) : -1), m_Handle(stmt)
|
||||||
{
|
{
|
||||||
SQMOD_VALIDATE_COLUMN(*this, m_Index);
|
SQMOD_VALIDATE_COLUMN(*this, m_Index);
|
||||||
@@ -1373,7 +1429,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Dynamic constructor.
|
* Dynamic constructor.
|
||||||
*/
|
*/
|
||||||
SQLiteColumn(StmtRef stmt, const Object & column)
|
SQLiteColumn(SQLiteStmtRef stmt, const Object & column)
|
||||||
: m_Index(-1), m_Handle(std::move(stmt))
|
: m_Index(-1), m_Handle(std::move(stmt))
|
||||||
{
|
{
|
||||||
if (!m_Handle)
|
if (!m_Handle)
|
||||||
@@ -1436,7 +1492,7 @@ public:
|
|||||||
// Can we attempt to return the parameter name?
|
// Can we attempt to return the parameter name?
|
||||||
if (m_Handle && m_Index)
|
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 the value if valid
|
||||||
return val ? val : String{};
|
return val ? val : String{};
|
||||||
}
|
}
|
||||||
@@ -1573,7 +1629,7 @@ class SQLiteStatement
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
StmtRef m_Handle; // Reference to the managed statement.
|
SQLiteStmtRef m_Handle; // Reference to the managed statement.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -1599,18 +1655,18 @@ protected:
|
|||||||
* Validate the managed statement handle and throw an error if invalid.
|
* Validate the managed statement handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const StmtRef & GetValid() const;
|
SQMOD_NODISCARD const SQLiteStmtRef & GetValid() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Validate the managed statement handle and throw an error if invalid.
|
* Validate the managed statement handle and throw an error if invalid.
|
||||||
*/
|
*/
|
||||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
#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
|
#else
|
||||||
SQMOD_NODISCARD const StmtRef & GetCreated() const;
|
SQMOD_NODISCARD const SQLiteStmtRef & GetCreated() const;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@@ -1654,12 +1710,21 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Construct a statement under the specified connection using the specified string.
|
* 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))
|
: m_Handle(new SQLiteStmtHnd(connection))
|
||||||
{
|
{
|
||||||
SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen);
|
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.
|
* Construct a statement under the specified connection using the specified string.
|
||||||
*/
|
*/
|
||||||
@@ -1668,7 +1733,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Direct handle constructor.
|
* Direct handle constructor.
|
||||||
*/
|
*/
|
||||||
explicit SQLiteStatement(StmtRef s)
|
explicit SQLiteStatement(SQLiteStmtRef s)
|
||||||
: m_Handle(std::move(s))
|
: m_Handle(std::move(s))
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
@@ -1715,7 +1780,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
operator sqlite3_stmt * () // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
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)
|
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.
|
* Retrieve the associated statement handle.
|
||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD const StmtRef & GetHandle() const
|
SQMOD_NODISCARD const SQLiteStmtRef & GetHandle() const
|
||||||
{
|
{
|
||||||
return m_Handle;
|
return m_Handle;
|
||||||
}
|
}
|
||||||
@@ -1755,7 +1820,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
SQMOD_NODISCARD bool IsPrepared() const
|
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.
|
* Construct using the direct connection handle.
|
||||||
*/
|
*/
|
||||||
explicit SQLiteTransaction(ConnRef db);
|
explicit SQLiteTransaction(SQLiteConnRef db);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Copy constructor. (disabled)
|
* Copy constructor. (disabled)
|
||||||
@@ -2495,7 +2560,7 @@ public:
|
|||||||
private:
|
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.
|
bool m_Committed{false}; // Whether changes were successfully committed to the database.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_DECL_TYPENAME(SqIdPoolTypename, _SC("SqIdPool"))
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Probably not the best implementation but should cover all sorts of weird cases.
|
* 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_Vector(HSQUIRRELVM vm, Table & ns);
|
||||||
extern void Register_Native_String(HSQUIRRELVM vm, Table & ns);
|
extern void Register_Native_String(HSQUIRRELVM vm, Table & ns);
|
||||||
extern void Register_ServerAnnouncer(HSQUIRRELVM vm, Table & ns);
|
extern void Register_ServerAnnouncer(HSQUIRRELVM vm, Table & ns);
|
||||||
|
|
||||||
|
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
void Register_Utils(HSQUIRRELVM vm)
|
void Register_Utils(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
Table ns(vm);
|
Table ns(vm);
|
||||||
|
|
||||||
|
Register_IdPool(vm, ns);
|
||||||
Register_Vector(vm, ns);
|
Register_Vector(vm, ns);
|
||||||
Register_Native_String(vm, ns);
|
Register_Native_String(vm, ns);
|
||||||
Register_ServerAnnouncer(vm, ns);
|
Register_ServerAnnouncer(vm, ns);
|
||||||
@@ -101,4 +107,35 @@ void Register_Utils(HSQUIRRELVM vm)
|
|||||||
RootTable(vm).Bind(_SC("SqUtils"), ns);
|
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
|
} // Namespace:: SqMod
|
||||||
|
|||||||
@@ -6,4 +6,187 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
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
|
} // 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)
|
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);
|
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.
|
* Send a log message.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+10
-3
@@ -17,7 +17,7 @@ namespace SqMod {
|
|||||||
static bool g_Reload = false;
|
static bool g_Reload = false;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
//extern void InitExports();
|
extern void InitExports();
|
||||||
extern void InitializeNet();
|
extern void InitializeNet();
|
||||||
extern void InitializePocoDataConnectors();
|
extern void InitializePocoDataConnectors();
|
||||||
extern void ProcessRoutines();
|
extern void ProcessRoutines();
|
||||||
@@ -97,7 +97,7 @@ static uint8_t OnServerInitialise()
|
|||||||
{
|
{
|
||||||
SQMOD_SV_EV_TRACEBACK("[TRACE<] OnServerInitialise")
|
SQMOD_SV_EV_TRACEBACK("[TRACE<] OnServerInitialise")
|
||||||
// Signal outside plug-ins to do fetch our proxies
|
// 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
|
// Attempt to load the module core
|
||||||
if (Core::Get().Execute())
|
if (Core::Get().Execute())
|
||||||
{
|
{
|
||||||
@@ -965,6 +965,11 @@ static void OnServerPerformanceReport(size_t /*entry_count*/, const char * * /*d
|
|||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* Automatically terminate the third-party allocator.
|
||||||
|
*/
|
||||||
|
static std::unique_ptr< SqMod::RPMallocInit > gsRPMallocInit;
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Plug-in initialization procedure.
|
* Plug-in initialization procedure.
|
||||||
*/
|
*/
|
||||||
@@ -989,6 +994,8 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback
|
|||||||
_Info->apiMinorVersion = PLUGIN_API_MINOR;
|
_Info->apiMinorVersion = PLUGIN_API_MINOR;
|
||||||
// Assign the plug-in name
|
// Assign the plug-in name
|
||||||
std::snprintf(_Info->name, sizeof(_Info->name), "%s", SQMOD_HOST_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
|
// Attempt to initialize the logger before anything else
|
||||||
Logger::Get().Initialize(nullptr);
|
Logger::Get().Initialize(nullptr);
|
||||||
// Attempt to initialize the plug-in core
|
// Attempt to initialize the plug-in core
|
||||||
@@ -1076,7 +1083,7 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback
|
|||||||
_Clbk->OnEntityStreamingChange = OnEntityStreamingChange;
|
_Clbk->OnEntityStreamingChange = OnEntityStreamingChange;
|
||||||
#endif
|
#endif
|
||||||
// Attempt to initialize the plug-in exports
|
// Attempt to initialize the plug-in exports
|
||||||
//InitExports();
|
InitExports();
|
||||||
// Dummy spacing
|
// Dummy spacing
|
||||||
puts("");
|
puts("");
|
||||||
// Initialization was successful
|
// Initialization was successful
|
||||||
|
|||||||
+123
-62
@@ -52,6 +52,66 @@ SQMOD_DECL_TYPENAME(CPickupTn, _SC("CPickup"))
|
|||||||
SQMOD_DECL_TYPENAME(CPlayerTn, _SC("CPlayer"))
|
SQMOD_DECL_TYPENAME(CPlayerTn, _SC("CPlayer"))
|
||||||
SQMOD_DECL_TYPENAME(CVehicleTn, _SC("CVehicle"))
|
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.
|
* Entity type enumeration.
|
||||||
*/
|
*/
|
||||||
@@ -250,10 +310,10 @@ void LgEntityQuaternion::Set()
|
|||||||
case LgEntityType::Vehicle:
|
case LgEntityType::Vehicle:
|
||||||
switch (mFlag)
|
switch (mFlag)
|
||||||
{
|
{
|
||||||
case LgVehicleVectorFlag::Angle:
|
case LgVehicleQuaternionFlag::Angle:
|
||||||
_Func->SetVehicleRotation(mID, x, y, z, w);
|
_Func->SetVehicleRotation(mID, x, y, z, w);
|
||||||
break;
|
break;
|
||||||
case LgVehicleVectorFlag::SpawnAngle:
|
case LgVehicleQuaternionFlag::SpawnAngle:
|
||||||
_Func->SetVehicleSpawnRotation(mID, x, y, z, w);
|
_Func->SetVehicleSpawnRotation(mID, x, y, z, w);
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
@@ -438,14 +498,14 @@ struct LgCheckpoint
|
|||||||
SQMOD_NODISCARD int GetWorld() const { return Get().GetWorld(); }
|
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 LgARGB GetColor() const { const Color4 c = Get().GetColor(); return LgARGB{c.a, c.r, c.g, c.b}; }
|
||||||
SQMOD_NODISCARD LgEntityVector GetPos() const
|
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 float GetRadius() const { return Get().GetRadius(); }
|
||||||
SQMOD_NODISCARD int GetID() const { return mID; }
|
SQMOD_NODISCARD int GetID() const { return mID; }
|
||||||
SQMOD_NODISCARD LgPlayer * GetOwner() const
|
SQMOD_NODISCARD LgPlayer * GetOwner() const
|
||||||
{ const int id = Get().GetOwnerID(); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
|
{ const int id = Get().GetOwnerID(); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
void Delete() const { _Func->DeleteCheckPoint(GetIdentifier()); }
|
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 GetAlpha() const { return Get().GetAlpha(); }
|
||||||
SQMOD_NODISCARD int GetWorld() const { return Get().GetWorld(); }
|
SQMOD_NODISCARD int GetWorld() const { return Get().GetWorld(); }
|
||||||
SQMOD_NODISCARD LgEntityVector GetPos() const
|
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
|
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
|
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 int GetID() const { return mID; }
|
||||||
SQMOD_NODISCARD bool GetReportingShots() const { return Get().GetShotReport(); }
|
SQMOD_NODISCARD bool GetReportingShots() const { return Get().GetShotReport(); }
|
||||||
SQMOD_NODISCARD bool GetReportingBumps() const { return Get().GetTouchedReport(); }
|
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 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 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)); }
|
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 bool GetAuto() const { return Get().GetAutomatic(); }
|
||||||
SQMOD_NODISCARD int GetAutoTimer() const { return Get().GetAutoTimer(); }
|
SQMOD_NODISCARD int GetAutoTimer() const { return Get().GetAutoTimer(); }
|
||||||
SQMOD_NODISCARD LgEntityVector GetPos() const
|
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 GetModel() const { return Get().GetModel(); }
|
||||||
SQMOD_NODISCARD int GetQuantity() const { return Get().GetQuantity(); }
|
SQMOD_NODISCARD int GetQuantity() const { return Get().GetQuantity(); }
|
||||||
SQMOD_NODISCARD int GetID() const { return mID; }
|
SQMOD_NODISCARD int GetID() const { return mID; }
|
||||||
@@ -595,7 +655,7 @@ struct LgPickup
|
|||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
void Delete() const { _Func->DeletePickup(GetIdentifier()); }
|
void Delete() const { _Func->DeletePickup(GetIdentifier()); }
|
||||||
void Respawn() const { Get().Refresh(); }
|
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 SetScore(int score) const { Get().SetScore(score); }
|
||||||
void SetImmunity(uint32_t immunity) const { Get().SetImmunity(immunity); }
|
void SetImmunity(uint32_t immunity) const { Get().SetImmunity(immunity); }
|
||||||
void SetHeading(float heading) const { Get().SetHeading(heading); }
|
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 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 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)); }
|
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); }
|
void SetWantedLevel(int level) const { Get().SetWantedLevel(level); }
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
SQMOD_NODISCARD LgEntityVector GetPosition() const
|
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 int GetClass() const { return Get().GetClass(); }
|
||||||
SQMOD_NODISCARD bool GetAdmin() const { return Get().GetAdmin(); }
|
SQMOD_NODISCARD bool GetAdmin() const { return Get().GetAdmin(); }
|
||||||
SQMOD_NODISCARD const SQChar * GetIP() const { return Get().GetIP(); }
|
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 const SQChar * GetName() const { return Get().GetName(); }
|
||||||
SQMOD_NODISCARD int GetTeam() const { return Get().GetTeam(); }
|
SQMOD_NODISCARD int GetTeam() const { return Get().GetTeam(); }
|
||||||
SQMOD_NODISCARD int GetSkin() const { return Get().GetSkin(); }
|
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 GetMoney() const { return Get().GetMoney(); }
|
||||||
SQMOD_NODISCARD int GetScore() const { return Get().GetScore(); }
|
SQMOD_NODISCARD int GetScore() const { return Get().GetScore(); }
|
||||||
SQMOD_NODISCARD int GetPing() const { return Get().GetPing(); }
|
SQMOD_NODISCARD int GetPing() const { return Get().GetPing(); }
|
||||||
@@ -724,7 +784,7 @@ struct LgPlayer
|
|||||||
SQMOD_NODISCARD LgPlayer * GetSpectateTarget() const
|
SQMOD_NODISCARD LgPlayer * GetSpectateTarget() const
|
||||||
{ const int id = _Func->GetPlayerSpectateTarget(GetIdentifier()); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
|
{ const int id = _Func->GetPlayerSpectateTarget(GetIdentifier()); return VALID_ENTITYEX(id, SQMOD_PLAYER_POOL) ? Core::Get().GetPlayer(id).mLgInst : nullptr; }
|
||||||
SQMOD_NODISCARD LgEntityVector GetSpeed() const
|
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 GetCanUseColors() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionChatTagsEnabled) >= 1; }
|
||||||
SQMOD_NODISCARD bool GetMarkerVisible() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker) >= 1; }
|
SQMOD_NODISCARD bool GetMarkerVisible() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker) >= 1; }
|
||||||
SQMOD_NODISCARD bool GetDrunkStatus() const { return _Func->GetPlayerOption(GetIdentifier(), vcmpPlayerOptionDrunkEffects) >= 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 GetWeaponAtSlot(int slot) const { return Get().GetWeaponAtSlot(slot); }
|
||||||
SQMOD_NODISCARD int GetAmmoAtSlot(int slot) const { return Get().GetAmmoAtSlot(slot); }
|
SQMOD_NODISCARD int GetAmmoAtSlot(int slot) const { return Get().GetAmmoAtSlot(slot); }
|
||||||
void SetAlpha(int alpha, int fadeTime) const { Get().SetAlphaEx(alpha, fadeTime); }
|
void SetAlpha(int alpha, int fadeTime) const { Get().SetAlphaEx(alpha, fadeTime); }
|
||||||
SQMOD_NODISCARD bool StreamedToPlayer(const LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
SQMOD_NODISCARD bool StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||||
void SetVehicleSlot(const LgVehicle & vehicle, int slot) const;
|
void SetVehicleSlot(LightObj & vehicle, int slot) const;
|
||||||
void Select() const { Get().ForceSelect(); }
|
void Select() const { Get().ForceSelect(); }
|
||||||
void RestoreCamera() const { Get().RestoreCamera(); }
|
void RestoreCamera() const { Get().RestoreCamera(); }
|
||||||
void RemoveMarker() const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker, 0); }
|
void RemoveMarker() const { _Func->SetPlayerOption(GetIdentifier(), vcmpPlayerOptionHasMarker, 0); }
|
||||||
@@ -875,13 +935,13 @@ struct LgVehicle
|
|||||||
SQMOD_NODISCARD int GetModel() const { return Get().GetModel(); }
|
SQMOD_NODISCARD int GetModel() const { return Get().GetModel(); }
|
||||||
SQMOD_NODISCARD uint32_t GetImmunity() const { return Get().GetImmunity(); }
|
SQMOD_NODISCARD uint32_t GetImmunity() const { return Get().GetImmunity(); }
|
||||||
SQMOD_NODISCARD LgEntityVector GetPosition() const
|
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
|
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
|
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
|
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 uint32_t GetIdleRespawnTimer() const { return Get().GetIdleRespawnTimer(); }
|
||||||
SQMOD_NODISCARD float GetHealth() const { return Get().GetHealth(); }
|
SQMOD_NODISCARD float GetHealth() const { return Get().GetHealth(); }
|
||||||
SQMOD_NODISCARD int GetColour1() const { return Get().GetPrimaryColor(); }
|
SQMOD_NODISCARD int GetColour1() const { return Get().GetPrimaryColor(); }
|
||||||
@@ -899,21 +959,21 @@ struct LgVehicle
|
|||||||
SQMOD_NODISCARD int GetSyncType() const { return Get().GetSyncType(); }
|
SQMOD_NODISCARD int GetSyncType() const { return Get().GetSyncType(); }
|
||||||
SQMOD_NODISCARD bool GetWrecked() const { return Get().IsWrecked(); }
|
SQMOD_NODISCARD bool GetWrecked() const { return Get().IsWrecked(); }
|
||||||
SQMOD_NODISCARD LgEntityQuaternion GetRotation() const
|
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
|
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
|
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
|
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
|
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
|
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 int GetRadio() const { return Get().GetRadio(); }
|
||||||
SQMOD_NODISCARD bool GetRadioLockStatus() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionRadioLocked) >= 1; }
|
SQMOD_NODISCARD bool GetRadioLockStatus() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionRadioLocked) >= 1; }
|
||||||
SQMOD_NODISCARD bool GetGhost() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionGhost) >= 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 GetSingleUse() const { return _Func->GetVehicleOption(GetIdentifier(), vcmpVehicleOptionSingleUse) >= 1; }
|
||||||
SQMOD_NODISCARD bool GetTaxiLight() const { return (_Func->GetVehicleLightsData(GetIdentifier()) & (1 << 8)) != 0; }
|
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); }
|
void SetPartStatus(int part, int status) const { Get().SetPartStatus(part, status); }
|
||||||
SQMOD_NODISCARD int GetTyreStatus(int tyre) const { return Get().GetTyreStatus(tyre); }
|
SQMOD_NODISCARD int GetTyreStatus(int tyre) const { return Get().GetTyreStatus(tyre); }
|
||||||
void SetTyreStatus(int part, int status) const { Get().SetTyreStatus(part, status); }
|
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
|
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; }
|
{ 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); }
|
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 LgCheckpoint::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||||
inline bool LgObject::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
inline bool LgObject::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||||
inline bool LgPickup::StreamedToPlayer(LgPlayer & player) const { return Get().IsStreamedFor(player.Get()); }
|
inline bool LgPickup::StreamedToPlayer(LightObj & player) const { return Get().IsStreamedFor(GetNativeEnt< LgPlayer, CPlayer >(player)); }
|
||||||
inline void LgPlayer::SetVehicle(LgVehicle & vehicle) const { Get().Embark(vehicle.Get()); }
|
inline void LgPlayer::SetVehicle(LightObj & vehicle) const { Get().Embark(GetNativeEnt< LgVehicle, CVehicle >(vehicle)); }
|
||||||
inline void LgPlayer::SetVehicleSlot(const LgVehicle & vehicle, int slot) const { Get().EmbarkEx(vehicle.Get(), slot, true, false); }
|
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; }
|
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)
|
static void LgClientMessage(StackStrF & msg, LightObj & player, int r, int g, int b)
|
||||||
{ _Func->SendClientMessage(player.GetIdentifier(), Color4(static_cast< uint8_t >(r), static_cast< uint8_t >(g),
|
{ _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_cast< uint8_t >(b), 255).GetRGBA(), "%s", msg.mPtr); }
|
||||||
static void LgClientMessageWithAlpha(StackStrF & msg, LgPlayer & player, int r, int g, int b, int a)
|
static void LgClientMessageWithAlpha(StackStrF & msg, LightObj & player, int r, int g, int b, int a)
|
||||||
{ _Func->SendClientMessage(player.GetIdentifier(), Color4(static_cast< uint8_t >(r), static_cast< uint8_t >(g),
|
{ _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_cast< uint8_t >(b), static_cast< uint8_t >(a)).GetRGBA(), "%s", msg.mPtr); }
|
||||||
static void LgClientMessageToAll(StackStrF & msg, int r, int g, int b) {
|
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),
|
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();
|
static_cast< uint8_t >(b), static_cast< uint8_t >(a)).GetRGBA();
|
||||||
ForeachActivePlayer([&](auto & p) { _Func->SendClientMessage(p.mID, c, "%s", msg.mPtr); });
|
ForeachActivePlayer([&](auto & p) { _Func->SendClientMessage(p.mID, c, "%s", msg.mPtr); });
|
||||||
}
|
}
|
||||||
static void LgGameMessage(StackStrF & msg, LgPlayer & player, int type)
|
static void LgGameMessage(StackStrF & msg, LightObj & player, int type)
|
||||||
{ _Func->SendGameMessage(player.GetIdentifier(), type, msg.mPtr); }
|
{ _Func->SendGameMessage(GetLgEntID< LgPlayer, CPlayer >(player), type, msg.mPtr); }
|
||||||
static void LgGameMessageAlternate(StackStrF & msg, LgPlayer & player)
|
static void LgGameMessageAlternate(StackStrF & msg, LightObj & player)
|
||||||
{ { _Func->SendGameMessage(player.GetIdentifier(), 1, msg.mPtr); } }
|
{ { _Func->SendGameMessage(GetLgEntID< LgPlayer, CPlayer >(player), 1, msg.mPtr); } }
|
||||||
static void LgGameMessageToAll(StackStrF & msg, int type)
|
static void LgGameMessageToAll(StackStrF & msg, int type)
|
||||||
{ _Func->SendGameMessage(-1, type, msg.mPtr); }
|
{ _Func->SendGameMessage(-1, type, msg.mPtr); }
|
||||||
static void LgGameMessageToAllAlternate(StackStrF & msg)
|
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 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 int LgGetPlayerIDFromName(StackStrF & name) { return _Func->GetPlayerIdFromName(name.mPtr); }
|
||||||
SQMOD_NODISCARD static bool LgIsWorldCompatibleWithPlayer (LgPlayer & player, int world)
|
SQMOD_NODISCARD static bool LgIsWorldCompatibleWithPlayer(LightObj & player, int world)
|
||||||
{ return _Func->IsPlayerWorldCompatible(player.GetIdentifier(), world) >= 1; }
|
{ return _Func->IsPlayerWorldCompatible(GetLgEntID< LgPlayer, CPlayer >(player), world) >= 1; }
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
static LightObj & LgCreatePickupCompat(int model, const Vector3 & pos)
|
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; }
|
{ 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)
|
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; }
|
{ 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) {
|
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;
|
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; }
|
SQMOD_NODISCARD static bool LgRemoveKeybind(int id) { return _Func->RemoveKeyBind(id) == vcmpErrorNone; }
|
||||||
static void LgRemoveAllKeybinds() { _Func->RemoveAllKeyBinds(); }
|
static void LgRemoveAllKeybinds() { _Func->RemoveAllKeyBinds(); }
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
SQMOD_NODISCARD static bool LgGetCinematicBorder(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWidescreen) >= 1; }
|
SQMOD_NODISCARD static bool LgGetCinematicBorder(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWidescreen) >= 1; }
|
||||||
SQMOD_NODISCARD static bool LgGetGreenScanLines(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionGreenScanlines) >= 1; }
|
SQMOD_NODISCARD static bool LgGetGreenScanLines(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionGreenScanlines) >= 1; }
|
||||||
SQMOD_NODISCARD static bool LgGetWhiteScanLines(LgPlayer & player) { return _Func->GetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWhiteScanlines) >= 1; }
|
SQMOD_NODISCARD static bool LgGetWhiteScanLines(LightObj & player) { return _Func->GetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionWhiteScanlines) >= 1; }
|
||||||
static void LgSetCinematicBorder(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWidescreen, static_cast< uint8_t >(toggle)); }
|
static void LgSetCinematicBorder(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), 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 LgSetGreenScanLines(LightObj & player, bool toggle) { _Func->SetPlayerOption(GetLgEntID< LgPlayer, CPlayer >(player), vcmpPlayerOptionGreenScanlines, static_cast< uint8_t >(toggle)); }
|
||||||
static void LgSetWhiteScanLines(LgPlayer & player, bool toggle) { _Func->SetPlayerOption(player.GetIdentifier(), vcmpPlayerOptionWhiteScanlines, 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 LgKickPlayer(LightObj & player) { _Func->KickPlayer(GetLgEntID< LgPlayer, CPlayer >(player)); }
|
||||||
static void LgBanPlayer(LgPlayer & player) { _Func->BanPlayer(player.GetIdentifier()); }
|
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 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 LgMessagePlayer(StackStrF & msg, LightObj & player) { _Func->SendClientMessage(GetLgEntID< LgPlayer, CPlayer >(player), 0x0b5fa5ff, "%s", msg.mPtr); }
|
||||||
static void LgMessageAllExcept(StackStrF & msg, LgPlayer & player) {
|
static void LgMessageAllExcept(StackStrF & msg, LightObj & player) {
|
||||||
const int32_t p = player.GetIdentifier();
|
const auto p = GetLgEntID< LgPlayer, CPlayer >(player);
|
||||||
const SQChar * m = msg.mPtr;
|
const SQChar * m = msg.mPtr;
|
||||||
ForeachConnectedPlayer([=](int32_t id) { if (id != p) _Func->SendClientMessage(id, 0x0b5fa5ff, "%s", m); });
|
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) {
|
static void LgPrivMessageAll(StackStrF & msg) {
|
||||||
const SQChar * m = msg.mPtr;
|
const SQChar * m = msg.mPtr;
|
||||||
ForeachConnectedPlayer([=](int32_t id) { _Func->SendClientMessage(id, 0x007f16ff, "** pm >> %s", m); });
|
ForeachConnectedPlayer([=](int32_t id) { _Func->SendClientMessage(id, 0x007f16ff, "** pm >> %s", m); });
|
||||||
}
|
}
|
||||||
static void LgSendPlayerMessage(LgPlayer & source, LgPlayer & target, StackStrF & msg) {
|
static void LgSendPlayerMessage(LightObj & source, LightObj & target, StackStrF & msg) {
|
||||||
_Func->SendClientMessage(target.GetIdentifier(), 0x007f16ff, "** pm from %s >> %s", source.Get().GetName(), msg.mPtr);
|
_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)); }
|
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;
|
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)); }
|
static void LgSetVehiclesForcedRespawnHeight(SQFloat height) { _Func->SetVehiclesForcedRespawnHeight(static_cast< float >(height)); }
|
||||||
SQMOD_NODISCARD static SQFloat LgGetVehiclesForcedRespawnHeight() { return _Func->GetVehiclesForcedRespawnHeight(); }
|
SQMOD_NODISCARD static SQFloat LgGetVehiclesForcedRespawnHeight() { return _Func->GetVehiclesForcedRespawnHeight(); }
|
||||||
@@ -1569,7 +1629,7 @@ SQMOD_NODISCARD static SQInteger LgFindPlayer(HSQUIRRELVM vm) {
|
|||||||
char name_buf[SQMOD_NAMELENGTH];
|
char name_buf[SQMOD_NAMELENGTH];
|
||||||
const int32_t id = ForeachConnectedPlayerUntil([&](int32_t id) -> bool {
|
const int32_t id = ForeachConnectedPlayerUntil([&](int32_t id) -> bool {
|
||||||
_Func->GetPlayerName(id, name_buf, 64);
|
_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)
|
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);
|
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)
|
.Func(_SC("SetVehiclesForcedRespawnHeight"), LgSetVehiclesForcedRespawnHeight)
|
||||||
|
|
||||||
.SquirrelFunc(_SC("FindPlayer"), LgFindPlayer)
|
.SquirrelFunc(_SC("FindPlayer"), LgFindPlayer)
|
||||||
|
.SquirrelFunc(_SC("FindPlayerCompat"), LgFindPlayer)
|
||||||
.SquirrelFunc(_SC("InPoly"), LgInPoly)
|
.SquirrelFunc(_SC("InPoly"), LgInPoly)
|
||||||
|
|
||||||
.SquirrelFunc(_SC("SetAmmuWeapon"), LgSetAmmuWeapon)
|
.SquirrelFunc(_SC("SetAmmuWeapon"), LgSetAmmuWeapon)
|
||||||
@@ -2261,8 +2322,8 @@ struct LgStream {
|
|||||||
int32_t id;
|
int32_t id;
|
||||||
if (target.IsNull()) id = -1;
|
if (target.IsNull()) id = -1;
|
||||||
else if (target.GetType() == OT_INTEGER || target.GetType() == OT_FLOAT) id = target.Cast< int32_t >();
|
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()) {
|
else if (target.GetType() == OT_INSTANCE) {
|
||||||
id = target.CastI< LgPlayer >()->GetIdentifier();
|
id = GetLgEntID< LgPlayer, CPlayer >(target);
|
||||||
} else STHROWF("Invalid target type");
|
} else STHROWF("Invalid target type");
|
||||||
if (id >= SQMOD_PLAYER_POOL) STHROWF("Invalid player ID");
|
if (id >= SQMOD_PLAYER_POOL) STHROWF("Invalid player ID");
|
||||||
_Func->SendClientScriptData(id, m_OutputStreamData, m_OutputStreamEnd);
|
_Func->SendClientScriptData(id, m_OutputStreamData, m_OutputStreamEnd);
|
||||||
|
|||||||
@@ -113,8 +113,8 @@ int32_t GetSkinID(StackStrF & name)
|
|||||||
{
|
{
|
||||||
// Clone the string into an editable version
|
// Clone the string into an editable version
|
||||||
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
||||||
// Strip non alphanumeric characters from the name
|
// Strip non-alphanumeric characters from the name
|
||||||
str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
|
str.erase(std::remove_if(str.begin(), str.end(), [](char c) -> bool { return std::isalnum(c) == 0; }), str.end());
|
||||||
// Convert the string to lowercase
|
// Convert the string to lowercase
|
||||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||||
// See if we still have a valid name after the cleanup
|
// 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
|
// Clone the string into an editable version
|
||||||
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
||||||
// Strip non alphanumeric characters from the name
|
// Strip non-alphanumeric characters from the name
|
||||||
str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
|
str.erase(std::remove_if(str.begin(), str.end(), [](char c) -> bool { return std::isalnum(c) == 0; }), str.end());
|
||||||
// Convert the string to lowercase
|
// Convert the string to lowercase
|
||||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||||
// See if we still have a valid name after the cleanup
|
// 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
|
// Clone the string into an editable version
|
||||||
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
String str(name.mPtr, static_cast< size_t >(name.mLen));
|
||||||
// Strip non alphanumeric characters from the name
|
// Strip non-alphanumeric characters from the name
|
||||||
str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
|
str.erase(std::remove_if(str.begin(), str.end(), [](char c) -> bool { return std::isalnum(c) == 0; }), str.end());
|
||||||
// Convert the string to lowercase
|
// Convert the string to lowercase
|
||||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||||
// See if we still have a valid name after the cleanup
|
// 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]PAS-12 Shotgun
|
||||||
// [S]tubby Shotgun
|
// [S]tubby Shotgun
|
||||||
// [S]uicide
|
// [S]uicide
|
||||||
|
// Pump action [S]hotgun
|
||||||
case 's':
|
case 's':
|
||||||
// [Sc]rewdriver
|
// [Sc]rewdriver
|
||||||
if (b == 'c') return SQMOD_WEAPON_SCREWDRIVER;
|
if (b == 'c') return SQMOD_WEAPON_SCREWDRIVER;
|
||||||
@@ -337,7 +338,7 @@ int32_t GetWeaponID(StackStrF & name)
|
|||||||
else if (b == 't') return SQMOD_WEAPON_STUBBY;
|
else if (b == 't') return SQMOD_WEAPON_STUBBY;
|
||||||
// [Su]icide
|
// [Su]icide
|
||||||
else if (b == 'u') return SQMOD_WEAPON_SUICIDE;
|
else if (b == 'u') return SQMOD_WEAPON_SUICIDE;
|
||||||
// Pump action [Sh]otgun
|
// Pump action [Sh]otgun
|
||||||
else if (b == 'h') return SQMOD_WEAPON_SHOTGUN;
|
else if (b == 'h') return SQMOD_WEAPON_SHOTGUN;
|
||||||
// Default to unknwon
|
// Default to unknwon
|
||||||
else return SQMOD_UNKNOWN;
|
else return SQMOD_UNKNOWN;
|
||||||
|
|||||||
+586
-3
@@ -1,5 +1,9 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include "PocoLib/Data.hpp"
|
#include "PocoLib/Data.hpp"
|
||||||
|
#include "Core/ThreadPool.hpp"
|
||||||
|
#include "Library/SQLite.hpp"
|
||||||
|
#include "Library/MySQL.hpp"
|
||||||
|
#include "Poco/Data/SessionImpl.h"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include <sqratConst.h>
|
#include <sqratConst.h>
|
||||||
@@ -33,6 +37,7 @@ SQMOD_DECL_TYPENAME(SqPcDataStatement, _SC("SqDataStatement"))
|
|||||||
SQMOD_DECL_TYPENAME(SqPcDataRecordSet, _SC("SqDataRecordSet"))
|
SQMOD_DECL_TYPENAME(SqPcDataRecordSet, _SC("SqDataRecordSet"))
|
||||||
SQMOD_DECL_TYPENAME(SqPcDataTransaction, _SC("SqDataTransaction"))
|
SQMOD_DECL_TYPENAME(SqPcDataTransaction, _SC("SqDataTransaction"))
|
||||||
SQMOD_DECL_TYPENAME(SqPcDataSessionPool, _SC("SqDataSessionPool"))
|
SQMOD_DECL_TYPENAME(SqPcDataSessionPool, _SC("SqDataSessionPool"))
|
||||||
|
SQMOD_DECL_TYPENAME(SqPcSqDataAsyncBuilder, _SC("SqSqDataAsyncBuilder"))
|
||||||
SQMOD_DECL_TYPENAME(SqPcDataStatementResult, _SC("SqDataStatementResult"))
|
SQMOD_DECL_TYPENAME(SqPcDataStatementResult, _SC("SqDataStatementResult"))
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -66,7 +71,7 @@ static LightObj SQLiteEscapeString(StackStrF & str)
|
|||||||
// Allocate a memory buffer
|
// Allocate a memory buffer
|
||||||
Buffer b(static_cast< Buffer::SzType >(str.mLen * 2 + 1));
|
Buffer b(static_cast< Buffer::SzType >(str.mLen * 2 + 1));
|
||||||
// Attempt to escape the specified string
|
// 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 the resulted string
|
||||||
return LightObj(b.Get< SQChar >(), -1);
|
return LightObj(b.Get< SQChar >(), -1);
|
||||||
}
|
}
|
||||||
@@ -90,7 +95,7 @@ static LightObj SQLiteEscapeStringEx(SQChar spec, StackStrF & str)
|
|||||||
// Allocate a memory buffer
|
// Allocate a memory buffer
|
||||||
Buffer b(static_cast< Buffer::SzType >(str.mLen * 2 + 1));
|
Buffer b(static_cast< Buffer::SzType >(str.mLen * 2 + 1));
|
||||||
// Attempt to escape the specified string
|
// 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 the resulted string
|
||||||
return LightObj(b.Get< SQChar >(), -1);
|
return LightObj(b.Get< SQChar >(), -1);
|
||||||
}
|
}
|
||||||
@@ -196,7 +201,7 @@ SqDataStatement SqDataSession::GetStatement(StackStrF & data)
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
SqDataRecordSet SqDataSession::GetRecordSet(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;
|
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)
|
LightObj SqDataSessionPool::GetProperty(StackStrF & name)
|
||||||
{
|
{
|
||||||
@@ -746,6 +1311,19 @@ void Register_POCO_Data(HSQUIRRELVM vm, Table &)
|
|||||||
.Overload(_SC("Value"), &SqDataRecordSet::GetValueOr)
|
.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"),
|
ns.Bind(_SC("SessionPool"),
|
||||||
Class< SqDataSessionPool, NoCopy< SqDataSessionPool > >(vm, SqPcDataSessionPool::Str)
|
Class< SqDataSessionPool, NoCopy< SqDataSessionPool > >(vm, SqPcDataSessionPool::Str)
|
||||||
// Constructors
|
// Constructors
|
||||||
@@ -764,6 +1342,11 @@ void Register_POCO_Data(HSQUIRRELVM vm, Table &)
|
|||||||
.Prop(_SC("IsActive"), &SqDataSessionPool::IsActive)
|
.Prop(_SC("IsActive"), &SqDataSessionPool::IsActive)
|
||||||
// Member Methods
|
// Member Methods
|
||||||
.Func(_SC("Get"), &SqDataSessionPool::Get)
|
.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("GetWithProperty"), &SqDataSessionPool::GetWithProperty)
|
||||||
.FmtFunc(_SC("GetWithFeature"), &SqDataSessionPool::GetWithFeature)
|
.FmtFunc(_SC("GetWithFeature"), &SqDataSessionPool::GetWithFeature)
|
||||||
.FmtFunc(_SC("SetFeature"), &SqDataSessionPool::SetFeature)
|
.FmtFunc(_SC("SetFeature"), &SqDataSessionPool::SetFeature)
|
||||||
|
|||||||
+115
-2
@@ -1707,7 +1707,7 @@ protected:
|
|||||||
}
|
}
|
||||||
SQ_UNREACHABLE
|
SQ_UNREACHABLE
|
||||||
// Unreachable
|
// Unreachable
|
||||||
return LightObj();
|
return {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1746,7 +1746,7 @@ struct SqDataSessionPool : public SessionPool
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Destroys the SessionPool.
|
* Destroys the SessionPool.
|
||||||
*/
|
*/
|
||||||
~SqDataSessionPool() = default;
|
~SqDataSessionPool() override = default;
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Assignment operator (disabled).
|
* Assignment operator (disabled).
|
||||||
@@ -1766,6 +1766,31 @@ struct SqDataSessionPool : public SessionPool
|
|||||||
return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get());
|
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.
|
* 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
|
} // 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_Crypto(HSQUIRRELVM vm, Table & ns);
|
||||||
extern void Register_POCO_Data(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_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_Time(HSQUIRRELVM vm, Table & ns);
|
||||||
extern void Register_POCO_Util(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_Crypto(vm, ns);
|
||||||
Register_POCO_Data(vm, ns);
|
Register_POCO_Data(vm, ns);
|
||||||
Register_POCO_Net(vm, ns);
|
Register_POCO_Net(vm, ns);
|
||||||
Register_POCO_RegEx(vm, ns);
|
|
||||||
Register_POCO_Time(vm, ns);
|
Register_POCO_Time(vm, ns);
|
||||||
Register_POCO_Util(vm, ns);
|
Register_POCO_Util(vm, ns);
|
||||||
|
|
||||||
|
|||||||
+2
-5
@@ -1,6 +1,3 @@
|
|||||||
#ifndef _REGISTER_HPP_
|
|
||||||
#define _REGISTER_HPP_
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
#include <squirrelex.h>
|
#include <squirrelex.h>
|
||||||
|
|
||||||
@@ -39,6 +36,7 @@ extern void Register_JSON(HSQUIRRELVM vm);
|
|||||||
extern void Register_MMDB(HSQUIRRELVM vm);
|
extern void Register_MMDB(HSQUIRRELVM vm);
|
||||||
extern void Register_Net(HSQUIRRELVM vm);
|
extern void Register_Net(HSQUIRRELVM vm);
|
||||||
extern void Register_Numeric(HSQUIRRELVM vm);
|
extern void Register_Numeric(HSQUIRRELVM vm);
|
||||||
|
extern void Register_RegEx(HSQUIRRELVM vm);
|
||||||
extern void Register_String(HSQUIRRELVM vm);
|
extern void Register_String(HSQUIRRELVM vm);
|
||||||
extern void Register_System(HSQUIRRELVM vm);
|
extern void Register_System(HSQUIRRELVM vm);
|
||||||
extern void Register_UTF8(HSQUIRRELVM vm);
|
extern void Register_UTF8(HSQUIRRELVM vm);
|
||||||
@@ -106,6 +104,7 @@ bool RegisterAPI(HSQUIRRELVM vm)
|
|||||||
Register_MMDB(vm);
|
Register_MMDB(vm);
|
||||||
Register_Net(vm);
|
Register_Net(vm);
|
||||||
Register_Numeric(vm);
|
Register_Numeric(vm);
|
||||||
|
Register_RegEx(vm);
|
||||||
Register_String(vm);
|
Register_String(vm);
|
||||||
Register_System(vm);
|
Register_System(vm);
|
||||||
Register_UTF8(vm);
|
Register_UTF8(vm);
|
||||||
@@ -142,5 +141,3 @@ bool RegisterAPI(HSQUIRRELVM vm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // 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_NAME "Squirrel Module"
|
||||||
#define SQMOD_AUTHOR "Sandu Liviu Catalin (S.L.C)"
|
#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_HOST_NAME "SqModHost"
|
||||||
#define SQMOD_VERSION 001
|
#define SQMOD_VERSION 001
|
||||||
#define SQMOD_VERSION_STR "0.0.1"
|
#define SQMOD_VERSION_STR "0.0.1"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include <squirrelex.h>
|
#include <squirrelex.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#include "sqratObject.h"
|
#include "sqratObject.h"
|
||||||
@@ -661,6 +662,80 @@ public:
|
|||||||
return *this;
|
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
|
/// Gets a Function from a name in the Class
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -88,6 +88,15 @@ struct LightObj {
|
|||||||
sq_addref(SqVM(), &mObj);
|
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
|
/// 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>
|
template<class T, class... A>
|
||||||
LightObj(SqTypeIdentity< T > SQ_UNUSED_ARG(t), HSQUIRRELVM vm, A&&... a) {
|
LightObj(SqTypeIdentity< T > SQ_UNUSED_ARG(t), HSQUIRRELVM vm, A&&... a) : LightObj(DeleteGuard< T >(new T(std::forward< 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -237,7 +232,21 @@ struct LightObj {
|
|||||||
///
|
///
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
template<class T>
|
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();
|
guard.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ template <class C,class R> struct SqMember {
|
|||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return sq_throwerror(vm, e.what());
|
return sq_throwerror(vm, e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||||
}
|
}
|
||||||
SQ_UNREACHABLE
|
SQ_UNREACHABLE
|
||||||
};
|
};
|
||||||
@@ -178,7 +178,7 @@ template <class C,class R> struct SqMember {
|
|||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return sq_throwerror(vm, e.what());
|
return sq_throwerror(vm, e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||||
}
|
}
|
||||||
SQ_UNREACHABLE
|
SQ_UNREACHABLE
|
||||||
};
|
};
|
||||||
@@ -206,7 +206,7 @@ template <class C, class R> struct SqMember<C,R&> {
|
|||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return sq_throwerror(vm, e.what());
|
return sq_throwerror(vm, e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||||
}
|
}
|
||||||
SQ_UNREACHABLE
|
SQ_UNREACHABLE
|
||||||
};
|
};
|
||||||
@@ -227,7 +227,7 @@ template <class C, class R> struct SqMember<C,R&> {
|
|||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return sq_throwerror(vm, e.what());
|
return sq_throwerror(vm, e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||||
}
|
}
|
||||||
SQ_UNREACHABLE
|
SQ_UNREACHABLE
|
||||||
};
|
};
|
||||||
@@ -256,7 +256,7 @@ template <class C> struct SqMember<C, void> {
|
|||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return sq_throwerror(vm, e.what());
|
return sq_throwerror(vm, e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||||
}
|
}
|
||||||
SQ_UNREACHABLE
|
SQ_UNREACHABLE
|
||||||
};
|
};
|
||||||
@@ -277,7 +277,7 @@ template <class C> struct SqMember<C, void> {
|
|||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return sq_throwerror(vm, e.what());
|
return sq_throwerror(vm, e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return sq_throwerror(vm, _SC("unknown exception occured"));
|
return sq_throwerror(vm, _SC("unknown exception occurred"));
|
||||||
}
|
}
|
||||||
SQ_UNREACHABLE
|
SQ_UNREACHABLE
|
||||||
};
|
};
|
||||||
|
|||||||
+166
-42
@@ -35,6 +35,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <Poco/Exception.h>
|
#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.
|
/// Helper structure for one element from the top of stack.
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
struct SqPopTopGuard
|
struct SqPopTopGuard
|
||||||
{
|
{
|
||||||
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
|
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// Base constructor.
|
/// 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.
|
/// Helper structure for popping elements from the stack.
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
struct SqPopGuard
|
struct SqPopGuard
|
||||||
{
|
{
|
||||||
HSQUIRRELVM mVM; // The VM from which the elements must be popped.
|
HSQUIRRELVM mVM{nullptr}; // The VM from which the elements must be popped.
|
||||||
SQInteger mNum; // The number of elements to be popped.
|
SQInteger mNum{0}; // The number of elements to be popped.
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// Base constructor.
|
/// 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.
|
/// Implements RAII to restore the VM stack to it's initial size on function exit.
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
struct StackGuard
|
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.
|
/// Default constructor.
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
StackGuard()
|
StackGuard()
|
||||||
: m_VM(SqVM()), m_Top(sq_gettop(m_VM))
|
: mVM(SqVM()), mTop(sq_gettop(mVM))
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
@@ -1677,8 +1816,8 @@ struct StackGuard
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// Base constructor.
|
/// Base constructor.
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
StackGuard(HSQUIRRELVM vm)
|
explicit StackGuard(HSQUIRRELVM vm)
|
||||||
: m_VM(vm), m_Top(sq_gettop(vm))
|
: mVM(vm), mTop(sq_gettop(vm))
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
@@ -1717,18 +1856,13 @@ struct StackGuard
|
|||||||
void Restore() const
|
void Restore() const
|
||||||
{
|
{
|
||||||
// Retrieve the new stack top
|
// Retrieve the new stack top
|
||||||
const SQInteger top = sq_gettop(m_VM);
|
const SQInteger top = sq_gettop(mVM);
|
||||||
// Did the stack size change?
|
// 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
|
template < typename T > struct DeleteGuard
|
||||||
{
|
{
|
||||||
private:
|
T * mPtr; // Pointer to the instance to manage.
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
|
||||||
T * m_Ptr; // Pointer to the instance to manage.
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// Default constructor.
|
/// Default constructor.
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
explicit DeleteGuard(T * ptr)
|
explicit DeleteGuard(T * ptr)
|
||||||
: m_Ptr(ptr)
|
: mPtr(ptr)
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
@@ -2152,7 +2281,7 @@ public:
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
template<class... A>
|
template<class... A>
|
||||||
explicit DeleteGuard(SqInPlace SQ_UNUSED_ARG(t), A&&... 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.
|
/// Move constructor.
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
DeleteGuard(DeleteGuard && o) noexcept
|
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()
|
~DeleteGuard()
|
||||||
{
|
{
|
||||||
if (m_Ptr)
|
if (mPtr)
|
||||||
{
|
{
|
||||||
delete m_Ptr;
|
delete mPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2197,7 +2326,7 @@ public:
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
operator T * () const
|
operator T * () const
|
||||||
{
|
{
|
||||||
return m_Ptr;
|
return mPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -2205,7 +2334,7 @@ public:
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
T * Get() const
|
T * Get() const
|
||||||
{
|
{
|
||||||
return m_Ptr;
|
return mPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -2213,7 +2342,7 @@ public:
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
void Release()
|
void Release()
|
||||||
{
|
{
|
||||||
m_Ptr = nullptr;
|
mPtr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -2221,8 +2350,8 @@ public:
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
T * Grab()
|
T * Grab()
|
||||||
{
|
{
|
||||||
T * ptr = m_Ptr;
|
T * ptr = mPtr;
|
||||||
m_Ptr = nullptr;
|
mPtr = nullptr;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2320,18 +2449,13 @@ template < typename T > T * SqChainedInstances< T >::sHead = nullptr;
|
|||||||
/// @cond DEV
|
/// @cond DEV
|
||||||
/// Used internally to get and manipulate the underlying type of variables - retrieved from cppreference.com
|
/// 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> using remove_const = std::remove_const< T >;
|
||||||
template<class T> struct remove_const<const T> {typedef T type;};
|
template<class T> using remove_volatile = std::remove_volatile< T >;
|
||||||
template<class T> struct remove_volatile {typedef T type;};
|
template<class T> using remove_cv = std::remove_cv< T >;
|
||||||
template<class T> struct remove_volatile<volatile T> {typedef T type;};
|
template<class T> struct is_pointer : public std::is_pointer< T > { };
|
||||||
template<class T> struct remove_cv {typedef typename remove_volatile<typename remove_const<T>::type>::type type;};
|
template<class T,class D> struct is_pointer<SharedPtr<T,D> > : public std::true_type { };
|
||||||
template<class T> struct is_pointer_helper {static constexpr bool value = false;};
|
template<class T,class D> struct is_pointer<WeakPtr<T,D> > : public std::true_type { };
|
||||||
template<class T> struct is_pointer_helper<T*> {static constexpr bool value = true;};
|
template<class T> using is_reference = std::is_lvalue_reference< T >;
|
||||||
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;};
|
|
||||||
/// @endcond
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -1,6 +1,7 @@
|
|||||||
add_subdirectory(ConcurrentQueue)
|
add_subdirectory(ConcurrentQueue)
|
||||||
add_subdirectory(Fmt)
|
add_subdirectory(Fmt)
|
||||||
add_subdirectory(xxHash)
|
add_subdirectory(xxHash)
|
||||||
|
add_subdirectory(RPMalloc)
|
||||||
add_subdirectory(Squirrel)
|
add_subdirectory(Squirrel)
|
||||||
add_subdirectory(SimpleIni)
|
add_subdirectory(SimpleIni)
|
||||||
add_subdirectory(TinyDir)
|
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_CUDA_TEST "Generate the cuda-test target." OFF)
|
||||||
option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
|
option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
|
||||||
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
|
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)
|
set(FMT_CAN_MODULE OFF)
|
||||||
if (CMAKE_CXX_STANDARD GREATER 17 AND
|
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
|
# The tests require {fmt} to be compiled as traditional library
|
||||||
message(STATUS "Testing is incompatible with build mode 'module'.")
|
message(STATUS "Testing is incompatible with build mode 'module'.")
|
||||||
endif ()
|
endif ()
|
||||||
|
set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
|
||||||
|
if (FMT_SYSTEM_HEADERS)
|
||||||
|
set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
|
||||||
|
endif ()
|
||||||
|
|
||||||
# Get version from core.h
|
# Get version from core.h
|
||||||
file(READ include/fmt/core.h core_h)
|
file(READ include/fmt/core.h core_h)
|
||||||
@@ -151,7 +156,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|||||||
-Wcast-align
|
-Wcast-align
|
||||||
-Wctor-dtor-privacy -Wdisabled-optimization
|
-Wctor-dtor-privacy -Wdisabled-optimization
|
||||||
-Winvalid-pch -Woverloaded-virtual
|
-Winvalid-pch -Woverloaded-virtual
|
||||||
-Wconversion -Wswitch-enum -Wundef
|
-Wconversion -Wundef
|
||||||
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
|
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
|
||||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
||||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
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}\" %*")
|
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||||
endif ()
|
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)
|
function(add_headers VAR)
|
||||||
set(headers ${${VAR}})
|
set(headers ${${VAR}})
|
||||||
foreach (header ${ARGN})
|
foreach (header ${ARGN})
|
||||||
@@ -239,17 +232,6 @@ endif ()
|
|||||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
||||||
add_library(fmt::fmt ALIAS fmt)
|
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)
|
if (FMT_WERROR)
|
||||||
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
||||||
endif ()
|
endif ()
|
||||||
@@ -262,7 +244,7 @@ endif ()
|
|||||||
|
|
||||||
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
|
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>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||||
|
|
||||||
@@ -270,6 +252,7 @@ set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
|
|||||||
|
|
||||||
set_target_properties(fmt PROPERTIES
|
set_target_properties(fmt PROPERTIES
|
||||||
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||||
|
PUBLIC_HEADER "${FMT_HEADERS}"
|
||||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||||
|
|
||||||
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
# 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_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
|
||||||
target_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES})
|
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>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||||
|
|
||||||
@@ -347,6 +330,8 @@ if (FMT_INSTALL)
|
|||||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
||||||
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
||||||
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
||||||
|
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
|
||||||
|
FRAMEWORK DESTINATION "."
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
# Use a namespace because CMake provides better diagnostics for namespaced
|
# Use a namespace because CMake provides better diagnostics for namespaced
|
||||||
@@ -363,7 +348,6 @@ if (FMT_INSTALL)
|
|||||||
|
|
||||||
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
|
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
|
||||||
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
||||||
install(FILES ${FMT_HEADERS} DESTINATION "${FMT_INC_DIR}/fmt")
|
|
||||||
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
||||||
endif ()
|
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
|
8.0.1 - 2021-07-02
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@@ -34,7 +405,7 @@
|
|||||||
`#2389 <https://github.com/fmtlib/fmt/pull/2389>`_,
|
`#2389 <https://github.com/fmtlib/fmt/pull/2389>`_,
|
||||||
`#2395 <https://github.com/fmtlib/fmt/pull/2395>`_,
|
`#2395 <https://github.com/fmtlib/fmt/pull/2395>`_,
|
||||||
`#2397 <https://github.com/fmtlib/fmt/pull/2397>`_,
|
`#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>`_,
|
`#2401 <https://github.com/fmtlib/fmt/issues/2401>`_,
|
||||||
`#2407 <https://github.com/fmtlib/fmt/pull/2407>`_).
|
`#2407 <https://github.com/fmtlib/fmt/pull/2407>`_).
|
||||||
Thanks `@zx2c4 (Jason A. Donenfeld) <https://github.com/zx2c4>`_,
|
Thanks `@zx2c4 (Jason A. Donenfeld) <https://github.com/zx2c4>`_,
|
||||||
@@ -50,7 +421,7 @@
|
|||||||
8.0.0 - 2021-06-21
|
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>`__):
|
For example (`godbolt <https://godbolt.org/z/sMxcohGjz>`__):
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
@@ -281,6 +652,9 @@
|
|||||||
This doesn't introduce a dependency on ``<locale>`` so there is virtually no
|
This doesn't introduce a dependency on ``<locale>`` so there is virtually no
|
||||||
compile time effect.
|
compile time effect.
|
||||||
|
|
||||||
|
* Deprecated an undocumented ``format_to`` overload that takes
|
||||||
|
``basic_memory_buffer``.
|
||||||
|
|
||||||
* Made parameter order in ``vformat_to`` consistent with ``format_to``
|
* Made parameter order in ``vformat_to`` consistent with ``format_to``
|
||||||
(`#2327 <https://github.com/fmtlib/fmt/issues/2327>`_).
|
(`#2327 <https://github.com/fmtlib/fmt/issues/2327>`_).
|
||||||
|
|
||||||
@@ -562,13 +936,13 @@
|
|||||||
`#2067 <https://github.com/fmtlib/fmt/pull/2067>`_,
|
`#2067 <https://github.com/fmtlib/fmt/pull/2067>`_,
|
||||||
`#2068 <https://github.com/fmtlib/fmt/pull/2068>`_,
|
`#2068 <https://github.com/fmtlib/fmt/pull/2068>`_,
|
||||||
`#2073 <https://github.com/fmtlib/fmt/pull/2073>`_,
|
`#2073 <https://github.com/fmtlib/fmt/pull/2073>`_,
|
||||||
`#2103 <https://github.com/fmtlib/fmt/issues/2103>`_
|
`#2103 <https://github.com/fmtlib/fmt/issues/2103>`_,
|
||||||
`#2105 <https://github.com/fmtlib/fmt/issues/2105>`_
|
`#2105 <https://github.com/fmtlib/fmt/issues/2105>`_,
|
||||||
`#2106 <https://github.com/fmtlib/fmt/pull/2106>`_,
|
`#2106 <https://github.com/fmtlib/fmt/pull/2106>`_,
|
||||||
`#2107 <https://github.com/fmtlib/fmt/pull/2107>`_,
|
`#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>`_,
|
`#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>`_,
|
`#2119 <https://github.com/fmtlib/fmt/pull/2119>`_,
|
||||||
`#2127 <https://github.com/fmtlib/fmt/issues/2127>`_,
|
`#2127 <https://github.com/fmtlib/fmt/issues/2127>`_,
|
||||||
`#2128 <https://github.com/fmtlib/fmt/pull/2128>`_,
|
`#2128 <https://github.com/fmtlib/fmt/pull/2128>`_,
|
||||||
@@ -641,7 +1015,7 @@
|
|||||||
`@yeswalrus (Walter Gray) <https://github.com/yeswalrus>`_,
|
`@yeswalrus (Walter Gray) <https://github.com/yeswalrus>`_,
|
||||||
`@Finkman <https://github.com/Finkman>`_,
|
`@Finkman <https://github.com/Finkman>`_,
|
||||||
`@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_,
|
`@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>`_,
|
`@concatime (Issam Maghni) <https://github.com/concatime>`_,
|
||||||
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
|
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
|
||||||
`@summivox (Yin Zhong) <https://github.com/summivox>`_,
|
`@summivox (Yin Zhong) <https://github.com/summivox>`_,
|
||||||
@@ -1098,7 +1472,7 @@
|
|||||||
`#1912 <https://github.com/fmtlib/fmt/issues/1912>`_,
|
`#1912 <https://github.com/fmtlib/fmt/issues/1912>`_,
|
||||||
`#1928 <https://github.com/fmtlib/fmt/issues/1928>`_,
|
`#1928 <https://github.com/fmtlib/fmt/issues/1928>`_,
|
||||||
`#1929 <https://github.com/fmtlib/fmt/pull/1929>`_,
|
`#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>`_,
|
`#1937 <https://github.com/fmtlib/fmt/pull/1937>`_,
|
||||||
`#1942 <https://github.com/fmtlib/fmt/pull/1942>`_,
|
`#1942 <https://github.com/fmtlib/fmt/pull/1942>`_,
|
||||||
`#1949 <https://github.com/fmtlib/fmt/issues/1949>`_).
|
`#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
|
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
||||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
: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
|
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||||
alternative to C stdio and C++ iostreams.
|
alternative to C stdio and C++ iostreams.
|
||||||
|
|
||||||
If you like this project, please consider donating to the BYSOL
|
If you like this project, please consider donating to one of the funds that
|
||||||
Foundation that helps victims of political repressions in Belarus:
|
help victims of the war in Ukraine: https://www.stopputin.net/.
|
||||||
https://bysol.org/en/bs/general/.
|
|
||||||
|
|
||||||
`Documentation <https://fmt.dev>`__
|
`Documentation <https://fmt.dev>`__
|
||||||
|
|
||||||
@@ -123,7 +124,7 @@ Output::
|
|||||||
Default format: 42s 100ms
|
Default format: 42s 100ms
|
||||||
strftime-like format: 03:15:30
|
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++
|
.. 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"``
|
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
|
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
||||||
further details refer to the `source
|
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
|
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
||||||
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
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
|
This is a very powerful library which supports both ``printf``-like format
|
||||||
strings and positional arguments. Its main drawback is performance. According to
|
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
|
Format also has excessive build times and severe code bloat issues (see
|
||||||
`Benchmarks`_).
|
`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>`_.
|
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
||||||
They take *fmt* and *args* as arguments.
|
They take *fmt* and *args* as arguments.
|
||||||
|
|
||||||
*fmt* is a format string that contains literal text and replacement
|
*fmt* is a format string that contains literal text and replacement fields
|
||||||
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
surrounded by braces ``{}``. The fields are replaced with formatted arguments
|
||||||
arguments in the resulting string. A function taking *fmt* doesn't
|
in the resulting string. `~fmt::format_string` is a format string which can be
|
||||||
participate in an overload resolution if the latter is not a string.
|
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.
|
*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:: vformat(string_view fmt, format_args args) -> std::string
|
||||||
|
|
||||||
.. doxygenfunction:: format_to(OutputIt out, format_string<T...> fmt, T&&... args) -> OutputIt
|
.. 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
|
.. doxygenfunction:: formatted_size(format_string<T...> fmt, T&&... args) -> size_t
|
||||||
|
|
||||||
.. doxygenstruct:: fmt::format_to_n_result
|
.. doxygenstruct:: fmt::format_to_n_result
|
||||||
@@ -59,7 +61,7 @@ participate in an overload resolution if the latter is not a string.
|
|||||||
.. _print:
|
.. _print:
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::print(format_string<T...> fmt, T&&... args)
|
.. 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:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
|
||||||
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args 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
|
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``
|
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||||
functions in their ``formatter`` specializations.
|
functions in their ``formatter`` specializations.
|
||||||
|
Requires C++14 and is a no-op in C++11.
|
||||||
|
|
||||||
.. doxygendefine:: FMT_STRING
|
.. 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
|
will fail to compile with regular strings. Runtime-checked
|
||||||
formatting is still possible using ``fmt::vformat``, ``fmt::vprint``, etc.
|
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
|
Named Arguments
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@@ -103,8 +113,7 @@ binary footprint, for example (https://godbolt.org/z/oba4Mc):
|
|||||||
|
|
||||||
template <typename S, typename... Args>
|
template <typename S, typename... Args>
|
||||||
void log(const char* file, int line, const S& format, Args&&... args) {
|
void log(const char* file, int line, const S& format, Args&&... args) {
|
||||||
vlog(file, line, format,
|
vlog(file, line, format, fmt::make_format_args(args...));
|
||||||
fmt::make_args_checked<Args...>(format, args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MY_LOG(format, ...) \
|
#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
|
Note that ``vlog`` is not parameterized on argument types which improves compile
|
||||||
times and reduces binary code size compared to a fully parameterized version.
|
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&...)
|
.. doxygenfunction:: fmt::make_format_args(const Args&...)
|
||||||
|
|
||||||
.. doxygenclass:: fmt::format_arg_store
|
.. doxygenclass:: fmt::format_arg_store
|
||||||
@@ -172,12 +179,19 @@ functions and locale support.
|
|||||||
Formatting User-defined Types
|
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
|
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
||||||
template and implement ``parse`` and ``format`` methods::
|
template and implement ``parse`` and ``format`` methods::
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
struct point { double x, y; };
|
struct point {
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
|
||||||
template <> struct fmt::formatter<point> {
|
template <> struct fmt::formatter<point> {
|
||||||
// Presentation format: 'f' - fixed, 'e' - exponential.
|
// 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++;
|
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
|
||||||
|
|
||||||
// Check if reached the end of the range:
|
// Check if reached the end of the range:
|
||||||
if (it != end && *it != '}')
|
if (it != end && *it != '}') throw format_error("invalid format");
|
||||||
throw format_error("invalid format");
|
|
||||||
|
|
||||||
// Return an iterator past the end of the parsed range:
|
// Return an iterator past the end of the parsed range:
|
||||||
return it;
|
return it;
|
||||||
@@ -211,12 +224,11 @@ template and implement ``parse`` and ``format`` methods::
|
|||||||
// Formats the point p using the parsed format specification (presentation)
|
// Formats the point p using the parsed format specification (presentation)
|
||||||
// stored in this formatter.
|
// stored in this formatter.
|
||||||
template <typename FormatContext>
|
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.
|
// ctx.out() is an output iterator to write to.
|
||||||
return format_to(
|
return presentation == 'f'
|
||||||
ctx.out(),
|
? format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
|
||||||
presentation == 'f' ? "({:.1f}, {:.1f})" : "({:.1e}, {:.1e})",
|
: format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
|
||||||
p.x, p.y);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -234,7 +246,7 @@ example::
|
|||||||
template <> struct fmt::formatter<color>: formatter<string_view> {
|
template <> struct fmt::formatter<color>: formatter<string_view> {
|
||||||
// parse is inherited from formatter<string_view>.
|
// parse is inherited from formatter<string_view>.
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(color c, FormatContext& ctx) {
|
auto format(color c, FormatContext& ctx) const {
|
||||||
string_view name = "unknown";
|
string_view name = "unknown";
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case color::red: name = "red"; break;
|
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>> :
|
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
|
||||||
fmt::formatter<std::string> {
|
fmt::formatter<std::string> {
|
||||||
template <typename FormatCtx>
|
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);
|
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::unique_ptr<T> &p) -> const void*
|
||||||
.. doxygenfunction:: fmt::ptr(const std::shared_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(const T &value) -> std::string
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_string_view(const Char *s) -> basic_string_view<Char>
|
.. 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::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
|
.. doxygenclass:: fmt::detail::buffer
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
@@ -434,16 +450,19 @@ The format syntax is described in :ref:`chrono-specs`.
|
|||||||
Format string compilation
|
Format string compilation
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
``fmt/compile.h`` provides format string compilation support when using
|
``fmt/compile.h`` provides format string compilation enabled via the
|
||||||
``FMT_COMPILE``. Format strings are parsed, checked and converted into efficient
|
``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
|
||||||
formatting code at compile-time. This supports arguments of built-in and string
|
marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
|
||||||
types as well as user-defined types with ``constexpr`` ``parse`` functions in
|
efficient formatting code at compile-time. This supports arguments of built-in
|
||||||
their ``formatter`` specializations. Format string compilation can generate more
|
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||||
binary code compared to the default API and is only recommended in places where
|
functions in their ``formatter`` specializations. Format string compilation can
|
||||||
formatting is a performance bottleneck.
|
generate more binary code compared to the default API and is only recommended in
|
||||||
|
places where formatting is a performance bottleneck.
|
||||||
|
|
||||||
.. doxygendefine:: FMT_COMPILE
|
.. doxygendefine:: FMT_COMPILE
|
||||||
|
|
||||||
|
.. doxygenfunction:: operator""_cf()
|
||||||
|
|
||||||
.. _color-api:
|
.. _color-api:
|
||||||
|
|
||||||
Terminal color and text style
|
Terminal color and text style
|
||||||
@@ -457,6 +476,8 @@ Terminal color and text style
|
|||||||
|
|
||||||
.. doxygenfunction:: bg(detail::color_type)
|
.. doxygenfunction:: bg(detail::color_type)
|
||||||
|
|
||||||
|
.. doxygenfunction:: styled(const T& value, text_style ts)
|
||||||
|
|
||||||
.. _os-api:
|
.. _os-api:
|
||||||
|
|
||||||
System APIs
|
System APIs
|
||||||
@@ -474,7 +495,9 @@ System APIs
|
|||||||
========================
|
========================
|
||||||
|
|
||||||
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
|
``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>
|
#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));
|
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
||||||
// s == "The date is 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)
|
.. doxygenfunction:: print(std::basic_ostream<Char> &os, const S &format_str, Args&&... args)
|
||||||
|
|
||||||
.. _printf-api:
|
.. _printf-api:
|
||||||
@@ -519,8 +541,8 @@ argument type doesn't match its format specification.
|
|||||||
``wchar_t`` Support
|
``wchar_t`` Support
|
||||||
===================
|
===================
|
||||||
|
|
||||||
The optional header ``fmt/wchar_t.h`` provides support for ``wchar_t`` and
|
The optional header ``fmt/xchar.h`` provides support for ``wchar_t`` and exotic
|
||||||
exotic character types.
|
character types.
|
||||||
|
|
||||||
.. doxygenstruct:: fmt::is_char
|
.. doxygenstruct:: fmt::is_char
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -90,12 +90,14 @@
|
|||||||
VERSION: '{{ release|e }}',
|
VERSION: '{{ release|e }}',
|
||||||
COLLAPSE_INDEX: false,
|
COLLAPSE_INDEX: false,
|
||||||
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
||||||
|
LINK_SUFFIX: '{{ link_suffix }}',
|
||||||
|
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}',
|
||||||
HAS_SOURCE: {{ has_source|lower }},
|
HAS_SOURCE: {{ has_source|lower }},
|
||||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
{%- for scriptfile in script_files %}
|
{%- for scriptfile in script_files %}
|
||||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
{{ js_tag(scriptfile) }}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
|||||||
Vendored
+5
-1
@@ -4,7 +4,7 @@
|
|||||||
import errno, os, re, sys
|
import errno, os, re, sys
|
||||||
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
|
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:
|
class Pip:
|
||||||
def __init__(self, venv_dir):
|
def __init__(self, venv_dir):
|
||||||
@@ -26,6 +26,8 @@ def create_build_env(venv_dir='virtualenv'):
|
|||||||
pip = Pip(venv_dir)
|
pip = Pip(venv_dir)
|
||||||
pip.install('wheel')
|
pip.install('wheel')
|
||||||
pip.install('six')
|
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('sphinx-doc/sphinx', 'v3.3.0')
|
||||||
pip.install('michaeljones/breathe', 'v4.25.0')
|
pip.install('michaeljones/breathe', 'v4.25.0')
|
||||||
|
|
||||||
@@ -58,10 +60,12 @@ def build_docs(version='dev', **kwargs):
|
|||||||
MACRO_EXPANSION = YES
|
MACRO_EXPANSION = YES
|
||||||
PREDEFINED = _WIN32=1 \
|
PREDEFINED = _WIN32=1 \
|
||||||
__linux__=1 \
|
__linux__=1 \
|
||||||
|
FMT_ENABLE_IF(...)= \
|
||||||
FMT_USE_VARIADIC_TEMPLATES=1 \
|
FMT_USE_VARIADIC_TEMPLATES=1 \
|
||||||
FMT_USE_RVALUE_REFERENCES=1 \
|
FMT_USE_RVALUE_REFERENCES=1 \
|
||||||
FMT_USE_USER_DEFINED_LITERALS=1 \
|
FMT_USE_USER_DEFINED_LITERALS=1 \
|
||||||
FMT_USE_ALIAS_TEMPLATES=1 \
|
FMT_USE_ALIAS_TEMPLATES=1 \
|
||||||
|
FMT_USE_NONTYPE_TEMPLATE_PARAMETERS=1 \
|
||||||
FMT_API= \
|
FMT_API= \
|
||||||
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
||||||
"FMT_END_NAMESPACE=}}" \
|
"FMT_END_NAMESPACE=}}" \
|
||||||
|
|||||||
Vendored
+1
-1
@@ -101,7 +101,7 @@ The code
|
|||||||
format(FMT_STRING("The answer is {:d}"), "forty-two");
|
format(FMT_STRING("The answer is {:d}"), "forty-two");
|
||||||
|
|
||||||
reports a compile-time error on compilers that support relaxed ``constexpr``.
|
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
|
The following code
|
||||||
|
|
||||||
|
|||||||
Vendored
+46
-18
@@ -112,18 +112,18 @@ meaning in this case.
|
|||||||
The *sign* option is only valid for number types, and can be one of the
|
The *sign* option is only valid for number types, and can be one of the
|
||||||
following:
|
following:
|
||||||
|
|
||||||
+---------+----------------------------------------------------------+
|
+---------+------------------------------------------------------------+
|
||||||
| Option | Meaning |
|
| Option | Meaning |
|
||||||
+=========+==========================================================+
|
+=========+============================================================+
|
||||||
| ``'+'`` | indicates that a sign should be used for both |
|
| ``'+'`` | 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 |
|
| ``'-'`` | indicates that a sign should be used only for negative |
|
||||||
| | numbers (this is the default behavior). |
|
| | numbers (this is the default behavior). |
|
||||||
+---------+----------------------------------------------------------+
|
+---------+------------------------------------------------------------+
|
||||||
| space | indicates that a leading space should be used on |
|
| 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
|
The ``'#'`` option causes the "alternate form" to be used for the
|
||||||
conversion. The alternate form is defined differently for different
|
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
|
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
|
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,
|
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
|
The ``'L'`` option uses the current locale setting to insert the appropriate
|
||||||
number separator characters. This option is only valid for numeric types.
|
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
|
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
|
.. productionlist:: sf
|
||||||
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
|
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)
|
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.
|
are valid only for ``std::tm`` and not durations or time points.
|
||||||
|
|
||||||
``std::tm`` uses the system's `strftime
|
.. range-specs:
|
||||||
<https://en.cppreference.com/w/cpp/chrono/c/strftime>`_ so refer to its
|
|
||||||
documentation for details on supported conversion specifiers.
|
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:
|
.. _formatexamples:
|
||||||
|
|
||||||
@@ -449,7 +477,7 @@ Using type-specific formatting::
|
|||||||
|
|
||||||
Using the comma as a thousands separator::
|
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);
|
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
|
||||||
// s == "1,234,567,890"
|
// s == "1,234,567,890"
|
||||||
|
|||||||
Vendored
+4
-14
@@ -95,10 +95,10 @@ class dynamic_format_arg_store
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using stored_type = conditional_t<detail::is_string<T>::value &&
|
using stored_type = conditional_t<
|
||||||
!has_formatter<T, Context>::value &&
|
std::is_convertible<T, std::basic_string<char_type>>::value &&
|
||||||
!detail::is_reference_wrapper<T>::value,
|
!detail::is_reference_wrapper<T>::value,
|
||||||
std::basic_string<char_type>, T>;
|
std::basic_string<char_type>, T>;
|
||||||
|
|
||||||
// Storage of basic_format_arg must be contiguous.
|
// Storage of basic_format_arg must be contiguous.
|
||||||
std::vector<basic_format_arg<Context>> data_;
|
std::vector<basic_format_arg<Context>> data_;
|
||||||
@@ -145,16 +145,6 @@ class dynamic_format_arg_store
|
|||||||
public:
|
public:
|
||||||
constexpr dynamic_format_arg_store() = default;
|
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
|
\rst
|
||||||
Adds an argument into the dynamic store for later passing to a formatting
|
Adds an argument into the dynamic store for later passing to a formatting
|
||||||
|
|||||||
Vendored
+992
-229
File diff suppressed because it is too large
Load Diff
Vendored
+110
-54
@@ -214,17 +214,16 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
|||||||
|
|
||||||
// color is a struct of either a rgb color or a terminal color.
|
// color is a struct of either a rgb color or a terminal color.
|
||||||
struct color_type {
|
struct color_type {
|
||||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
|
||||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
|
||||||
value{} {
|
|
||||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
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) |
|
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
|
||||||
value{} {
|
: is_rgb(), value{} {
|
||||||
value.term_color = static_cast<uint8_t>(term_color);
|
value.term_color = static_cast<uint8_t>(term_color);
|
||||||
}
|
}
|
||||||
bool is_rgb;
|
bool is_rgb;
|
||||||
@@ -239,10 +238,8 @@ FMT_END_DETAIL_NAMESPACE
|
|||||||
/** A text style consisting of foreground and background colors and emphasis. */
|
/** A text style consisting of foreground and background colors and emphasis. */
|
||||||
class text_style {
|
class text_style {
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||||
set_background_color(),
|
|
||||||
ems(em) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
||||||
if (!set_foreground_color) {
|
if (!set_foreground_color) {
|
||||||
@@ -283,34 +280,32 @@ class text_style {
|
|||||||
return lhs.and_assign(rhs);
|
return lhs.and_assign(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_foreground() const noexcept {
|
||||||
return set_foreground_color;
|
return set_foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_background() const noexcept {
|
||||||
return set_background_color;
|
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;
|
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");
|
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||||
return foreground_color;
|
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");
|
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||||
return background_color;
|
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");
|
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||||
return ems;
|
return ems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
detail::color_type text_color) FMT_NOEXCEPT
|
detail::color_type text_color) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems() {
|
||||||
set_background_color(),
|
|
||||||
ems() {
|
|
||||||
if (is_foreground) {
|
if (is_foreground) {
|
||||||
foreground_color = text_color;
|
foreground_color = text_color;
|
||||||
set_foreground_color = true;
|
set_foreground_color = true;
|
||||||
@@ -345,11 +340,11 @@ class text_style {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
friend FMT_CONSTEXPR_DECL text_style
|
||||||
FMT_NOEXCEPT;
|
fg(detail::color_type foreground) noexcept;
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
friend FMT_CONSTEXPR_DECL text_style
|
||||||
FMT_NOEXCEPT;
|
bg(detail::color_type background) noexcept;
|
||||||
|
|
||||||
detail::color_type foreground_color;
|
detail::color_type foreground_color;
|
||||||
detail::color_type background_color;
|
detail::color_type background_color;
|
||||||
@@ -359,17 +354,16 @@ class text_style {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Creates a text style from the foreground (text) color. */
|
/** 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);
|
return text_style(true, foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a text style from the background color. */
|
/** 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);
|
return text_style(false, background);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
|
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
|
||||||
emphasis rhs) FMT_NOEXCEPT {
|
|
||||||
return text_style(lhs) | rhs;
|
return text_style(lhs) | rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +371,7 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
|||||||
|
|
||||||
template <typename Char> struct ansi_color_escape {
|
template <typename Char> struct ansi_color_escape {
|
||||||
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
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
|
// If we have a terminal color, we need to output another escape code
|
||||||
// sequence.
|
// sequence.
|
||||||
if (!text_color.is_rgb) {
|
if (!text_color.is_rgb) {
|
||||||
@@ -412,7 +406,7 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
to_esc(color.b, buffer + 15, 'm');
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
buffer[19] = static_cast<Char>(0);
|
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] = {};
|
uint8_t em_codes[num_emphases] = {};
|
||||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
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);
|
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 const Char* begin() const noexcept { return buffer; }
|
||||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
|
||||||
return buffer + std::char_traits<Char>::length(buffer);
|
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];
|
Char buffer[7u + 3u * num_emphases + 1u];
|
||||||
|
|
||||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
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[0] = static_cast<Char>('0' + c / 100);
|
||||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
out[2] = static_cast<Char>('0' + c % 10);
|
out[2] = static_cast<Char>('0' + c % 10);
|
||||||
out[3] = static_cast<Char>(delimiter);
|
out[3] = static_cast<Char>(delimiter);
|
||||||
}
|
}
|
||||||
static FMT_CONSTEXPR bool has_emphasis(emphasis em,
|
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
|
||||||
emphasis mask) FMT_NOEXCEPT {
|
|
||||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
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;");
|
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
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;");
|
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
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);
|
return ansi_color_escape<Char>(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
|
||||||
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
|
int result = std::fputs(chars, stream);
|
||||||
std::fputs(chars, stream);
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
|
||||||
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
|
int result = std::fputws(chars, stream);
|
||||||
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);
|
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);
|
fputs(L"\x1b[0m", stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||||
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
|
|
||||||
auto reset_color = string_view("\x1b[0m");
|
auto reset_color = string_view("\x1b[0m");
|
||||||
buffer.append(reset_color.begin(), reset_color.end());
|
buffer.append(reset_color.begin(), reset_color.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> struct styled_arg {
|
||||||
|
const T& value;
|
||||||
|
text_style style;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||||
basic_string_view<Char> format_str,
|
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_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
detail::vformat_to(buf, ts, to_string_view(format), args);
|
detail::vformat_to(buf, ts, to_string_view(format), args);
|
||||||
buf.push_back(Char(0));
|
if (detail::is_utf8()) {
|
||||||
detail::fputs(buf.data(), f);
|
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,
|
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
vprint(f, ts, format_str,
|
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,
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return fmt::vformat(ts, to_string_view(format_str),
|
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) ->
|
Args&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
return vformat_to(out, ts, to_string_view(format_str),
|
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
|
FMT_MODULE_EXPORT_END
|
||||||
|
|||||||
Vendored
+29
-65
@@ -13,45 +13,6 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
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>
|
template <typename Char, typename InputIt>
|
||||||
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
||||||
counting_iterator it) {
|
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);
|
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
#ifdef __cpp_if_constexpr
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
# define FMT_COMPILE(s) \
|
# define FMT_COMPILE(s) \
|
||||||
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
|
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
|
||||||
#else
|
#else
|
||||||
@@ -168,7 +129,7 @@ template <typename Char, size_t N,
|
|||||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||||
struct udl_compiled_string : compiled_string {
|
struct udl_compiled_string : compiled_string {
|
||||||
using char_type = Char;
|
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};
|
return {Str.data, N - 1};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -179,7 +140,7 @@ const T& first(const T& value, const Tail&...) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cpp_if_constexpr
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
template <typename... Args> struct type_list {};
|
template <typename... Args> struct type_list {};
|
||||||
|
|
||||||
// Returns a reference to the argument at index N from [first, rest...].
|
// 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)
|
if constexpr (N == 0)
|
||||||
return first;
|
return first;
|
||||||
else
|
else
|
||||||
return get<N - 1>(rest...);
|
return detail::get<N - 1>(rest...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename... Args>
|
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> struct get_type_impl;
|
||||||
|
|
||||||
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
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>
|
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&`.
|
// This ensures that the argument type is convertible to `const T&`.
|
||||||
template <typename T, int N, typename... Args>
|
template <typename T, int N, typename... Args>
|
||||||
constexpr const T& get_arg_checked(const Args&... 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)>>()) {
|
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
||||||
return arg.value;
|
return arg.value;
|
||||||
} else {
|
} else {
|
||||||
@@ -399,7 +361,9 @@ template <typename Char> struct arg_id_handler {
|
|||||||
return 0;
|
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 {
|
template <typename Char> struct parse_arg_id_result {
|
||||||
@@ -527,12 +491,12 @@ constexpr auto compile(S format_str) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // __cpp_if_constexpr
|
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_MODULE_EXPORT_BEGIN
|
||||||
|
|
||||||
#ifdef __cpp_if_constexpr
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
|
|
||||||
template <typename CompiledFormat, typename... Args,
|
template <typename CompiledFormat, typename... Args,
|
||||||
typename Char = typename CompiledFormat::char_type,
|
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());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
|
return fmt::format(
|
||||||
std::forward<Args>(args)...);
|
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} 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());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format_to(out,
|
return fmt::format_to(
|
||||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
return format_to(out, compiled, std::forward<Args>(args)...);
|
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -596,22 +561,23 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||||
const S& format_str, Args&&... args) {
|
const S& format_str, Args&&... args) {
|
||||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
|
auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
|
||||||
std::forward<Args>(args)...);
|
format_str, std::forward<Args>(args)...);
|
||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
size_t formatted_size(const S& format_str, const Args&... args) {
|
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,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
||||||
memory_buffer buffer;
|
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()});
|
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
|
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
template <detail_exported::fixed_string Str>
|
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
|
||||||
constexpr detail::udl_compiled_string<
|
using char_t = remove_cvref_t<decltype(Str.data[0])>;
|
||||||
remove_cvref_t<decltype(Str.data[0])>,
|
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
|
||||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
|
Str>();
|
||||||
operator""_cf() {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Vendored
+530
-314
File diff suppressed because it is too large
Load Diff
Vendored
+1098
-1046
File diff suppressed because it is too large
Load Diff
Vendored
+823
-446
File diff suppressed because it is too large
Load Diff
Vendored
+46
-82
@@ -9,10 +9,8 @@
|
|||||||
#define FMT_OS_H_
|
#define FMT_OS_H_
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <clocale> // locale_t
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib> // strtod_l
|
|
||||||
#include <system_error> // std::system_error
|
#include <system_error> // std::system_error
|
||||||
|
|
||||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||||
@@ -21,17 +19,20 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
#ifndef FMT_USE_FCNTL
|
||||||
// UWP doesn't provide _pipe.
|
// UWP doesn't provide _pipe.
|
||||||
#if FMT_HAS_INCLUDE("winapifamily.h")
|
# if FMT_HAS_INCLUDE("winapifamily.h")
|
||||||
# include <winapifamily.h>
|
# include <winapifamily.h>
|
||||||
#endif
|
# endif
|
||||||
#if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||||
defined(__linux__)) && \
|
defined(__linux__)) && \
|
||||||
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
(!defined(WINAPI_FAMILY) || \
|
||||||
# include <fcntl.h> // for O_RDONLY
|
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||||
# define FMT_USE_FCNTL 1
|
# include <fcntl.h> // for O_RDONLY
|
||||||
#else
|
# define FMT_USE_FCNTL 1
|
||||||
# define FMT_USE_FCNTL 0
|
# else
|
||||||
|
# define FMT_USE_FCNTL 0
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_POSIX
|
#ifndef FMT_POSIX
|
||||||
@@ -138,7 +139,7 @@ template <typename Char> struct formatter<std::error_code, Char> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#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
|
FMT_BEGIN_DETAIL_NAMESPACE
|
||||||
// A converter from UTF-16 to UTF-8.
|
// 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,
|
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_END_DETAIL_NAMESPACE
|
||||||
|
|
||||||
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
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.
|
// Reports a Windows error without throwing an exception.
|
||||||
// Can be used to report errors from destructors.
|
// Can be used to report errors from destructors.
|
||||||
FMT_API void report_windows_error(int error_code,
|
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
||||||
const char* message) FMT_NOEXCEPT;
|
|
||||||
#else
|
#else
|
||||||
inline const std::error_category& system_category() FMT_NOEXCEPT {
|
inline const std::error_category& system_category() noexcept {
|
||||||
return std::system_category();
|
return std::system_category();
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@@ -234,13 +234,13 @@ class buffered_file {
|
|||||||
void operator=(const buffered_file&) = delete;
|
void operator=(const buffered_file&) = delete;
|
||||||
|
|
||||||
// Constructs a buffered_file object which doesn't represent any file.
|
// 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.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
FMT_API ~buffered_file() noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
||||||
other.file_ = nullptr;
|
other.file_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +258,11 @@ class buffered_file {
|
|||||||
FMT_API void close();
|
FMT_API void close();
|
||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
// 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
|
// We place parentheses around fileno to workaround a bug in some versions
|
||||||
// of MinGW that define fileno as a macro.
|
// of MinGW that define fileno as a macro.
|
||||||
|
// DEPRECATED! Rename to descriptor to avoid issues with macros.
|
||||||
FMT_API int(fileno)() const;
|
FMT_API int(fileno)() const;
|
||||||
|
|
||||||
void vprint(string_view format_str, format_args args) {
|
void vprint(string_view format_str, format_args args) {
|
||||||
@@ -276,12 +277,12 @@ class buffered_file {
|
|||||||
|
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
// A file. Closed file is represented by a file object with descriptor -1.
|
// 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
|
// 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
|
// closing the file multiple times will cause a crash on Windows rather
|
||||||
// than an exception. You can get standard behavior by overriding the
|
// than an exception. You can get standard behavior by overriding the
|
||||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||||
class file {
|
class FMT_API file {
|
||||||
private:
|
private:
|
||||||
int fd_; // File descriptor.
|
int fd_; // File descriptor.
|
||||||
|
|
||||||
@@ -300,16 +301,16 @@ class file {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a file object which doesn't represent any 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.
|
// 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:
|
public:
|
||||||
file(const file&) = delete;
|
file(const file&) = delete;
|
||||||
void operator=(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.
|
// Move assignment is not noexcept because close may throw.
|
||||||
file& operator=(file&& other) {
|
file& operator=(file&& other) {
|
||||||
@@ -320,43 +321,43 @@ class file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~file() FMT_NOEXCEPT;
|
~file() noexcept;
|
||||||
|
|
||||||
// Returns the file descriptor.
|
// Returns the file descriptor.
|
||||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
int descriptor() const noexcept { return fd_; }
|
||||||
|
|
||||||
// Closes the file.
|
// Closes the file.
|
||||||
FMT_API void close();
|
void close();
|
||||||
|
|
||||||
// Returns the file size. The size has signed type for consistency with
|
// Returns the file size. The size has signed type for consistency with
|
||||||
// stat::st_size.
|
// 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.
|
// 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.
|
// 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
|
// Duplicates a file descriptor with the dup function and returns
|
||||||
// the duplicate as a file object.
|
// 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
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd);
|
void dup2(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// 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
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||||
// and writing respectively.
|
// 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
|
// Creates a buffered_file object associated with this file and detaches
|
||||||
// this file object from the file.
|
// 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.
|
// Returns the memory page size.
|
||||||
@@ -390,6 +391,13 @@ struct ostream_params {
|
|||||||
: ostream_params(params...) {
|
: ostream_params(params...) {
|
||||||
this->buffer_size = bs.value;
|
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
|
FMT_END_DETAIL_NAMESPACE
|
||||||
@@ -452,7 +460,7 @@ class FMT_API ostream final : private detail::buffer<char> {
|
|||||||
|
|
||||||
* ``<integer>``: Flags passed to `open
|
* ``<integer>``: Flags passed to `open
|
||||||
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
<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
|
* ``buffer_size=<integer>``: Output buffer size
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
@@ -467,50 +475,6 @@ inline ostream output_file(cstring_view path, T... params) {
|
|||||||
}
|
}
|
||||||
#endif // FMT_USE_FCNTL
|
#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_MODULE_EXPORT_END
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
|||||||
Vendored
+48
-86
@@ -14,73 +14,20 @@
|
|||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
template <typename Char> class basic_printf_parse_context;
|
|
||||||
template <typename OutputIt, typename Char> class basic_printf_context;
|
template <typename OutputIt, typename Char> class basic_printf_context;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
// Checks if T has a user-defined operator<<.
|
||||||
private:
|
template <typename T, typename Char, typename Enable = void>
|
||||||
using int_type = typename std::basic_streambuf<Char>::int_type;
|
class is_streamable {
|
||||||
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 {
|
|
||||||
private:
|
private:
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
|
static auto test(int)
|
||||||
<< std::declval<U>()),
|
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
|
||||||
void_t<>>::value>
|
<< std::declval<U>()) != 0>;
|
||||||
test(int);
|
|
||||||
|
|
||||||
template <typename> static std::false_type test(...);
|
template <typename> static auto test(...) -> std::false_type;
|
||||||
|
|
||||||
using result = decltype(test<T>(0));
|
using result = decltype(test<T>(0));
|
||||||
|
|
||||||
@@ -90,7 +37,21 @@ template <typename T, typename Char> class is_streamable {
|
|||||||
static const bool value = result::value;
|
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.
|
// Write the content of buf to os.
|
||||||
|
// It is a separate function rather than a part of vprint to simplify testing.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||||
const Char* buf_data = buf.data();
|
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>
|
template <typename Char, typename T>
|
||||||
void format_value(buffer<Char>& buf, const T& value,
|
void format_value(buffer<Char>& buf, const T& value,
|
||||||
locale_ref loc = locale_ref()) {
|
locale_ref loc = locale_ref()) {
|
||||||
formatbuf<Char> format_buf(buf);
|
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
|
||||||
std::basic_ostream<Char> output(&format_buf);
|
auto&& output = std::basic_ostream<Char>(&format_buf);
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
if (loc) output.imbue(loc.get<std::locale>());
|
if (loc) output.imbue(loc.get<std::locale>());
|
||||||
#endif
|
#endif
|
||||||
@@ -117,34 +78,35 @@ void format_value(buffer<Char>& buf, const T& value,
|
|||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
buf.try_resize(buf.size());
|
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<<.
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
||||||
: private formatter<basic_string_view<Char>, Char> {
|
: basic_ostream_formatter<Char> {
|
||||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
using basic_ostream_formatter<Char>::format;
|
||||||
-> decltype(ctx.begin()) {
|
// DEPRECATED!
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
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 {
|
-> OutputIt {
|
||||||
basic_memory_buffer<Char> buffer;
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
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;
|
|
||||||
format_value(buffer, value, ctx.locale());
|
format_value(buffer, value, ctx.locale());
|
||||||
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
||||||
}
|
}
|
||||||
@@ -155,7 +117,7 @@ FMT_MODULE_EXPORT
|
|||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
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::vformat_to(buffer, format_str, args);
|
||||||
detail::write_buffer(os, buffer);
|
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>>>
|
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) {
|
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||||
vprint(os, to_string_view(format_str),
|
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
|
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) {
|
OutputIt write_null_pointer(bool is_string = false) {
|
||||||
auto s = this->specs;
|
auto s = this->specs;
|
||||||
s.type = 0;
|
s.type = presentation_type::none;
|
||||||
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
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.
|
// std::is_same instead.
|
||||||
if (std::is_same<T, Char>::value) {
|
if (std::is_same<T, Char>::value) {
|
||||||
format_specs fmt_specs = this->specs;
|
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));
|
return (*this)(static_cast<int>(value));
|
||||||
|
}
|
||||||
fmt_specs.sign = sign::none;
|
fmt_specs.sign = sign::none;
|
||||||
fmt_specs.alt = false;
|
fmt_specs.alt = false;
|
||||||
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
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. */
|
/** Formats a null-terminated C string. */
|
||||||
OutputIt operator()(const char* value) {
|
OutputIt operator()(const char* value) {
|
||||||
if (value) return base::operator()(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. */
|
/** Formats a null-terminated wide C string. */
|
||||||
OutputIt operator()(const wchar_t* value) {
|
OutputIt operator()(const wchar_t* value) {
|
||||||
if (value) return base::operator()(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) {
|
OutputIt operator()(basic_string_view<Char> value) {
|
||||||
@@ -490,13 +492,13 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
|
|
||||||
// Parse type.
|
// Parse type.
|
||||||
if (it == end) FMT_THROW(format_error("invalid format string"));
|
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()) {
|
if (arg.is_integral()) {
|
||||||
// Normalize type.
|
// Normalize type.
|
||||||
switch (specs.type) {
|
switch (type) {
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'u':
|
case 'u':
|
||||||
specs.type = 'd';
|
type = 'd';
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
visit_format_arg(
|
visit_format_arg(
|
||||||
@@ -505,6 +507,9 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
specs.type = parse_presentation_type(type);
|
||||||
|
if (specs.type == presentation_type::none)
|
||||||
|
parse_ctx.on_error("invalid type specifier");
|
||||||
|
|
||||||
start = it;
|
start = it;
|
||||||
|
|
||||||
|
|||||||
Vendored
+234
-355
@@ -13,37 +13,13 @@
|
|||||||
#define FMT_RANGES_H_
|
#define FMT_RANGES_H_
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
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 {
|
namespace detail {
|
||||||
|
|
||||||
template <typename RangeT, typename OutputIterator>
|
template <typename RangeT, typename OutputIterator>
|
||||||
@@ -71,7 +47,7 @@ OutputIterator copy(wchar_t ch, OutputIterator out) {
|
|||||||
return 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 T> class is_std_string_like {
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static auto check(U* p)
|
static auto check(U* p)
|
||||||
@@ -80,12 +56,40 @@ template <typename T> class is_std_string_like {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
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>
|
template <typename Char>
|
||||||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
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... Ts> struct conditional_helper {};
|
||||||
|
|
||||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||||
@@ -163,7 +167,7 @@ struct is_range_<T, void>
|
|||||||
# undef FMT_DECLTYPE_RETURN
|
# undef FMT_DECLTYPE_RETURN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// tuple_size and tuple_element check.
|
// tuple_size and tuple_element check.
|
||||||
template <typename T> class is_tuple_like_ {
|
template <typename T> class is_tuple_like_ {
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
|
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
|
#endif
|
||||||
|
|
||||||
template <class Tuple, class F, size_t... Is>
|
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 std::get;
|
||||||
// using free function get<I>(T) now.
|
// using free function get<I>(T) now.
|
||||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
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));
|
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>
|
template <typename Range>
|
||||||
using value_type =
|
using range_reference_type =
|
||||||
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
|
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) {
|
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||||
*out++ = ',';
|
*out++ = ',';
|
||||||
@@ -227,283 +250,22 @@ template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
|||||||
return 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>
|
template <typename Char, typename OutputIt>
|
||||||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
||||||
*out++ = '"';
|
return write_escaped_string(out, str);
|
||||||
auto begin = str.begin(), end = str.end();
|
}
|
||||||
do {
|
|
||||||
auto escape = find_escape(begin, end);
|
template <typename Char, typename OutputIt, typename T,
|
||||||
out = copy_str<Char>(begin, escape.begin, out);
|
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
|
||||||
begin = escape.end;
|
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
|
||||||
if (!begin) break;
|
auto sv = std_string_view<Char>(str);
|
||||||
auto c = static_cast<Char>(escape.cp);
|
return write_range_entry<Char>(out, basic_string_view<Char>(sv));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename Arg,
|
template <typename Char, typename OutputIt, typename Arg,
|
||||||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||||
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||||
*out++ = '\'';
|
return write_escaped_char(out, v);
|
||||||
*out++ = v;
|
|
||||||
*out++ = '\'';
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@@ -524,63 +286,153 @@ template <typename T> struct is_tuple_like {
|
|||||||
template <typename TupleT, typename Char>
|
template <typename TupleT, typename Char>
|
||||||
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
||||||
private:
|
private:
|
||||||
// C++11 generic lambda for format()
|
// C++11 generic lambda for format().
|
||||||
template <typename FormatContext> struct format_each {
|
template <typename FormatContext> struct format_each {
|
||||||
template <typename T> void operator()(const T& v) {
|
template <typename T> void operator()(const T& v) {
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
out = detail::write_range_entry<Char>(out, v);
|
out = detail::write_range_entry<Char>(out, v);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
formatting_tuple<Char>& formatting;
|
int i;
|
||||||
size_t& i;
|
typename FormatContext::iterator& out;
|
||||||
typename std::add_lvalue_reference<
|
|
||||||
decltype(std::declval<FormatContext>().out())>::type out;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
formatting_tuple<Char> formatting;
|
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return formatting.parse(ctx);
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext = format_context>
|
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();
|
auto out = ctx.out();
|
||||||
size_t i = 0;
|
*out++ = '(';
|
||||||
|
detail::for_each(values, format_each<FormatContext>{0, out});
|
||||||
detail::copy(formatting.prefix, out);
|
*out++ = ')';
|
||||||
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
return out;
|
||||||
detail::copy(formatting.postfix, out);
|
|
||||||
|
|
||||||
return ctx.out();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Char> struct is_range {
|
template <typename T, typename Char> struct is_range {
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::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_convertible<T, std::basic_string<Char>>::value &&
|
||||||
!std::is_constructible<detail::std_string_view<Char>, T>::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>
|
template <typename T, typename Char>
|
||||||
struct formatter<
|
struct formatter<
|
||||||
T, Char,
|
T, Char,
|
||||||
enable_if_t<
|
enable_if_t<detail::is_map<T>::value
|
||||||
fmt::is_range<T, Char>::value
|
// Workaround a bug in MSVC 2019 and earlier.
|
||||||
// Workaround a bug in MSVC 2017 and earlier.
|
#if !FMT_MSC_VER
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
|
&& (is_formattable<detail::uncvref_type<T>, Char>::value ||
|
||||||
&& (has_formatter<detail::value_type<T>, format_context>::value ||
|
detail::has_fallback_formatter<detail::uncvref_type<T>,
|
||||||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
Char>::value)
|
||||||
#endif
|
#endif
|
||||||
>> {
|
>> {
|
||||||
formatting_range<Char> formatting;
|
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return formatting.parse(ctx);
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@@ -588,17 +440,20 @@ struct formatter<
|
|||||||
FMT_ENABLE_IF(
|
FMT_ENABLE_IF(
|
||||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
||||||
const T, T>>::value)>
|
const T, T>>::value)>
|
||||||
auto format(U& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(U& map, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
auto out = detail::copy(formatting.prefix, ctx.out());
|
auto out = ctx.out();
|
||||||
size_t i = 0;
|
*out++ = '{';
|
||||||
auto it = std::begin(values);
|
int i = 0;
|
||||||
auto end = std::end(values);
|
for (const auto& item : map) {
|
||||||
for (; it != end; ++it) {
|
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
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;
|
++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>
|
template <typename Char, typename... T>
|
||||||
using tuple_arg_join = tuple_join_view<Char, 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>
|
template <typename Char, typename... T>
|
||||||
struct formatter<tuple_join_view<Char, T...>, Char> {
|
struct formatter<tuple_join_view<Char, T...>, Char> {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
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>
|
template <typename FormatContext>
|
||||||
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx) ->
|
auto format(const tuple_join_view<Char, T...>& value,
|
||||||
typename FormatContext::iterator {
|
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||||
return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
|
return do_format(value, ctx,
|
||||||
|
std::integral_constant<size_t, sizeof...(T)>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename FormatContext, size_t... N>
|
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
|
||||||
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
|
||||||
detail::index_sequence<N...>) ->
|
template <typename ParseContext>
|
||||||
typename FormatContext::iterator {
|
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||||
using std::get;
|
std::integral_constant<size_t, 0>)
|
||||||
return format_args(value, ctx, get<N>(value.tuple)...);
|
-> 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>
|
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 {
|
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();
|
return ctx.out();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext, typename Arg, typename... Args>
|
template <typename FormatContext, size_t N>
|
||||||
auto format_args(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||||
const Arg& arg, const Args&... args) ->
|
std::integral_constant<size_t, N>) const ->
|
||||||
typename FormatContext::iterator {
|
typename FormatContext::iterator {
|
||||||
using base = formatter<typename std::decay<Arg>::type, Char>;
|
auto out = std::get<sizeof...(T) - N>(formatters_)
|
||||||
auto out = base().format(arg, ctx);
|
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
|
||||||
if (sizeof...(Args) > 0) {
|
if (N > 1) {
|
||||||
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
||||||
ctx.advance_to(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;
|
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