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/Role.cpp Library/DPP/Role.hpp
|
||||
Library/DPP/User.cpp Library/DPP/User.hpp
|
||||
Library/DPP/Utilities.cpp Library/DPP/Utilities.hpp
|
||||
)
|
||||
endif()
|
||||
# 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