diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index c691c14c..261af55f 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -46,7 +46,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp # Entity Entity/Blip.cpp Entity/Blip.hpp Entity/Checkpoint.cpp Entity/Checkpoint.hpp - Entity/KeyBind.cpp Entity/KeyBind.hpp + Entity/KeyBind.cpp Entity/KeyBind.hpp Entity/Object.cpp Entity/Object.hpp Entity/Pickup.cpp Entity/Pickup.hpp Entity/Player.cpp Entity/Player.hpp @@ -64,8 +64,6 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp Library/IO/Buffer.cpp Library/IO/Buffer.hpp Library/IO/File.cpp Library/IO/File.hpp Library/IO/INI.cpp Library/IO/INI.hpp - Library/IO/JSON.cpp Library/IO/JSON.hpp - Library/IO/XML.cpp Library/IO/XML.hpp Library/Numeric.cpp Library/Numeric.hpp Library/Numeric/Long.cpp Library/Numeric/Long.hpp Library/Numeric/Math.cpp Library/Numeric/Math.hpp @@ -76,6 +74,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp Library/System/Env.cpp Library/System/Env.hpp Library/System/Path.cpp Library/System/Path.hpp Library/Utils.cpp Library/Utils.hpp + Library/Utils/Vector.cpp Library/Utils/Vector.hpp # Misc Misc/Broadcast.cpp Misc/Constants.cpp @@ -86,6 +85,14 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp Misc/Player.cpp Misc/Player.hpp Misc/Vehicle.cpp Misc/Vehicle.hpp Misc/Weapon.cpp Misc/Weapon.hpp + # POCO + PocoLib/Crypto.cpp PocoLib/Crypto.hpp + PocoLib/Data.cpp PocoLib/Data.hpp + PocoLib/Foundation.cpp PocoLib/Foundation.hpp + PocoLib/JSON.cpp PocoLib/JSON.hpp + PocoLib/Net.cpp PocoLib/Net.hpp + PocoLib/Util.cpp PocoLib/Util.hpp + PocoLib/XML.cpp PocoLib/XML.hpp # Core.cpp Core.hpp Logger.cpp Logger.hpp @@ -99,7 +106,30 @@ endif() # Link to base libraries target_link_libraries(SqModule Squirrel FmtLib SimpleINI TinyDir ConcurrentQueue cpr::cpr) # Link to POCO libraries -target_link_libraries(SqModule Poco::Foundation Poco::Encodings Poco::Crypto Poco::Util Poco::Data Poco::Net Poco::JSON Poco::XML Poco::Zip Poco::JWT Poco::Redis) +target_link_libraries(SqModule Poco::Foundation Poco::Encodings Poco::Crypto Poco::Util Poco::Data Poco::Net Poco::JSON Poco::XML Poco::Zip Poco::JWT Poco::Redis Poco::MongoDB) +# Does POCO have SQLite support? +if(ENABLE_DATA_SQLITE) + # Link the libraries + target_link_libraries(SqModule Poco::DataSQLite) + # Inform the plugin that it can make use of this library + target_compile_definitions(SqModule PRIVATE SQMOD_POCO_HAS_SQLITE=1) +endif() +# Does POCO have MySLQ support? +find_package(MySQL) +if(MYSQL_FOUND) + # Link the libraries + target_link_libraries(SqModule Poco::DataMySQL) + # Inform the plugin that it can make use of this library + target_compile_definitions(SqModule PRIVATE SQMOD_POCO_HAS_MYSQL=1) +endif() +# Does POCO have PostgreSQL support? +find_package(PostgreSQL) +if(POSTGRESQL_FOUND) + # Link the libraries + target_link_libraries(SqModule Poco::DataPostgreSQL) + # Inform the plugin that it can make use of this library + target_compile_definitions(SqModule PRIVATE SQMOD_POCO_HAS_POSTGRESQL=1) +endif() # Determine if build mode if(CMAKE_BUILD_TYPE MATCHES "(Release)+") target_compile_definitions(SqModule PRIVATE NDEBUG=1) diff --git a/module/Core.cpp b/module/Core.cpp index 7de9efd7..80804b18 100644 --- a/module/Core.cpp +++ b/module/Core.cpp @@ -37,6 +37,7 @@ namespace SqMod { extern bool RegisterAPI(HSQUIRRELVM vm); // ------------------------------------------------------------------------------------------------ +extern void PocoStartup(); extern void InitializeTasks(); extern void InitializeRoutines(); extern void TerminateAreas(); diff --git a/module/Library/IO/JSON.cpp b/module/Library/IO/JSON.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/module/Library/IO/JSON.hpp b/module/Library/IO/JSON.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/module/Library/IO/XML.cpp b/module/Library/IO/XML.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/module/Library/IO/XML.hpp b/module/Library/IO/XML.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/module/Library/Utils.cpp b/module/Library/Utils.cpp index 21f807f0..888d6049 100644 --- a/module/Library/Utils.cpp +++ b/module/Library/Utils.cpp @@ -81,12 +81,19 @@ static SQInteger SqExtractIPv4(HSQUIRRELVM vm) return 1; } +// ------------------------------------------------------------------------------------------------ +extern void Register_Vector(HSQUIRRELVM vm, Table & ns); + // ================================================================================================ void Register_Utils(HSQUIRRELVM vm) { - RootTable(vm).Bind(_SC("SqUtils"), Table(vm) - .SquirrelFunc(_SC("ExtractIPv4"), &SqExtractIPv4) - ); + Table ns(vm); + + Register_Vector(vm, ns); + + ns.SquirrelFunc(_SC("ExtractIPv4"), &SqExtractIPv4); + + RootTable(vm).Bind(_SC("SqUtils"), ns); } } // Namespace:: SqMod diff --git a/module/Library/Utils/Vector.cpp b/module/Library/Utils/Vector.cpp new file mode 100644 index 00000000..d2de1140 --- /dev/null +++ b/module/Library/Utils/Vector.cpp @@ -0,0 +1,77 @@ +// ------------------------------------------------------------------------------------------------ +#include "Library/Utils/Vector.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQMOD_DECL_TYPENAME(SqVectorInteger, _SC("SqVectorInteger")) +SQMOD_DECL_TYPENAME(SqVectorString, _SC("SqVectorString")) +SQMOD_DECL_TYPENAME(SqVectorFloat, _SC("SqVectorFloat")) +SQMOD_DECL_TYPENAME(SqVectorByte, _SC("SqVectorByte")) +SQMOD_DECL_TYPENAME(SqVectorBool, _SC("SqVectorBool")) + +// ------------------------------------------------------------------------------------------------ +template < class T, class U > +static void Register_Vector(HSQUIRRELVM vm, Table & ns, const SQChar * name) +{ + using Vector = SqVector< T >; + // -------------------------------------------------------------------------------------------- + Class< Vector, NoCopy< Vector > > cls(vm, U::Str); + // Constructors + cls.Ctor() + .template Ctor< SQInteger >() + .template Ctor< SQInteger, typename Vector::OptimalArg >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &U::Fn) + // Properties + .Prop(_SC("Null"), &Vector::IsNull) + .Prop(_SC("Front"), &Vector::Front) + .Prop(_SC("Back"), &Vector::Back) + .Prop(_SC("Empty"), &Vector::Empty) + .Prop(_SC("Size"), &Vector::Size, &Vector::Resize) + .Prop(_SC("Capacity"), &Vector::Capacity, &Vector::Reserve) + // Member Methods + .Func(_SC("Get"), &Vector::Get) + .Func(_SC("Set"), &Vector::Set) + .Func(_SC("Resize"), &Vector::ResizeEx) + .Func(_SC("Reserve"), &Vector::Reserve) + .Func(_SC("Compact"), &Vector::Compact) + .Func(_SC("Clear"), &Vector::Clear) + .Func(_SC("Push"), &Vector::Push) + .Func(_SC("Pop"), &Vector::Pop) + .Func(_SC("EraseAt"), &Vector::EraseAt) + .Func(_SC("EraseFrom"), &Vector::EraseFrom) + .Func(_SC("EraseValue"), &Vector::EraseValue) + .Func(_SC("InsertAt"), &Vector::InsertAt) + .Func(_SC("Insert"), &Vector::Insert) + .Func(_SC("Locate"), &Vector::Locate) + .Func(_SC("LocateFrom"), &Vector::LocateFrom) + .Func(_SC("Count"), &Vector::Count) + .Func(_SC("Equal"), &Vector::Equal) + .Func(_SC("Each"), &Vector::Each) + .Func(_SC("EachRange"), &Vector::EachRange) + .Func(_SC("While"), &Vector::While) + .Func(_SC("WhileRange"), &Vector::WhileRange) + .Func(_SC("AsArray"), &Vector::AsArray) + .Func(_SC("Reverse"), &Vector::Reverse) + .Func(_SC("Generate"), &Vector::Generate) + .Func(_SC("GenerateSome"), &Vector::GenerateSome) + .Func(_SC("GenerateFrom"), &Vector::GenerateFrom); + // -------------------------------------------------------------------------------------------- + ns.Bind(name, cls); + // Bind it to the root table with a `Sq` prefix + RootTable(vm).Bind(fmt::format("Sq{}", name).c_str(), cls); +} + +// ================================================================================================ +void Register_Vector(HSQUIRRELVM vm, Table & ns) +{ + Register_Vector< SQInteger, SqVectorInteger >(vm, ns, _SC("IntVec")); + Register_Vector< String, SqVectorString >(vm, ns, _SC("StrVec")); + Register_Vector< SQFloat, SqVectorFloat >(vm, ns, _SC("FloatVec")); + Register_Vector< uint8_t, SqVectorByte >(vm, ns, _SC("ByteVec")); + Register_Vector< bool, SqVectorBool >(vm, ns, _SC("BoolVec")); +} + +} // Namespace:: SqMod diff --git a/module/Library/Utils/Vector.hpp b/module/Library/Utils/Vector.hpp new file mode 100644 index 00000000..6a4b8b37 --- /dev/null +++ b/module/Library/Utils/Vector.hpp @@ -0,0 +1,496 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Utility.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Utility used to transform optimal argument type to stored type. +*/ +template < class T > struct SqVectorOpt +{ + /* -------------------------------------------------------------------------------------------- + * Optimal argument type. + */ + using Type = T; + + /* -------------------------------------------------------------------------------------------- + * Convert the optimal type to the stored type. Does nothing special in this case. + */ + inline static Type & Get(Type & v) { return v; } + inline static const Type & Get(const Type & v) { return v; } + // -------------------------------------------------------------------------------------------- + inline static void Put(std::vector< T > & c, SQInteger i, Type & v) + { c[ConvTo< size_t >::From(i)] = v; } + inline static void Put(std::vector< T > & c, SQInteger i, const Type & v) + { c[ConvTo< size_t >::From(i)] = v; } +}; + +/* ------------------------------------------------------------------------------------------------ + * Specialization of SqVectorOpt for String type. +*/ +template < > struct SqVectorOpt< String > +{ + /* -------------------------------------------------------------------------------------------- + * Optimal argument type. + */ + using Type = StackStrF; + + /* -------------------------------------------------------------------------------------------- + * Convert the optimal type to the stored type. + */ + inline static String Get(Type & v) { return v.ToStr(); } + inline static String Get(const Type & v) { return v.ToStr(); } + // -------------------------------------------------------------------------------------------- + inline static void Put(std::vector< String > & c, SQInteger i, Type & v) + { c[ConvTo< size_t >::From(i)].assign(v.mPtr, v.GetSize()); } + inline static void Put(std::vector< String > & c, SQInteger i, const Type & v) + { c[ConvTo< size_t >::From(i)].assign(v.mPtr, v.GetSize()); } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper around a vector of values. Space efficient array. +*/ +template < class T > struct SqVector +{ + /* -------------------------------------------------------------------------------------------- + * Type given via the template parameter. + */ + using Type = T; + + /* -------------------------------------------------------------------------------------------- + * The typeof vector that will be used. + */ + using Vector = std::vector< T >; + + /* -------------------------------------------------------------------------------------------- + * Reference to the vector. + */ + using Reference = std::shared_ptr< Vector >; + + /* -------------------------------------------------------------------------------------------- + * Optimal type to receive a value of this type as function argument. Mainly for strings. + */ + using OptimalType = typename SqVectorOpt< T >::Type; + + /* -------------------------------------------------------------------------------------------- + * Same as OptimalType but preferably with a reference qualifier to avoid copies. + */ + using OptimalArg = typename std::conditional< std::is_same< T, OptimalType >::value, T, OptimalType & >::type; + + /* -------------------------------------------------------------------------------------------- + * A vector of bool needs special treatment from the other types. + */ + using ReturnType = typename std::conditional< std::is_same< T, bool >::value, T, T & >::type; + + /* -------------------------------------------------------------------------------------------- + * Reference to the container instance. + */ + Reference mC; + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + SqVector() + : mC(std::make_shared< Vector >()) + { + } + + /* -------------------------------------------------------------------------------------------- + * Construct with initial capacity. No element is created. + */ + explicit SqVector(SQInteger n) + : SqVector() + { + mC->reserve(static_cast< size_t >(n)); + } + + /* -------------------------------------------------------------------------------------------- + * Construct with initial size. Filled with copies of specified element. + */ + SqVector(SQInteger n, OptimalArg v) + : SqVector() + { + ResizeEx(n, v); + } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + SqVector(SqVector &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destroys the Statement. + */ + ~SqVector() = default; + + /* -------------------------------------------------------------------------------------------- + * Assignment operator. + */ + SqVector & operator = (const SqVector &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment. + */ + SqVector & operator = (SqVector &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Make sure a container instance is referenced. + */ + void Validate() const + { + if (!mC) + { + STHROWF("Invalid container instance"); + } + } + + /* -------------------------------------------------------------------------------------------- + * Make sure a container instance is referenced and return it. + */ + Vector & Valid() const { Validate(); return *mC; } + + /* -------------------------------------------------------------------------------------------- + * Make sure an index is within rance and return the container it. Container must exist. + */ + Vector & ValidIdx(SQInteger i) const + { + if (static_cast< size_t >(i) >= mC->size()) + { + STHROWF("Invalid container index"); + } + return *mC; + } + + /* -------------------------------------------------------------------------------------------- + * Make sure a container instance is referenced and is populated, then return it. + */ + Vector & ValidPop() const + { + Validate(); + if (mC->empty()) + { + STHROWF("Container is empty"); + } + return *mC; + } + + /* -------------------------------------------------------------------------------------------- + * Check if a container instance is referenced. + */ + SQMOD_NODISCARD bool IsNull() const + { + return static_cast< bool >(mC); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve a value from the container. + */ + SQMOD_NODISCARD typename std::add_const< ReturnType >::type Get(SQInteger i) const { return ValidIdx(i).at(ConvTo< size_t >::From(i)); } + + /* -------------------------------------------------------------------------------------------- + * Modify a value from the container. + */ + void Set(SQInteger i, OptimalArg v) + { + SqVectorOpt< T >::Put(ValidIdx(i), i, v); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the first element in the container. + */ + SQMOD_NODISCARD typename std::add_const< ReturnType >::type Front() const { return ValidPop().front(); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the last element in the container. + */ + SQMOD_NODISCARD typename std::add_const< ReturnType >::type Back() const { return ValidPop().back(); } + + /* -------------------------------------------------------------------------------------------- + * Check if the container has no elements. + */ + SQMOD_NODISCARD bool Empty() const { return Valid().empty(); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of elements in the container. + */ + SQMOD_NODISCARD SQInteger Size() const { return static_cast< SQInteger >(Valid().size()); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of elements that the container has currently allocated space for. + */ + SQMOD_NODISCARD SQInteger Capacity() const { return static_cast< SQInteger >(Valid().capacity()); } + + /* -------------------------------------------------------------------------------------------- + * Resize the container to contain a specific amount of elements. + */ + void Resize(SQInteger n) + { + return Valid().resize(ConvTo< size_t >::From(n), T()); + } + + /* -------------------------------------------------------------------------------------------- + * Resize the container to contain a specific amount of elements. + */ + void ResizeEx(SQInteger n, OptimalArg v) + { + return Valid().resize(ConvTo< size_t >::From(n), SqVectorOpt< T >::Get(v)); + } + + /* -------------------------------------------------------------------------------------------- + * Increase the capacity of the vector to a value that's greater or equal to the one specified. + */ + void Reserve(SQInteger n) { return Valid().reserve(ConvTo< size_t >::From(n)); } + + /* -------------------------------------------------------------------------------------------- + * Request the removal of unused capacity. + */ + void Compact() { return Valid().shrink_to_fit(); } + + /* -------------------------------------------------------------------------------------------- + * Erase all elements from the container. + */ + void Clear() { return Valid().clear(); } + + /* -------------------------------------------------------------------------------------------- + * Push a value at the back of the container. + */ + void Push(OptimalArg v) { return Valid().push_back(SqVectorOpt< T >::Get(v)); } + + /* -------------------------------------------------------------------------------------------- + * Pop the last element in the container. + */ + void Pop() { ValidPop().pop_back(); } + + /* -------------------------------------------------------------------------------------------- + * Erase the element at a certain position. + */ + void EraseAt(SQInteger i) + { + Validate(); + mC->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) + { + Validate(); + mC->erase(ValidIdx(i).begin() + static_cast< size_t >(i), + ValidIdx(i + n).begin() + static_cast< size_t >(i + n)); + } + + /* -------------------------------------------------------------------------------------------- + * Erase all occurrences of value from the container. + */ + void EraseValue(OptimalArg v) + { + Validate(); + mC->erase(std::remove(mC->begin(), mC->end(), SqVectorOpt< T >::Get(v)), mC->end()); + } + + /* -------------------------------------------------------------------------------------------- + * Insert a specific value starting from a certain position. + */ + void InsertAt(SQInteger i, OptimalArg v) + { + Validate(); + mC->insert(ValidIdx(i).begin() + static_cast< size_t >(i), SqVectorOpt< T >::Get(v)); + } + + /* -------------------------------------------------------------------------------------------- + * Insert a certain amount of copies of a value starting from a specific position. + */ + void Insert(SQInteger i, SQInteger n, OptimalArg v) + { + Validate(); + mC->insert(ValidIdx(i).begin() + static_cast< size_t >(i), ConvTo< size_t >::From(n), SqVectorOpt< T >::Get(v)); + } + + /* -------------------------------------------------------------------------------------------- + * Locate the position of a value. + */ + SQMOD_NODISCARD SQInteger Locate(OptimalArg v) const + { + auto itr = std::find(Valid().begin(), Valid().end(), SqVectorOpt< T >::Get(v)); + return itr == mC->end() ? -1 : static_cast< SQInteger >(std::distance(mC->begin(), itr)); + } + + /* -------------------------------------------------------------------------------------------- + * Locate the position of a value starting from an offset. + */ + SQMOD_NODISCARD SQInteger LocateFrom(SQInteger p, OptimalArg v) const + { + Validate(); + auto itr = std::find(ValidIdx(p).begin() + static_cast< size_t >(p), + Valid().end(), SqVectorOpt< T >::Get(v)); + return itr == mC->end() ? -1 : static_cast< SQInteger >(std::distance(mC->begin(), itr)); + } + + /* -------------------------------------------------------------------------------------------- + * Count the occurrences of a value in the container. + */ + SQMOD_NODISCARD SQInteger Count(OptimalArg v) const + { + return static_cast< SQInteger >(std::count(Valid().begin(), Valid().end(), SqVectorOpt< T >::Get(v))); + } + + /* -------------------------------------------------------------------------------------------- + * See if values are the same as another container. + */ + SQMOD_NODISCARD bool Equal(SqVector & o) const { return Valid() == o.Valid(); } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values. + */ + void Each(Function & fn) const + { + Validate(); + for (const auto & e : *mC) + { + fn.Execute(e); + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate values in range. + */ + void EachRange(SQInteger p, SQInteger n, Function & fn) const + { + Validate(); + std::for_each(ValidIdx(p).begin() + static_cast< size_t >(p), + ValidIdx(p + n).begin() + static_cast< size_t >(p + n), + [&](const T & e) { + fn.Execute(e); + }); + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values until stopped. + */ + void While(Function & fn) const + { + Validate(); + for (const auto & e : *mC) + { + auto ret = fn.Eval(e); + // (null || true) == continue & false == break + if (!ret.IsNull() || !ret.template Cast< bool >()) + { + break; + } + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate values in range until stopped. + */ + void WhileRange(SQInteger p, SQInteger n, Function & fn) const + { + Validate(); + 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(*itr); + // (null || true) == continue & false == break + if (!ret.IsNull() || !ret.template Cast< bool >()) + { + break; + } + } + } + + /* -------------------------------------------------------------------------------------------- + * Create a script array with the elements from the container. + */ + SQMOD_NODISCARD Array AsArray() const + { + Validate(); + // Create a script array + Array arr(SqVM()); + // Reserve space in advance + arr.Reserve(static_cast< SQInteger >(mC->size())); + // Make sure to preserve the stack + StackGuard sg(SqVM()); + // Populate the array with vector elements + arr.AppendFromCounted([](HSQUIRRELVM vm, SQInteger i, const Vector & v) -> bool { + if (static_cast< size_t >(i) < v.size()) + { + Var< T >::push(vm, v[static_cast< size_t >(i)]); + // There's a value on the stack + return true; + } + // No more elements + return false; + }, *mC); + // Return the array + return arr; + } + + /* -------------------------------------------------------------------------------------------- + * Reverse the order of elements in the container. + */ + void Reverse() + { + std::reverse(Valid().begin(), Valid().end()); + } + + /* -------------------------------------------------------------------------------------------- + * Generate new elements at the back of the container. + */ + void Generate(LightObj & ctx, Function & fn) + { + for (;;) + { + auto ret = fn.Eval(ctx); + // null == break + if (ret.IsNull()) + { + break; + } + // Extract the value from object + mC->push_back(ret.Cast< T >()); + } + } + + /* -------------------------------------------------------------------------------------------- + * Generate new elements at the back of the container. + */ + void GenerateSome(SQInteger n, LightObj & ctx, Function & fn) + { + while (n--) + { + auto ret = fn.Eval(ctx); + // Extract the value from object + mC->push_back(ret.Cast< T >()); + } + } + + /* -------------------------------------------------------------------------------------------- + * Generate new elements at specified position. + */ + void GenerateFrom(SQInteger p, SQInteger n, LightObj & ctx, Function & fn) + { + Validate(); + if (static_cast< size_t >(p) >= mC->size()) + { + STHROWF("Invalid container index"); + } + for (auto i = static_cast< size_t >(p); n--; ++i) + { + auto ret = fn.Eval(ctx); + // Extract the value from object and insert it + mC->insert(mC->begin() + i, ret.Cast< T >()); + } + } +}; + +} // Namespace:: SqMod diff --git a/module/Main.cpp b/module/Main.cpp index 5a5a4875..2677674a 100644 --- a/module/Main.cpp +++ b/module/Main.cpp @@ -18,6 +18,7 @@ static bool g_Reload = false; // ------------------------------------------------------------------------------------------------ //extern void InitExports(); +extern void InitializePocoDataConnectors(); extern void ProcessTasks(); extern void ProcessRoutines(); @@ -969,6 +970,9 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback // Attempt to initialize the plug-in core try { + // External plugs that need to happen (once) before initialization + InitializePocoDataConnectors(); + // Proceed with plug-in initialization if (!Core::Get().Initialize()) { LogFtl("Unable to initialize the plug-in central core"); diff --git a/module/PocoLib/Crypto.cpp b/module/PocoLib/Crypto.cpp new file mode 100644 index 00000000..d9abca6d --- /dev/null +++ b/module/PocoLib/Crypto.cpp @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------------------------ +#include "PocoLib/Crypto.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ + + +// ================================================================================================ +void Register_POCO_Crypto(HSQUIRRELVM vm) +{ + Table ns(vm); + + RootTable(vm).Bind(_SC("SqCrypto"), ns); +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/Crypto.hpp b/module/PocoLib/Crypto.hpp new file mode 100644 index 00000000..4eca0ee6 --- /dev/null +++ b/module/PocoLib/Crypto.hpp @@ -0,0 +1,11 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + + + +} // Namespace:: SqMod diff --git a/module/PocoLib/Data.cpp b/module/PocoLib/Data.cpp new file mode 100644 index 00000000..f12f9acb --- /dev/null +++ b/module/PocoLib/Data.cpp @@ -0,0 +1,324 @@ +// ------------------------------------------------------------------------------------------------ +#include "PocoLib/Data.hpp" + +// ------------------------------------------------------------------------------------------------ +#ifdef SQMOD_POCO_HAS_SQLITE + #include +#endif +#ifdef SQMOD_POCO_HAS_MYSQL + #include +#endif +#ifdef SQMOD_POCO_HAS_POSTGRESQL + #include +#endif +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQMOD_DECL_TYPENAME(SqIntegerBinding, _SC("SqIntegerBinding")) +SQMOD_DECL_TYPENAME(SqStringBinding, _SC("SqStringBinding")) +SQMOD_DECL_TYPENAME(SqFloatBinding, _SC("SqFloatBinding")) +SQMOD_DECL_TYPENAME(SqBoolBinding, _SC("SqBoolBinding")) + +// ------------------------------------------------------------------------------------------------ +SQMOD_DECL_TYPENAME(SqPcDataSession, _SC("SqDataSession")) +SQMOD_DECL_TYPENAME(SqPcDataStatement, _SC("SqDataStatement")) + +// ------------------------------------------------------------------------------------------------ +static const Poco::Data::NullData g_NullData{Poco::NULL_GENERIC}; + +// ------------------------------------------------------------------------------------------------ +void InitializePocoDataConnectors() +{ +#ifdef SQMOD_POCO_HAS_SQLITE + Poco::Data::SQLite::Connector::registerConnector(); +#endif +#ifdef SQMOD_POCO_HAS_MYSQL + Poco::Data::MySQL::Connector::registerConnector(); +#endif +#ifdef SQMOD_POCO_HAS_POSTGRESQL + Poco::Data::PostgreSQL::Connector::registerConnector(); +#endif +} + +// ------------------------------------------------------------------------------------------------ +void SqDataSession::SetProperty(const LightObj & value, StackStrF & name) +{ + switch (value.GetType()) + { + case OT_NULL: { + setProperty(name.ToStr(), Poco::Any(nullptr)); + } break; + case OT_INTEGER: { + setProperty(name.ToStr(), Poco::Any(value.Cast())); + } break; + case OT_FLOAT: { + setProperty(name.ToStr(), Poco::Any(value.Cast())); + } break; + case OT_BOOL: { + setProperty(name.ToStr(), Poco::Any(value.Cast())); + } break; + case OT_STRING: { + setProperty(name.ToStr(), Poco::Any(value.Cast())); + } break; + default: STHROWF("Unsupported property value type"); + } +} + +// ------------------------------------------------------------------------------------------------ +LightObj SqDataSession::GetProperty(StackStrF & name) const +{ + HSQUIRRELVM vm = name.mVM; + // Preserve stack + const StackGuard sg(vm); + // Retrieve the property value + Poco::Any a = getProperty(name.ToStr()); + // Retrieve the value type + const auto & ti = a.type(); + // Identify the stored value + if (a.empty() || ti == typeid(void) || ti == typeid(nullptr)) sq_pushnull(vm); + else if (ti == typeid(bool)) sq_pushbool(vm, Poco::AnyCast< bool >(a)); + else if (ti == typeid(char)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< char >(a))); + else if (ti == typeid(wchar_t)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< wchar_t >(a))); + else if (ti == typeid(signed char)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< signed char >(a))); + else if (ti == typeid(unsigned char)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned char >(a))); + else if (ti == typeid(short int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< short int >(a))); + else if (ti == typeid(unsigned short int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned short int >(a))); + else if (ti == typeid(int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< int >(a))); + else if (ti == typeid(unsigned int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned int >(a))); + else if (ti == typeid(long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< long int >(a))); + else if (ti == typeid(unsigned long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned long int >(a))); + else if (ti == typeid(long long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< long long int >(a))); + else if (ti == typeid(unsigned long long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned long long int >(a))); + else if (ti == typeid(float)) sq_pushfloat(vm, ConvTo< SQFloat >::From(Poco::AnyCast< float >(a))); + else if (ti == typeid(double)) sq_pushfloat(vm, ConvTo< SQFloat >::From(Poco::AnyCast< double >(a))); + else if (ti == typeid(long double)) sq_pushfloat(vm, ConvTo< SQFloat >::From(Poco::AnyCast< long double >(a))); + else if (ti == typeid(std::string)) { + const auto & s = Poco::RefAnyCast< std::string >(a); + sq_pushstring(vm, s.data(), ConvTo< SQFloat >::From(s.size())); + } else { + sq_throwerrorf(vm, "Unable to convert value of type (%s) to squirrel.", a.type().name()); + sq_pushnull(vm); + } + // Return the object from the stack + return Var< LightObj >(vm, -1).value; + +} + +// ------------------------------------------------------------------------------------------------ +SqDataStatement SqDataSession::GetStatement(StackStrF & data) +{ + return SqDataStatement(*this, data); +} + +// ------------------------------------------------------------------------------------------------ +SqDataStatement & SqDataStatement::UseEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) +{ + // + switch (obj.GetType()) + { + case OT_NULL: addBind(new Poco::Data::Binding(const_cast(g_NullData), name, dir)); break; + case OT_INTEGER: + case OT_FLOAT: + case OT_BOOL: + case OT_STRING: STHROWF("Use Bind(...) for non-reference types."); break; + case OT_INSTANCE: { + auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); + // Integer reference? + if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< SQInteger >(obj.CastI< SqDataBinding< SQInteger > >()->mV, name, dir)); break; + } // Float reference? + else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< SQFloat >(obj.CastI< SqDataBinding< SQFloat > >()->mV, name, dir)); break; + } // String reference? + else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< String >(obj.CastI< SqDataBinding< String > >()->mV, name, dir)); break; + } // Bool reference? + else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< bool >(obj.CastI< SqDataBinding< bool > >()->mV, name, dir)); break; + } // Unknown! + else + { + Var< LightObj >::push(SqVM(), obj); + String type_name = SqTypeName(SqVM(), -1); + sq_poptop(SqVM()); + STHROWF("Can't use (%s) values", type_name.c_str()); break; + } + + } break; + default: STHROWF("Can't use (%s) values", SqTypeName(obj.GetType())); break; + } + // + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SqDataStatement & SqDataStatement::BindEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) +{ + // + switch (obj.GetType()) + { + case OT_NULL: { + addBind(new Poco::Data::Binding(const_cast(g_NullData), name, dir)); + } break; + case OT_INTEGER: { + auto v = obj.Cast(); + addBind(new Poco::Data::CopyBinding(v, name, dir)); + } break; + case OT_FLOAT: { + auto v = obj.Cast(); + addBind(new Poco::Data::CopyBinding(v, name, dir)); + } break; + case OT_BOOL: { + auto v = obj.Cast(); + addBind(new Poco::Data::CopyBinding(v, name, dir)); + } break; + case OT_STRING: { + Var< LightObj >::push(SqVM(), obj); + StackStrF str(SqVM(), -1); + str.Proc(false); + sq_poptop(SqVM()); + addBind(new Poco::Data::CopyBinding(str.mPtr, name, dir)); + } break; + case OT_INSTANCE: { + auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); + // Integer reference? + if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) + { + //addBind(new Poco::Data::ReferenceBinding< SQInteger >(obj.CastI< SqDataBinding< SQInteger > >()->mV, name, dir)); break; + } // Float reference? + else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) + { + //addBind(new Poco::Data::ReferenceBinding< SQFloat >(obj.CastI< SqDataBinding< SQFloat > >()->mV, name, dir)); break; + } // String reference? + else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) + { + //addBind(new Poco::Data::ReferenceBinding< String >(obj.CastI< SqDataBinding< String > >()->mV, name, dir)); break; + } // Bool reference? + else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) + { + //addBind(new Poco::Data::ReferenceBinding< bool >(obj.CastI< SqDataBinding< bool > >()->mV, name, dir)); break; + } // Unknown! + else + { + Var< LightObj >::push(SqVM(), obj); + String type_name = SqTypeName(SqVM(), -1); + sq_poptop(SqVM()); + STHROWF("Can't use (%s) values", type_name.c_str()); break; + } + + } break; + default: STHROWF("Can't use (%s) values", SqTypeName(obj.GetType())); break; + } + // + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template < class T, class U > +static void Register_POCO_Data_Binding(HSQUIRRELVM vm, Table & ns, const SQChar * name) +{ + using Binding = SqDataBinding< T >; + // -------------------------------------------------------------------------------------------- + ns.Bind(name, + Class< Binding, NoCopy< Binding > >(vm, U::Str) + // Constructors + .Ctor() + .template Ctor() + .template Ctor< typename Binding::OptimalArg >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &U::Fn) + // Properties + .Prop(_SC("V"), &Binding::Get, &Binding::Set) + .Prop(_SC("Value"), &Binding::Get, &Binding::Set) + // Member Methods + .Func(_SC("Set"), &Binding::SetEx) + .Func(_SC("Bind"), &Binding::Bind) + .Func(_SC("BindAs"), &Binding::BindAs) + ); +} + +// ================================================================================================ +void Register_POCO_Data(HSQUIRRELVM vm) +{ + Table ns(vm); + + // -------------------------------------------------------------------------------------------- + ns.Bind(_SC("Session"), + Class< SqDataSession >(vm, SqPcDataSession::Str) + // Constructors + .Ctor< StackStrF &, SQInteger >() + .Ctor< StackStrF &, StackStrF &, SQInteger >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqPcDataSession::Fn) + // Properties + .Prop(_SC("IsConnected"), &SqDataSession::IsConnected) + .Prop(_SC("IsGood"), &SqDataSession::IsGood) + .Prop(_SC("LoginTimeout"), &SqDataSession::GetLoginTimeout, &SqDataSession::SetLoginTimeout) + .Prop(_SC("ConnectionTimeout"), &SqDataSession::GetConnectionTimeout, &SqDataSession::SetConnectionTimeout) + .Prop(_SC("CanTransact"), &SqDataSession::CanTransact) + .Prop(_SC("IsTransaction"), &SqDataSession::IsTransaction) + .Prop(_SC("TransactionIsolation"), &SqDataSession::GetTransactionIsolation, &SqDataSession::SetTransactionIsolation) + .Prop(_SC("Connector"), &SqDataSession::GetConnector) + .Prop(_SC("URI"), &SqDataSession::GetURI) + // Member Methods + .FmtFunc(_SC("Open"), &SqDataSession::Open) + .Func(_SC("Close"), &SqDataSession::Close) + .Func(_SC("Reconnect"), &SqDataSession::Reconnect) + .Func(_SC("Statement"), &SqDataSession::GetStatement) + .Func(_SC("Begin"), &SqDataSession::Begin) + .Func(_SC("Commit"), &SqDataSession::Commit) + .Func(_SC("Rollback"), &SqDataSession::Rollback) + .Func(_SC("HasTransactionIsolation"), &SqDataSession::HasTransactionIsolation) + .Func(_SC("IsTransactionIsolation"), &SqDataSession::IsTransactionIsolation) + .FmtFunc(_SC("SetFeature"), &SqDataSession::SetFeature) + .FmtFunc(_SC("GetFeature"), &SqDataSession::GetFeature) + .FmtFunc(_SC("SetProperty"), &SqDataSession::SetProperty) + .FmtFunc(_SC("GetProperty"), &SqDataSession::GetProperty) + // Static Functions + .StaticFunc(_SC("GetURI"), &SqDataSession::BuildURI) + // Static Values + .SetStaticValue(_SC("LoginTimeoutDefault"), static_cast< SQInteger >(Session::LOGIN_TIMEOUT_DEFAULT)) + .SetStaticValue(_SC("TransactionReadUncommitted"), static_cast< SQInteger >(Session::TRANSACTION_READ_UNCOMMITTED)) + .SetStaticValue(_SC("TransactionReadCommitted"), static_cast< SQInteger >(Session::TRANSACTION_READ_COMMITTED)) + .SetStaticValue(_SC("TransactionRepeatableRead"), static_cast< SQInteger >(Session::TRANSACTION_REPEATABLE_READ)) + .SetStaticValue(_SC("TransactionSerializable"), static_cast< SQInteger >(Session::TRANSACTION_SERIALIZABLE)) + ); + // -------------------------------------------------------------------------------------------- + ns.Bind(_SC("Statement"), + Class< SqDataStatement >(vm, SqPcDataStatement::Str) + // Constructors + .Ctor< SqDataSession & >() + .Ctor< SqDataSession &, StackStrF & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqPcDataStatement::Fn) + // Properties + .Prop(_SC("Async"), &SqDataStatement::GetAsync, &SqDataStatement::SetAsync) + .Prop(_SC("Initialized"), &SqDataStatement::Initialized) + .Prop(_SC("Paused"), &SqDataStatement::Paused) + .Prop(_SC("Done"), &SqDataStatement::Done) + // Member Methods + .Func(_SC("Add"), &SqDataStatement::Add) + .Func(_SC("Execute"), &SqDataStatement::Execute) + .Func(_SC("ExecuteAsync"), &SqDataStatement::ExecuteAsync) + .Func(_SC("SetAsync"), &SqDataStatement::SetAsync) + .Func(_SC("Reset"), &SqDataStatement::Reset) + .Func(_SC("Use"), &SqDataStatement::Use) + .Func(_SC("UseAs"), &SqDataStatement::UseAs) + .Func(_SC("Bind"), &SqDataStatement::Bind) + .Func(_SC("BindAs"), &SqDataStatement::BindAs) + ); + // -------------------------------------------------------------------------------------------- + Register_POCO_Data_Binding< SQInteger, SqIntegerBinding >(vm, ns, _SC("IntBind")); + Register_POCO_Data_Binding< String, SqStringBinding >(vm, ns, _SC("StrBind")); + Register_POCO_Data_Binding< SQFloat, SqFloatBinding >(vm, ns, _SC("FloatBind")); + Register_POCO_Data_Binding< bool, SqBoolBinding >(vm, ns, _SC("BoolBind")); + + RootTable(vm).Bind(_SC("SqData"), ns); +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/Data.hpp b/module/PocoLib/Data.hpp new file mode 100644 index 00000000..a6685a9e --- /dev/null +++ b/module/PocoLib/Data.hpp @@ -0,0 +1,640 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Utility.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include +#include + +// ------------------------------------------------------------------------------------------------ +namespace std { // NOLINT(cert-dcl58-cpp) + +/* ------------------------------------------------------------------------------------------------ + * Allows the StackStrF to write its data into a std::ostream type. +*/ +inline std::ostream & operator << (std::ostream & out, const ::Sqrat::StackStrF & str) +{ + if (str.mLen) + { + out.write(str.mPtr, str.mLen); + } + return out; +} + +/* ------------------------------------------------------------------------------------------------ + * Allows the StackStrF to write its data into a std::ostringstream type. +*/ +inline std::ostringstream & operator << (std::ostringstream & out, const ::Sqrat::StackStrF & str) +{ + if (str.mLen) + { + out.write(str.mPtr, str.mLen); + } + return out; +} + +} // Namespace:: std + +// ------------------------------------------------------------------------------------------------ +namespace Poco { // NOLINT(modernize-concat-nested-namespaces) +namespace Data { + +/* ------------------------------------------------------------------------------------------------ + * Implementation of AbstractBinding for shared ownership binding of values. + * Because we cannot take references to script variables, we use this as a proxy. +*/ +template struct ReferenceBinding : public AbstractBinding +{ + using ValType = T; + using ValPtr = SharedPtr; + using Type = ReferenceBinding; + using Ptr = SharedPtr; + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + explicit ReferenceBinding(const ValPtr& val, const std::string& name = "", Direction direction = PD_IN) + : AbstractBinding(name, direction), m_Value(val), m_Bound(false) + { + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~ReferenceBinding() override = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve columns occupied. + */ + SQMOD_NODISCARD std::size_t numOfColumnsHandled() const override + { + return TypeHandler::size(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve rows occupied. + */ + SQMOD_NODISCARD std::size_t numOfRowsHandled() const override + { + return 1; + } + + /* -------------------------------------------------------------------------------------------- + * Check if binding is available. + */ + SQMOD_NODISCARD bool canBind() const override + { + return !m_Bound; + } + + /* -------------------------------------------------------------------------------------------- + * Bind the value. + */ + void bind(std::size_t pos) override + { + poco_assert_dbg(!getBinder().isNull()); + TypeHandler::bind(pos, *m_Value, getBinder(), getDirection()); + m_Bound = true; + } + + /* -------------------------------------------------------------------------------------------- + * Reset the binding. + */ + void reset () override + { + m_Bound = false; + AbstractBinder::Ptr pBinder = getBinder(); + poco_assert_dbg (!pBinder.isNull()); + pBinder->reset(); + } + +private: + + ValPtr m_Value; + bool m_Bound; +}; + +} // Namespace:: Data +} // Namespace:: Poco + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +using namespace Poco::Data::Keywords; +// ------------------------------------------------------------------------------------------------ +using Poco::Data::Session; +using Poco::Data::Statement; +using Poco::Data::RecordSet; +using Poco::Data::ReferenceBinding; + +// ------------------------------------------------------------------------------------------------ +struct SqDataSession; +struct SqDataStatement; + +/* ------------------------------------------------------------------------------------------------ + * Utility used to transform optimal argument type to stored type. +*/ +template < class T > struct SqDataBindingOpt +{ + /* -------------------------------------------------------------------------------------------- + * Optimal argument type. Unchanged when not specialized. + */ + using Type = T; + + /* -------------------------------------------------------------------------------------------- + * Convert the optimal type to the stored type. Does nothing special in this case. + */ + inline static Type & Get(Type & v) { return v; } + inline static const Type & Get(const Type & v) { return v; } + // -------------------------------------------------------------------------------------------- + inline static void Put(T & o, Type & v) { o = v; } + inline static void Put(T & o, const Type & v) { o = v; } +}; + +/* ------------------------------------------------------------------------------------------------ + * Specialization of SqDataBindingOpt for std::string type. +*/ +template < > struct SqDataBindingOpt< String > +{ + /* -------------------------------------------------------------------------------------------- + * Optimal argument type. + */ + using Type = StackStrF; + + /* -------------------------------------------------------------------------------------------- + * Convert the optimal type to the stored type. + */ + inline static String Get(Type & v) { return v.ToStr(); } + inline static String Get(const Type & v) { return v.ToStr(); } + // -------------------------------------------------------------------------------------------- + inline static void Put(String & o, Type & v) { o.assign(v.mPtr, v.GetSize()); } + inline static void Put(String & o, const Type & v) { o.assign(v.mPtr, v.GetSize()); } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper around values that must be passed as reference. Manual lifetime management! +*/ +template < class T > struct SqDataBinding +{ + /* -------------------------------------------------------------------------------------------- + * Reference binding type. + */ + using Binding = ReferenceBinding< T >; + + /* -------------------------------------------------------------------------------------------- + * Optimal type to receive a value of this type as function argument. Mainly for strings. + */ + using OptimalType = typename SqDataBindingOpt< T >::Type; + + /* -------------------------------------------------------------------------------------------- + * Same as OptimalType but preferably with a reference qualifier to avoid copies. + */ + using OptimalArg = typename std::conditional< std::is_same< T, OptimalType >::value, T, OptimalType & >::type; + + /* -------------------------------------------------------------------------------------------- + * Reference value. + */ + typename Binding::ValPtr mV{}; + + /* -------------------------------------------------------------------------------------------- + * Default constructor. Initializes to a default value. + */ + SqDataBinding() + : mV(new T()) + { + } + + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. Initializes to a specific value. + */ + explicit SqDataBinding(OptimalArg v) + : mV(new T()) + { + SqDataBindingOpt< T >::Put(*mV, v); + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + SqDataBinding(const SqDataBinding &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + SqDataBinding(SqDataBinding &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destroys the Statement. + */ + ~SqDataBinding() = default; + + /* -------------------------------------------------------------------------------------------- + * Assignment operator. + */ + SqDataBinding & operator = (const SqDataBinding &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment. + */ + SqDataBinding & operator = (SqDataBinding &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve a value from the instance. + */ + SQMOD_NODISCARD const T & Get() const { return *mV; } + + /* -------------------------------------------------------------------------------------------- + * Modify a value from the instance. + */ + void Set(OptimalArg v) { SqDataBindingOpt< T >::Put(*mV, v); } + + /* -------------------------------------------------------------------------------------------- + * Modify a value from the instance. + */ + SqDataBinding & SetEx(OptimalArg v) { SqDataBindingOpt< T >::Put(*mV, v); return *this; } + + /* -------------------------------------------------------------------------------------------- + * Bind the value to a statement. + */ + SqDataBinding & Bind(SqDataStatement & stmt); + + /* -------------------------------------------------------------------------------------------- + * Bind the value to a statement with a specific name. + */ + SqDataBinding & BindAs(SqDataStatement & stmt, StackStrF & name); +}; + +/* ------------------------------------------------------------------------------------------------ + * A Session holds a connection to a Database and creates Statement objects. +*/ +struct SqDataSession : public Session +{ + /* -------------------------------------------------------------------------------------------- + * Creates a new session, using the given connection (must be in "connection:///info" format). + */ + SqDataSession(StackStrF & conn, SQInteger timeout) + : Session(conn.ToStr(), ConvTo< size_t >::From(timeout)) + { + } + + /* -------------------------------------------------------------------------------------------- + * Creates a new session, using the given connector, and connection information. + */ + SqDataSession(StackStrF & conn, StackStrF & info, SQInteger timeout) + : Session(conn.ToStr(), info.ToStr(), ConvTo< size_t >::From(timeout)) + { + } + + /* -------------------------------------------------------------------------------------------- + * Creates a session by copying another one. + */ + SqDataSession(const SqDataSession &) = default; + + /* -------------------------------------------------------------------------------------------- + * Creates a session by moving another one. + */ + SqDataSession(SqDataSession &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destroys the Session. + */ + ~SqDataSession() = default; + + /* -------------------------------------------------------------------------------------------- + * Assignment operator. + */ + SqDataSession & operator = (const SqDataSession &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment. + */ + SqDataSession & operator = (SqDataSession &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Opens the session using the supplied string. + * Can also be used with default empty string to reconnect a disconnected session. + */ + void Open(StackStrF & connect) { open(connect.ToStr()); } + + /* -------------------------------------------------------------------------------------------- + * Closes the session. + */ + void Close() { close(); } + + /* -------------------------------------------------------------------------------------------- + * Returns true if session is connected, false otherwise. + */ + bool IsConnected() { return isConnected(); } + + /* -------------------------------------------------------------------------------------------- + * Closes the session and opens it. + */ + void Reconnect() { return reconnect(); } + + /* -------------------------------------------------------------------------------------------- + * Returns true if the session is good and can be used, false otherwise. + */ + SQMOD_NODISCARD bool IsGood() { return isGood(); } + + /* -------------------------------------------------------------------------------------------- + * Sets the session login timeout value. + */ + void SetLoginTimeout(SQInteger timeout) { setLoginTimeout(ConvTo< size_t >::From(timeout)); } + + /* -------------------------------------------------------------------------------------------- + * Returns the session login timeout value. + */ + SQMOD_NODISCARD SQInteger GetLoginTimeout() const { return static_cast< SQInteger >(getLoginTimeout()); } + + /* -------------------------------------------------------------------------------------------- + * Sets the session connection timeout value. + */ + void SetConnectionTimeout(SQInteger timeout) { setConnectionTimeout(ConvTo< size_t >::From(timeout)); } + + /* -------------------------------------------------------------------------------------------- + * Returns the session connection timeout value. + */ + SQInteger GetConnectionTimeout() { return static_cast< SQInteger >(getConnectionTimeout()); } + + /* -------------------------------------------------------------------------------------------- + * Starts a transaction. + */ + void Begin() { begin(); } + + /* -------------------------------------------------------------------------------------------- + * Commits and ends a transaction. + */ + void Commit() { commit(); } + + /* -------------------------------------------------------------------------------------------- + * Rolls back and ends a transaction. + */ + void Rollback() { rollback(); } + + /* -------------------------------------------------------------------------------------------- + * Returns true if session has transaction capabilities. + */ + SQMOD_NODISCARD bool CanTransact() { return canTransact(); } + + /* -------------------------------------------------------------------------------------------- + * Returns true if a transaction is in progress, false otherwise. + */ + SQMOD_NODISCARD bool IsTransaction() { return isTransaction(); } + + /* -------------------------------------------------------------------------------------------- + * Sets the transaction isolation level. + */ + void SetTransactionIsolation(SQInteger ti) { setTransactionIsolation(static_cast< uint32_t >(ti)); } + + /* -------------------------------------------------------------------------------------------- + * Returns the transaction isolation level. + */ + SQMOD_NODISCARD SQInteger GetTransactionIsolation() { return static_cast< SQInteger >(getTransactionIsolation()); } + + /* -------------------------------------------------------------------------------------------- + * Returns true if the transaction isolation level corresponding to the supplied bitmask is supported. + */ + bool HasTransactionIsolation(SQInteger ti) { return hasTransactionIsolation(static_cast< uint32_t >(ti)); } + + /* -------------------------------------------------------------------------------------------- + * Returns true if the transaction isolation level corresponds to the supplied bitmask. + */ + bool IsTransactionIsolation(SQInteger ti) { return isTransactionIsolation(static_cast< uint32_t >(ti)); } + + /* -------------------------------------------------------------------------------------------- + * Returns the connector name for this session. + */ + SQMOD_NODISCARD std::string GetConnector() const { return connector(); } + + /* -------------------------------------------------------------------------------------------- + * Returns the URI for this session. + */ + SQMOD_NODISCARD std::string GetURI() const { return uri(); } + + /* -------------------------------------------------------------------------------------------- + * Utility function that teturns the URI formatted from supplied arguments as "connector:///info". + */ + SQMOD_NODISCARD static std::string BuildURI(StackStrF & connector, StackStrF & info) + { + return uri(connector.ToStr(), info.ToStr()); + } + + /* -------------------------------------------------------------------------------------------- + * Set the state of a feature. + */ + void SetFeature(bool state, StackStrF & name) { setFeature(name.ToStr(), state); } + + /* -------------------------------------------------------------------------------------------- + * Look up the state of a feature. + */ + SQMOD_NODISCARD bool GetFeature(StackStrF & name) const { return getFeature(name.ToStr()); } + + /* -------------------------------------------------------------------------------------------- + * Set the value of a property. + */ + void SetProperty(const LightObj & value, StackStrF & name); + + /* -------------------------------------------------------------------------------------------- + * Look up the value of a property. + */ + SQMOD_NODISCARD LightObj GetProperty(StackStrF & name) const; + + /* -------------------------------------------------------------------------------------------- + * Look up the value of a property. + */ + SQMOD_NODISCARD SqDataStatement GetStatement(StackStrF & data); +}; + +/* ------------------------------------------------------------------------------------------------ + * Statement is used to execute SQL statements. +*/ +struct SqDataStatement : public Statement +{ + /* -------------------------------------------------------------------------------------------- + * Creates the Statement for the given Session. + */ + explicit SqDataStatement(SqDataSession & session) + : Statement(session) + { + } + + /* -------------------------------------------------------------------------------------------- + * Creates the Statement for the given Session and adds initial SQL code. + */ + explicit SqDataStatement(SqDataSession & session, StackStrF & data) + : Statement(session) + { + Add(data); + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. If the statement has been executed asynchronously and has not been + * synchronized prior to copy operation (i.e. is copied while executing), this constructor shall synchronize it. + */ + SqDataStatement(const SqDataStatement &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + SqDataStatement(SqDataStatement &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destroys the Statement. + */ + ~SqDataStatement() = default; + + /* -------------------------------------------------------------------------------------------- + * Assignment operator. + */ + SqDataStatement & operator = (const SqDataStatement &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment. + */ + SqDataStatement & operator = (SqDataStatement &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Concatenates data with the SQL statement string. + */ + SqDataStatement & Add(StackStrF & data) + { + Statement::operator<<(data); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Returns true if statement was marked for asynchronous execution. + */ + bool GetAsync() + { + return isAsync(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns true if the statement was initialized (i.e. not executed yet). + */ + bool Initialized() + { + return initialized(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns true if the statement was paused (a range limit stopped it and there is more work to do). + */ + bool Paused() + { + return paused(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns true if the statement was completely executed or false if a range limit stopped it + * and there is more work to do. When no limit is set, it will always return true after calling execute(). + */ + bool Done() + { + return done(); + } + + /* -------------------------------------------------------------------------------------------- + * Sets the asynchronous flag. This setting does not affect the statement's capability + * to be executed synchronously by directly calling Execute(). + */ + SqDataStatement & SetAsync(bool async) + { + setAsync(async); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Executes the statement synchronously or asynchronously. + */ + SQInteger Execute(bool reset) + { + return static_cast< SQInteger >(execute(reset)); + } + + /* -------------------------------------------------------------------------------------------- + * Executes the statement asynchronously. + */ + SqDataStatement & ExecuteAsync(bool reset) + { + executeAsync(reset); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Waits for the execution completion for asynchronous statements or returns immediately for synchronous ones. + */ + SQInteger Wait(SQInteger milliseconds) + { + return static_cast< SQInteger >(wait(static_cast< long >(milliseconds))); + } + + /* -------------------------------------------------------------------------------------------- + * Resets the Statement so that it can be filled with a new SQL command. + */ + SqDataStatement & Reset(SqDataSession & session) + { + reset(session); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * + */ + SqDataStatement & Use(LightObj & obj) + { + return UseEx(obj, String(), Poco::Data::AbstractBinding::PD_IN); + } + + /* -------------------------------------------------------------------------------------------- + * + */ + SqDataStatement & UseAs(LightObj & obj, StackStrF & name) + { + return UseEx(obj, String(name.mPtr, name.GetSize()), Poco::Data::AbstractBinding::PD_IN); + } + + /* -------------------------------------------------------------------------------------------- + * + */ + SqDataStatement & UseEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); + + /* -------------------------------------------------------------------------------------------- + * + */ + SqDataStatement & Bind(LightObj & obj) + { + return BindEx(obj, String(), Poco::Data::AbstractBinding::PD_IN); + } + + /* -------------------------------------------------------------------------------------------- + * + */ + SqDataStatement & BindAs(LightObj & obj, StackStrF & name) + { + return BindEx(obj, String(name.mPtr, name.GetSize()), Poco::Data::AbstractBinding::PD_IN); + } + + /* -------------------------------------------------------------------------------------------- + * + */ + SqDataStatement & BindEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); +}; + +// ------------------------------------------------------------------------------------------------ +template < class T > inline SqDataBinding< T > & SqDataBinding< T >::Bind(SqDataStatement & stmt) +{ + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template < class T > inline SqDataBinding< T > & SqDataBinding< T >::BindAs(SqDataStatement & stmt, StackStrF & name) +{ + return *this; +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/Foundation.cpp b/module/PocoLib/Foundation.cpp new file mode 100644 index 00000000..ddfce6f5 --- /dev/null +++ b/module/PocoLib/Foundation.cpp @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------------------------ +#include "PocoLib/Foundation.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ + + +// ================================================================================================ +void Register_POCO_Foundation(HSQUIRRELVM vm) +{ + Table ns(vm); + + RootTable(vm).Bind(_SC("SqPOCO"), ns); +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/Foundation.hpp b/module/PocoLib/Foundation.hpp new file mode 100644 index 00000000..4eca0ee6 --- /dev/null +++ b/module/PocoLib/Foundation.hpp @@ -0,0 +1,11 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + + + +} // Namespace:: SqMod diff --git a/module/PocoLib/JSON.cpp b/module/PocoLib/JSON.cpp new file mode 100644 index 00000000..c66c7c39 --- /dev/null +++ b/module/PocoLib/JSON.cpp @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------------------------ +#include "PocoLib/JSON.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ + + +// ================================================================================================ +void Register_POCO_JSON(HSQUIRRELVM vm) +{ + Table ns(vm); + + RootTable(vm).Bind(_SC("SqJSON"), ns); +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/JSON.hpp b/module/PocoLib/JSON.hpp new file mode 100644 index 00000000..4eca0ee6 --- /dev/null +++ b/module/PocoLib/JSON.hpp @@ -0,0 +1,11 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + + + +} // Namespace:: SqMod diff --git a/module/PocoLib/Net.cpp b/module/PocoLib/Net.cpp new file mode 100644 index 00000000..9876a643 --- /dev/null +++ b/module/PocoLib/Net.cpp @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------------------------ +#include "PocoLib/Net.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ + + +// ================================================================================================ +void Register_POCO_Net(HSQUIRRELVM vm) +{ + Table ns(vm); + + RootTable(vm).Bind(_SC("SqNet"), ns); +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/Net.hpp b/module/PocoLib/Net.hpp new file mode 100644 index 00000000..4eca0ee6 --- /dev/null +++ b/module/PocoLib/Net.hpp @@ -0,0 +1,11 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + + + +} // Namespace:: SqMod diff --git a/module/PocoLib/Util.cpp b/module/PocoLib/Util.cpp new file mode 100644 index 00000000..f3abd7d6 --- /dev/null +++ b/module/PocoLib/Util.cpp @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------------------------ +#include "PocoLib/Util.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ + + +// ================================================================================================ +void Register_POCO_Util(HSQUIRRELVM vm) +{ + +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/Util.hpp b/module/PocoLib/Util.hpp new file mode 100644 index 00000000..4eca0ee6 --- /dev/null +++ b/module/PocoLib/Util.hpp @@ -0,0 +1,11 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + + + +} // Namespace:: SqMod diff --git a/module/PocoLib/XML.cpp b/module/PocoLib/XML.cpp new file mode 100644 index 00000000..5c4dcebb --- /dev/null +++ b/module/PocoLib/XML.cpp @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------------------------ +#include "PocoLib/XML.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ + + +// ================================================================================================ +void Register_POCO_XML(HSQUIRRELVM vm) +{ + Table ns(vm); + + RootTable(vm).Bind(_SC("SqXML"), ns); +} + +} // Namespace:: SqMod diff --git a/module/PocoLib/XML.hpp b/module/PocoLib/XML.hpp new file mode 100644 index 00000000..4eca0ee6 --- /dev/null +++ b/module/PocoLib/XML.hpp @@ -0,0 +1,11 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + + + +} // Namespace:: SqMod diff --git a/module/Register.cpp b/module/Register.cpp index edf84458..66295a85 100644 --- a/module/Register.cpp +++ b/module/Register.cpp @@ -47,6 +47,9 @@ extern void Register_Utils(HSQUIRRELVM vm); extern void Register_Worker(HSQUIRRELVM vm); extern void Register_Web(HSQUIRRELVM vm); +// ------------------------------------------------------------------------------------------------ +extern void Register_POCO_Data(HSQUIRRELVM vm); + // ------------------------------------------------------------------------------------------------ extern void Register_Constants(HSQUIRRELVM vm); extern void Register_Log(HSQUIRRELVM vm); @@ -101,6 +104,8 @@ bool RegisterAPI(HSQUIRRELVM vm) //Register_Worker(vm); //Register_Web(vm); + Register_POCO_Data(vm); + Register_Constants(vm); Register_Log(vm); Register_Core(vm);