mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Add a basic ID pool.
This commit is contained in:
parent
c0d142ab34
commit
8d15f4b6e9
@ -8,6 +8,9 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_DECL_TYPENAME(SqIdPoolTypename, _SC("SqIdPool"))
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
* Probably not the best implementation but should cover all sorts of weird cases.
|
* Probably not the best implementation but should cover all sorts of weird cases.
|
||||||
*/
|
*/
|
||||||
@ -83,15 +86,18 @@ static SQInteger SqExtractIPv4(HSQUIRRELVM vm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
extern void Register_IdPool(HSQUIRRELVM vm, Table & ns);
|
||||||
extern void Register_Vector(HSQUIRRELVM vm, Table & ns);
|
extern void Register_Vector(HSQUIRRELVM vm, Table & ns);
|
||||||
extern void Register_Native_String(HSQUIRRELVM vm, Table & ns);
|
extern void Register_Native_String(HSQUIRRELVM vm, Table & ns);
|
||||||
extern void Register_ServerAnnouncer(HSQUIRRELVM vm, Table & ns);
|
extern void Register_ServerAnnouncer(HSQUIRRELVM vm, Table & ns);
|
||||||
|
|
||||||
|
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
void Register_Utils(HSQUIRRELVM vm)
|
void Register_Utils(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
Table ns(vm);
|
Table ns(vm);
|
||||||
|
|
||||||
|
Register_IdPool(vm, ns);
|
||||||
Register_Vector(vm, ns);
|
Register_Vector(vm, ns);
|
||||||
Register_Native_String(vm, ns);
|
Register_Native_String(vm, ns);
|
||||||
Register_ServerAnnouncer(vm, ns);
|
Register_ServerAnnouncer(vm, ns);
|
||||||
@ -101,4 +107,35 @@ void Register_Utils(HSQUIRRELVM vm)
|
|||||||
RootTable(vm).Bind(_SC("SqUtils"), ns);
|
RootTable(vm).Bind(_SC("SqUtils"), ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void Register_IdPool(HSQUIRRELVM vm, Table & ns)
|
||||||
|
{
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
ns.Bind(_SC("IdPool"),
|
||||||
|
Class< SqIdPool, NoCopy< SqIdPool > >(vm, SqIdPoolTypename::Str)
|
||||||
|
// Constructors
|
||||||
|
.Ctor()
|
||||||
|
.template Ctor< SqIdPool::Type >()
|
||||||
|
.template Ctor< SqIdPool::Type, SqIdPool::Type >()
|
||||||
|
// Meta-methods
|
||||||
|
.SquirrelFunc(_SC("_typename"), &SqIdPoolTypename::Fn)
|
||||||
|
// Member Variables
|
||||||
|
.ConstVar(_SC("Next"), &SqIdPool::mNext)
|
||||||
|
.ConstVar(_SC("Step"), &SqIdPool::mStep)
|
||||||
|
.ConstVar(_SC("Start"), &SqIdPool::mStart)
|
||||||
|
// Properties
|
||||||
|
.Prop(_SC("FreeCount"), &SqIdPool::FreeCount)
|
||||||
|
.Prop(_SC("UsedCount"), &SqIdPool::UsedCount)
|
||||||
|
// Member Methods
|
||||||
|
.Func(_SC("Reset"), &SqIdPool::Reset)
|
||||||
|
.Func(_SC("Acquire"), &SqIdPool::Acquire)
|
||||||
|
.Func(_SC("Release"), &SqIdPool::Release)
|
||||||
|
.Func(_SC("Using"), &SqIdPool::Using)
|
||||||
|
.Func(_SC("EachUsed"), &SqIdPool::EachUsed)
|
||||||
|
.Func(_SC("WhileUsed"), &SqIdPool::WhileUsed)
|
||||||
|
.Func(_SC("EachFree"), &SqIdPool::EachFree)
|
||||||
|
.Func(_SC("WhileFree"), &SqIdPool::WhileFree)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
@ -6,4 +6,187 @@
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* Helper utility used to provide reusable unique IDs of signed integer type.
|
||||||
|
* It is not thread-safe since the script runs in single-threaded mode.
|
||||||
|
*/
|
||||||
|
struct SqIdPool
|
||||||
|
{
|
||||||
|
using Type = SQInteger; // Type that is used to represent an ID.
|
||||||
|
using Pool = std::vector< Type >; // Container for both used and unused IDs.
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
// Pool of available IDs.
|
||||||
|
Pool mPool{};
|
||||||
|
// Pool of currently used IDs.
|
||||||
|
Pool mUsed{};
|
||||||
|
// The ID that will be generated next time the pool is empty.
|
||||||
|
Type mNext{0};
|
||||||
|
// How much to increment with each ID.
|
||||||
|
Type mStep{1};
|
||||||
|
// Where to start generating IDs.
|
||||||
|
Type mStart{0};
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Base constructors.
|
||||||
|
*/
|
||||||
|
SqIdPool() noexcept = default;
|
||||||
|
SqIdPool(Type start) noexcept
|
||||||
|
: SqIdPool(start, 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
SqIdPool(Type start, Type step) noexcept
|
||||||
|
: mPool(), mUsed(), mNext(start), mStep(step), mStart(start)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copy/Move constructors (disabled).
|
||||||
|
*/
|
||||||
|
SqIdPool(const SqIdPool &) noexcept = delete;
|
||||||
|
SqIdPool(SqIdPool &&) noexcept = delete;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copy/Move assignment operators (disabled).
|
||||||
|
*/
|
||||||
|
SqIdPool & operator = (const SqIdPool &) noexcept = delete;
|
||||||
|
SqIdPool & operator = (SqIdPool &&) noexcept = delete;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Discard all current IDs (free and used) and reset the start to the specified start.
|
||||||
|
* This invalidates all IDs that are currently left in use.
|
||||||
|
*/
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
mNext = mStart;
|
||||||
|
mPool.clear();
|
||||||
|
mUsed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Acquire a unique ID from the pool.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD Type Acquire()
|
||||||
|
{
|
||||||
|
Type id = mNext;
|
||||||
|
// Do we have some reusable IDs?
|
||||||
|
if (mPool.empty())
|
||||||
|
{
|
||||||
|
mNext += mStep; // Create a new one and update the next one
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id = mPool.back(); // Get one from the back of the pool
|
||||||
|
mPool.pop_back(); // Remove it from the free pool
|
||||||
|
}
|
||||||
|
// Store it in the list of active IDs
|
||||||
|
mUsed.push_back(id);
|
||||||
|
// Return this ID
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Release a unique ID back to the pool.
|
||||||
|
*/
|
||||||
|
bool Release(Type id)
|
||||||
|
{
|
||||||
|
// Find the specified ID into
|
||||||
|
for (Pool::size_type i = 0; i < mUsed.size(); ++i)
|
||||||
|
{
|
||||||
|
// Is this the ID we're looking for?
|
||||||
|
if (mUsed[i] == id)
|
||||||
|
{
|
||||||
|
// Swap the element with the last one
|
||||||
|
std::swap(mUsed[i], mUsed.back());
|
||||||
|
// Remove the last element
|
||||||
|
mUsed.pop_back();
|
||||||
|
// Make this ID available, again
|
||||||
|
mPool.push_back(id);
|
||||||
|
// We actually found this ID
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This ID does not belong to this pool
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Check if the pool has the specified ID currently in use.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD bool Using(Type id)
|
||||||
|
{
|
||||||
|
return std::find(mUsed.begin(), mUsed.end(), id) != mUsed.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the number of IDs that are currently available in the free pool.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD SQInteger FreeCount() const
|
||||||
|
{
|
||||||
|
return mPool.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the number of IDs that are currently in use.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD SQInteger UsedCount() const
|
||||||
|
{
|
||||||
|
return mUsed.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate all used IDs through a functor.
|
||||||
|
*/
|
||||||
|
void EachUsed(Function & fn) const
|
||||||
|
{
|
||||||
|
for (const auto & id : mUsed)
|
||||||
|
{
|
||||||
|
fn.Execute(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate all used IDs through a functor until stopped (i.e false is returned).
|
||||||
|
*/
|
||||||
|
void WhileUsed(Function & fn) const
|
||||||
|
{
|
||||||
|
for (const auto & id : mUsed)
|
||||||
|
{
|
||||||
|
auto ret = fn.Eval(id);
|
||||||
|
// (null || true) == continue & false == break
|
||||||
|
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate all free IDs through a functor.
|
||||||
|
*/
|
||||||
|
void EachFree(Function & fn) const
|
||||||
|
{
|
||||||
|
for (const auto & id : mPool)
|
||||||
|
{
|
||||||
|
fn.Execute(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate all free IDs through a functor until stopped (i.e false is returned).
|
||||||
|
*/
|
||||||
|
void WhileFree(Function & fn) const
|
||||||
|
{
|
||||||
|
for (const auto & id : mPool)
|
||||||
|
{
|
||||||
|
auto ret = fn.Eval(id);
|
||||||
|
// (null || true) == continue & false == break
|
||||||
|
if (!ret.IsNull() || !ret.template Cast< bool >())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
Loading…
Reference in New Issue
Block a user