1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2026-07-09 10:07:10 +02:00

64 Commits

Author SHA1 Message Date
Sandu Liviu Catalin 483ac37bdb Update CMakeLists.txt
continuous-integration/drone/push Build was killed
2022-10-04 02:29:05 +03:00
Sandu Liviu Catalin 78dc76e6b4 Object to typename helper. 2022-10-03 18:32:06 +03:00
Sandu Liviu Catalin e29070af49 Update Official.cpp 2022-10-03 18:31:48 +03:00
Sandu Liviu Catalin 1f25b3ea60 Update sqratUtil.h 2022-10-03 18:31:36 +03:00
Sandu Liviu Catalin 52cfa235be Update JSON.hpp
continuous-integration/drone/push Build was killed
2022-10-02 21:47:20 +03:00
Sandu Liviu Catalin ec7f1183d8 Basic hooking into json parsing.
Also allow customization of the fallback meta-method.
2022-10-02 21:24:12 +03:00
Sandu Liviu Catalin a788e059a5 Implement _tojson meta-method for base types. 2022-09-18 15:02:39 +03:00
Sandu Liviu Catalin 5f20ffc4de Remove the manual comma. 2022-09-17 23:49:37 +03:00
Sandu Liviu Catalin 08106156c4 Don't add comma for the root container. 2022-09-17 23:42:48 +03:00
Sandu Liviu Catalin 60119ff8fa Include comma after separator braces. 2022-09-17 23:41:43 +03:00
Sandu Liviu Catalin f4720ae77a Implement custom types in JSON. 2022-09-17 23:25:16 +03:00
Sandu Liviu Catalin c9fb257f48 Update ThreadPool.hpp 2022-09-15 23:03:50 +03:00
Sandu Liviu Catalin 475a428366 Update Data.hpp 2022-09-15 23:03:44 +03:00
Sandu Liviu Catalin 42ac0e32b7 Implement JSON serialization.
Just the basics.
2022-09-15 23:03:38 +03:00
Sandu Liviu Catalin 3e75e36cdf Add auto-close option for web-socket client.
continuous-integration/drone/push Build was killed
2022-08-14 21:00:57 +03:00
Sandu Liviu Catalin ac7d18f297 Allow chaining in traversal methods for buffer type. 2022-08-14 21:00:30 +03:00
Sandu Liviu Catalin 39473a68f4 Fix formatting in buffer type. 2022-08-14 21:00:10 +03:00
Sandu Liviu Catalin 5a57bf2fbf Prevent double closing event in web-sockets.
continuous-integration/drone/push Build was killed
2022-08-14 20:29:32 +03:00
Sandu Liviu Catalin 15e85f1394 Update Net.hpp 2022-08-14 20:11:53 +03:00
Sandu Liviu Catalin e8fa9e0259 Update sqratLightObj.h 2022-08-14 18:53:36 +03:00
Sandu Liviu Catalin c551390999 Helper Base32/64 methods on SqBufer type. 2022-08-14 18:53:28 +03:00
Sandu Liviu Catalin 804a5abb29 Update Official.cpp
continuous-integration/drone/push Build was killed
2022-07-23 23:17:31 +03:00
Sandu Liviu Catalin 68551e4466 Allow either player type for announcing in legacy mode. 2022-07-23 23:16:53 +03:00
Sandu Liviu Catalin 4618577ae4 Implement .Legacy member for native entity types. 2022-07-23 22:09:30 +03:00
Sandu Liviu Catalin 2f428962c8 Update Official.cpp 2022-07-23 21:55:46 +03:00
Sandu Liviu Catalin 34a78dc166 More work on async statements for SQLite. 2022-07-23 21:41:10 +03:00
Sandu Liviu Catalin 49df7b75ee Asynchronous statements implementation for SQLite.
Extend worker threads to allow tasks to re-queue themselves during completion.
2022-07-23 19:27:40 +03:00
Sandu Liviu Catalin 0d927f5d72 Remove log. 2022-07-23 17:50:58 +03:00
Sandu Liviu Catalin 44243aadd2 Fix removal of non alpha-numeric characters from strings. 2022-07-23 17:42:01 +03:00
Sandu Liviu Catalin aa3952fd45 Update SqBase.hpp
continuous-integration/drone/push Build was killed
2022-07-21 23:45:09 +03:00
Sandu Liviu Catalin ebe60ebf4b Update Data.cpp
continuous-integration/drone/push Build was killed
2022-07-19 20:03:00 +03:00
Sandu Liviu Catalin fa9c3a5821 Check for a valid session pointer. 2022-07-19 19:43:30 +03:00
Sandu Liviu Catalin f238588abe More work on async sql.
Current implementation only provides execution for sqlite queries in worker threads. Statements and MySQL is on the TODO list.
2022-07-19 19:29:32 +03:00
Sandu Liviu Catalin 39524098f1 Extend worker pool.
Task exceptions are caught and they can provide custom information to identify the task that failed.
Take ownership of the task instance sooner.
2022-07-19 19:28:13 +03:00
Sandu Liviu Catalin ea63899c9a Mark unreachable code. 2022-07-04 20:05:21 +03:00
Sandu Liviu Catalin 8f11e08150 Allow session pool to be used with legacy database wrappers (experimental). 2022-07-04 19:39:41 +03:00
Sandu Liviu Catalin b8b5e89216 Update sqmem.cpp 2022-06-25 02:31:05 +03:00
Sandu Liviu Catalin 87387999f3 Remove old POCO RegEx. 2022-06-25 02:30:33 +03:00
Sandu Liviu Catalin d6a56feb87 Update sqmem.cpp 2022-06-25 00:35:57 +03:00
Sandu Liviu Catalin 9c94fb7afc Update CMakeLists.txt 2022-06-25 00:35:53 +03:00
Sandu Liviu Catalin 2f3684e251 Update sqratMemberMethods.h 2022-06-25 00:35:44 +03:00
Sandu Liviu Catalin 7afc05e52b Add rpmalloc as a thread-safe alternative. 2022-06-24 22:51:20 +03:00
Sandu Liviu Catalin eca11b73ba Update SimpleIni.h 2022-06-24 22:49:23 +03:00
Sandu Liviu Catalin 5c54dc6a95 Update sqratClass.h 2022-06-24 22:49:09 +03:00
Sandu Liviu Catalin 9330cd4eb3 Update Weapon.cpp 2022-06-24 22:49:03 +03:00
Sandu Liviu Catalin 7576409ceb Update Vehicle.cpp 2022-06-24 22:48:58 +03:00
Sandu Liviu Catalin f278d151d6 Update Player.cpp 2022-06-24 22:48:54 +03:00
Sandu Liviu Catalin b3b57d5b2b Update VecMap.hpp 2022-06-24 22:48:48 +03:00
Sandu Liviu Catalin c4130c589f Update ThreadPool.hpp 2022-06-23 21:50:23 +03:00
Sandu Liviu Catalin 2d24860905 Update RegEx.hpp 2022-06-23 21:07:52 +03:00
Sandu Liviu Catalin eb90d9bc99 Update Net.hpp 2022-06-23 21:07:48 +03:00
Sandu Liviu Catalin b87e68b9fc Add an extra method to the logger. 2022-06-23 21:07:44 +03:00
Sandu Liviu Catalin a1a71ee031 Validate sub-str range. 2022-06-13 04:00:41 +03:00
Sandu Liviu Catalin c4b9b4c0a5 Basic implementation of PCRE.
Just the foundation is currently implemented. Utilities are to be added with time.
2022-06-13 03:51:39 +03:00
Sandu Liviu Catalin b3f9f9e47a Fix entity quaternion properties.
Vector flag enumeration was used instead of Quaternion flag enumeration.
2022-03-22 21:11:17 +02:00
Sandu Liviu Catalin a2421afca1 Fix player iteration. 2022-03-19 23:51:34 +02:00
Sandu Liviu Catalin e2cbd7d5cf Update SQLite. 2022-03-16 22:37:44 +02:00
Sandu Liviu Catalin 2725387112 Update MySQL.hpp 2022-03-16 22:36:50 +02:00
Sandu Liviu Catalin 7248351469 Update Areas.cpp 2022-03-16 22:36:48 +02:00
Sandu Liviu Catalin e253dc2038 Update formatting library. 2022-03-16 22:36:44 +02:00
Sandu Liviu Catalin 38f0a53cd8 Fix areas with a temporary workaround. 2022-03-16 21:58:00 +02:00
Sandu Liviu Catalin 1c7fee69ea Update RegEx.cpp 2022-03-16 18:33:49 +02:00
Sandu Liviu Catalin 2b85b3a035 Update Signal.cpp 2022-03-16 17:21:53 +02:00
Sandu Liviu Catalin 11fb1fa25c Update Events.inc 2022-03-16 17:02:11 +02:00
149 changed files with 27103 additions and 14072 deletions
+17
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+3
View File
@@ -6,6 +6,9 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------
struct CtxJSON;
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Helper constants used by the bas types. * Helper constants used by the bas types.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+15
View File
@@ -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 >)
+5
View File
@@ -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.
*/ */
+12 -3
View File
@@ -80,6 +80,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 +107,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
@@ -132,7 +132,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?
@@ -203,6 +203,15 @@ endif(WIN32)
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}/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)
@@ -218,7 +227,7 @@ if(WIN32 AND MINGW AND COPY_DEPENDENCIES)
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")
+70 -5
View File
@@ -993,28 +993,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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+8
View File
@@ -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
View File
@@ -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
+2 -1
View File
@@ -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
} }
+1
View File
@@ -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)
+35 -6
View File
@@ -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
View File
@@ -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
+14
View File
@@ -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:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
+13
View File
@@ -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)
+6
View File
@@ -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
+13
View File
@@ -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)
+6
View File
@@ -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
+13
View File
@@ -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)
+6
View File
@@ -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
+13 -1
View File
@@ -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)
+6
View File
@@ -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
+13
View File
@@ -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)
+6
View File
@@ -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
+6 -2
View File
@@ -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;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
+56 -13
View File
@@ -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,7 @@ 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};
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@@ -352,7 +359,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 +372,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 +498,8 @@ 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)
); );
} }
+47 -7
View File
@@ -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;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@@ -761,6 +791,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
+592 -5
View File
@@ -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,600 @@ static SQInteger SqFromJSON(HSQUIRRELVM vm) noexcept
return SQ_SUCCEEDED(r) ? 1 : r; 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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+237 -179
View File
File diff suppressed because it is too large Load Diff
+14
View File
@@ -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
View File
@@ -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
+191
View File
@@ -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
+885
View File
@@ -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
View File
@@ -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
View File
@@ -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.
}; };
+15
View File
@@ -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)
{ {
+5
View File
@@ -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.
*/ */
+7
View File
@@ -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
+123 -62
View File
@@ -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);
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
+4 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
-112
View File
@@ -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
-481
View File
@@ -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
-2
View File
@@ -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
View File
@@ -39,6 +39,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 +107,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);
+1 -1
View File
@@ -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"
+75
View File
@@ -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
/// ///
+25 -16
View File
@@ -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();
} }
+6 -6
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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)
+11 -27
View File
@@ -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 ()
+382 -8
View File
@@ -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>`_).
+9 -8
View File
@@ -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`_).
+55 -33
View File
@@ -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
View File
@@ -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 %}
+5 -1
View File
@@ -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=}}" \
+1 -1
View File
@@ -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
+46 -18
View File
@@ -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"
+4 -14
View File
@@ -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
+992 -229
View File
File diff suppressed because it is too large Load Diff
+110 -54
View File
@@ -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
+29 -65
View File
@@ -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
+530 -314
View File
File diff suppressed because it is too large Load Diff
+1098 -1046
View File
File diff suppressed because it is too large Load Diff
+823 -446
View File
File diff suppressed because it is too large Load Diff
+46 -82
View File
@@ -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
+48 -86
View File
@@ -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
+12 -7
View File
@@ -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;
+234 -355
View File
@@ -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;
} }
+18 -18
View File
@@ -5,8 +5,8 @@
// //
// For the license information refer to format.h. // For the license information refer to format.h.
#ifndef FMT_WCHAR_H_ #ifndef FMT_XCHAR_H_
#define FMT_WCHAR_H_ #define FMT_XCHAR_H_
#include <cwchar> #include <cwchar>
#include <tuple> #include <tuple>
@@ -92,8 +92,8 @@ auto vformat(basic_string_view<Char> format_str,
template <typename S, typename... Args, typename Char = char_t<S>, template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)> FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> { auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); return vformat(to_string_view(format_str),
return vformat(to_string_view(format_str), vargs); fmt::make_format_args<buffer_context<Char>>(args...));
} }
template <typename Locale, typename S, typename Char = char_t<S>, template <typename Locale, typename S, typename Char = char_t<S>,
@@ -113,7 +113,7 @@ template <typename Locale, typename S, typename... Args,
inline auto format(const Locale& loc, const S& format_str, Args&&... args) inline auto format(const Locale& loc, const S& format_str, Args&&... args)
-> std::basic_string<Char> { -> std::basic_string<Char> {
return detail::vformat(loc, to_string_view(format_str), return detail::vformat(loc, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...)); fmt::make_format_args<buffer_context<Char>>(args...));
} }
template <typename OutputIt, typename S, typename Char = char_t<S>, template <typename OutputIt, typename S, typename Char = char_t<S>,
@@ -132,8 +132,8 @@ template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)> detail::is_exotic_char<Char>::value)>
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt { inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...); return vformat_to(out, to_string_view(fmt),
return vformat_to(out, to_string_view(fmt), vargs); fmt::make_format_args<buffer_context<Char>>(args...));
} }
template <typename S, typename... Args, typename Char, size_t SIZE, template <typename S, typename... Args, typename Char, size_t SIZE,
@@ -141,8 +141,8 @@ template <typename S, typename... Args, typename Char, size_t SIZE,
FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf, FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
const S& format_str, Args&&... args) -> const S& format_str, Args&&... args) ->
typename buffer_context<Char>::iterator { typename buffer_context<Char>::iterator {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); detail::vformat_to(buf, to_string_view(format_str),
detail::vformat_to(buf, to_string_view(format_str), vargs, {}); fmt::make_format_args<buffer_context<Char>>(args...), {});
return detail::buffer_appender<Char>(buf); return detail::buffer_appender<Char>(buf);
} }
@@ -167,8 +167,8 @@ template <
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
Args&&... args) -> Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type { typename std::enable_if<enable, OutputIt>::type {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); return vformat_to(out, loc, to_string_view(format_str),
return vformat_to(out, loc, to_string_view(format_str), vargs); fmt::make_format_args<buffer_context<Char>>(args...));
} }
template <typename OutputIt, typename Char, typename... Args, template <typename OutputIt, typename Char, typename... Args,
@@ -190,16 +190,16 @@ template <typename OutputIt, typename S, typename... Args,
detail::is_exotic_char<Char>::value)> detail::is_exotic_char<Char>::value)>
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
const Args&... args) -> format_to_n_result<OutputIt> { const Args&... args) -> format_to_n_result<OutputIt> {
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...); return vformat_to_n(out, n, to_string_view(fmt),
return vformat_to_n(out, n, to_string_view(fmt), vargs); fmt::make_format_args<buffer_context<Char>>(args...));
} }
template <typename S, typename... Args, typename Char = char_t<S>, template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t { inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
detail::counting_buffer<Char> buf; detail::counting_buffer<Char> buf;
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...); detail::vformat_to(buf, to_string_view(fmt),
detail::vformat_to(buf, to_string_view(fmt), vargs); fmt::make_format_args<buffer_context<Char>>(args...));
return buf.count(); return buf.count();
} }
@@ -217,11 +217,11 @@ inline void vprint(wstring_view fmt, wformat_args args) {
template <typename... T> template <typename... T>
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return vprint(f, wstring_view(fmt), make_wformat_args(args...)); return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
} }
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
return vprint(wstring_view(fmt), make_wformat_args(args...)); return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
} }
/** /**
@@ -233,4 +233,4 @@ template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
FMT_MODULE_EXPORT_END FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_WCHAR_H_ #endif // FMT_XCHAR_H_
-1
View File
@@ -79,7 +79,6 @@ export module fmt;
#define FMT_END_DETAIL_NAMESPACE \ #define FMT_END_DETAIL_NAMESPACE \
} \ } \
export { export {
// all library-provided declarations and definitions // all library-provided declarations and definitions
// must be in the module purview to be exported // must be in the module purview to be exported
#include "fmt/args.h" #include "fmt/args.h"
+50 -4
View File
@@ -10,6 +10,52 @@
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace detail { namespace detail {
// DEPRECATED!
template <typename T = void> struct basic_data {
FMT_API static constexpr const char digits[100][2] = {
{'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
{'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
{'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
{'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
{'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
{'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
{'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
{'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
{'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
{'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
{'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
{'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
{'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
{'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
{'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
FMT_API static constexpr const char hex_digits[] = "0123456789abcdef";
FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '};
FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1,
0};
FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1,
0};
FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
0x1000000u | ' '};
};
#ifdef FMT_SHARED
// Required for -flto, -fivisibility=hidden and -shared to work
extern template struct basic_data<void>;
#endif
#if __cplusplus < 201703L
// DEPRECATED! These are here only for ABI compatiblity.
template <typename T> constexpr const char basic_data<T>::digits[][2];
template <typename T> constexpr const char basic_data<T>::hex_digits[];
template <typename T> constexpr const char basic_data<T>::signs[];
template <typename T> constexpr const char basic_data<T>::left_padding_shifts[];
template <typename T>
constexpr const char basic_data<T>::right_padding_shifts[];
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
#endif
template <typename T> template <typename T>
int format_float(char* buf, std::size_t size, const char* format, int precision, int format_float(char* buf, std::size_t size, const char* format, int precision,
T value) { T value) {
@@ -24,10 +70,10 @@ int format_float(char* buf, std::size_t size, const char* format, int precision,
: snprintf_ptr(buf, size, format, precision, value); : snprintf_ptr(buf, size, format, precision, value);
} }
template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x) template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(
FMT_NOEXCEPT; float x) noexcept;
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x) template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(
FMT_NOEXCEPT; double x) noexcept;
} // namespace detail } // namespace detail
// Workaround a bug in MSVC2013 that prevents instantiation of format_float. // Workaround a bug in MSVC2013 that prevents instantiation of format_float.
+26 -18
View File
@@ -26,19 +26,23 @@
# endif # endif
# include <io.h> # include <io.h>
# define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC
# ifndef S_IRUSR # ifndef S_IRUSR
# define S_IRUSR _S_IREAD # define S_IRUSR _S_IREAD
# endif # endif
# ifndef S_IWUSR # ifndef S_IWUSR
# define S_IWUSR _S_IWRITE # define S_IWUSR _S_IWRITE
# endif # endif
# ifndef S_IRGRP
# ifdef __MINGW32__ # define S_IRGRP 0
# define _SH_DENYNO 0x40 # endif
# ifndef S_IWGRP
# define S_IWGRP 0
# endif
# ifndef S_IROTH
# define S_IROTH 0
# endif
# ifndef S_IWOTH
# define S_IWOTH 0
# endif # endif
# endif // _WIN32 # endif // _WIN32
#endif // FMT_USE_FCNTL #endif // FMT_USE_FCNTL
@@ -109,7 +113,7 @@ class system_message {
unsigned long result_; unsigned long result_;
wchar_t* message_; wchar_t* message_;
static bool is_whitespace(wchar_t c) FMT_NOEXCEPT { static bool is_whitespace(wchar_t c) noexcept {
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
} }
@@ -128,15 +132,15 @@ class system_message {
} }
} }
~system_message() { LocalFree(message_); } ~system_message() { LocalFree(message_); }
explicit operator bool() const FMT_NOEXCEPT { return result_ != 0; } explicit operator bool() const noexcept { return result_ != 0; }
operator basic_string_view<wchar_t>() const FMT_NOEXCEPT { operator basic_string_view<wchar_t>() const noexcept {
return basic_string_view<wchar_t>(message_, result_); return basic_string_view<wchar_t>(message_, result_);
} }
}; };
class utf8_system_category final : public std::error_category { class utf8_system_category final : public std::error_category {
public: public:
const char* name() const FMT_NOEXCEPT override { return "system"; } const char* name() const noexcept override { return "system"; }
std::string message(int error_code) const override { std::string message(int error_code) const override {
system_message msg(error_code); system_message msg(error_code);
if (msg) { if (msg) {
@@ -151,7 +155,7 @@ class utf8_system_category final : public std::error_category {
} // namespace detail } // namespace detail
FMT_API const std::error_category& system_category() FMT_NOEXCEPT { FMT_API const std::error_category& system_category() noexcept {
static const detail::utf8_system_category category; static const detail::utf8_system_category category;
return category; return category;
} }
@@ -163,7 +167,7 @@ std::system_error vwindows_error(int err_code, string_view format_str,
} }
void detail::format_windows_error(detail::buffer<char>& out, int error_code, void detail::format_windows_error(detail::buffer<char>& out, int error_code,
const char* message) FMT_NOEXCEPT { const char* message) noexcept {
FMT_TRY { FMT_TRY {
system_message msg(error_code); system_message msg(error_code);
if (msg) { if (msg) {
@@ -178,12 +182,12 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
format_error_code(out, error_code, message); format_error_code(out, error_code, message);
} }
void report_windows_error(int error_code, const char* message) FMT_NOEXCEPT { void report_windows_error(int error_code, const char* message) noexcept {
report_error(detail::format_windows_error, error_code, message); report_error(detail::format_windows_error, error_code, message);
} }
#endif // _WIN32 #endif // _WIN32
buffered_file::~buffered_file() FMT_NOEXCEPT { buffered_file::~buffered_file() noexcept {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0) if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
report_system_error(errno, "cannot close file"); report_system_error(errno, "cannot close file");
} }
@@ -213,7 +217,11 @@ int buffered_file::fileno() const {
#if FMT_USE_FCNTL #if FMT_USE_FCNTL
file::file(cstring_view path, int oflag) { file::file(cstring_view path, int oflag) {
int mode = S_IRUSR | S_IWUSR; # ifdef _WIN32
using mode_t = int;
# endif
constexpr mode_t mode =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
# if defined(_WIN32) && !defined(__MINGW32__) # if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1; fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
@@ -224,7 +232,7 @@ file::file(cstring_view path, int oflag) {
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str())); FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
} }
file::~file() FMT_NOEXCEPT { file::~file() noexcept {
// Don't retry close in case of EINTR! // Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
@@ -298,7 +306,7 @@ void file::dup2(int fd) {
} }
} }
void file::dup2(int fd, std::error_code& ec) FMT_NOEXCEPT { void file::dup2(int fd, std::error_code& ec) noexcept {
int result = 0; int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) ec = std::error_code(errno, std::generic_category()); if (result == -1) ec = std::error_code(errno, std::generic_category());
+29
View File
@@ -0,0 +1,29 @@
cc_library(
name = "fmt",
srcs = [
#"src/fmt.cc", # No C++ module support
"src/format.cc",
"src/os.cc",
],
hdrs = [
"include/fmt/args.h",
"include/fmt/chrono.h",
"include/fmt/color.h",
"include/fmt/compile.h",
"include/fmt/core.h",
"include/fmt/format.h",
"include/fmt/format-inl.h",
"include/fmt/locale.h",
"include/fmt/os.h",
"include/fmt/ostream.h",
"include/fmt/printf.h",
"include/fmt/ranges.h",
"include/fmt/xchar.h",
],
includes = [
"include",
"src",
],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)
+73
View File
@@ -0,0 +1,73 @@
# Bazel support
To get [Bazel](https://bazel.build/) working with {fmt} you can copy the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` from this folder (`support/bazel`) to the root folder of this project. This way {fmt} gets bazelized and can be used with Bazel (e.g. doing a `bazel build //...` on {fmt}).
## Using {fmt} as a dependency
The following minimal example shows how to use {fmt} as a dependency within a Bazel project.
The following file structure is assumed:
```
example
├── BUILD.bazel
├── main.cpp
└── WORKSPACE.bazel
```
*main.cpp*:
```c++
#include "fmt/core.h"
int main() {
fmt::print("The answer is {}\n", 42);
}
```
The expected output of this example is `The answer is 42`.
*WORKSPACE.bazel*:
```python
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "fmt",
branch = "master",
remote = "https://github.com/fmtlib/fmt",
patch_cmds = [
"mv support/bazel/.bazelrc .bazelrc",
"mv support/bazel/.bazelversion .bazelversion",
"mv support/bazel/BUILD.bazel BUILD.bazel",
"mv support/bazel/WORKSPACE.bazel WORKSPACE.bazel",
],
# Windows-related patch commands are only needed in the case MSYS2 is not installed.
# More details about the installation process of MSYS2 on Windows systems can be found here:
# https://docs.bazel.build/versions/main/install-windows.html#installing-compilers-and-language-runtimes
# Even if MSYS2 is installed the Windows related patch commands can still be used.
patch_cmds_win = [
"Move-Item -Path support/bazel/.bazelrc -Destination .bazelrc",
"Move-Item -Path support/bazel/.bazelversion -Destination .bazelversion",
"Move-Item -Path support/bazel/BUILD.bazel -Destination BUILD.bazel",
"Move-Item -Path support/bazel/WORKSPACE.bazel -Destination WORKSPACE.bazel",
],
)
```
In the *WORKSPACE* file, the {fmt} GitHub repository is fetched. Using the attribute `patch_cmds` the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` are moved to the root of the {fmt} repository. This way the {fmt} repository is recognized as a bazelized workspace.
*BUILD.bazel*:
```python
cc_binary(
name = "Demo",
srcs = ["main.cpp"],
deps = ["@fmt"],
)
```
The *BUILD* file defines a binary named `Demo` that has a dependency to {fmt}.
To execute the binary you can run `bazel run //:Demo`.

Some files were not shown because too many files have changed in this diff Show More