mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Add std::vector proxy type.
This commit is contained in:
parent
83f2ab79e0
commit
26ccfa62b9
@ -150,6 +150,7 @@ if(ENABLE_DISCORD)
|
|||||||
Library/DPP/Other.cpp Library/DPP/Other.hpp
|
Library/DPP/Other.cpp Library/DPP/Other.hpp
|
||||||
Library/DPP/Role.cpp Library/DPP/Role.hpp
|
Library/DPP/Role.cpp Library/DPP/Role.hpp
|
||||||
Library/DPP/User.cpp Library/DPP/User.hpp
|
Library/DPP/User.cpp Library/DPP/User.hpp
|
||||||
|
Library/DPP/Utilities.cpp Library/DPP/Utilities.hpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
# Link to POCO libraries
|
# Link to POCO libraries
|
||||||
|
12
module/Library/DPP/Utilities.cpp
Normal file
12
module/Library/DPP/Utilities.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "Library/DPP/Utilities.hpp"
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
namespace SqMod {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
} // Namespace:: SqMod
|
415
module/Library/DPP/Utilities.hpp
Normal file
415
module/Library/DPP/Utilities.hpp
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "Core/Utility.hpp"
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include <dpp/dpp.h>
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
namespace SqMod {
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* Wrapper around a std::vector of DPP values.
|
||||||
|
*/
|
||||||
|
template < class T, class W > struct DpVectorProxy
|
||||||
|
{
|
||||||
|
using Ptr = std::unique_ptr< std::vector< T > >;
|
||||||
|
using Vec = std::vector< std::pair< LightObj, W * > >;
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Referenced vector instance.
|
||||||
|
*/
|
||||||
|
Ptr mPtr{nullptr};
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Cached script objects vector.
|
||||||
|
*/
|
||||||
|
Vec mVec{};
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Whether the referenced pointer is owned.
|
||||||
|
*/
|
||||||
|
bool mOwned{false};
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
DpVectorProxy() noexcept = default;
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Explicit constructor.
|
||||||
|
*/
|
||||||
|
explicit DpVectorProxy(typename Ptr::pointer ptr, bool owned = false)
|
||||||
|
: mPtr(ptr), mVec(), mOwned(owned)
|
||||||
|
{ if (mPtr) mVec.resize(mPtr->size()); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Explicit constructor.
|
||||||
|
*/
|
||||||
|
explicit DpVectorProxy(const typename Ptr::element_type & o) noexcept
|
||||||
|
: DpVectorProxy(new typename Ptr::element_type(o), true)
|
||||||
|
{ }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Move constructor.
|
||||||
|
*/
|
||||||
|
explicit DpVectorProxy(typename Ptr::element_type && o) noexcept
|
||||||
|
: DpVectorProxy(new typename Ptr::element_type(std::forward< Ptr::element_type >(o)), true)
|
||||||
|
{ }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copy constructor (disabled).
|
||||||
|
*/
|
||||||
|
DpVectorProxy(const DpVectorProxy & o) = delete;
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Move constructor.
|
||||||
|
*/
|
||||||
|
DpVectorProxy(DpVectorProxy && o) noexcept = default;
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~DpVectorProxy() noexcept { Cleanup(); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copy assignment operator (disabled).
|
||||||
|
*/
|
||||||
|
DpVectorProxy & operator = (const DpVectorProxy & o) = delete;
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Move assignment operator.
|
||||||
|
*/
|
||||||
|
DpVectorProxy & operator = (DpVectorProxy && o) noexcept
|
||||||
|
{
|
||||||
|
if (this != &o) {
|
||||||
|
Cleanup();
|
||||||
|
// Transfer members values
|
||||||
|
mPtr = std::move(o.mPtr);
|
||||||
|
mVec = std::move(o.mVec);
|
||||||
|
mOwned = o.mOwned;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Release any referenced resources and default to an empty/invalid state.
|
||||||
|
*/
|
||||||
|
void Cleanup()
|
||||||
|
{
|
||||||
|
// Invalidate cached instances
|
||||||
|
ClearCache();
|
||||||
|
// Do we own this to try delete it?
|
||||||
|
if (!mOwned && mPtr) {
|
||||||
|
// Not our job, simply forget about it
|
||||||
|
[[maybe_unused]] auto p = mPtr.release();
|
||||||
|
} else mPtr.reset(); // We own this so delete the instance
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Validate the managed handle.
|
||||||
|
*/
|
||||||
|
void Validate() const { if (!mPtr) STHROWF("Invalid discord vector handle"); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Validate the managed handle and retrieve a const reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD typename Ptr::element_type & Valid() const { Validate(); return *mPtr; }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Check whether a valid instance is managed.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD bool IsValid() const { return static_cast< bool >(mPtr); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure an index is within range and return the container. Container must exist.
|
||||||
|
*/
|
||||||
|
void ValidIdx_(SQInteger i)
|
||||||
|
{
|
||||||
|
if (static_cast< size_t >(i) >= Valid().size())
|
||||||
|
{
|
||||||
|
STHROWF("Invalid vector container index({})", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typename Ptr::element_type & ValidIdx(SQInteger i) { ValidIdx_(i); return *mPtr; }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure an index is within range and return the container. Container must exist.
|
||||||
|
*/
|
||||||
|
void ValidIdx_(SQInteger i) const
|
||||||
|
{
|
||||||
|
if (static_cast< size_t >(i) >= Valid().size())
|
||||||
|
{
|
||||||
|
STHROWF("Invalid vector container index({})", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const typename Ptr::element_type & ValidIdx(SQInteger i) const { ValidIdx_(i); return *mPtr; }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a container instance is referenced and is populated, then return it.
|
||||||
|
*/
|
||||||
|
void ValidPop_()
|
||||||
|
{
|
||||||
|
if (Valid().empty())
|
||||||
|
{
|
||||||
|
STHROWF("Vector container is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typename Ptr::element_type & ValidPop() { ValidPop_(); return *mPtr; }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a container instance is referenced and is populated, then return it.
|
||||||
|
*/
|
||||||
|
void ValidPop_() const
|
||||||
|
{
|
||||||
|
if (Valid().empty())
|
||||||
|
{
|
||||||
|
STHROWF("Vector container is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const typename Ptr::element_type & ValidPop() const { ValidPop_(); return *mPtr; }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Check if a container instance is referenced.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD bool IsNull() const { return !mPtr; }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a value from the container.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD LightObj & Get_(SQInteger i)
|
||||||
|
{
|
||||||
|
// Is the element cached?
|
||||||
|
if (mVec[static_cast< size_t >(i)].first.IsNull())
|
||||||
|
{
|
||||||
|
mVec[static_cast< size_t >(i)] = Obj(&mPtr->at(static_cast< size_t >(i)));
|
||||||
|
}
|
||||||
|
// Return the object from the cache
|
||||||
|
return mVec[static_cast< size_t >(i)].first;
|
||||||
|
}
|
||||||
|
SQMOD_NODISCARD LightObj & Get(SQInteger i) { ValidIdx_(i); return Get_(i); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Modify a value from the container.
|
||||||
|
*/
|
||||||
|
void Set(SQInteger i, const W & v) { ValidIdx(i)[static_cast< size_t >(i)] = v.Valid(); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* 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()); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Synchronize cache container instances.
|
||||||
|
*/
|
||||||
|
void CacheSync()
|
||||||
|
{
|
||||||
|
// Invalidate cached instances, if any
|
||||||
|
for (size_t i = 0; i < mVec.size(); ++i)
|
||||||
|
{
|
||||||
|
// Is this element cached?
|
||||||
|
if (mVec[i].second != nullptr)
|
||||||
|
{
|
||||||
|
// Discard previous instance, if any
|
||||||
|
[[maybe_unused]] auto _ = mVec[i].second->mPtr.release();
|
||||||
|
// Sync to new instance
|
||||||
|
mVec[i].second->mPtr.reset(&mPtr->at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Increase the capacity of the container to a value that's greater or equal to the one specified.
|
||||||
|
*/
|
||||||
|
DpVectorProxy & Reserve(SQInteger n)
|
||||||
|
{
|
||||||
|
Valid().reserve(ClampL< SQInteger, size_t >(n));
|
||||||
|
mVec.reserve(mPtr->size());
|
||||||
|
CacheSync();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Request the removal of unused capacity.
|
||||||
|
*/
|
||||||
|
void Compact() { Valid().shrink_to_fit(); CacheSync(); mVec.shrink_to_fit(); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Erase all elements from the cache container.
|
||||||
|
*/
|
||||||
|
void ClearCache()
|
||||||
|
{
|
||||||
|
// Invalidate cached instances, if any
|
||||||
|
for (auto & e : mVec)
|
||||||
|
{
|
||||||
|
// Is this element cached?
|
||||||
|
if (e.second != nullptr)
|
||||||
|
{
|
||||||
|
// Invalidate the instance
|
||||||
|
e.second->Cleanup();
|
||||||
|
// Forget about it
|
||||||
|
e.second = nullptr;
|
||||||
|
// Release script object
|
||||||
|
e.first.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clear the cache vector
|
||||||
|
mVec.clear();
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Erase all elements from the container.
|
||||||
|
*/
|
||||||
|
void Clear() { Validate(); ClearCache(); mPtr->clear(); }
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Push a value at the back of the container.
|
||||||
|
*/
|
||||||
|
void Push(const W & v)
|
||||||
|
{
|
||||||
|
Valid().push_back(v.Valid());
|
||||||
|
mVec.emplace_back();
|
||||||
|
CacheSync();
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Extends the Container by appending all the items in the given container.
|
||||||
|
*/
|
||||||
|
void Extend(DpVectorProxy & v)
|
||||||
|
{
|
||||||
|
Valid().insert(Valid().end(), v.Valid().begin(), v.Valid().end());
|
||||||
|
mVec.resize(mPtr->size());
|
||||||
|
CacheSync();
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Pop the last element in the container.
|
||||||
|
*/
|
||||||
|
void Pop()
|
||||||
|
{
|
||||||
|
Validate();
|
||||||
|
// Is this element cached?
|
||||||
|
if (mVec.back().second != nullptr)
|
||||||
|
{
|
||||||
|
// Invalidate the instance
|
||||||
|
mVec.back().second->Cleanup();
|
||||||
|
mVec.back().first.Release();
|
||||||
|
}
|
||||||
|
// Safe to remove
|
||||||
|
mPtr->pop_back();
|
||||||
|
mVec.pop_back();
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Erase the element at a certain position.
|
||||||
|
*/
|
||||||
|
void EraseAt(SQInteger i)
|
||||||
|
{
|
||||||
|
ValidIdx_(i);
|
||||||
|
// Is this element cached?
|
||||||
|
if (mVec[static_cast< size_t >(i)].second != nullptr)
|
||||||
|
{
|
||||||
|
// Invalidate the instance
|
||||||
|
mVec[static_cast< size_t >(i)].second->Cleanup();
|
||||||
|
mVec[static_cast< size_t >(i)].first.Release();
|
||||||
|
}
|
||||||
|
// Safe to remove
|
||||||
|
mPtr->erase(mPtr->begin() + static_cast< size_t >(i));
|
||||||
|
mVec.erase(mVec.begin() + static_cast< size_t >(i));
|
||||||
|
// Synchronize cache
|
||||||
|
CacheSync();
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate all values through a functor.
|
||||||
|
*/
|
||||||
|
void Each(Function & fn)
|
||||||
|
{
|
||||||
|
Validate();
|
||||||
|
// Iterate referenced vector elements
|
||||||
|
for (size_t i = 0; i < mVec.size(); ++i)
|
||||||
|
{
|
||||||
|
fn.Execute(Get(static_cast< SQInteger >(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate values in range through a functor.
|
||||||
|
*/
|
||||||
|
void EachRange(SQInteger p, SQInteger n, Function & fn)
|
||||||
|
{
|
||||||
|
ValidIdx_(p);
|
||||||
|
ValidIdx_(p + n);
|
||||||
|
// Iterate specified range
|
||||||
|
for (n += p; p < n; ++p)
|
||||||
|
{
|
||||||
|
fn.Execute(Get(static_cast< SQInteger >(p)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate all values through a functor until stopped (i.e false is returned).
|
||||||
|
*/
|
||||||
|
void While(Function & fn)
|
||||||
|
{
|
||||||
|
Validate();
|
||||||
|
// Iterate referenced vector elements
|
||||||
|
for (size_t i = 0; i < mVec.size(); ++i)
|
||||||
|
{
|
||||||
|
auto ret = fn.Eval(Get(static_cast< SQInteger >(i)));
|
||||||
|
// (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)
|
||||||
|
{
|
||||||
|
ValidIdx_(p);
|
||||||
|
ValidIdx_(p + n);
|
||||||
|
// Iterate specified range
|
||||||
|
for (n += p; p < n; ++p)
|
||||||
|
{
|
||||||
|
auto ret = fn.Eval(Get(static_cast< SQInteger >(p)));
|
||||||
|
// (null || true) == continue & false == break
|
||||||
|
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a wrapped instance as a script object.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD static std::pair< LightObj, W * > Obj(T * ptr, bool owned = false)
|
||||||
|
{
|
||||||
|
// Create the wrapper instance for given pointer
|
||||||
|
auto wp = std::make_unique< W >(ptr, false);
|
||||||
|
// Create script object for wrapper instance
|
||||||
|
std::pair< LightObj, W * > p{LightObj{wp.get()}, wp.get()};
|
||||||
|
// Release ownership of the wrapper instance
|
||||||
|
[[maybe_unused]] auto _ = wp.release();
|
||||||
|
// Return the script object and wrapper instance
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a wrapped instance as a script object.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD static std::pair< LightObj, W * > Obj(const T * ptr, bool owned = false)
|
||||||
|
{
|
||||||
|
return Obj(const_cast< T * >(ptr), owned);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template < class T, class W, class U > inline void Register_DPP_VectorProxy(HSQUIRRELVM vm, Table & ns, const SQChar * name)
|
||||||
|
{
|
||||||
|
using Container = DpVectorProxy< T, W >;
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
ns.Bind(name,
|
||||||
|
Class< Container, NoConstructor< Container > >(vm, U::Str)
|
||||||
|
// Meta-methods
|
||||||
|
.SquirrelFunc(_SC("_typename"), &U::Fn)
|
||||||
|
// Properties
|
||||||
|
.Prop(_SC("Null"), &Container::IsNull)
|
||||||
|
.Prop(_SC("Empty"), &Container::Empty)
|
||||||
|
.Prop(_SC("Size"), &Container::Size)
|
||||||
|
.Prop(_SC("Capacity"), &Container::Capacity, &Container::Reserve)
|
||||||
|
// Member Methods
|
||||||
|
.Func(_SC("Get"), &Container::Get)
|
||||||
|
.Func(_SC("Set"), &Container::Set)
|
||||||
|
.Func(_SC("Reserve"), &Container::Reserve)
|
||||||
|
.Func(_SC("Compact"), &Container::Compact)
|
||||||
|
.Func(_SC("Clear"), &Container::Clear)
|
||||||
|
.Func(_SC("Push"), &Container::Push)
|
||||||
|
.Func(_SC("Append"), &Container::Push)
|
||||||
|
.Func(_SC("Extend"), &Container::Extend)
|
||||||
|
.Func(_SC("Pop"), &Container::Pop)
|
||||||
|
.Func(_SC("EraseAt"), &Container::EraseAt)
|
||||||
|
.Func(_SC("Each"), &Container::Each)
|
||||||
|
.Func(_SC("EachRange"), &Container::EachRange)
|
||||||
|
.Func(_SC("While"), &Container::While)
|
||||||
|
.Func(_SC("WhileRange"), &Container::WhileRange)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Namespace:: SqMod
|
Loading…
Reference in New Issue
Block a user